# DF-5046 VERDICT — idad detach UAF under open fds / in-flight bios

**status: untested (hardware-gated) | impact: none demonstrated (UAF-write by code trace) | confidence: likely**

## Reproduced?

No — and it cannot be reproduced on this audit guest: the trigger requires a
physical Compaq SMART/IDA (SMART-2/P, SMART-2SL, SA3200/3100ES/221, Integrated
Array, RAID LC2, SA4200/4250ES/431) PCI array controller. Evidence of gating
(env.txt, captured live from the guest):

- `pciconf -l` contains no vendor `0x0e11` (Compaq) function -> `ida_pci_match()`
  (sys/dev/raid/ida/ida_pci.c:193-210) can never match, `ida_pci_attach` never
  runs, no `idad` children are created, and `/dev/idad*` does not exist
  (`ls /dev/idad*` -> NO_IDAD_DEVS).
- The driver code itself is present in the guest kernel build
  (`kldstat -v` lists `ida/idad` and `pci/ida`), i.e. this is dormant code one
  PCI match away from live on any machine with the card — not dead code.

## Why the finding is real (line-accurate trace)

1. `idad_attach` sets `dsk->si_drv1 = drv` (ida_disk.c:280) where `drv` is the
   driver softc owned by the devclass, freed shortly after `idad_detach`
   returns (ida_disk.c:302-311).
2. `idad_detach` has **no** open-count gate, **no** in-flight drain, and never
   clears `si_drv1`. Compare the modern DFly pattern (e.g. nvme_disk, mmcsd)
   which refuses EBUSY while the disk is open.
3. `disk_destroy` (sys/kern/subr_disk.c:876-880) -> DISK_DISK_DESTROY handler
   (subr_disk.c:527-556): waits for `dp->d_refs` (disk *enumeration* refs
   only), then `destroy_dev(dp->d_cdev)` + `destroy_only_dev(dp->d_rawdev)`.
4. `destroy_dev` -> `devfs_destroy_dev` is **asynchronous**
   (sys/vfs/devfs/devfs_core.c:759-763); the worker (devfs_core.c:1440-1459)
   unlinks nodes and `release_dev()`s the sysref. The cdev object survives
   while any fd holds it open, and its `si_ops` stays `id_ops`,
   `si_drv1` stays the freed softc.
5. Post-detach I/O through a still-open fd: physio -> `dev_dstrategy`
   (sys/kern/kern_device.c:355-389) -> `idad_strategy` (ida_disk.c:145-189):
   - `idad_getsoftc(dev)` (ida_disk.c:94-99) returns dangling `si_drv1`;
   - reads `drv->flags` (ida_disk.c:161);
   - `devstat_start_transaction(&drv->stats)` (ida_disk.c:174) — **write into
     freed softc**;
   - `ida_submit_buf(drv->controller, bio)` (ida_disk.c:175) — dereferences
     freed `drv->controller` and inserts the bio into freed queue heads
     (sys/dev/raid/ida/ida.c:365-370).
6. In-flight bios are equally unguarded: `bio_track_ref` in `dev_dstrategy`
   pins the *cdev*, nothing waits on `dev->si_track_*` in any cdev destroy
   path (`bio_track_wait` is only used by vnode drain, sys/kern/vfs_subr.c:326,
   377, 526, 799), and a late completion runs `idad_intr`
   (ida_disk.c:213-226) -> `devstat_end_transaction_buf(&drv->stats, bp)` —
   another freed-softc write.

## Exploit chain (assessment, not exercised)

Local root is already the precondition (kldunload), so this is not an
escalation primitive — it is a root-triggerable UAF-write (kernel memory
corruption class). With heap grooming around the freed `idad_softc`/
`ida_softc` (both large, controllable size), the `devstat`/queue-head writes
could be steered into attacker-planted objects; on this intentionally
unhardened guest that would be a viable corruption primitive, but it buys an
attacker nothing beyond the root they already have. Real-world impact:
crash/UAF on detach, integrity of the write path if the softc is reallocated.

## Fix assessment

fix.diff adds the open-count gate (`idad_open`/`idad_close` increment/
decrement, `idad_detach` returns EBUSY while open) — the same remedy as the
DF-5025/DF-5013 family fixes. It intentionally does not attempt to fix the
controller-side in-flight problem (that is DF-1915's fix: bus_generic_detach +
drain in ida_detach). fix_status=not_testable: no IDA hardware exists on the
guest to build/boot a validated fix kernel against; the diff is line-accurate
against sys/dev/raid/ida/ida_disk.c + idavar.h and compiles by inspection
(trivial counter + EBUSY).

## Bottom line

Genuine DF-5025-family UAF, code-certain, untestable here solely because the
guest has no Compaq SMART/IDA hardware (proven in env.txt). Low severity:
root-only trigger, no unprivileged path (unlike DF-5013's AEN path).

## Fix status (batch validation)
Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest `make -j6 nativekernel KERNCONF=X86_64_GENERIC` completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.
