From 6561d63e5a47092d8b8f2a8128ad05ca9ffd2203 Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Fri, 29 May 2026 10:55:42 +0300 Subject: test(generate): lock in map_shadow_stack BPF handler field wiring Audit of the x86 CET map_shadow_stack syscall (Linux 6.6+, void *map_shadow_stack(unsigned long addr, unsigned long size, unsigned int flags)) confirmed the existing tracing is correct: KindMem / FamilyMemory classification, memFieldSpec wires addr=args[0], length=args[1] (size), flags=args[2], length2=0, and the return (mapped address or -errno) is captured generically as ev->ret like every other KindMem exit. Docs and classify tests already match. The only gap was the lack of a codegen lock-in test for the BPF handler field wiring, which mlock2/remap_file_pages/mprotect/brk all have. Add TestGenerateMemHandlerMapShadowStack to guard against future drift. Co-Authored-By: Claude Opus 4.8 --- internal/generate/codegen_test.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'internal') diff --git a/internal/generate/codegen_test.go b/internal/generate/codegen_test.go index ae2d643..09a23a5 100644 --- a/internal/generate/codegen_test.go +++ b/internal/generate/codegen_test.go @@ -280,6 +280,24 @@ func TestGenerateMemHandlerPkeyMprotect(t *testing.T) { requireContains(t, output, "ev->flags = (__u64)ctx->args[2];") } +// TestGenerateMemHandlerMapShadowStack locks in the BPF handler wiring for the +// x86 CET map_shadow_stack syscall (Linux 6.6+): +// void *map_shadow_stack(unsigned long addr, unsigned long size, unsigned int flags). +// The hint addr and size are args[0]/args[1] and flags is args[2]; there is no +// second length, so length2 must stay zero. The return is a mapped address (or +// -errno), captured generically via ev->ret like every other KindMem exit. +func TestGenerateMemHandlerMapShadowStack(t *testing.T) { + output := GenerateTracepointsC(mustParseAll(t, syntheticPair("map_shadow_stack"))) + + requireContains(t, output, `SEC("tracepoint/syscalls/sys_enter_map_shadow_stack")`) + requireContains(t, output, "struct mem_event *ev") + requireContains(t, output, "ev->event_type = ENTER_MEM_EVENT;") + requireContains(t, output, "ev->addr = (__u64)ctx->args[0];") + requireContains(t, output, "ev->length = (__u64)ctx->args[1];") + requireContains(t, output, "ev->length2 = 0;") + requireContains(t, output, "ev->flags = (__u64)ctx->args[2];") +} + func TestGenerateMemHandlerBrk(t *testing.T) { output := GenerateTracepointsC(mustParseAll(t, syntheticPair("brk"))) -- cgit v1.2.3