# DF-2918 — Unynchronized vfsconf registry: mount/kldunload race → hard kernel deadlock (and by-construction UAF)

File: sys/kern/vfs_init.c (pass 2)

## Build (in guest)

    cc -O2 -o /root/mountloop mountloop.c
    cc -O2 -o /root/kldloop   kldloop.c     # optional gap arg, default 10000 usec
    cc -O2 -o /root/sysctlloop sysctlloop.c

Guest setup (root):

    pw useradd -m -n poc ; pw usermod -n poc -s /bin/sh
    mkdir -p /home/poc/mnt ; chown -R poc:poc /home/poc
    cp /root/sysctlloop /home/poc/ ; chown poc /home/poc/sysctlloop
    sysctl vfs.usermount=1          # only needed for the (currently
                                    # stock-unreachable) unpriv mounter variant
    kldload /boot/kernel/fuse.ko

## Run

    sh race.sh 3 600                    # MODE=race default; also starts 2
                                        # unpriv sysctl readers as user poc
    # control (no unload churn — must stay healthy):
    MODE=control sh race.sh 4 90

Artifacts: /root/race.log, /tmp/mloop.*, /tmp/kld.out, /tmp/sloop.*

## Expected (stock INVARIANTS kernel, observed 2026-09-03)

* CONTROL run: mounters complete >600k mount(2) attempts each in 90 s
  (all EFAULT/EPERM — the mounts are *supposed* to fail; the vulnerable
  window vfs_syscalls.c:313→:359 is crossed on every attempt) with zero
  adverse effects. Guest stays healthy.
* RACE run: within 15–25 s every mounter thread wedges permanently in
  kernel D-state (wchan `ncplk` / `syncexit` / `vnode`), kldloop wedges
  inside the linker, fuse.ko is pinned loaded, mount(2) and kldload/
  kldunload are dead system-wide, wedged threads survive SIGKILL, the
  guest can no longer shut down cleanly ("guest not answering"), and a
  forced debug.panic hangs in `syncing disks...`. Only a hard reset
  recovers. Reproduced 3/3 race runs; control clean 1/1.

## Key observation about the failure shape

kldloop immediately reloads the module after each unload, so the freed
module address range is typically re-mapped (likely at the same address)
before a mounting thread dereferences its stale `vfsp`/`vfsops` pointer —
the stale pointer hits *valid* memory of the fresh module copy and the
corruption manifests as corrupted lock/refcount state → the observed
irrecoverable deadlock, rather than a page-fault panic. With a post-unload
gap (`GAP=10000/50000`) the range stays unmapped longer, but the lock
cascade still wins the race on this kernel.
