BPF验证器拒绝使用inode指针作为BPF映射键的问题咨询
问题根因
你的错误属于bpf_map_lookup_elem函数的参数语义使用错误:bpf_map_lookup_elem的第二个入参要求是指向存放键内容的内存区域的指针,而非键本身的值。你定义的映射键类型为struct inode *,即键的内容是inode结构体的地址数值,你直接把这个地址数值作为参数传入,相当于告诉BPF内核“要查找的键存在这个inode地址指向的内存里”,既不符合函数参数要求,也完全违背了你要把inode地址作为键的业务逻辑。
同时BPF验证器要求映射操作的键指针必须指向安全可访问的内存区域(通常是栈内存),你直接传入的inode指针不属于验证器认可的合法内存区域类型,因此触发了报错。
修正方案
你只需要先把作为键的inode指针值存到栈上的变量中,再传入该变量的地址给bpf_map_lookup_elem即可。
代码示例1(从dentry读取inode场景)
struct value { char data[10]; }; struct bpf_map_def info SEC("maps") ={ .type = BPF_MAP_TYPE_HASH, .max_entries = 100, .key_size = sizeof(struct inode *), .value_size = sizeof(struct value), .map_flags = BPF_F_NO_PREALLOC, }; SEC("fexit/vfs_unlink") int BPF_PROG( vfs_unlink_exit, const struct user_namespace *mnt_userns, const struct inode *dir, const struct dentry *dentry, const struct inode **delegated_inode, int ret) { struct inode * p = BPF_CORE_READ(dentry,d_inode); // 新增:将键值存入栈变量 struct inode *inode_key = p; // 修正:传入栈变量的地址作为键指针 struct value *val = bpf_map_lookup_elem(&info, &inode_key); if (val == NULL) { bpf_printk("not handling"); return 0; } return 0; }
代码示例2(直接用入参dir作为键场景)
SEC("fexit/vfs_unlink") int BPF_PROG( vfs_unlink_exit, const struct user_namespace *mnt_userns, const struct inode *dir, const struct dentry *dentry, const struct inode **delegated_inode, int ret) { // 新增:将键值存入栈变量 struct inode *inode_key = (struct inode *)dir; // 修正:传入栈变量的地址作为键指针 struct value *val = bpf_map_lookup_elem(&info, &inode_key); if (val == NULL) { bpf_printk("not handling"); return 0; } return 0; }
额外说明
你之前用struct socket *作为键的逻辑可以正常运行,大概率是你之前的写法已经正确把socket指针存入栈变量再传入了地址,和指针本身的类型没有关系,所有指针类型作为映射键的用法都遵循上述规则。
内容的提问来源于stack exchange,提问作者Igor Polevoy
相关产品推荐
相关产品推荐

