# DF-5289 — VERDICT

**Status: reproduced** (vkernel-in-guest, baseline panic; fixed kernel clean).
**Impact: panic** (deterministic whole-vkernel kernel panic on the 2nd
mlock/munlock cycle) **+ silent kernel-slab wire-count corruption on the 1st
cycle** (live kmalloc'd kernel page loses its only wire count →
reclaim/UAF-class primitive). **Confidence: certain.**

## The chain, proven end-to-end

1. Guest process (root) mmaps `/dev/upmap` (mode 0666,
   sys/kern/kern_memio.c:845). The char device has `.d_uksmap = memuksmap`
   (kern_memio.c:95), so vm_mmap creates a **VM_MAPTYPE_UKSMAP** map entry
   (sys/vm/vm_mmap.c:1356-1371, 1456-1460).
2. `mlock()` → `sys_mlock` (priv-gated `SYSCAP_RESTRICTEDROOT`,
   vm_mmap.c:1030 — root passes) → `vm_map_user_wiring(wire=0)`
   (sys/vm/vm_map.c:2631-2654; no maptype exclusion) → `vm_fault_wire`
   (vm_fault.c:2590-2616; UKSMAP correctly treated as fictitious for its
   own unwind bookkeeping) → `vm_fault` on the UKSMAP entry.
3. `vm_fault` UKSMAP branch (vm_fault.c:562-580): builds a **stack**
   `struct vm_page fakem` with `PG_FICTITIOUS`; `memuksmap()` sets
   `fakem.phys_addr` = the real upmap page's frame (kern_memio.c:446-471 →
   `pmap_kextract(p->p_upmap + offset)`); `vm_map_lookup` sets `FW_WIRED`
   from `entry->wired_count` (vm_map.c:4540) → `pmap_enter(pmap, va,
   &fakem, prot, wired=TRUE, entry)`.
4. **pmap.c:2429-2432** (`wired` block): `pm_stats.wired_count++` +
   `vm_page_wire(m)` — the latter is a **no-op for PG_FICTITIOUS**
   (vm_page.c `vm_page_wire`: `if ((m->flags & PG_FICTITIOUS) == 0)`).
   PTE installed: `pa | prot | V | U | WIRED`, **unmanaged**
   (pmap.c:2404-2417 skips the pv/managed path for fictitious m).
   → a wired PTE exists with **zero page-wire backing**.
5. `munlock()` → `vm_map_user_wiring(wire=1)` → `vm_fault_unwire`.
   **vm_fault.c:2679-2681**: `fictitious = entry->ba.object && (DEVICE…)`
   — UKSMAP entries have `ba.object == NULL` → **fictitious = 0**
   (asymmetric with vm_fault_wire:2614 which handles UKSMAP).
6. **pmap.c:2652-2657**: PTE is wired → clear WIRED, then
   `pa = *pte & VPTE_FRAME; m = PHYS_TO_VM_PAGE(pa);` — fabricates the
   **real vm_page of the kmalloc'd upmap page** for an unmanaged PTE.
7. vm_fault.c:2691-2696: `vm_page_busy_wait(m); vm_page_unwire(m, 1);`
   - kernel slab pages carry exactly wire_count==1 from
     `kmem_slab_alloc`'s `pmap_enter(kernel_pmap, ..., 1, ...)`
     (sys/kern/kern_slaballoc.c:1830).
   - **cycle 0**: wire 1 → 0 on a live kernel heap page (silent
     corruption: the page is now unwired/requeueable while kmalloc still
     owns it and the kernel pmap still maps it).
   - **cycle 1**: `vm_page_unwire` sees `(int)m->wire_count <= 0` →
     `panic("vm_page_unwire: invalid wire count")` — deterministic.

## Guest evidence

- Baseline (stock vkernel64 build): `run.baseline.log` —
  `panic: vm_page_unwire: invalid wire count: 0`, backtrace
  `vm_page_unwire ← vm_fault_unwire ← vm_map_user_wiring ← sys_munlock`,
  cycle-0 munlock returned 0 (the silent corruption) before the panic.
- Fixed kernel (`fix.diff`: vm_fault.c classification mirror + pmap.c
  managed-only return in pmap_unwire): `run.fixed.log` — all 4 cycles
  return 0, `DF5289: SURVIVED - no panic`, shell prompt returns, vkernel
  process alive. Identical PoC, identical run driver.

## Why it is in this file's scope

The finding is filed against `sys/platform/vkernel64/platform/pmap.c`
because the two pmap-side semantic defects live here:
- `pmap_enter` (2429-2442) takes a "wire" on a **transient** caller stack
  page and marks the PTE wired regardless, creating wired PTEs with no
  backing wire;
- `pmap_unwire` (2652-2657) returns a vm_page for **unmanaged** wired PTEs
  ("held by wired count" is false for them), handing callers a page to
  unwire that the pmap never wired.

The trigger-side classification omission is in shared code
(sys/vm/vm_fault.c:2679), which is why the same chain exists on pc64
(pc64 pmap_unwire has the identical unmanaged shape, pc64/pmap.c:5598-5603,
5627-5633). Fixing only vm_fault.c stops this trigger; the pmap.c hunks
close the class for any future caller.

## Privilege / threat model

mlock is `SYSCAP_RESTRICTEDROOT`-gated (root inside the vkernel / root on
pc64). Within the audit's vkernel threat model (processes inside the
vkernel attacking the vkernel kernel): a root process in the vkernel
corrupts/panics the vkernel kernel. Severity Medium (gated privilege, but
a genuine kernel memory-accounting corruption primitive, not a mere
assertion: cycle 0's wire drop on a live slab page is reclaimable-UAF
class). CVSS vector reflects local, privileged, availability+integrity
impact.

## Deviations from stock environment (recorded honestly)

- The vkernel64 target at this commit does not link out of the box
  (`kern_mib.c` references `__build_id_start/end` since 2026-06-22; the
  vkernel `SYSTEM_LD` links as a host userspace binary with no script
  PROVIDE). A 2-symbol shim was appended to the guest's
  `sys/platform/vkernel64/platform/init.c` (build plumbing only; the code
  under audit untouched). Alternative (equivalent): DF-3218's pack used
  `-Wl,--defsym,__build_id_start=0 -Wl,--defsym,__build_id_end=0`.
- Root image is a whole-disk UFS (vkd0 has no partitions); the vkernel
  mountroot prompt is answered `ufs:vkd0` by the driver. The prompt cannot
  be answered interactively on a vkernel because `vconscheckc` (console.c)
  returns -1 ("EOF") when no input is buffered — the answer is pre-fed
  into the console fifo before boot reaches the prompt.
- No `id(1)` on the minimal image (the shell reports `id: not found`);
  PID1 vkinit→sh runs as root (uid 0), which the mlock privilege check
  requires and the successful mlock return (0) demonstrates.

## Bottom line

Real, deterministically reproducible kernel memory-accounting corruption
in the audited file's enter/unwire pair, reachable by a root process inside
the vkernel with three syscalls (open+mmap+mlock), panic-proven and
fix-proven on the live vkernel; the same trigger also exists on pc64 via
shared vm_fault.c.

## Fix status (batch validation)
Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest `make -j6 nativekernel KERNCONF=X86_64_GENERIC` completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.
