# VERDICT — DF-4211

**status: untested (hardware-gated) · impact: memory corruption (panic-class, uid0 theoretical) · confidence: certain (source)**

## Reproduced?

No. The single QEMU guest available to this run exposes no LSI MPT Fusion
controller (`env.txt`: `pciconf -l` lists only hostb/isab/atapci/virtio/bochs
VGA), so `mpt.ko` never attaches and `mpt_raid_attach`/`mpt_refresh_raid_vol`
cannot run. This is a *device-present* code path: the entire RAID personality
only loads when `mpt_raid_probe` sees `ioc_page2->MaxPhysDisks != 0`
(`sys/dev/disk/mpt/mpt_raid.c:264-272`), which requires a real IOC. Per the
honest-status table this is "guest reachable but the target device/feature is
absent" — recorded as `untested` with the device-absence evidence in `env.txt`.

## Why the bug is certain anyway (line-level trace)

1. `mpt_issue_raid_req(..., wait=TRUE)` →
   `mpt_wait_req(mpt, req, REQ_STATE_DONE, REQ_STATE_DONE, sleep_ok=FALSE,
   2000)` (`mpt_raid.c:1327-1328`, `mpt.c:621-623`).
2. Timeout path in `mpt_wait_req` (`mpt.c:1344-1361`): busy-polls
   `DELAY(500)`+`mpt_intr()` until `--timeout == 0` → breaks, sets
   `REQ_STATE_TIMEDOUT`, returns `ETIMEDOUT`. **The request is never removed
   from `request_pending_list` and stays `REQ_STATE_QUEUED`** — the chip
   still owns the frame.
3. `mpt_refresh_raid_vol` then calls `mpt_free_request(mpt, req)`
   (`mpt_raid.c:1332`).
4. `mpt_free_request` (`mpt.c:1194-1251`) puts the request on
   `request_free_list`. Its pending-list guard is `KASSERT`
   (`mpt.c:1213-1215`) — compiled out without INVARIANTS
   (`sys/sys/systm.h:95-119` shows KASSERT is a no-op unless INVARIANTS).
5. From here either
   - the request is re-allocated (`mpt_get_request`, `mpt.c:1255-1279`) and
     re-queued (`mpt_send_cmd` TAILQ_INSERT_HEAD, `mpt.c:1298`) while still
     linked once on the pending list → double-link corruption; or
   - the late RAID-action reply arrives: context is
     `req->index | raid_handler_id` (`mpt_raid.c:616`), so `mpt_intr`
     (`mpt.c:809-821`) dispatches `mpt_raid_reply_handler`
     (`mpt_raid.c:521-550`) on a request now owned by an unrelated user —
     it completes and frees the *new* owner's request (use-after-free /
     double-free).
6. Sibling helpers prove intent: `mpt_verify_mwce` (`mpt_raid.c:977-981`) and
   `mpt_verify_resync_rate` (`mpt_raid.c:1030-1034`, `1066-1070`) all
   `return` on `ETIMEDOUT` **without** freeing; the late reply frees via
   `free_req=TRUE` (`mpt_raid.c:545-547`), exactly the protocol documented in
   `mpt_config_reply_handler` ("Whew- we can free this request (late
   completion)", `mpt.c:520-525`). `mpt_refresh_raid_vol` is the one
   deviant.

## Exploit chain

Not developed: no device. With hardware: primitive = one request_t
(double-linked on two TAILQs / completed-cross-command). The request frame is
IOC-DMA memory; control over *contents* is indirect. Realistic ceiling on
this hardware-fault trigger is a reliable panic; a uid0 chain would require
the attacker to control the IOC (malicious firmware / PCIe device), in which
case they already own the bus. Severity Medium is the right call.

## Fix

Remove the free on the timeout path (`fix.diff`, mirrors the sibling
helpers; late replies are reclaimed by `mpt_raid_reply_handler`). Fix not
runtime-validated for the same hardware reason — `fix_status:
not_testable`.

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