# DF-5057 — mlxd lifetime TOCTOU: MLX_DETACH_DRIVE deletes the mlxd child
across a sleeping flush with no open-gate raised, and mlxd_detach neither
rechecks MLXD_OPEN nor drains in-flight bios → softc UAF

**file:** `sys/dev/raid/mlx/mlx_disk.c` (+ trigger window in `sys/dev/raid/mlx/mlx.c`)
**bucket:** memcorrupt (DF-5013 / DF-5025 / DF-5046 family — the last LD sibling)
**severity:** Low (trigger requires root: /dev/mlxN control node is 0600
root:operator, mlx.c:466-468; no unprivileged runtime delete path exists in
mlx, unlike mfi's AEN path)

## Reproduce

Not runnable on this guest: the driver is compiled into the running kernel
(`device mlx`, X86_64_GENERIC:134; `kldload mlx` → "already loaded or in
kernel") but the guest has **no Mylex PCI function** (env.txt: vendor 0x1069
absent, 0x1011:1065 absent) so no controller ever attaches and `/dev/mlxd*`
does not exist. This is the same hardware-gated situation as the family
twins DF-5046/DF-5048 (packs contain the live-guest probe output).

## Expected behavior on real hardware

1. `mlxcontrol detach <unit>` (or any root caller of `ioctl(mlxctl,
   MLX_DETACH_DRIVE, unit)`).
2. Concurrently, open `/dev/mlxdN` in a loop (any user with the device
   permission, e.g. operator group).
3. The open that lands inside the flush window succeeds →
   `device_delete_child` frees the mlxd_softc while the fd (and any bio it
   then submits) references it → `mlxd_close` / `mlxd_strategy` /
   `mlxd_ioctl` write into freed kernel memory; a late controller
   completion runs `mlxd_intr` → `devstat_end_transaction_buf(&sc->mlxd_stats)`
   into freed memory.

## Fix

`fix.diff` (git-apply-able against this tree):
* MLX_DETACH_DRIVE raises `MLX_STATE_SHUTDOWN` for the whole flush+delete
  window so the *existing* `mlxd_open` gate (mlx_disk.c:98) rejects racing
  opens with ENXIO (the flag is cleared again at `detach_out`).
* `mlxd_detach` rechecks `MLXD_OPEN` and returns EBUSY (belt-and-suspenders
  for the check-then-act gap at mlx.c:782→794).

Full remediation additionally needs an in-flight drain (wait for
`mlx_waitbufs == 0` / outstanding mlxd commands before `disk_destroy`).
