Home > Software engineering >  Cannot access __skb_buff in eBPF
Cannot access __skb_buff in eBPF

Time:06-24

I am trying to access the __sk_buff struct passed within the consume_skb tracepoint. However nothing I tried has worked so far. I am running the kernel version 5.4.0. This is what I tried so far, and in what it resulted:

Loader gist

Direct access

SEC("tracepoint/skb/consume_skb")
int handle_skb(struct __sk_buff *skb)
{
    void *data = (void *)(long)skb->data;
    void *data_end = (void *)(long)skb->data_end;
    struct ethhdr *eth = data;
    struct iphdr *iph = data   sizeof(*eth);

    if (data   sizeof(*eth) > data_end)
        return 0;

    if (data   sizeof(*eth)   sizeof(*iph) > data_end)
        return 0;

    bpf_trace_printk("%x\n", eth->h_proto);

    return 0;
}

results in:

libbpf: prog 'handle_skb': BPF program load failed: Permission denied
libbpf: prog 'handle_skb': -- BEGIN PROG LOAD LOG --
; void *data = (void *)(long)skb->data;
0: (61) r2 = *(u32 *)(r1  76)
; void *data_end = (void *)(long)skb->data_end;
1: (61) r1 = *(u32 *)(r1  80)
; struct iphdr *iph = data   sizeof(*eth);
2: (bf) r3 = r2
3: (07) r3  = 14
; if (data   sizeof(*eth) > data_end)
4: (2d) if r3 > r1 goto pc 7
 R1_w=inv(id=0,umax_value=4294967295,var_off=(0x0; 0xffffffff)) R2_w=inv(id=0,umax_value=4294967295,var_off=(0x0; 0xffffffff)) R3_w=inv(id=0,umin_value=14,umax_value=4294967309,var_off=(0x0; 0x1ffffffff)) R10=fp0
;
5: (bf) r3 = r2
6: (07) r3  = 34
; if (data   sizeof(*eth) > data_end)
7: (2d) if r3 > r1 goto pc 4
 R1_w=inv(id=0,umax_value=4294967295,var_off=(0x0; 0xffffffff)) R2_w=inv(id=0,umax_value=4294967295,var_off=(0x0; 0xffffffff)) R3_w=inv(id=0,umin_value=34,umax_value=4294967329,var_off=(0x0; 0x1ffffffff)) R10=fp0
; bpf_trace_printk("%x\n", eth->h_proto);
8: (69) r2 = *(u16 *)(r2  12)
R2 invalid mem access 'inv'
processed 9 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0
-- END PROG LOAD LOG --
libbpf: failed to load program 'handle_skb'
libbpf: failed to load object 'skb_bpf'
libbpf: failed to load BPF skeleton 'skb_bpf': -13
Failed to load and verify BPF skeleton

The way I understand it, is that direct access to skb is not allowed in this context (why?).

bpf_skb_load_bytes

SEC("tracepoint/skb/consume_skb")
int handle_skb(struct __sk_buff *skb)
{
    struct ethhdr *eth;

    int ret;
    ret = skb_load_bytes(skb, 0, eth, sizeof(struct ethhdr));
    //Or alternatively
    //ret = bpf_skb_load_bytes(skb, 0, eth, sizeof(struct ethhdr));

    if (!ret)
    {
        return 0;
    }

    bpf_trace_printk("%x\n", eth->h_proto);

    return 0;
}

which results in:

libbpf: prog 'handle_skb': BPF program load failed: Invalid argument
libbpf: prog 'handle_skb': -- BEGIN PROG LOAD LOG --
; ret = bpf_skb_load_bytes(skb, 0, eth, sizeof(struct ethhdr));
0: (b7) r2 = 0
1: (b7) r4 = 14
2: (85) call bpf_skb_load_bytes#26
unknown func bpf_skb_load_bytes#26
processed 3 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0
-- END PROG LOAD LOG --
libbpf: failed to load program 'handle_skb'
libbpf: failed to load object 'skb_bpf'
libbpf: failed to load BPF skeleton 'skb_bpf': -22
Failed to load and verify BPF skeleton

This confuses me even more, as bpf_skb_load_bytes should be an available helper function.

Now I am doubting how to even access and read (not even write) the __sk_buff. Is there just no way? Or have I missed something?

CodePudding user response:

There are a few things going on here. First is that the argument to the tracepoint is of type struct sk_buff, not struct __sk_buff. I believe you have to use thebpf_probe_read helper to read memory the pointer is pointing to.

Second is that bpf_skb_load_bytes would only work with a __sk_buff. Besides, not all helpers are available for each program type, tracing programs can't use the bpf_skb_load_bytes helper. Here is the code that lists all available helpers for tracepoint programs:

  • Related