# DF-5115 — ips_pci.c detach clears `configured` before EBUSY can abort: state permanently corrupted → live IRQ handler UAF after a retried detach

## Verdict: UNTESTED — trigger requires physical IBM ServeRAID hardware; the single audit guest has none (proved below). Static logic is certain.

## Where

- `sys/dev/raid/ips/ips_pci.c:195-210` (`ips_pci_detach`)
- `sys/dev/raid/ips/ips_pci.c:213-221` (`ips_pci_shutdown` gated on `sc->configured`)
- EBUSY sources: `sys/dev/raid/ips/ips.c:525-537` (`ips_adapter_free`: `IPS_DEV_OPEN`, `ips_diskdev_free()` failure, `ips_cmdqueue_free()` failure when `used_commands != 0`)

## Root cause

```c
	if (sc->configured) {
		sc->configured = 0;              /* <-- cleared BEFORE cleanup    */
		ips_flush_cache(sc);
		if (ips_adapter_free(sc))
			return EBUSY;            /* <-- detach fails, state stays 0 */
		ips_pci_free(sc);
	}
	return 0;
```

`sc->configured` is the *only* state gate for detach/shutdown (it is referenced
nowhere else in the ips family — verified with rg over sys/dev/raid/ips/*.c).
Clearing it before knowing cleanup succeeded corrupts the driver state machine
on every failed detach.

## Consequences (two)

1. **Shutdown data loss:** after one failed detach, `ips_pci_shutdown`
   (ips_pci.c:218-219) skips `ips_flush_cache()` forever — the adapter's
   volatile write cache is never flushed on reboot/halt.

2. **IRQ-handler use-after-free:** every *subsequent* detach attempt takes the
   `configured == 0` path and returns 0 **without** running `ips_adapter_free`
   or `ips_pci_free`. The interrupt installed at attach
   (ips_pci.c:131-133, `bus_setup_intr(..., sc->ips_adapter_intr, sc, ...)`)
   is never torn down. newbus completes the detach; on module unload the
   devclass unit is destroyed and the softc is freed, while the registered
   handler still holds `sc` as its argument. The next adapter interrupt calls
   `ips_morpheus_intr`/`ips_copperhead_intr` on freed memory — interrupt-
   context UAF read/write. After the module text itself is unmapped, the
   handler vector is dangling and *any* interrupt faults.

   The ipsd disk children are also orphaned (their `device_delete_child` in
   `ips_diskdev_free` is never re-attempted) and are force-deleted during unit
   destruction while possibly open/mounted.

## Trigger (needs hardware)

On a machine with a real ServeRAID adapter, as root:

```sh
# keep a disk busy so the FIRST detach fails EBUSY
dd if=/dev/zero of=/dev/serno/ipsd0s0 bs=64k count=100000 &
kldunload ips        # -> EBUSY, but sc->configured is now 0
kldunload ips        # -> "succeeds"; IRQ still live, softc freed at unit delete
# wait for adapter IRQ -> ips_*_intr() on freed softc
```

## Why untested on this audit's guest

`pciconf -l` shows no IBM (0x1014:0x01bd / 0x1014:0x002e) or Adaptec
(0x9005:0x0250) ServeRAID device (see hwabsence.log). The `ips` driver is
compiled into X86_64_GENERIC (config line 133) and `ips.ko` loads, but probe
never matches, so no softc, no attach, no detach path exists. This finding is
therefore filed from static analysis with `status=untested`.

## Not a duplicate

- DF-5025 (ipsd open/detach TOCTOU, ips_disk.c): userland racing a
  *successful* detach — different defect, different file.
- DF-4613/DF-4614/DF-4640: ips.c/ips_commands.c lifecycle (deadlock, cmdqueue
  double-free, attach-timeout UAF) — this finding is purely the PCI-glue
  state machine that turns a *failed* detach into a silent success on retry.

## Fix

Minimal: keep `configured` set until cleanup fully succeeds (fix.diff).

## 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.
