bpf - BPF 验证者拒绝使用 inode ptr 作为密钥
问题描述
我正在尝试实现一个 eBPF 代码,其中我有一个带有类型键 struct inode *
和一些值的 BPF MAP。请看下面的示例代码
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 value *val = bpf_map_lookup_elem(&info, p);
if (val == NULL)
{
bpf_printk("not handling");
return 0;
}
return 0;
}
验证者不喜欢这样:
libbpf: -- BEGIN DUMP LOG ---
libbpf:
R1 type=ctx expected=fp
; int BPF_PROG(
0: (b7) r2 = 48
; int BPF_PROG(
1: (79) r3 = *(u64 *)(r1 +16)
func 'vfs_unlink' arg2 has btf_id 691 type STRUCT 'dentry'
2: (0f) r3 += r2
last_idx 2 first_idx 0
regs=4 stack=0 before 1: (79) r3 = *(u64 *)(r1 +16)
regs=4 stack=0 before 0: (b7) r2 = 48
3: (bf) r1 = r10
;
4: (07) r1 += -16
; struct inode * p = BPF_CORE_READ(dentry,d_inode);
5: (b7) r2 = 8
6: (85) call bpf_probe_read_kernel#113
last_idx 6 first_idx 0
regs=4 stack=0 before 5: (b7) r2 = 8
; struct inode * p = BPF_CORE_READ(dentry,d_inode);
7: (79) r2 = *(u64 *)(r10 -16)
; struct value *val = bpf_map_lookup_elem(&info, p);
8: (18) r1 = 0xffff93c9f43fc000
10: (85) call bpf_map_lookup_elem#1
R2 type=inv expected=fp, pkt, pkt_meta, map_key, map_value
processed 10 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0
libbpf: -- END LOG --
我也无法直接将参数 ptr 作为键传递,例如:
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 value *val = bpf_map_lookup_elem(&info, dir);
if (val == NULL)
{
bpf_printk("not handling");
return 0;
}
return 0;
}
产生:
libbpf: -- BEGIN DUMP LOG ---
libbpf:
R1 type=ctx expected=fp
; int BPF_PROG(
0: (79) r2 = *(u64 *)(r1 +8)
func 'vfs_unlink' arg1 has btf_id 694 type STRUCT 'inode'
; struct value *val = bpf_map_lookup_elem(&info, dir);
1: (18) r1 = 0xffff93caed64c400
3: (85) call bpf_map_lookup_elem#1
R2 type=ptr_ expected=fp, pkt, pkt_meta, map_key, map_value
processed 3 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0
libbpf: -- END LOG --
我不明白为什么,因为与 eg 类似的方法struct socket *
效果很好。任何帮助将不胜感激。内核 v 5.13.0-051300-generic
解决方案
R2 type=inv expected=fp, pkt, pkt_meta, map_key, map_value
验证程序告诉您R2
调用的第二个参数 (in )bpf_map_lookup_elem()
不是预期的类型。它可以指向堆栈 ( fp
)、数据包数据 ( pkt
) 或元数据 ( pkt_meta
),或者指向另一个映射键或值 ( map_key
, map_value
)。
在您的情况下,BPF_CORE_READ()
返回标量 ( inv
) 和dir
BTF id ( ptr_
),两者都不合适。您可以尝试先将密钥的数据复制到 eBPF 堆栈(将其分配给临时变量,并将对该变量的引用传递给帮助程序)。无论如何,您可能不想使用完整 struct inode
的密钥。
推荐阅读
- javascript - fetchAPI 没有返回响应,因为 then() 被跳过
- c++ - 用累加器添加二进制数
- opengl - GLFW 3:如何使用 ScrollCallback (LWJGL 3) 获取鼠标滚轮的增量
- sql - 无法使用“read_sql”调用 SQL 查询类
- javascript - Jquery根据id克隆带有标签的输入
- python - 给定一组三角形顶点和面,分离对象并形成单独的网格
- microsoft-teams - 自适应卡片输入切换(复选框)IOS问题
- javascript - 下拉菜单在 Chrome 中显示正常,但在 Safari 中不显示(由图像覆盖)
- javascript - RegExp (javascript) :: find a group of php variables including the $ character (Enlighter JS)
- python - Python - TypeError: super(type, obj): obj 必须是类型的实例或子类型?