{
  "finding_id": "DF-5244",
  "status": "reproduced",
  "verdict": "pmap_unwire() (user branch, pmap.c:5627-5635) clears PG_W and re-reads the PTE frame non-atomically; a concurrent cmpset-based teardown from pmap_remove_all() (reached cross-process via msync(MS_INVALIDATE) -> vm_object_page_remove -> wired-page branch -> vm_page_protect(NONE)) holds none of the unwire paths locks, so both sides can unwire the single wire -> panic(vm_page_unwire: invalid wire count: 0), or the unwire can read a zeroed PTE and compute PHYS_TO_VM_PAGE(0) = &vm_page_array[-1] (out-of-bounds forged vm_page_t that the kernel busy-waits and atomically decrements). Reproduced as the exact predicted panic on a kernel instrumented with a ~10us delay inside the few-ns window (panic.txt: sys_munlock -> vm_map_user_wiring -> vm_fault_unwire -> vm_page_unwire); the stock kernel raced 20+ minutes without a lottery win. The atomic cmpset clear-and-capture fix was validated on the same instrumented kernel: identical stress that panicked in <40s ran 8+ minutes clean. NOTE: on stock DF, mlock()/mlockall() are SYSCAP_RESTRICTEDROOT-gated (vm_mmap.c:1030), so the trigger requires root here; on any system permitting unprivileged memory wiring this is an unprivileged kernel corruption/panic.",
  "reproduced": true,
  "impact": "panic",
  "confidence": "certain",
  "exploit_chain": "unprivileged-user route exists only where mlock is permitted (root-only on stock DF): (1) process A mmap(MAP_SHARED) of a file on a vnode-pager FS (hammer2) and mlock the mapping (PG_W PTEs, page wired once); (2) process B maps the same file and loops msync(MS_INVALIDATE) -> vm_object_page_remove -> pmap_remove_all cmpset-zeroes As PG_W PTE and unwires the page; (3) A loops munlock -> pmap_unwire: if Bs cmpset lands between As W-clear and frame re-read, A builds m = &vm_page_array[atop(0)-first_page] (index -1: memory before the array) and the kernel runs vm_page_busy_wait/vm_page_unwire on the forged vm_page (32-bit decrement at a fixed pre-array offset, or a thread hung on a garbage busy channel); if it lands just after, both sides unwire -> deterministic panic. Proven stage: panic (double-unwire). Corruption stage present in code (same window), not separately triggered.",
  "evidence": "panic.txt (panic: vm_page_unwire: invalid wire count: 0; backtrace sys_munlock -> vm_map_user_wiring -> vm_fault_unwire -> vm_page_unwire); serial_panic.log (full console capture); VERDICT.md (full path:line chain and 6-attempt history); run.stock.log (stock-kernel attempt, no hit in ~20 min); run.fixed.log (fix-validated run); instrument.diff (window-widening instrumentation); fix.diff (git-apply-able verified fix)",
  "kernel_refs": [
    "sys/platform/pc64/x86_64/pmap.c:5627-5635",
    "sys/platform/pc64/x86_64/pmap.c:5598-5603",
    "sys/platform/pc64/x86_64/pmap.c:4777-4887",
    "sys/platform/pc64/x86_64/pmap.c:4816",
    "sys/platform/pc64/x86_64/pmap.c:425-441",
    "sys/vm/vm_fault.c:2686-2697",
    "sys/vm/vm_object.c:1543-1551",
    "sys/vm/vm_map.c:3164-3169",
    "sys/vm/vm_mmap.c:1024-1036",
    "sys/vm/vm_page.h:454-455",
    "sys/vm/vm_page.c:410",
    "sys/vm/vm_page.c:3297-3317"
  ],
  "poc_changes": "seed evolved: (1) mlock as unprivileged user maxx failed EPERM (DF gates mlock by SYSCAP_RESTRICTEDROOT) -> run as root; (2) B-side ftruncate on tmpfs does NOT tear down mapped PTEs (tmpfs_reg_resize bookkeeping skips removal) -> moved file to hammer2 /var; (3) ftruncate on hammer2 also never reached pmap_remove_all in practice (proven with in-kernel counters: pmap_remove_all entry/cmpset counters stayed 0 across 500k truncates) -> B-side switched to cross-process msync(MS_INVALIDATE) on a second MAP_SHARED mapping of the same file (vm_map.c:3164 path); (4) single-process threaded version serialized by the vm_map lock -> A/B split into separate processes; (5) stock-kernel window (~ns) too tight to hit in 20 min -> instrumented kernel (instrument.diff) widens the gap between W-clear and frame re-read to ~10us, panic in <40s; fix validated with the same delay inside the cmpset retry loop.",
  "attempts": 6,
  "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 (baseline); reproduction on audit-built kernels from the same tree + instrumentation/fix",
  "runtime_sec": 7500,
  "guest_dirty": 0,
  "build_cmd": "cc -O2 -pthread -o df5244 df5244.c",
  "run_cmd": "./df5244 6   (root; A=mlock/munlock hammer2 MAP_SHARED 1MB, B=msync(MS_INVALIDATE) on own mapping of same file)",
  "code_hash": "dc2c7a5c00dee4dbe8602a0df03eed4493c42c70d49aef2a6b53753b12ca12de",
  "notes": "Counter-instrumented kernels proved: pmap_unwire user branch fires PG_W-clears at 60k+/s under load; pmap_remove_alls backing-scan cmpset is the ONLY unserialized PTE modifier vs pt_pv. DF-0976..0980 (pass-1 findings) not re-reported. tmpfs and hammer2 ftruncate do not invalidate already-mapped pages on this system - a notable behavioral fact for future DF pmap/vfs work. Guest reset clean (with-src) after validation.",
  "recommended_fix": "In both branches of pmap_unwire(), replace atomic_clear_long(W) + re-read of the frame with a single cmpset loop that clears PG_W and captures opte & PG_FRAME atomically from the PTE the race was won on; decline to unwire when the cmpset is lost to a concurrent teardown (fix.diff, validated).",
  "fix_status": "fixed",
  "fix_baseline_reproduced": true,
  "fix_patched_reproduced": false,
  "fix_verdict": "Applied fix.diff semantics (atomic cmpset clear-and-capture) to the guest kernel WITH the same ~10us adversarial delay moved inside the cmpset retry loop; the identical PoC stress (12 processes, 8+ minutes) that panicked the unfixed instrumented kernel in <40s produced no panic, no hang, and clean completion. Baseline panic vs patched silence is decisive.",
  "fix_evidence": "run.fixed.log (fixed kernel, no panic); compare panic.txt (baseline instrumented kernel, panic in <40s under identical stress); fix.diff (git apply --check verified against pristine sys/)"
}