# DF-5798 — unmount_allproc_cb manipulates p->p_textnch without p_token (exec race → refcount underflow/UAF)

## What
`unmount_allproc_cb()` (sys/kern/vfs_syscalls.c:768-787) reads and drops
`p->p_textnch` while holding only the allproc list token (via
allproc_scan, kern_proc.c:1401) — **not** `p->p_token`. Every other
p_textnch mutation site serializes under p_token:

- kern_exec.c:549-552: `if (p->p_textnch.ncp) cache_drop(&p->p_textnch);
  if (nch->mount) cache_copy(nch, &p->p_textnch);`
- kern_exit.c:498, kern_shutdown.c:599, kern_fork.c:541.

The unsynchronized pair (compare-then-drop in the callback vs
drop-then-copy in exec) can interleave: the callback samples
`p->p_textnch.mount == mp` on the OLD handle, exec then swaps in the NEW
handle, and the callback's `cache_drop()` releases the new handle's
references and zeroes it. The freshly-installed ncp/mount refs are then
one too low → premature free of a live namecache entry / mount refcount
skew → use-after-free. The callback runs on every retry-loop iteration
of `dounmount()` (vfs_syscalls.c:931-947) for MNT_FORCE unmounts, so
each `umount -f` attempt re-rolls the window up to 50 times.

Reachability: root by default (`umount -f`); unprivileged if
`vfs.usermount=1` (mount owner may force-umount their own mount).

## Reproduce attempt (guest)
```
sh stress.sh   # 6 rounds: tmpfs on /mnt/df5798, 8x400 self-reexecing
               # binaries placed ON the mount, respawning cd-holder to
               # keep the retry loop iterating, 10x umount -f per round
```
~4.5 minutes, >100k execs, 60 umount -f attempts, 243
"nlookup: warning umount race avoided" messages (the namecache layer's
own umount-race defusing for nlookup paths) — **no panic, no crash**.
The p_textnch interleave window (compare→drop gap ~tens of ns must
contain exec's entire drop+copy swap) was not hit.

## Expected if the race is won
Refcount underflow on the new textnch ncp → delayed panic/UAF on later
use (exec/exit/vp resolution). Not observed.
