eBPF 验证器在使用 __u64 元素读取映射值结构时出错

问题描述 投票:0回答:1

我正在尝试使用如下所示的 eBPF 映射:

struct {
    __uint(type, BPF_MAP_TYPE_HASH);
    __uint(max_entries, MAX_ENTRIES);
    __type(key, u32);
    __type(value, struct sock_info *);
} lookup SEC(".maps");

和sock_info定义如下:

struct sock_info {
    __u64 ctime;
    __u16 sport;
    __u16 dport;
};

当我尝试从地图访问值时,我能够正确读取 ctime 但在访问 sport 和 dport 时遇到验证程序错误

struct sock_info *og_sock = bpf_map_lookup_elem(&lookup,&pid);

if(og_sock) {
    const char foo[] = "output %llu";
    bpf_trace_printk(foo,sizeof(foo),og_sock->ctime);
}
10: (b7) r1 = 7695468
; const char foo[] = "output %llu";
11: (63) *(u32 *)(r10 -8) = r1
12: (18) r1 = 0x252074757074756f
14: (7b) *(u64 *)(r10 -16) = r1
; bpf_trace_printk(foo,sizeof(foo),og_sock->sport);
15: (69) r3 = *(u16 *)(r0 +8)
 R0=map_value(id=0,off=0,ks=4,vs=8,imm=0) R1_w=inv2675266226404750703 R10=fp0 fp-8=mmmmmmmm fp-16_w=inv2675266226404750703
invalid access to map value, value_size=8 off=8 size=2
R0 min value is outside of the allowed memory range
processed 14 insns (limit 1000000) max_states_per_insn 0 total_states 1 peak_states 1 mark_read 1
-- END PROG LOAD LOG --

当我修改结构如下:

struct sock_info {
    __u16 sport;
    __u16 dport;
    __u64 ctime;
};

我可以阅读运动和运动的价值,但 ctime 休息

; if(og_sock) {
9: (15) if r0 == 0x0 goto pc+10
 R0=map_value(id=0,off=0,ks=4,vs=8,imm=0) R10=fp0 fp-8=mmmm????
10: (b7) r1 = 7695468
; const char foo[] = "output %llu";
11: (63) *(u32 *)(r10 -8) = r1
12: (18) r1 = 0x252074757074756f
14: (7b) *(u64 *)(r10 -16) = r1
; bpf_trace_printk(foo,sizeof(foo),og_sock->ctime);
15: (79) r3 = *(u64 *)(r0 +8)
 R0=map_value(id=0,off=0,ks=4,vs=8,imm=0) R1_w=inv2675266226404750703 R10=fp0 fp-8=mmmmmmmm fp-16_w=inv2675266226404750703
invalid access to map value, value_size=8 off=8 size=8
R0 min value is outside of the allowed memory range
processed 14 insns (limit 1000000) max_states_per_insn 0 total_states 1 peak_states 1 mark_read 1
-- END PROG LOAD LOG --

我看了这篇文章,但它似乎与我没有使用的 bpf_sock_ops 有关。

内核信息:

$ uname -a
Linux debian 5.10.0-20-arm64 #1 SMP Debian 5.10.158-2 (2022-12-13) aarch64 GNU/Linux
ebpf libbpf
1个回答
0
投票

如果你想在 BPF 映射中存储

struct sock_info
类型的对象,那么它的声明应该是:

struct {
    __uint(type, BPF_MAP_TYPE_HASH);
    __uint(max_entries, MAX_ENTRIES);
    __type(key, u32);
    __type(value, struct sock_info);
} lookup SEC(".maps");

注意

value
类型不再是指针。 用于查找的 C 代码不需要更改。


验证器以这种方式失败,因为它假定您想要将指针存储到地图中。因此它允许您访问 64 位的映射值,因为这是指针的大小。任何更多,它假设你正在进行越界访问。

© www.soinside.com 2019 - 2024. All rights reserved.