DF-5802 / verdict.json
{ "finding_id": "DF-5802", "status": "reproduced", "reproduced": true, "impact": "panic", "confidence": "certain", "verdict": "vm_fault_unwire() (sys/vm/vm_fault.c:2679-2681) derives fictitious only from entry->ba.object->type, while vm_fault_wire() (:2614-2616) additionally treats VM_MAPTYPE_UKSMAP as fictitious; UKSMAP entries have ba.object==NULL, so munlock()/exit-unwire of a mlock()ed /dev/upmap or /dev/mem UKSMAP range runs pmap_unwire()->PHYS_TO_VM_PAGE(pa) (unchecked vm_page_array index, vm_page.h:454) and vm_page_unwire() on a page the wire path never wired. Reproduced on the stock guest: panic vm_page_unwire: invalid wire count: 0 via sys_munlock->vm_map_user_wiring->vm_fault_unwire->vm_page_unwire for /dev/mem pa 0xFF000000 (~4000 entries past vm_page_array, v_page_count 998273); the RAM-backed /dev/upmap variant silently steals a wiring from the live kernel upmap page. Single-fix nativekernel rebuild with fix.diff (mirror vm_fault_wire()s maptype switch): both variants survive, rc=0, guest healthy. Trigger is privileged (mlock is SYSCAP_RESTRICTEDROOT-gated on pc64, sys/vm/vm_mmap.c:1030; /dev/mem is 0640) -> Low severity, no unprivileged user->root route.", "exploit_chain": "", "evidence": "panic.txt (full serial-console backtrace), run.log (stock decisive run: upmap survived, mem killed guest at munlock), run.patched.log/fix_run.log (both variants SURVIVED on fix kernel), fix_build.log (Hunk #1 succeeded at 2676; kernel #1 Mon Oct 12 23:04:55 UTC 2026)", "kernel_refs": [ "sys/vm/vm_fault.c:2614", "sys/vm/vm_fault.c:2679", "sys/vm/vm_fault.c:2691", "sys/vm/vm_page.h:454", "sys/vm/vm_page.c:3302", "sys/platform/pc64/x86_64/pmap.c:5633", "sys/kern/kern_memio.c:448", "sys/vm/vm_mmap.c:1030" ], "poc_changes": "no seed existed; trigger written fresh for this pass. Two variants: upmap (RAM-backed kernel page, silent wiring corruption) and mem (pa above Maxmem, OOB vm_page_array index -> panic). fix.diff first drafted by hand was malformed; regenerated mechanically with diff -u against the tree.", "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": 3000, "guest_dirty": 0, "build_cmd": "in-guest as root: cc -O2 -o /tmp/mt/uksmap_unwire uksmap_unwire.c", "run_cmd": "in-guest as root: /tmp/mt/uksmap_unwire upmap && /tmp/mt/uksmap_unwire mem 0xFF000000", "code_hash": "48029f29283b51e4badb218713de30a498bc83c801c580a3b58081342600efd8", "notes": "Guest reset to clean with-src snapshot after fix validation. buildkernel refused (no buildworld tools) -> used make nativekernel then make installkernel. /dev/upmap is 0666 but mlock(2) gate (SYSCAP_RESTRICTEDROOT, pc64 lacks pmap_wired_count) keeps the trigger privileged; hence Low severity despite the clean OOB primitive.", "recommended_fix": "In vm_fault_unwire(), mirror vm_fault_wire()s maptype switch: treat VM_MAPTYPE_UKSMAP entries as fictitious so pmap_unwire()/vm_page_unwire() never run on their never-wired device ptes.", "fix_status": "fixed", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "fix.diff applied to guest /usr/src (hunk at 2676), nativekernel rebuild + installkernel, reboot into DragonFly 6.5-DEVELOPMENT #1 Mon Oct 12 23:04:55 UTC 2026; identical run.sh then printed SURVIVED munlock for both variants with rc=0 and the guest stayed up - the stock panic and the silent upmap unwire are both gone.", "fix_evidence": "fix_build.log (patch + kernel build/install), fix_run.log == run.patched.log (both variants survive), VERDICT.md fix-validation section", "fix_kernel_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #1: Mon Oct 12 23:04:55 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64" } |