From 04881431fb051fc9915184c54dffdcbb9aa5c65e Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Sat, 30 May 2026 22:11:15 +0300 Subject: test(perf_event_open): lock in audit findings Audited perf_event_open(2) against the man page: it returns a new fd (or -1), args[0] is a struct perf_event_attr* userspace pointer (NOT an fd), args[1] is a monitored pid, and only args[3] group_fd is a real fd. The existing implementation is correct (KindPerfOpen by name, not KindFd; FamilySecurity; exit as UNCLASSIFIED RetEvent). Add lock-in tests: - codegen: assert args[0] is read via bpf_probe_read_user as the attr struct and never captured as an fd (negative assertions on args[0]/args[1]). - eventloop: a failed return (-1) registers no fd in fdState. - perfDescriptorName format pin (perf: prefix). Co-Authored-By: Claude Opus 4.8 --- internal/generate/codegen_test.go | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'internal/generate') diff --git a/internal/generate/codegen_test.go b/internal/generate/codegen_test.go index e841f45..58ed60c 100644 --- a/internal/generate/codegen_test.go +++ b/internal/generate/codegen_test.go @@ -1992,6 +1992,16 @@ func TestGeneratePerfEventOpenHandler(t *testing.T) { requireContains(t, output, "ev->target_pid = (__s32)ctx->args[1];") requireContains(t, output, "ev->group_fd = (__s32)ctx->args[3];") requireContains(t, output, "ev->event_type = EXIT_RET_EVENT;") + + // Audit lock-in (perf_event_open(2)): args[0] is a + // `struct perf_event_attr *` userspace pointer, NOT an fd, and args[1] + // is a pid (not an fd). The handler must read args[0] only via + // bpf_probe_read_user (the attr struct) and never capture args[0] or + // args[1] as an fd. Only group_fd at args[3] is a genuine fd. + requireContains(t, output, "bpf_probe_read_user(&attr, sizeof(attr), (void *)ctx->args[0])") + requireNotContains(t, output, "ev->fd = (__s32)ctx->args[0];") + requireNotContains(t, output, "ev->fd = (__s32)ctx->args[1];") + requireNotContains(t, output, "ev->group_fd = (__s32)ctx->args[0];") } func TestGenerateNameToHandleAtHandler(t *testing.T) { -- cgit v1.2.3