Skip to content

libbpf-tools: Fix ringbuf leaks that leak prior events to userspace#5506

Open
vdasu wants to merge 1 commit intoiovisor:masterfrom
vdasu:ringbuf_leaks
Open

libbpf-tools: Fix ringbuf leaks that leak prior events to userspace#5506
vdasu wants to merge 1 commit intoiovisor:masterfrom
vdasu:ringbuf_leaks

Conversation

@vdasu
Copy link
Copy Markdown

@vdasu vdasu commented May 1, 2026

Five libbpf-tools (mountsnoop, opensnoop, filelife, oomkill, and tcppktlat) call reserve_buf() to obtain an event buffer, populate a subset of the event's fields, and emit the full sizeof(*eventp) bytes via submit_buf(). Neither path of reserve_buf() (bpf_ringbuf_reserve() or the per-CPU array heap fallback) zero-initializes the returned memory. Any bytes the source-level path leaves unwritten retain whatever the slot held previously. This can leak previously emitted record content back to userspace on subsequent events.

The mountsnoop leak was tested on Linux 6.8. Since struct event contains a tagged union with one active arm per syscall operation, and only the arm matching argp->op is written, the inactive union bytes contained prior MOUNT records' src, dest, fs, and data paths.

A natural approach to zero the memory would be to use __builtin_memset(eventp, 0, sizeof(*eventp)). This does not seem to work reliably for larger BPF event structs: once the size exceeds LLVM's inline-store budget, LLVM may lower the memset into a libcall. BPF programs cannot link against libc, so the BPF backend has no memset symbol to resolve and compilation fails. The added zero_buf() helper avoids this by writing the byte loop explicitly in a __noinline subprogram, so it lands as a single BPF-to-BPF call shared across sites, and by using volatile writes so LLVM's loop-idiom recognition does not re-lower it back into __builtin_memset.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR mitigates information leaks in several libbpf-tools eBPF programs by ensuring reserved event buffers are explicitly zero-initialized before only a subset of fields are populated and the full event struct is emitted to userspace.

Changes:

  • Add a shared zero_buf() helper in compat.bpf.h to reliably zero event buffers without relying on __builtin_memset codegen.
  • Call zero_buf() immediately after reserve_buf() in mountsnoop, opensnoop, filelife, oomkill, and tcppktlat BPF programs.
  • Ensure that inactive/unused bytes in event structs (e.g., union arms) don’t retain prior record contents.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
libbpf-tools/compat.bpf.h Adds zero_buf() helper to clear reserved event buffers safely for BPF.
libbpf-tools/mountsnoop.bpf.c Zero-initializes struct event after reserving buffer to avoid union residue leaks.
libbpf-tools/opensnoop.bpf.c Zero-initializes struct event after reserving buffer before populating fields.
libbpf-tools/filelife.bpf.c Zero-initializes struct event after reserving buffer prior to filling output.
libbpf-tools/oomkill.bpf.c Zero-initializes struct data_t after reserving buffer prior to filling output.
libbpf-tools/tcppktlat.bpf.c Zero-initializes struct event after reserving buffer before populating fields.

Comment thread libbpf-tools/compat.bpf.h
Comment on lines +49 to +54
* recognition, which would otherwise re-lower this back to __builtin_memset
* (which the BPF backend cannot inline for buffers larger than ~256 bytes). */
static __noinline void zero_buf(void *p, __u64 sz)
{
for (__u64 i = 0; i < sz; i++)
*(volatile char *)((char *)p + i) = 0;
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ekyooo I can commit this optimization if you think it is necessary.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants