{
  "finding_id": "DF-2918",
  "status": "reproduced",
  "reproduced": 1,
  "impact": "dos",
  "confidence": "certain",
  "verdict": "REPRODUCED. The vfsconf registry in sys/kern/vfs_init.c has no synchronization of any kind: vfs_unregister() (vfs_init.c:469) checks vfc_refcount != 0 and removes the entry with nothing serializing it against sys_mount()'s unlocked vfsconf_find_by_name() (vfs_syscalls.c:313) followed by vfc_refcount++ (:359) - a window containing an M_WAITOK kmalloc and a syncer-kthread creation, crossed by every mount(2) attempt. A concurrent kldunload can unregister and unload a filesystem module while a mount thread is mid-window; by construction the mounter then writes refcount into freed module address space and dereferences vfsops pointers into the unloaded module (UAF write + UAF indirect call). On the stock INVARIANTS guest the observable manifestation (reproduced 4/4, in 15-100 s) is an irrecoverable kernel deadlock of the mount/linker subsystem: all mounters D-state (wchan ncplk/syncexit/vnode), fuse.ko pinned, mount(2)/kldload/kldunload dead system-wide, SIGKILL ineffective, clean shutdown impossible, and even a forced panic wedges in 'syncing disks...' so no crash dump completes. The control run (identical mount loop, no unload churn) is clean (600k+ iterations/mounter, 90 s). A contributing second edge in the same envelope is sys_mount's in-syscall auto-load (vfs_syscalls.c:324) which enters the linker while holding the mountpoint vnode lock, deadlocking against kldunload holding the linker lock (AB-BA), plus vn_syncer_thr_stop()'s unconditional wait on a syncer thread whose creation result is ignored (vfs_sync.c:318-322). NOT uid0: the unload side requires root (privileged conspirator), so this is a DoS/memory-corruption race, not an unpriv->root primitive; the fully-unprivileged mounter variant is additionally blocked on stock GENERIC because every user-mountable fstype (null/devfs/procfs/tmpfs) is compiled in and modular fuse is cap-gated out by the get_fscap('fusefs') vs vfc_name('fuse') mismatch.",
  "exploit_chain": "root: kldloop cycles kldload/kldunload of a modular filesystem (fuse.ko) || racer: mount(2) loop crosses vfs_syscalls.c:313->:359 on every attempt; when kldunload's racy refcount read observes 0 during a mounter's pre-increment window, vfsconf_remove() unlinks the entry and the linker frees/unmaps the module while the mounter still holds vfsp/mp->mnt_op into it -> vfc_refcount++ write into freed module pages + indirect calls through freed vfsops; observed outcome: permanent kernel deadlock (mount/linker subsystem), unkillable threads, host requires hard reset",
  "evidence": [
    "run.log: control clean (iter=600000 ok=0 fail=600001 x4 mounters, 90 s) vs 3/3 race wedges with ps D-state/wchan captures (ncplk/syncexit/vnode), fuse pinned (kldstat id 4), 'guest not answering' resets",
    "run.log: dmesg fuse_init(mountloop|1367) proving sys_mount's in-syscall autoload interleaved with kldunload churn of the same module",
    "panic.txt: forced debug.panic on the wedged guest hangs in 'syncing disks...' - crash-dump sync deadlocked on the corrupted state, no vmcore produced",
    "run.2.log: fix validation - stock wedge <=100 s; fix v1 (registry lock+acquire/release) still wedges at ~150 s (2nd edge identified); fix v2 (+in-flight-mount veto) survives the full 600 s with 6.6M/4.8M/5.0M mount attempts and 161M unpriv sysctl enumerations, zero wedges"
  ],
  "kernel_refs": [
    "sys/kern/vfs_init.c:458-480",
    "sys/kern/vfs_init.c:469",
    "sys/kern/vfs_init.c:264-284",
    "sys/kern/vfs_init.c:240-308",
    "sys/kern/vfs_init.c:338-343",
    "sys/kern/vfs_syscalls.c:313",
    "sys/kern/vfs_syscalls.c:315-342",
    "sys/kern/vfs_syscalls.c:354-359",
    "sys/kern/vfs_syscalls.c:468",
    "sys/kern/vfs_syscalls.c:1079",
    "sys/kern/vfs_mount.c:340-351",
    "sys/kern/vfs_sync.c:318-322",
    "sys/kern/kern_linker.c:477-569"
  ],
  "poc_changes": "PoC authored from scratch (the finding had no seed pack): mountloop (unpriv-mountable mount(2) hammer; mounts intentionally fail after the vulnerable window), kldloop (root kldload/kldunload churn with EBUSY veto-retry and post-unload gap), sysctlloop (unpriv vfs.generic enumeration hammer), race.sh (control/race driver). Iterations: ext2fs -> tmpfs -> nullfs -> fuse (only genuinely modular user-relevant fs type on the stock guest); added post-unload gap after observing silent re-mapping of freed module addresses; fixed sysctl oid vfs.generic.0 -> vfs.generic; escaped nested-su quoting by pushing a driver script.",
  "attempts": 5,
  "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT #0: Thu Jul  2 06:02:54 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64 (baseline); fix kernel #1 2026-09-03 10:40:23; fix kernel #2 2026-09-03 10:56:41",
  "runtime_sec": 5400,
  "guest_dirty": 0,
  "build_cmd": "cc -O2 -o /root/mountloop mountloop.c && cc -O2 -o /root/kldloop kldloop.c && cc -O2 -o /root/sysctlloop sysctlloop.c",
  "run_cmd": "MODE=race GAP=10000 sh race.sh 3 600",
  "code_hash": "mountloop.c 065d5e4fb7c2015a0c8366829e32bbc15055b09243b3c608b56dc4200aa1015d; kldloop.c b83939645c993d4407896026b44286294461c815013e6e8b31983ea79709285e; sysctlloop.c 9e388f6f7e5d2d25c911f61c7b0a2c7af7251fbf7f374d1218399a675b23b700; race.sh 8cc8eb30dc316cf92878b9b82869b69e684901d7108a5dde79ef3dfafcad99ee",
  "notes": "Severity honest-basis: Medium (not High) because the unload side of the race requires a privileged actor (kldunload), so this is corruption-class/DoS with a privileged conspirator, not unpriv->root. The write-side UAF (refcount++/vfsops deref into freed module pages) is established by construction and closes under fix.diff; the dominant observed manifestation is the deadlock. Residual items discovered and recorded: (1) sys_mount's autoload holds the mountpoint vnode lock across linker_load_file (AB-BA with kldunload) - closed by the in-flight-mount veto in fix v2; (2) vn_syncer_thr_create ignores kthread_create failure while vn_syncer_thr_stop waits unconditionally (vfs_sync.c:318-322) - independent latent hang worth its own ticket; (3) get_fscap whitelists 'fusefs' but the fuse module registers vfc_name 'fuse', functionally disabling unprivileged fuse mounts on stock systems; (4) sys_mount's autoload path only takes lf->userrefs when IT autoloads - mounts of manually-kldloaded modules rely solely on the (formerly racy) refcount. Guest was reset to the clean-source snapshot after validation.",
  "recommended_fix": "Serialize the vfsconf registry: lockmgr registry lock (shared lookups/iteration/acquire, exclusive register/unregister), atomic vfc_refcount via vfsconf_acquire()/vfsconf_release() used by sys_mount/dounmount/vfs_rootmountalloc, and an in-flight-mount counter vetoing vfs_unregister with EBUSY while any mount(2) syscall runs (see fix.diff)",
  "fix_status": "fixed",
  "fix_kernel_uname": "DragonFly dfbsd 6.5-DEVELOPMENT #2: Thu Sep  3 10:56:41 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64",
  "fix_baseline_reproduced": 1,
  "fix_patched_reproduced": 0,
  "fix_verdict": "Baseline stock kernel wedged irrecoverably in <=100 s under the race workload (3/3 full runs + 2 partials). fix.diff v1 (registry lock + acquire/release) closed the vfsconf lifetime TOCTOU but the deadlock persisted (~150 s) via the autoload/vnode vs linker AB-BA edge. fix.diff v2 (adds vfsconf_mount_begin/end bracketing sys_mount and an in-flight-mount EBUSY veto in vfs_unregister) was built in-guest (make nativekernel RC=0, installkernel RC=0), booted as kernel #2, and the IDENTICAL workload ran the full 600 s with 16.4M total mount attempts, 161M unpriv sysctl enumerations, zero wedged D-threads, no panic - bad behavior GONE.",
  "fix_evidence": [
    "findings/poc/DF-2918/run.2.log (baseline wedge timing, v1 partial result, v2 600 s survival with counters)",
    "findings/poc/DF-2918/fix.diff (21 hunks, git-apply clean against sys/)",
    "guest /root/build3.log RC=0, /root/install3.log RC=0, uname #2 after reboot"
  ]
}
