# DF-5579 — VERDICT

**status: reproduced (panic — fatal crash of the whole vkernel) · fix validated · impact: root-in-vkernel unprivileged-to-that-vkernel? NO — requires root inside the vkernel (PR:H) → availability kill of the vkernel host process**

## Bottom line

A single 8-byte `pread(2)` on `/dev/kmem` at a kernel virtual address inside
the vkernel's fixed 512 GB KVA window but beyond the grown portion of the
kernel page tables aborts the entire vkernel process from inside the
`kvm_access_check()` residency validator itself:

```
DF5579 mode=trigger offset=0xe400000000 (KVA=[0x8000000000,0x10000000000))
open ok, preading 8 bytes...
Assertion failed: (x != NULL), function vtopde, file /usr/src/sys/platform/vkernel64/platform/pmap.c, line 357.
=== vkernel alive? ===
DEAD
```

(run.baseline.log / panic.txt)

## Reachability and privilege

* Caller: `memrw()` minor 1 (/dev/kmem), sys/kern/kern_memio.c:270-296 —
  `kvm_access_check(saddr, eaddr, prot)` at :285 runs **before** the
  `uiomove()` and is the only gate.
* `/dev/kmem` is root-only (0640 root:kmem, kern_memio.c:841). So the
  attacker is root *inside the vkernel* (or root on the host driving the
  vkernel's /dev/kmem through any file channel). The victim is the vkernel
  process itself — every guest, every user process in it, all vcpus die with
  no core state preserved for the guest. Not a guest-user privesc; a
  privileged-user DoS. Severity Low, matching DF-5358 (pc64 twin).

## Root cause chain (path:line)

1. `sys/platform/vkernel64/x86_64/vm_machdep.c:322-325` — the validator loops
   `pmap_kextract(addr)` over every page of the requested range with zero
   prior knowledge that the paging structures exist.
2. `sys/platform/vkernel64/platform/pmap.c:717-747` — `pmap_kextract()`:
   `KKASSERT(va >= KvaStart && va < KvaEnd)` then `pde = *vtopde(va)` (:732).
   The KKASSERT passes: the trigger address IS inside [KvaStart, KvaEnd).
3. `sys/platform/vkernel64/platform/pmap.c:353-358` — `vtopde()`:
   `x = pmap_pde(kernel_pmap, va); assert(x != NULL);` (:357).
4. `sys/platform/vkernel64/platform/pmap.c:273-280` — `pmap_pde()` returns
   NULL when the PDPT entry is invalid — exactly the case for any VA beyond
   the `pmap_growkernel()` frontier (`kernel_vm_end`, pmap.c:1563-64, grows
   from `KvaStart`; a 512 MB vkernel grows a few hundred MB of the 512 GB
   window defined by KERNEL_KVA_START/SIZE, vmparam.h:80-81, mapped MAP_FIXED
   at init.c:609-621).
5. libc `assert()` is live in the vkernel build (no -DNDEBUG anywhere in
   sys/conf or the platform makefiles) → `__assert_fail` → SIGABRT →
   not in the vkernel's handled signal set (exception.c:226-250) → default
   action → vkernel process terminates, core dumped.

Secondary observation (same loop, benign outcome): for a KVA whose PDPT entry
IS valid but whose PDE is zero, `pmap_pde_to_pte()` (pmap.c:283-289) computes
`PHYS_TO_DMAP(0)+idx*8` and reads physical page 0 through the DMAP — the
returned garbage-PA is non-zero so the page passes the `== 0` check; the
subsequent `kernacc()` (vm_machdep.c:326, vm_glue.c:106) `kernel_map` entry
check rejects it with EFAULT. So only the PDPT-invalid case crashes; the
observed control (`pread` at KvaStart+1MB → clean EFAULT, run.ctl.log) is
consistent.

## What was run (rig: DF-5337/5538/5556 proven vkernel rig)

Guest: DragonFly 6.5-DEVELOPMENT X86_64_GENERIC (env.txt). VKERNEL64 built
with the DF-5474 `--defsym __build_id_*` link workaround; booted
`kernel.debug -m 512m -r /vkroot.img -n 1 -e init_path=/bin/vkinit`
(1 vCPU). PoC `vkmem.c` (static) runs inside the vkernel as root.

Three boots (all logs in this pack):

* **run.baseline.log** (unfixed kernel): devcheck `/dev/kmem` opens;
  `control` → EFAULT, SURVIVED; `trigger` → assertion → vkernel DEAD.
* **run.ctl.log** (unfixed kernel, second boot): positive control
  `/root/vkmem 0x454780` (vkernel image text via the `_start.._end`
  shortcut, vm_machdep.c:314-317) → `pread returned 8`,
  bytes `41 56 41 55 41 54 53 48` (push r14/r13/r12/rbx; sub rsp —
  genuine kernel prologue) — /dev/kmem reads work normally;
  `control` again EFAULT/SURVIVED.
* **run.fixed.log** (fix.diff applied, kernel rebuilt, vkfixbuild.log):
  text control → same 8 bytes; KVA control → EFAULT;
  **trigger → `pread returned -1 errno=14`, `DF5579_trigger_SURVIVED`,
  VKDONE reached, vkernel ALIVE.**

## Fix

`fix.diff` (git-apply-able against sys/): after the KvaStart/KvaEnd gates in
`kvm_access_check()`, reject `eaddr > kernel_vm_end` (vm/vm_kern.h:107,
already included via vm_machdep.c:70) — the grown frontier — before the first
`pmap_kextract()` call. Everything legitimately reachable through /dev/kmem
(the `_start.._end` image shortcut returns earlier; grown KVA is below
`kernel_vm_end` by construction of `pmap_growkernel()`) is unaffected;
validated by run.fixed.log with byte-identical positive control.

## Why not higher severity

No guest-user reachability: /dev/kmem open requires root. No memory
corruption, no info leak (the zero-PDE garbage read is discarded; kernacc
backstops). Same class/severity as the pc64 twin DF-5358
(Low, CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:C/C:N/I:N/A:H).

## 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.
