I'm trying to use an eBPF map which looks like this:
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, MAX_ENTRIES);
__type(key, u32);
__type(value, struct sock_info *);
} lookup SEC(".maps");
and sock_info is defined as follows:
struct sock_info {
__u64 ctime;
__u16 sport;
__u16 dport;
};
When I try to access the value from the map, I am able to read ctime correctly but run into a verifier error accessing sport and 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 --
When I modify the struct as follows:
struct sock_info {
__u16 sport;
__u16 dport;
__u64 ctime;
};
I can read the values of sport and dport but ctime breaks
; 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 --
I looked at this article but it seems to be related to bpf_sock_ops which I'm not working with.
Kernel info:
$ uname -a
Linux debian 5.10.0-20-arm64 #1 SMP Debian 5.10.158-2 (2022-12-13) aarch64 GNU/Linux
If you want to store object of type struct sock_info
in your BPF map, then its declaration should be:
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, MAX_ENTRIES);
__type(key, u32);
__type(value, struct sock_info);
} lookup SEC(".maps");
Note how the value
type is not a pointer anymore. Your C code for the lookup doesn't need to change.
The verifier fails in this way because it assumes that you wanted to store pointers into the map. So it allows you to access 64-bits worth of map value since that's the size of a pointer. Any more and it assumes you're doing an out-of-bound access.