# DF-5049 — mfi syspd lifetime UAF: AEN PD removal frees the softc under open descriptors and parked bios

## What this is

`sys/dev/raid/mfi/mfi_syspd.c` (raw system-PD / JBOD half of mfi(4)) lets the
`struct mfi_system_pd` softc be freed while (a) userspace still holds an open
descriptor on `/dev/mfisyspdN` and (b) bios referencing the softc via
`bio->bio_driver_info` are still parked on the controller bioq. The AEN
`MR_EVT_PD_REMOVED` trigger additionally walks the syspd list **with no locks
at all**. This is the syspd twin of DF-5013 (mfi_disk.c LD half) — same family
pattern, different file, different delete paths, different sinks.

## Reproduce

```
./build.sh   # cc -O -o syspd_hold syspd_hold.c   (on the DF guest)
./run.sh     # ./syspd_hold /dev/mfisyspd0
```

On real hardware (LSI MegaRAID with a SYSTEM PD exposed): open succeeds, four
readers issue `pread(2)`; pull the drive (or let firmware raise
MR_EVT_PD_REMOVED) → `mfi.c:1513-1532` deletes the syspd child → softc freed
(`subr_bus.c:1944` via `device_set_driver(dev, NULL)`) → the held fd keeps its
`si_drv1` dangling → every subsequent `pread(2)`/`close(2)` writes into the
freed slab (`devstat_start_transaction(&sc->pd_devstat)`, completion
`devstat_end_transaction_buf(&sc->ld_devstat)`), and parked bios are later
dereferenced by `mfi_bio_command` (`mfid->ld_flags`) and `mfi_build_syspdio`
(`disk->pd_id`).

On THIS QEMU guest (no MegaRAID PCI device — proven in run.log):

```
open(/dev/mfisyspd0) failed: No such file or directory  <- hardware-gated guest
```

The finding is source-proven end-to-end (VERDICT.md); the guest run documents
the hardware gate, exactly as for DF-5013.

## Fix

`fix.diff` — 2 parts: lock+`mfi_syspd_disable()` gate in the AEN
MR_EVT_PD_REMOVED handler (mfi.c), and open-gate + DISABLED + bioq drain in
`mfi_syspd_detach` with a DISABLED re-check in `mfi_syspd_strategy`
(mfi_syspd.c). Compile-validated against stock X86_64_GENERIC on the guest
(`make nativekernel` clean, see VERDICT.md).
