# DF-3171 — VERDICT

**Status: not_reproduced (for the hypothesized trigger). The code hazard is
real but no reachable trigger was demonstrable; see the honesty record
below. Confidence: speculative. Impact: none demonstrated.**

## What was hypothesized

`mfsclose()` (mfs_vfsops.c:136-147) clears `mfs_active` unconditionally,
taking the I/O server down on ANY device close. devfs calls `d_close` on
VRECLAIMED vnodes regardless of the remaining open count
(devfs_vnops.c:1169-1171), so a non-final close (vnode reclaim while the
mount still holds the device) would kill the server under a live mount →
`destroy_dev` (async, devfs_core.c:754-763) + `kfree(mfsp)`
(mfs_vfsops.c:494-498) → still-mounted filesystem doing I/O through a
freed mfsnode (UAF).

## What actually happened (honesty record)

1. First stock attempt (~15:56): `exec 8<>/mnt/d2/mfs853` + `umount -f`.
   The box panicked with `Bad tailq NEXT(...->tqh_last) != NULL` from
   mfsstrategy — **initially filed as this finding's reproduction. That
   attribution was wrong**: the `8<>` (O_RDWR) open of a mounted-RW D_DISK
   device fails EBUSY in devfs_specopen (devfs_vnops.c:1006-1020), so no fd
   existed and no d_close ever fired. The panic was DF-3170's
   producer/consumer race, which the concurrently-running writers were
   exercising (full reanalysis in findings/poc/DF-3170/run.2.log — the
   panic evidence has been reattributed to DF-3170).
2. Second stock attempt (read-only open, fd held by a short-lived `sh -c`):
   the fd closed when the shell exited before umount — vclean had no
   opencount to force-close. Server survived.
3. Third stock attempt (read-only fd held by a `sleep 90` holder process
   across `umount -f /mnt/d2`): umount succeeded, **server survived, mount
   healthy, I/O fine** — because devfs device opens migrate to the device's
   PRIMARY vnode (devfs_specopen's orig_vp handling,
   devfs_vnops.c:956-1000 — "the returned ... might not be using the vp we
   supplied"), leaving the second-devfs vnode with zero open count; its
   reclaim fires no VOP_CLOSE, and the primary vnode (in the main /dev
   devfs) is never reclaimed while the system runs.

## Why this is still filed (speculative, Low)

The hazard is one miscount away: devfs_vnops.c:1148 and :1102 compute the
close gate with `count_dev(dev)` and are annotated **"XXX NOT SMP SAFE"**
in-tree. A miscount that yields a false `opencount == 1` on some close
while the mount holds another reference makes `mfsclose` fire early with
exactly the consequences hypothesized (server exit under a live mount,
destroy_dev + kfree of the serving mfsnode, bios on freed memory). The
in-tree comment at mfs_vfsops.c:120-121 ("We allow the underlying MFS block
device to be opened and read") makes stray opens an expected condition.
This reviewer could not win that race on demand in the time budget; no
reachable deterministic trigger exists via the devfs#2 construction.

## Fix (defense-in-depth, validated harmless)

`fix.diff`: `mfsclose()` ignores closes while `dev->si_mountpoint != NULL`
(ffs_unmount clears it before the real final close, ffs_vfsops.c:851-855).
Validated on a patched in-guest kernel (#1 Mon Sep 7 16:11:15 2026 and
rebuilt #2 16:51:08):
- mount / I/O / **normal unmount lifecycle fully intact** (umount rc=0,
  mount gone, server exited via EMOUNTEXIT, /dev/mfsN removed);
- read-only-fd + forced devfs umount construction: server survives, mount
  continues serving I/O;
- 11+ minutes of DF-3170 stress (plus ENOSPC churn) across multiple
  concurrent MFS mounts: no regression.

Since the bug itself never manifested, fix validation is recorded as
`inconclusive` (guard proven safe and lifecycle-preserving; bad behavior
absent on both stock and patched).

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