# DF-4707 — amr_pci_detach's EBUSY guard is defeated: AMR_STATE_OPEN is
# cleared on ANY close (and is TOCTOU) → kldunload frees the softc
# while a /dev/amr0 descriptor is still open

## What
`sys/dev/raid/amr/amr_pci.c:365-366` refuses detach only while
`AMR_STATE_OPEN` is set:

```c
if (sc->amr_state & AMR_STATE_OPEN)
        return(EBUSY);
```

But the flag is not a reference count:

- `amr_open()` (`amr.c:422-431`) sets the single bit on **every**
  open;
- `amr_close()` (`amr.c:438-447`) clears the single bit on **any**
  close — not the last close.

With two descriptors open on `/dev/amr0` (mode 0660, group
`operator`), closing **one** clears the flag while the other fd is
still live. `kldunload amr` (privileged) then passes the guard →
`amr_pci_shutdown` + `amr_pci_free` run: `destroy_dev()`, the softc /
DMA teardown, `devclass` release — while the surviving descriptor
still points at the cdev. Its next ioctl resolves the softc via
`dev->si_drv1` (`amr.c:707`), which now dangles → use-after-free on
the freed softc (or NULL/stale devclass deref after the module is
fully unloaded).

Secondary aspect of the same guardlessness: `amr_open()` sets the bit
unconditionally, so an open that races past `amr_pci_detach`'s check
(before `amr_pci_free`) sets the flag on a sc that is being torn down
— classic TOCTOU; there is no lock or freeze around the check.

## Reachability / gating
- Requires LSI MegaRAID hardware (amr must be attached) — absent from
  the audit guest (verified: no such PCI device, `/dev/amr*` missing),
  so this is hw-gated `inconclusive`.
- The unload itself needs privilege; the *victim* fd can belong to an
  unprivileged `operator`-group user. Security value: robustness /
  admin-foot-gun + memory-safety fallout, hence Low.

## Trigger (requires hardware)
```
exec 3<>/dev/amr0     # open #1  -> AMR_STATE_OPEN set
exec 4<>/dev/amr0     # open #2  (same bit, no counting)
exec 4>&-             # ANY close -> flag cleared, fd 3 still open
kldunload amr         # guard passes; softc + cdev torn down
dd if=/dev/amr0 of=/dev/null bs=1 count=0   # ioctl/read via stale si_drv1
```

## Fix
Make the guard a real open-count (see `fix.diff`): counter in the
softc, incremented in `amr_open`, decremented in `amr_close`,
`amr_pci_detach` returns EBUSY while non-zero.
