mpssas_fw_work dereferences fixed-offset event members without checking EventDataLength covers the struct: pre-loop ConfigElement[0].VolDevHandle at +0x0A and LOG_ENTRY LogData[0] at +0x14 read past the kmalloc'd event copy
Summary
The event copy is exactly EventDataLength*4 bytes but handlers read fixed-offset members unconditionally: the IR pre-loop element[0] read at +0x0A executes even when NumElements==0 (so a DF-1697 loop clamp does not remove it), and LOG_ENTRY reads LogData[0] at +0x14. Distinct sinks from DF-1696/1697 - a driver patched for both still takes these reads OOB on short-but-nonzero events. Guard-page harness verified on guest (IR EDL=2 faults at +0x0A; LOG EDL=4 covers the qualifier but faults at LogData[0]). Carry-the-size-and-gate fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4560 Β· 9 files| File | Type | Description | Size | |
|---|---|---|---|---|
| df4560_harness.c | β | 6.5 KB | view raw | |
| build.sh | β | 94 B | view raw | |
| run.sh | β | 89 B | view raw | |
| build.log | β | 404 B | view raw | |
| run.log | β | 1.7 KB | view raw | |
| env.txt | β | 230 B | view raw | |
| fix.diff | β | 2.4 KB | view raw | |
| VERDICT.md | β | 2.8 KB | β raw | |
| verdict.json | β | 3.9 KB | view raw |
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.
Fix verification
fixedFix modeled in-harness by the exact-fit controls (IR EDL=3, LOG EDL=6 run clean β precisely the minimum sizes fix.diff enforces); baseline EDL=2/1/4 arms fault. fix.diff not applied to the read-only sys/ tree; kernel-build validation not meaningful for a harness-verified HBA driver finding.
run.log: EDL=3 and EDL=6 controls clean vs EDL=2/1/4 faulting; fix.diff in pack.
Confirmed kernel references
Detail
Exploit chain
malicious fw sends IR CONFIG CHANGE LIST (or LOG ENTRY ADDED) with small nonzero EventDataLength -> kmalloc(EDL*4) copy -> mpssas_fw_work reads ConfigElement[0].VolDevHandle at +0x0A (unconditionally, before any NumElements check) / LogData[0] at +0x14 -> heap OOB read past the event copy; values feed mapping lookups and log-branch selection only.
Evidence (decisive lines)
run.log: '[IR EDL=2] SIGSEGV β OOB read past the EventDataLength-sized allocation (expected)', '[IR EDL=3] clean', '[LOG EDL=1] SIGSEGV', '[LOG EDL=4] SIGSEGV', '[LOG EDL=6] clean', plus the full EDL 0..6 arithmetic table.
PoC changes
No seed PoC (pass-2 new finding). Harness written from scratch: guard-placed EDL*4 buffers with the exact member offsets from mpi2_ioc.h structs (ConfigElement@0x08, VolDevHandle@0x0A, LogEntryQualifier@0x0E, LogData@0x14), qualifier pre-set to MPI2_WD_LOG_ENTRY (0x8002, mpsvar.h:111) to keep the LogData read on-path, fork()ed cases, plus the pure-arithmetic EDL table.
Verified recommended fix
Carry the validated size in mps_fw_event_work (u16 sz set at enqueue) and gate the IR pre-loop element deref (sz >= header+element && NumElements > 0) and the LOG_ENTRY handler (sz >= offsetof(LogData)+1) in mpssas_fw_work.
Verdict
REPRODUCED (harness; guest has no LSI mps HBA β same methodology as DF-1696/DF-1697/DF-4363). mpssas_evt_handler copies exactly EventDataLength*4 bytes (mps_sas_lsi.c:140-148) but mpssas_fw_work dereferences fixed-offset members with no coverage check at two sinks NOT covered by DF-1696/DF-1697: (1) the pre-loop element->VolDevHandle read at offset 0x0A (mps_sas_lsi.c:276-279) which executes even when NumElements==0, so a DF-1697 loop clamp does not remove it β with EventDataLength<=2 the 8-byte allocation is read 2 bytes OOB; (2) LOG ENTRY ADDED LogEntryQualifier@0x0E / LogData[0]@0x14 (mps_sas_lsi.c:515-518) β OOB for EventDataLength<=3 / <=5. Guard-page harness: IR EDL=2 faults at +0x0A (control EDL=3 clean); LOG EDL=1 faults at the qualifier, EDL=4 covers the qualifier but still faults at LogData[0] (control EDL=6 clean). Impact honestly Low: bounded 1-2 byte heap reads consumed internally (mapping-table lookup / kprintf branch), no userspace disclosure; panic only at a slab/page boundary. fix.diff (carry sz in mps_fw_event_work + gate both sinks) modeled by the clean controls.
No comments yet.