From 0528557ee9f14ed292de49be09e65b8662185c38 Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Sat, 2 May 2026 10:01:15 +0300 Subject: fix BPF tracepoint context type for RHEL 9 stock kernel The BPF handler generator emitted struct trace_event_raw_sys_enter/ trace_event_raw_sys_exit (the BTF-blessed aliases). RHEL 9 carries an rt-tree backport that adds preempt_lazy_count to struct trace_entry, which widens those aliases by 8 bytes and shifts args/ret. The actual tracepoint context the kernel hands the program is still syscall_trace_enter / syscall_trace_exit, where the offsets did not move. Programs typed against the wider alias read past max_ctx_offset and the verifier rejects the attach with EACCES. Switching the generator to emit syscall_trace_enter/exit lines up with the real context on RHEL 9 (and is identical on every other distro, since the two structs only diverge there). Same fix bcc shipped in iovisor/bcc#4920 and inspektor-gadget did in inspektor-gadget#2546. Field accesses (ctx->args[N], ctx->ret) are unchanged. Verified end-to-end on Rocky Linux 9.7 stock 5.14.0-611.5.1.el9_7 (no kernel-ml needed) and Fedora 6.19. README rewritten accordingly: drops the elrepo kernel-ml step and the trailing 'permission denied' troubleshooting paragraph; adds a historical note explaining why the old workaround existed. Co-Authored-By: Claude Opus 4.7 --- internal/generate/codegen_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'internal/generate/codegen_test.go') diff --git a/internal/generate/codegen_test.go b/internal/generate/codegen_test.go index caad340..7a7d469 100644 --- a/internal/generate/codegen_test.go +++ b/internal/generate/codegen_test.go @@ -16,7 +16,7 @@ func TestGenerateFdHandler(t *testing.T) { output := generateFromPair(t, FormatRead, FormatExitRead) requireContains(t, output, `SEC("tracepoint/syscalls/sys_enter_read")`) - requireContains(t, output, "struct trace_event_raw_sys_enter *ctx") + requireContains(t, output, "struct syscall_trace_enter *ctx") requireContains(t, output, "struct fd_event *ev = bpf_ringbuf_reserve(&event_map, sizeof(struct fd_event), 0);") requireContains(t, output, "ev->event_type = ENTER_FD_EVENT;") requireContains(t, output, "ev->trace_id = SYS_ENTER_READ;") @@ -70,7 +70,7 @@ func TestGenerateRetHandlerRead(t *testing.T) { output := generateFromPair(t, FormatRead, FormatExitRead) requireContains(t, output, `SEC("tracepoint/syscalls/sys_exit_read")`) - requireContains(t, output, "struct trace_event_raw_sys_exit *ctx") + requireContains(t, output, "struct syscall_trace_exit *ctx") requireContains(t, output, "struct ret_event *ev") requireContains(t, output, "ev->event_type = EXIT_RET_EVENT;") requireContains(t, output, "ev->trace_id = SYS_EXIT_READ;") @@ -226,7 +226,7 @@ func TestGenerateDefinesSortedByIDDesc(t *testing.T) { func TestGenerateHandlerStructure(t *testing.T) { output := generateFromPair(t, FormatClose, FormatExitClose) - requireContains(t, output, "int handle_sys_enter_close(struct trace_event_raw_sys_enter *ctx) {") + requireContains(t, output, "int handle_sys_enter_close(struct syscall_trace_enter *ctx) {") requireContains(t, output, "__u32 pid, tid;") requireContains(t, output, "if (filter(&pid, &tid))") requireContains(t, output, "ev->pid = pid;") -- cgit v1.2.3