【问题标题】:BPF verifier rejetcs the use of an inode ptr as a keyBPF 验证者拒绝使用 inode ptr 作为密钥
【发布时间】:2021-10-02 01:56:23
【问题描述】:

我正在尝试实现一个 eBPF 代码,其中我有一个 BPF MAP,其键类型为 struct 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 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 --

我不明白为什么,因为与 struct socket * 类似的方法可以正常工作。 任何帮助将不胜感激。 内核 v 5.13.0-051300-generic

【问题讨论】:

    标签: bpf ebpf


    【解决方案1】:
    R2 type=inv expected=fp, pkt, pkt_meta, map_key, map_value
    

    验证器告诉您调用bpf_map_lookup_elem() 的第二个参数(在R2 中)不是预期的类型。它可以指向堆栈 (fp)、数据包数据 (pkt) 或元数据 (pkt_meta),或另一个映射键或值 (map_keymap_value)。

    在您的情况下,BPF_CORE_READ() 返回一个标量 (inv),而 dir 返回一个 BTF id (ptr_),两者都不合适。您可以尝试先将密钥的数据复制到 eBPF 堆栈(将其分配给临时变量,并将对该变量的引用传递给帮助程序)。无论如何,您可能不想使用 full struct inode 作为密钥。

    【讨论】:

    • 谢谢。我实际上不想使用完整的 struct inode 而是使用指向它的指针作为键。事实证明,据我所知,BPF 不允许这些操作,除非它是一个 socket struct *,这是一种特殊情况。我可以将它分配给一些 unsigned long 变量并将其用作键
    猜你喜欢
    • 2013-01-21
    • 2020-08-25
    • 2017-02-26
    • 2014-06-02
    • 2021-07-27
    • 2019-04-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多