我正在尝试使用如下所示的 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
如果你想在 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 位的映射值,因为这是指针的大小。任何更多,它假设你正在进行越界访问。