使用bpf_probe_read_kernel_str时变量作第二个参数引发eBPF验证器报错
解决eBPF验证器"R2 unbounded memory access"报错问题
问题原因
eBPF验证器报错是因为它无法确认name_len的取值范围,认为传入bpf_probe_read_kernel_str的长度参数可能导致越界访问。你加const修饰没用是因为const只是限制变量不能被修改,没法让验证器知道这个值的实际边界范围。
解决步骤
核心思路是给name_len加上明确的上限约束,让验证器能确定它不会超出安全范围,具体可以这么改:
- 定义文件名长度上限常量
先定义一个符合系统实际的文件名最大长度(通用的NAME_MAX是255,也可以手动设置合理值):
#define MAX_NAME_LEN 255
- 添加边界检查约束
在获取name_len后,立即加上限制,确保它不会超过上限:
int name_len = BPF_CORE_READ(curr_dentry, d_name.len); // 超过文件名最大长度直接退出当前循环 if (name_len > MAX_NAME_LEN) { break; }
- 结合剩余缓冲区空间做双重限制
目标缓冲区filename的剩余空间是512 - pos,把传入bpf_probe_read_kernel_str的长度参数设为两者的最小值,进一步确保安全:
int copy_len = name_len; if (copy_len > 512 - pos) { copy_len = 512 - pos; } name_len = bpf_probe_read_kernel_str(filename + pos, copy_len, name);
修改后的完整代码片段
#define MAX_NAME_LEN 255 size_t pos = 0; const u32 MAX_BACKTRACE_DEPTH = 20; for (u32 cnt = MAX_BACKTRACE_DEPTH; cnt != 0; --cnt) { if (err || curr_dentry == NULL) { break; } int name_len = BPF_CORE_READ(curr_dentry, d_name.len); const u8 *name = BPF_CORE_READ(curr_dentry, d_name.name); // 限制name_len不超过文件名最大长度 if (name_len > MAX_NAME_LEN) { break; } if (name_len <= 1) { break; } if (name_len + pos > 512) { break; } // 确保拷贝长度不超过剩余缓冲区空间 int copy_len = name_len; if (copy_len > 512 - pos) { copy_len = 512 - pos; } name_len = bpf_probe_read_kernel_str(filename + pos, copy_len, name); if (name_len <= 1) { break; } pos += name_len; filename[pos - 1] = '/'; struct dentry *temp_dentry = BPF_CORE_READ(curr_dentry, d_parent); if (temp_dentry == curr_dentry || temp_dentry == NULL) { break; } curr_dentry = temp_dentry; }
为什么这样能解决问题
eBPF验证器需要明确知道内存访问的边界,通过显式的name_len > MAX_NAME_LEN判断,验证器能确定name_len的最大值不会超过255;再结合剩余缓冲区空间的检查,彻底消除了越界访问的风险,自然就能通过验证。
内容的提问来源于stack exchange,提问作者nothing_hooooo
相关产品推荐
相关产品推荐

