# DF-1223 — mpr XPT_RESET_DEV pool mismatch (regular alloc, high-pri free)

## Verdict
**INCONCLUSIVE (not_testable on this guest)** — bug confirmed in source; the
LSI MPT-Fusion SAS controller is absent from the audit guest. Fix authored,
applied, and compiled clean as part of a single-fix `nativekernel` build.

## Finding summary
`mprsas_action_resetdev()` in sys/dev/raid/mpr/mpr_sas.c allocates the task
from the **regular command pool** at :3351:
```c
tm = mpr_alloc_command(sc);   /* pops from sc->req_list */
```
…then sends the request with a HighPriority descriptor at :3370
(`MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY`), and on completion the path
`mprsas_resetdev_complete` (:3384) → `mprsas_free_tm` (:3425) →
`mpr_free_high_priority_command` (mprvar.h:642) **frees it back to the
high-priority pool** (`sc->high_priority_req_list`).

Every other task-management path in this driver uses `mprsas_alloc_tm(sc)`
(mpr_sas.c:234 → `mpr_alloc_high_priority_command`), so the alloc/free pools
match. Only `mprsas_action_resetdev` uses `mpr_alloc_command` directly — that
is the bug. Each device reset:
1. **Leaks one slot** from the regular `req_list` (it never comes back).
2. **Pushes an out-of-range SMID command** onto the high-priority list
   (the regular alloc gives SMIDs in the regular-command range, which the
   high-pri free assumes are in the high-pri SMID range).
3. After N resets, `mpr_alloc_command` returns NULL → all disk I/O on the
   controller stalls → persistent DoS until reload/reboot. The corrupted
   high-pri list can also cause downstream KKASSERTs / use-after-free on the
   next high-pri task (the KASSERT at mprvar.h:654 may catch some shapes).

Triggered by `camcontrol reset da0` (operator/cambreaker privilege — typically
`operator` group or root; reachable from any user in `operator`).

## Source confirmation (audited tree)
- mpr_sas.c:3351 — `tm = mpr_alloc_command(sc);` — pops `sc->req_list`.
- mpr_sas.c:3370–3371 — `tm->cm_desc.HighPriority.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;` — sent as high-priority.
- mpr_sas.c:3425 — `mprsas_free_tm(sc, tm);` — completion frees via the helper.
- mpr_sas.c:244–270 — `mprsas_free_tm()` → `mpr_free_high_priority_command(sc, tm);` (line 269) — pushes `sc->high_priority_req_list`.
- mprvar.h:605–619 — `mpr_alloc_command` — pops `req_list`.
- mprvar.h:622–643 — `mpr_free_high_priority_command` — pushes `high_priority_req_list`.
- mprvar.h:646–660 — `mpr_alloc_high_priority_command` — pops `high_priority_req_list`.
- mpr_sas.c:234 — `mprsas_alloc_tm()` → `mpr_alloc_high_priority_command(sc);` — the *correct* helper.
- mpr_sas.c:461, 524, 1723 — every other TM path uses `mprsas_alloc_tm(sc)`. Only the reset path uses the regular alloc.

## Why not runtime-reproduced on this guest
The QEMU/KVM guest has no LSI MPT-Fusion SAS controller (only virtio-blk for
storage). The `mpr` driver never attaches, no `mpr_softc` is created, no
SIM is registered with CAM, and `camcontrol reset` would target nothing.
The `mpr.ko` module is present but not loaded. The bug path is unreachable
at runtime on this guest.

Triggering the bug requires a real LSI MPT-Fusion SAS controller (or an
emulated one) with an attached target, and an unprivileged-ish user able to
issue `camcontrol reset <target>` (typically via the `operator` group, which
on multi-user systems is often granted to semi-trusted users).

## Fix (fix.diff)
Use the existing `mprsas_alloc_tm()` helper, which allocates from the
high-priority pool that the completion path expects:
```c
-    tm = mpr_alloc_command(sc);
+    tm = mprsas_alloc_tm(sc);
```
One-line change, exactly matches what every other TM path in the same file
already does (`mprsas_action_bus_reset`, `mprsas_action_target_reset`,
`mprsas_scsiio_timeout`, etc. all use `mprsas_alloc_tm(sc)`). After the fix,
the alloc and free pools match: high-pri alloc, high-pri free.

## Fix validation
- `git apply --check -p1` — clean.
- Applied to in-guest `/usr/src`, built with `make -j6 nativekernel` (with
  DF-1212 and DF-1214) — compiled clean, `NK_DONE rc=0`.
- `fix_status: not_testable` — no LSI SAS hardware on this guest; cannot do
  a runtime before/after `camcontrol reset` demonstration.

## Run / reproduce
Not runnable on this guest. On a system with an mpr-attached SAS target, the
PoC is:
```sh
for i in $(seq 1 N); do camcontrol reset da0; done
# after enough iterations: disk I/O stalls, mpr_alloc_command returns NULL,
# and dmesg shows "command alloc failure in mprsas_action_resetdev"
```
