-
Notifications
You must be signed in to change notification settings - Fork 707
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
perf readRawSample fails when bpf_perf_event_output submit buffer larger than 64k (appending skb) #1633
Comments
Thanks @alban for the detailed report 🙏 |
Thanks @florianl for looking into this. tl;dr: maybe the issues are in the kernel and in my code (and not in cilium/ebpf). The bpf program itself does not copy any bytes from the packet into event: this is done by the
/* BPF_FUNC_perf_event_output, BPF_FUNC_perf_event_read and
* BPF_FUNC_perf_event_read_value flags.
*/
enum {
BPF_F_INDEX_MASK = 0xffffffffULL,
BPF_F_CURRENT_CPU = BPF_F_INDEX_MASK,
/* BPF_FUNC_perf_event_output for sk_buff input context. */
BPF_F_CTXLEN_MASK = (0xfffffULL << 32),
}; AFAIU, the semantics of the ---
title: "bpf_perf_event_output(u64 flags)"
---
packet-beta
0-19: "reserved (12 bits)"
20-31: "ctx size (20 bits)"
32-63: "index in map, or BPF_F_CURRENT_CPU (-1) to select the current CPU (32 bits)"
So my code is meant to say:
There might be several things to address:
On the other hand, I noticed the following code pattern in cilium/ebpf: for {
record, err := rd.Read()
if err != nil {
if errors.Is(err, ringbuf.ErrClosed) {
log.Println("received signal, exiting..")
return
}
log.Printf("reading from reader: %s", err)
continue
} So the error is just ignored, and we "continue" to the next iteration of the loop. Whereas my code has the following pattern: for {
rec, err := t.perfReader.Read()
if err != nil {
return err
} So the error is not ignored and we stop iterating the loop. I have not yet tested if the userspace reader recovers if we replace the return by a continue. This is probably why it stopped working (and not due a bug in cilium/ebpf). |
Describe the bug
Perf events of type PERF_RECORD_SAMPLE contains a header with the 16-bit size, read in readRecord:
It is followed by another 32-bit size field, read in readRawSample:
Unfortunately, it is possible for a bpf program to submit a record larger than 64kB by appending a small event with a 65507-byte UDP packet:
The kernel calculates the header size in perf_sample_data_size. This returns a u32. Then, it just casts it in the u16 field in perf_prepare_header. See also bpf_event_output and perf_sample_save_raw_data.
This means that
perfEventHeader->Size
has a small number due to integer overflow. AndperfEventSample->Size
has a >64kB number.Unfortunately, cilium/ebpf does not notice the inconsistency and I get errors such as:
How to reproduce
Generate a large UDP packet:
Attach a socket filter using cilium/ebpf and read from the perf ring buffer:
Version information
github.com/cilium/ebpf v0.16.0 => github.com/cilium/ebpf v0.16.1-0.20241023154409-d3c63ab2edcb
The text was updated successfully, but these errors were encountered: