DF-3238 / verdict.json
{ "finding_id": "DF-3238", "status": "reproduced", "reproduced": 1, "impact": "panic", "confidence": "certain", "verdict": "Unprivileged two-thread process (reader on /proc/self/map + munmap churn of the lowest file-backed mappings) panics the stock kernel: procfs_domaps timestamp revalidation ignores vm_map_lookup_entrys failure and stores *entry=NULL into the RB_FOREACH iterator; RB_NEXT(NULL) executes movq 0x8(%rdi),%rax -> fatal kernel-mode fault at address 0x8, DDB halt. Reproduced on the first run against DragonFly 6.5-DEVELOPMENT #0 X86_64_GENERIC. Same crash is reachable against any dying process whose map is read (exit stage-1 teardown empties the tree under the reader). Panic is a hard local DoS; not an escalation primitive (fixed NULL+8 address). fix.diff (break on reentry==NULL) was built as kernel #1 and the identical PoC ran 240s/596k iterations with no panic: fix validated.", "exploit_chain": "", "evidence": [ "panic.txt: Fatal user address access from kernel mode from df3238_mapwalk_n, fault virtual address = 0x8, Stopped at vm_map_rb_tree_RB_NEXT: movq 0x8(%rdi),%rax (stock kernel #0)", "run.2.log: patched kernel #1 (Wed Sep 9 04:36:32 2026), same PoC, 596k+ reader iterations over 240s, POC_EXIT=0, guest up", "fix_validation.log: make nativekernel BUILD_RC=0, installkernel INSTALL_RC=0, reboot, re-run clean", "source chain: sys/vfs/procfs/procfs_map.c:236-240 + sys/vm/vm_map.c:1215-1232 + sys/sys/tree.h:815-817,1037" ], "kernel_refs": [ "sys/vfs/procfs/procfs_map.c:236", "sys/vfs/procfs/procfs_map.c:238", "sys/vfs/procfs/procfs_map.c:239", "sys/vm/vm_map.c:1215", "sys/vm/vm_map.c:1232", "sys/sys/tree.h:817", "sys/sys/tree.h:1037" ], "poc_changes": "Seed sketch (none existed) authored fresh: reader must lseek(fd,0) per iteration (fd offset otherwise EOFs); churn block placed below the non-PIE text base at 0x100000 with alternating file offsets so entries do not merge; one big munmap deletes all lowest entries during the readers per-entry unlock window.", "attempts": 2, "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64", "runtime_sec": 620, "guest_dirty": 0, "build_cmd": "cc -O2 -Wall -o df3238_mapwalk_null df3238_mapwalk_null.c -lpthread", "run_cmd": "./df3238_mapwalk_null (unprivileged; baseline panic <4min; patched run 240s clean)", "code_hash": "a93eb967ecd1d71a96d45cce16cb6bcaff03c7c891cbabd1b4e25d69bfc8e26c", "notes": "Impact=panic is the ceiling: NULL+8 fixed-address load, page 0 never mapped. Baseline guest wedged at db> (all CPUs stopped) -> vm.sh reset with-src afterwards; final state reset to clean snapshot.", "recommended_fix": "In the revalidation block, break out of the RB_FOREACH when vm_map_lookup_entry() yields a NULL predecessor instead of assigning it to the iterator (see fix.diff).", "fix_status": "fixed", "fix_kernel_uname": "DragonFly dfbsd 6.5-DEVELOPMENT #1: Wed Sep 9 04:36:32 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "Baseline kernel #0 panics on first PoC run (panic.txt). Patched kernel #1 (reentry==NULL -> break) survives the identical PoC for 240s / 596k+ iterations with no panic; guest healthy. fix validated.", "fix_evidence": "fix_validation.log; run.2.log; fix.diff" } |