如何在eBPF程序中从pt_regs读取socket->sk并通过验证器
解决eBPF kprobe读取newsock->sk的权限拒绝问题
问题核心
你遇到的R6 invalid mem access 'inv'错误,是eBPF验证器对内核内存访问的安全限制导致的:直接解引用内核指针的多层访问(比如newsock->sk)会被验证器判定为非法,即使你用bpf_probe_read_kernel读取单个字段成功,多层指针访问仍需严格遵循安全规则。
读取newsock->sk的正确方法
1. 用嵌套的bpf_probe_read_kernel读取
struct socket中的sk是二级指针,不能直接访问,必须通过bpf_probe_read_kernel先将sk指针读取到局部变量,再操作该变量。示例代码如下:
// 仅定义需要的字段,偏移需匹配目标内核版本 struct socket { struct sock *sk; }; struct sock { // 根据需求定义需要的字段,比如连接状态 int sk_state; }; SEC("kprobe/inet_accept") int BPF_KPROBE(inet_accept, struct socket *sock, struct socket *newsock, int flags) { struct sock *sk; // 先读取newsock->sk到局部变量sk if (bpf_probe_read_kernel(&sk, sizeof(sk), &newsock->sk) != 0) { return 0; } // 读取sk的字段,比如连接状态 int sk_state; if (bpf_probe_read_kernel(&sk_state, sizeof(sk_state), &sk->sk_state) != 0) { return 0; } // 后续处理逻辑 return 0; }
2. 确认内核结构体偏移的正确性
不同内核版本中struct socket的字段偏移可能不同,你可以通过以下命令查看目标内核的结构体定义:
bpftool btf dump file /sys/kernel/btf/vmlinux format c | grep -A 30 "struct socket"
确保代码中sk字段的偏移与内核实际定义一致,偏移错误会直接触发验证器的非法访问报错。
3. 增加指针有效性检查
在读取sk之前,先通过读取newsock的其他字段(比如type)验证newsock指针的合法性,只有读取成功后再继续操作sk,验证器会认可这种安全的访问流程。
通过eBPF验证器的关键规则
- 必须使用安全读取函数:所有内核内存访问都要通过
bpf_probe_read_kernel(内核空间)或bpf_probe_read_user(用户空间),禁止直接解引用内核指针。 - 避免多层直接解引用:二级及以上指针必须先读取到局部变量,再对局部变量进行操作。
- 匹配内核结构体偏移:确保代码中使用的字段偏移与目标内核的BTF定义一致,可通过
bpftool工具确认。 - 添加错误检查:对
bpf_probe_read_kernel的返回值进行判断,只有读取成功时才执行后续逻辑,验证器会认为这种访问是安全的。
内容的提问来源于stack exchange,提问作者dcy
相关产品推荐
相关产品推荐

