summaryrefslogtreecommitdiff
path: root/internal/generate
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-05-29 22:15:30 +0300
committerPaul Buetow <paul@buetow.org>2026-05-29 22:15:30 +0300
commit6a73390713c5248a1ea1cf0baa223afcee64fd01 (patch)
tree2b1a64ebb7a009be403ef836dab1f4ef1de7637e /internal/generate
parent9bd6ed5a7d40ff922a344ab636f804f1c9bb1f12 (diff)
test(remap_file_pages): harden mem handler lock-in test
Audit of remap_file_pages(2): int remap_file_pages(void *addr, size_t size, int prot, size_t pgoff, int flags). The implementation was already correct (KindMem, FamilyMemory, addr=args[0], length=args[1], length2=pgoff=args[3], flags=args[4]), but the lock-in test was thinner than its madvise/mincore/munlock siblings. Strengthen TestGenerateMemHandlerRemapFilePages to: - negative-assert flags is never read from args[2] (prot, always 0) or args[0] (addr), guarding the prot/flags index hazard - verify the exit handler captures the int 0/-1 status generically as UNCLASSIFIED, like every other KindMem exit - document the wiring and the prot-vs-flags pitfall in the comment Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Diffstat (limited to 'internal/generate')
-rw-r--r--internal/generate/codegen_test.go28
1 files changed, 28 insertions, 0 deletions
diff --git a/internal/generate/codegen_test.go b/internal/generate/codegen_test.go
index 8d348f8..423972d 100644
--- a/internal/generate/codegen_test.go
+++ b/internal/generate/codegen_test.go
@@ -645,6 +645,20 @@ func TestGenerateMemHandlerMunlock(t *testing.T) {
requireContains(t, output, "ev->ret_type = UNCLASSIFIED;")
}
+// TestGenerateMemHandlerRemapFilePages locks in the BPF handler wiring for the
+// (deprecated) remap_file_pages(2):
+// int remap_file_pages(void *addr, size_t size, int prot, size_t pgoff, int flags).
+// The mapping address range is args[0]/args[1] (addr/length). Crucially, the
+// flags argument is at args[4], NOT args[2] — args[2] is `prot` (which the man
+// page requires to be 0 and which carries no useful information). The pgoff
+// argument (args[3]) is a file offset in pages and is parked in the generic
+// length2 slot. The historical hazard here is wiring flags from args[2] (prot)
+// the way flags-bearing siblings (madvise/mlock2/mseal/mprotect) legitimately
+// do — doing so would surface the always-zero prot value as flags and drop the
+// real MAP_NONBLOCK flag. remap_file_pages returns int 0 on success / -1 on
+// error, captured generically via ev->ret as UNCLASSIFIED like every other
+// KindMem exit (it is not a byte-count, so it is intentionally absent from
+// retClassifications).
func TestGenerateMemHandlerRemapFilePages(t *testing.T) {
output := GenerateTracepointsC(mustParseAll(t, syntheticPair("remap_file_pages")))
@@ -653,8 +667,22 @@ func TestGenerateMemHandlerRemapFilePages(t *testing.T) {
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];")
+ // pgoff (args[3]) is parked in the generic length2 slot.
requireContains(t, output, "ev->length2 = (__u64)ctx->args[3];")
+ // flags is at args[4]; prot (args[2]) must never be wired into ev->flags.
requireContains(t, output, "ev->flags = (__u64)ctx->args[4];")
+ if strings.Contains(output, "ev->flags = (__u64)ctx->args[2];") {
+ t.Error("remap_file_pages handler must read flags from args[4]; args[2] is prot (always 0), not a flags value")
+ }
+ // addr (args[0]) must never be reused as flags.
+ if strings.Contains(output, "ev->flags = (__u64)ctx->args[0];") {
+ t.Error("remap_file_pages handler must read flags from args[4]; args[0] is the addr, not a flags value")
+ }
+ // The exit handler returns the int status generically (0 on success, -1 on
+ // error), not via a byte-count classification.
+ requireContains(t, output, `SEC("tracepoint/syscalls/sys_exit_remap_file_pages")`)
+ requireContains(t, output, "ev->ret = ctx->ret;")
+ requireContains(t, output, "ev->ret_type = UNCLASSIFIED;")
}
func TestGenerateMemHandlerMprotect(t *testing.T) {