# DF-5534 VERDICT — reproduced (panic), fix validated

## Result

| kernel | behavior under identical boot args |
|---|---|
| baseline `a3a76c8c358d3df60cea81a31587ccf6` | `nfs_mountroot: mount 127.0.0.1: on /: 65` → immediately `Fatal trap 12` (VA 0x450, `lwkt_gettoken+0x64`), then an unbounded db> re-fault loop (4,186,854 console lines) |
| patched `3cb21e35f1447c8d69ceb1401226fefee` | `Root mount failed: 65` → manual `mountroot>` prompt → `ufs:vkd0` mounts → boots to userland; **0 traps, 57-line console, vkernel alive** |

## Root cause (path:line)

1. Operator kenv (vkernel `-e`, pc64 loader/PXE) → `pxe_setup_nfsdiskless()`
   parses `boot.netif.*`/`boot.nfsroot.*` (all writes bounded;
   sys/platform/vkernel64/x86_64/autoconf.c:388-486) and sets
   `nfs_diskless_valid = 1` (:485). `cpu_rootconf()` sets
   `rootdevnames[0] = "nfs:"` (:279).
2. `vfs_mountroot_try()` allocates the root mount (one `vfc_refcount++`,
   sys/kern/vfs_mount.c:344; `mnt_data == NULL` via `M_ZERO`, :340) and calls
   `VFS_MOUNT(mp, NULL, NULL, ...)` (sys/kern/vfs_conf.c:441).
3. `nfs_mount()` sees `path == NULL` → `nfs_mountroot(mp); return (0);`
   (**sys/vfs/nfs/nfs_vfsops.c:942-945 — the error is discarded**).
4. NFS server unreachable → `md_mount` RPC fails 65 →
   `nfs_mountdiskless` haderror: `mp->mnt_vfc->vfc_refcount--` (:772) →
   `nfs_mountroot` error path: `vfc_refcount--` **again** (:660; double drop
   of the single alloc reference) → returns 65 — into the void.
5. `nfs_mount` returns 0 → `vfs_mountroot_try` takes the success branch
   (vfs_conf.c:441-476): `mountlist_insert(mp)`, then `VFS_ROOT(mp, &vp)`.
6. `nfs_root()`: `nmp = VFSTONFS(mp)` = `mp->mnt_data` = **NULL**
   (`mountnfs()` never ran; `md_mount` failed first) →
   `lwkt_gettoken(&nmp->nm_token)` → read at 0x450 =
   `offsetof(struct nfsmount, nm_token)` → **Fatal trap 12**, swapper,
   boot CPU. Every ddb continue re-faults (`lwkt_relalltokens` at 0x458)
   → panic-spin loop. The intended behavior ("Root mount failed", manual
   prompt fallback, as observed patched) never runs.

## Why it matters

- Any vkernel booted with NFS-root boot args whose server is unreachable
  panic-loops at boot instead of failing cleanly (operator/guest-of-guest
  DoS; the vkernel process spin-crashes in ddb).
- Same shared nfs_vfsops.c code on pc64: an NFS-root machine whose server is
  down/unreachable at boot panics in the mountroot path (remote-triggerable
  boot DoS: an on-path attacker who blackholes the server port converts a
  transient outage into a kernel panic loop). NULL-deref only — fixed offset,
  not attacker-controlled data — so impact ceiling is DoS, not corruption.

## Not this bug

- The `boot.netif.*`/`boot.nfsroot.*` parsing itself (this file) is bounded
  and survived every hostile-input boot in matrix.sh: overflow `%d` fields,
  unbounded `%x` runs, 90-char path truncated byte-exact at MNAMELEN-1=87
  with clean NUL termination, 20-byte in-bounds nfshandle both failure and
  success (closing-X) branches, `kern.nbuf=99999999999` safely clamped
  ("Warning: nbufs capped at 2097104 for valloc considerations",
  autoconf.c:156-160).
- DF-1101 (decode_nfshandle one-past write into root_saddr.sin_len) is a
  separate, already-filed finding; not re-verified here.

## Fix

`fix.diff`: propagate the error (`return (nfs_mountroot(mp));`) and drop the
redundant `vfc_refcount--` at nfs_vfsops.c:660 so exactly one reference drop
(the one in `nfs_mountdiskless` haderror) pairs the `vfs_rootmountalloc`
reference. Validated on the guest: bad behavior gone, clean fallback + boot.

## Honesty notes

- The guest-side baseline crash console was overwritten by the fix-validation
  run (run_vk reuses the console filename); the decisive baseline evidence is
  preserved in run.log (filtered), run.crashloop_tail.log (raw tail of the
  4.2M-line crash loop) and panic.txt (verbatim trap blocks incl. the first
  0x450 fault). The patched run.fixed.log is complete and untrimmed.
- RUN A of matrix.sh (same class, no closing-X handle) spent its whole 120s
  window in RPC retransmit ("RPC timeout for server 127.0.0.1") and never
  reached the crash within the window; RUN E (deepX, TCP connect refused fast)
  reproduced deterministically. Both are the same unwind.

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