# DF-4560 VERDICT — reproduced (harness), Low, OOB fixed-offset reads on short fw events

## Bottom line

`mpssas_fw_work()` dereferences fixed-offset members of the
`EventDataLength*4`-sized heap copy with no size validation at two sinks
that are NOT covered by the known findings: (a) the pre-loop
`element->VolDevHandle` read at offset 0x0A
(sys/dev/raid/mps/mps_sas_lsi.c:276-279) which executes even when
`NumElements == 0`, so clamping the DF-1697 loop does not remove it; and
(b) the LOG ENTRY ADDED `LogEntryQualifier`/`LogData[0]` reads at 0x0E/0x14
(sys/dev/raid/mps/mps_sas_lsi.c:515-518). With firmware-supplied
`EventDataLength` of 1-2 (IR) or 1-5 (LOG) words these reads run past the
kmalloc'd buffer.

## Evidence

Guard-page harness (`df4560_harness.c`), guest DragonFly 6.5-DEVELOPMENT,
run.log:

- IR, EDL=2 (8-byte alloc): read at +0x0A faults — 2 bytes OOB. Control
  EDL=3 (12 B): exact fit, clean.
- LOG, EDL=1: faults at the qualifier read (+0x0E); EDL=4 (16 B):
  qualifier in-bounds but `LogData[0]` (+0x14) still faults — the sinks
  are independently reachable; control EDL=6: clean.
- Arithmetic table in the same log enumerates every EDL 0..6.

## Impact assessment (honest ceiling)

Bounded OOB reads (2 bytes / 1 byte) of heap memory adjacent to a fresh
small kmalloc: the IR value feeds `mps_mapping_get_raid_id_from_handle`
(a table walk; a garbage handle simply fails the lookup or yields an id
within the IR range — whose use is DF-4559's problem, not made worse
here), the LOG value only selects a kprintf branch. No bytes are returned
to userspace — no disclosure; realistic worst case is a page-fault panic
at a slab boundary (impact=panic class, low likelihood). Rated Low.

## Root cause & fix

Root cause: `mpssas_evt_handler` records only the event type, not the
validated length (sys/dev/raid/mps/mps_sas_lsi.c:83-87, 140-149), so
handlers cannot check coverage. `fix.diff` adds `u16 sz` to
`mps_fw_event_work`, sets it at enqueue, and gates both sinks (IR:
`sz >= sizeof(header)+sizeof(element)` and `NumElements > 0` before
reading `element[0]`; LOG: `sz >= offsetof(LogData)+1`). Pure arithmetic
model of the fix: the guarded minimums are exactly the EDL=3 / EDL=6
controls which run clean in run.log.

## Notes

Distinct from DF-1696 (u16 truncation of `sz` itself / kmalloc(0)) and
DF-1697 (loop counts vs. allocation): a driver patched for both would
still take these two reads OOB on short-but-nonzero events.

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