# DF-4835 — mrsas frame-pool failure path frees frames + destroys tag; attach unwind double-frees them

- File: `sys/dev/raid/mrsas/mrsas_ioctl.c:422-431` (+ `mrsas_free_frame` :532-538;
  consequence site `mrsas.c:1011-1018` via `mrsas.c:800,842`)
- Severity: Low (attach-time, OOM-gated double-free; same bucket as DF-4438)
- Reproduced: **harness on the DragonFly guest** (no mrsas hardware in guest).

## Root cause

`mrsas_alloc_mfi_cmds()` calls `mrsas_create_frame_pool()` (mrsas_ioctl.c:422).
On partial failure (a `bus_dmamem_alloc`/`bus_dmamap_load` fails for one of the
32 MFI commands — kernel OOM at attach, all allocations are `BUS_DMA_NOWAIT`),
the error path:

1. calls `mrsas_free_frame()` on **all** commands (:424-427) — which unloads and
   frees `cmd->frame_mem` but **never clears `frame_mem`/`frame_phys_addr`**
   (:532-538), and
2. destroys `sc->mficmd_frame_tag` (:428-429) **without NULLing it**, and
3. returns ENOMEM **leaving `sc->mfi_cmd_list` fully populated**.

`mrsas_init_fw()` propagates the failure (mrsas.c:1719-1722) → `mrsas_attach()`
unwinds via `attach_fail_fw:` → `mrsas_free_mem()` (mrsas.c:800,842), which:

4. calls `mrsas_free_frame()` on every command **again** (mrsas.c:1011-1016) →
   `bus_dmamap_unload` through the **destroyed (freed) tag**, then
   `bus_dmamem_free` of the **already-freed frame memory** — double free, and
5. destroys `sc->mficmd_frame_tag` **again** (mrsas.c:1017-1018) — double
   `bus_dma_tag_destroy` (double `kfree(dmat->segments)` + `kfree(dmat)`).

## Build / run (on the DragonFly guest)

```
cc -O2 -Wall -o df4835 df4835_harness.c
./df4835          # baseline: verbatim kernel sequence
./df4835 fixed    # fixed model: error path leaves cleanup to mrsas_free_mem
```

## Expected

- baseline: `** USE-AFTER-FREE touch of freed <tag>` per frame (unload through
  the destroyed tag), `** DOUBLE FREE of <frame>` for each allocated frame
  (5 with the injected failure at cmd #5), final `** DOUBLE FREE` of the tag,
  child exit 42.
- fixed: `mrsas_free_mem: clean`, exit 0.

See `run.log`, `VERDICT.md`, `fix.diff`.
