libbpf / libbpf-bootstrap

Scaffolding for BPF application development with libbpf and BPF CO-RE
BSD 3-Clause "New" or "Revised" License
1.09k stars 294 forks source link

How to read arbitrary len bytes using helper bpf_skb_load_bytes()? #254

Open 0x000001A4 opened 8 months ago

0x000001A4 commented 8 months ago

Background

I am currently trying to build an eBPF program to read the content of application data (of arbitrary length) transmitted through two processes.

I tried intercepting packets with Linux TC (like it is done in example tc.bpf.c of this repo) Also tried intercepting packets with Socket Filters (like it is done in example sockfilter.bpf.c of this repo)

Problem

When reading from bpf_skb_load_bytes(), I need to provide an argument len (the last argument). Given variable length messages, that can be smaller than the MAX_BUF_SIZE, for bpf_skb_load_bytes() not to return an error I need to specify the exact size of the payload that should be read.

Question

Can anyone help me understand how to read the amount of bytes that are in the packet's payload? Passing to bpf_skb_load_bytes an arbitrary len argument, computed as the exact number of those bytes?

Attempt 1 to solve the problem

In case it is MAX_BUF_SIZE and the payload size happens to be smaller than MAX_BUF_SIZE, error -14 is returned by bpf_skb_load_bytes; and no information is read. (I also tried this using sockfilter example on this repo and it is exactly what happens if the payload simply having an integer is intercepted).

This takes us to the necessity of computing the size of the payload to read the correct number of bytes from the payload.

Attempt 2 to solve the problem

In case I try to compute the payload_size from skb->len - total_hlen, I have problems with the verifier, which states that payload_len has a negative min value. total_hlen is the total size in bytes used by the eth header (eth_hlen), IP header (ip_hlen) and transport header (tp_hlen). Example in a program below: `

__u32 eth_hlen, ip_hlen, tp_hlen, data_len, total_hlen, payload_len;
char payload[MAX_PAYLOAD_SIZE];
...
total_hlen = eth_hlen + ip_hlen + tp_hlen;

if (skb->len > total_hlen) {
    payload_len = skb->len - total_hlen;
    if (payload_len > sizeof(payload)) payload_len = sizeof(payload);

    long err = bpf_skb_load_bytes(skb, total_hlen, payload, payload_len);
    if (!err) {
        bpf_printk("New packet -> skb_len: %d, data_len: %d | Total_Hlen: %d ETH_Hlen: %d, IP_Hlen: %d, TP_Hlen: %d | payload_len: %d, payload: %s",
            skb->len, data_len, total_hlen, eth_hlen, ip_hlen, tp_hlen, payload_len, payload);
    } else bpf_printk("%d\n", err);
}`
Shreyas220 commented 6 months ago

Hey @0x000001A4 I am facing the exact same error, were you able to find a solution ?

chenhengqi commented 6 months ago

What's your use-case ? Typical network BPF programs don't do that, i.e. load the full packet.