# DF-4895 — vinum complete_raid5_write(): second-phase RAID-5 I/O launched via vn_strategy(drive->vp) on a teardown-vulnerable vnode — deterministic NULL-vp panic (fatal trap 12 in vn_strategy), closed-vnode UAF in the mid-flight window

## What this proves

`complete_raid5_write()` (sys/dev/raid/vinum/vinuminterrupt.c) launches the
second phase of a RAID-4/5 group write (data blocks at :427, parity block
at :464) with `vn_strategy(drive->vp, ...)`.  The first phase launches the
*same requests* through `dev_dstrategy(bio_driver_info=cdev, ...)`
(vinumrequest.c:436) — the cdev survives drive teardown, the vnode does
not: `set_drive_state(down)` queues `daemonrq_closedrive`, and the vinum
daemon runs `close_locked_drive()` → `vn_close(drive->vp); drive->vp=NULL`
(vinumio.c:225-227) with **no synchronization** against the completion
path.  Any group write whose subdisks' states say "up" then faults in
`vn_strategy` (`vp->v_flag` deref, vfs_bio.c:3375).

Teardown routes that leave/NULL the vp while writes continue:
- `complete_rqe()`'s own ENXIO branch (vinuminterrupt.c:129-139) force-downs
  the drive and, in the same call, proceeds into `complete_raid5_write()`
  which launches more `vn_strategy()`s — racing the daemon's `vn_close()`
  (closed-vnode use-after-close / memory corruption window);
- `vinum stop -f <drive>` (the only CLI route to real `set_drive_state`
  with force; plain `setstate -f down` pokes `DRIVE[].state` directly via
  `setstate_by_force()` and never closes anything);
- post-stop state-poke recovery (`vinum setstate -f up ...`), which is the
  sequence the DF-4714/DF-4482 packs used for years on this guest.

## Reproduced (deterministic, no fault injection)

1. `sh ./setup_vinum.sh` — 2 md drives, 3-sd RAID-5 volume `rv`, sanity
   32KB roundtrip OK (proves vp path works when up).
2. `vinum stop -f d2` — real down: daemon `vn_close`s vp, sds cascade
   crashed (dmesg shows the state cascade).
3. `sleep 3`
4. `vinum setstate -f up d2; vinum setstate -f up rv.p0.s0 rv.p0.s1 rv.p0.s2 rv.p0 rv`
   — states "up", vp still NULL.
5. `dd of=/dev/vinum/vol/rv bs=32768 seek=5 count=1 if=/tmp/cc conv=notrunc`

Result: **fatal trap 12**, `Stopped at vn_strategy+0x38: testb $0x40,0x5c(%r13)`,
fault address 0x5c (NULL vp + offset), current process = dd.
See `panic.txt` (serial console), `run.log` (transcript+analysis).

Impact ceiling: privileged local DoS (guaranteed panic) via the
deterministic route; vnode use-after-close (memory corruption potential)
via the mid-flight/ENXIO route.  Requires vinum administrative control
(root) or a genuine component ENXIO failure → severity Medium.

## Fix

`fix.diff`: use the cdev the code already stores in `bio_driver_info` at
:404/:440 — `dev_dstrategy(rqe->b.b_bio1.bio_driver_info, &rqe->b.b_bio1)`
at both sites, identical to the first-phase launch mechanism.

Fix validation: `vm.sh reset with-src`, apply fix.diff in guest /usr/src,
`make quickkernel + installkernel`, reboot, re-run the exact trigger
(steps 1-5): write must NOT panic (baseline panicked 1/1).  See
`run.patched.log`, `fix_build.log`.

## Related

`sdio()` (vinumrequest.c:980) uses the same `vn_strategy(drive->vp)`
pattern for raw-subdisk I/O and needs the same fix (different file).
