# DF-4789 VERDICT

* **Status:** untested (hardware-gated)
* **Confidence:** likely
* **Severity filed:** Low (CWE-125 OOB read / CWE-476 NULL deref, firmware-gated)

## Line-accurate trace

1. Entry: `mpr_sas.c:2813-2816`
   ```c
   case MPI2_IOCSTATUS_INVALID_SGL:
           mpr_print_scsiio_cmd(sc, cm);   /* unconditional — no mpr_debug gating */
           mprsas_set_ccbstatus(ccb, CAM_UNREC_HBA_ERROR);
   ```
   Any CAM SCSI IO completion path (`mprsas_scsiio_complete`) funnels here; the IOC
   status byte is produced by the controller. Unprivileged users issue disk IO through
   /dev/da* constantly, so the *caller* context is unprivileged — the *status* is
   firmware-controlled.
2. `mpr_table.c:587-593` `mpr_print_scsiio_cmd` → `mpr_print_sgl(sc, cm,
   req->SGLOffset0)`.
3. `mpr_table.c:541-547`: `frame = cm->cm_req` (request-frame pool, DMA-coherent,
   per-frame size `sc->req_framesz` from IOC facts); `hexdump(frame, 128, ...)` fixed
   128.
4. IEEE walk `:548-572`: reads `ieee_sge->Flags/Length/Address`, prints them; the ONLY
   exits are END_OF_LIST flag or the `flags & CHAIN_ELEMENT` transition. No counter
   bounds `ieee_sge` to the frame ⇒ malformed SGL (precisely what INVALID_SGL denotes)
   walks past the frame and prints adjacent DMA-pool memory to the console.
5. Chain transition `:557-568`: first chain via `TAILQ_FIRST`, later via
   `TAILQ_NEXT`; then `frame = (char *)chain->chain;` at `:568` — if the TAILQ is
   empty/exhausted, `chain == NULL` ⇒ read of `NULL->chain` at offset 0x10
   (`struct mpr_chain`: `chain_link` TAILQ_ENTRY = 16 bytes, then `void *chain`,
   mprvar.h:191-195) ⇒ clean NULL-page panic, not an exploitable primitive).
6. Simple walk `:573-583`: identical unbounded `sge++` (no chain transition at all).

## Impact ceiling

* Console/syslog disclosure of request-pool heap contents (OOB read) — modest.
* NULL-deref panic — local DoS attributed to disk IO storms.
* No attacker-controlled write; the printer only reads.

## Why Low and not higher

Every value the walker trusts (SGE flags, chain offsets) lives in the request frame the
*driver itself built*; on a correctly operating controller the walk is well-formed. The
bug fires only when the firmware flags the SGL invalid (malicious/buggy IOC, corrupted
DMA, or a driver bug elsewhere) — same trust boundary as pass-1's DF-3816/DF-3817 (Low).

## Why untested on this run

Audit guest is KVM/virtio-only: no LSI (vendor 0x1000) storage controller exists
(`env.txt`), so `mpr` never attaches and no INVALID_SGL completion can be synthesized
from inside the guest. Code-read verification only.

## Recommended fix summary

Guard the chain-list exhaustion (`if (chain == NULL) break;` before `chain->chain`) and
cap the per-frame SGE walk (fix.diff).

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