mrsas_sync_map_info writes firmware-controlled ldCount Γ 4-byte entries into a fixed 172,200-byte RAID-map DMA buffer β unbounded linear kernel heap overflow (computed bound size_sync_info is dead code)
Summary
mrsas_sync_map_info takes the sync-loop bound from the firmware-authored RAID map: num_lds = map->raidMap.ldCount, a full u_int32_t, then writes one 4-byte MR_LD_TARGET_SYNC per iteration into raidmap_mem - a buffer allocated at exactly 172,200 bytes. The author's intended bound, size_sync_info, is computed and never used. Capacity is 43,050 entries; on-guest proof shows ldCount=65536 with the matching totalSize PASSES MR_ValidateMapInfo and makes the loop write 262,144 bytes - 89,944 bytes past the bus_dmamem allocation - with 3 of every 4 bytes firmware-chosen. The same loop OOB-reads the source map via ldSpanMap[i] for i >= 64. Validation cannot save it: MR_ValidateMapInfo only requires totalSize (also firmware-supplied) to be arithmetically consistent with ldCount in u32 math. Malicious or compromised controller firmware: arbitrary-length linear overwrite of kernel memory adjacent to the raidmap allocation, 3-of-4 controlled bytes per entry - full kernel compromise primitive. Strictly stronger than the known DF-1242/1243/1244 family (write, firmware-chosen length). Hardware-gated on this guest; source-certain with on-guest arithmetic proof.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-3843 Β· 10 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 2.6 KB | β raw | |
| VERDICT.md | β | 3.9 KB | β raw | |
| map_sync_overflow_proof.c | β | 7.7 KB | view raw | |
| build.sh | β | 114 B | view raw | |
| run.sh | β | 98 B | view raw | |
| build.log | β | 9 B | view raw | |
| run.log | β | 1.1 KB | view raw | |
| env.txt | β | 260 B | view raw | |
| fix.diff | β | 1.9 KB | view raw | |
| verdict.json | β | 4.1 KB | view raw |
DF-3843 β mrsas_sync_map_info: firmware ldCount drives an unbounded OOB write past the RAID-map DMA buffer
Where
sys/dev/raid/mrsas/mrsas.c:3207βnum_lds = map->raidMap.ldCount;(full u32, firmware-authored)sys/dev/raid/mrsas/mrsas.c:3210βsize_sync_info = sizeof(MR_LD_TARGET_SYNC) * num_lds;β computed and never usedsys/dev/raid/mrsas/mrsas.c:3213-3224β write loop intoraidmap_mem[(map_id-1)&1], a fixedmap_sz = sizeof(MR_FW_RAID_MAP) + sizeof(MR_LD_SPAN_MAP)*(MAX_LOGICAL_DRIVES-1)= 172,200-bytebus_dmamem_allocbuffer (size set atmrsas.c:1645-1646)- Validation gap:
sys/dev/raid/mrsas/mrsas_fp.c:257-265(MR_ValidateMapInfo) only checkstotalSize == sizeof(MR_FW_RAID_MAP) - sizeof(MR_LD_SPAN_MAP) + sizeof(MR_LD_SPAN_MAP)*ldCountin u32 arithmetic β the firmware supplies both sides of that equation, so anyldCountpasses.
Class
Linear kernel-heap overflow past a DMA allocation: length fully firmware-chosen (u32 count Γ 4 bytes),
content = per 4-byte entry {targetId: FW u8, 0x00, seqNum: FW u16} (3 of 4 bytes attacker-chosen).
The same loop also OOB-reads the source map via MR_LdRaidGet(i)/MR_GetLDTgtId(i)
(mrsas_fp.c:174-182, unbounded ldSpanMap[i]).
Reachability
mrsas_sync_map_info is called from:
1. mrsas_setup_raidmap (mrsas.c:1680) at attach β after MR_ValidateMapInfo "passes",
2. mrsas_complete_mptmfi_passthru (mrsas.c:2965) on every RAID-map sync completion (AEN-driven),
3. mrsas_reset_ctrl (mrsas.c:2477) after OCR.
Threat actor: malicious/compromised controller firmware or a device that DMA-authors the map (the map buffer is filled by the card). No purely-local unprivileged trigger β this is the same gating as DF-1528 (mrsas_fp.c map reads), DF-1242/1243/1244.
Reproduce (arithmetic proof on the audit guest)
./build.sh # cc -O2 -Wall -o /tmp/df3843_proof map_sync_overflow_proof.c ./run.sh # runs the harness; struct definitions copied verbatim from mrsas.h
Expected decisive lines (see run.log):
map_sz (mrsas.c:1645) = 172200 <- bus_dmamem_alloc size capacity in sync entries = 43050 (max ldCount before OOB) Firmware supplies ldCount=65536, totalSize=0x9e028a8: MR_ValidateMapInfo: totalSize(0x9e028a8) == expected(0x9e028a8) -> PASSES => 89944 bytes written PAST the end of the DMA allocation
The kernel-side execution itself needs a MegaRAID SAS HBA (Thunderbolt/Invader/Fury); the audit
QEMU guest has none (no LSI/Avago PCI device present, no /dev/mrsas* nodes) although the
driver is compiled into X86_64_GENERIC (kldstat -v | grep mrsas β 80 pci/mrsas).
VERDICT β DF-3843
status: inconclusive (hardware-gated; source-certain) impact class: kernel memory corruption (linear OOB write, firmware-chosen length) confidence: certain (source + on-guest struct-math proof)
What was verified
-
Source trace (certain).
mrsas_sync_map_info()reads the loop bound straight from the firmware-authored RAID map: -sys/dev/raid/mrsas/mrsas.c:3207num_lds = map->raidMap.ldCount;-sys/dev/raid/mrsas/mrsas.c:3210computessize_sync_info = sizeof(MR_LD_TARGET_SYNC) * num_ldsand never uses it β the bound the author intended is dead code. -sys/dev/raid/mrsas/mrsas.c:3220-3224writes oneMR_LD_TARGET_SYNC(4 bytes) per iteration intotarget_map = sc->raidmap_mem[(sc->map_id - 1) & 1](mrsas.c:3213), a buffer of exactlymap_szbytes (mrsas.c:1645-1646). -MR_ValidateMapInfo(sys/dev/raid/mrsas/mrsas_fp.c:257-265) does not boundldCount; it only requirestotalSize(another firmware field) to be arithmetically consistent with it in u32 math. EveryldCounthas a passingtotalSize. -
Struct-math proof executed on the audit guest (
map_sync_overflow_proof.c,run.log): -sizeof(MR_FW_RAID_MAP)=12936,sizeof(MR_LD_SPAN_MAP)=2528,sizeof(MR_FW_RAID_MAP_ALL)=172200β matches the header's own comments (0x3288 / 0x9E0). -map_sz = 12936 + 2528*63 = 172200bytes = 43,050 four-byte sync entries of capacity. - A map withldCount=65536, totalSize=0x9e028a8passesMR_ValidateMapInfoand makes the loop write 262,144 bytes β 89,944 bytes past thebus_dmamem_allocregion, with 22,486 fully-OOB entries of firmware-chosen{u8,u8=0,u16}payload. Larger counts (up to 2^32-1) overflow proportionally further; a malicious device picks length and content. -
Guest execution of the kernel path: impossible on this host. The driver is compiled into the running kernel (
kldstat -vβ80 pci/mrsas;sys/config/X86_64_GENERIC:123), but the guest has no LSI/Avago PCI device and no/dev/mrsas*node β the driver never attaches, so the firmware-facing trigger surface does not exist in the VM. Reproducing the corruption itself would require a MegaRAID HBA (or a hacked QEMUmegasasmodel emitting a crafted map), which is outside this guest's capability. Henceinconclusive, notreproduced.
Exploit chain (if hardware/firmware control exists)
firmware DMA-authors RAID map with ldCount = K > 43050 (+consistent totalSize) β
attach/AEN/OCR triggers mrsas_sync_map_info β linear overwrite of kernel memory adjacent to the
172,200-byte raidmap bus_dmamem_alloc, 3 controllable bytes per 4, length β 4Kβ172200 β
classic heap-metadata/vtable overwrite β code execution in kernel context. With K chosen near
43,050 the write stays small and surgical; with large K it is a destructive sledgehammer.
Why not false positive
The bound (size_sync_info) is computed and then ignored β the intent to bound exists in the
code. Linux's megaraid_sas upstream equivalents allocate the sync buffer from ldCount
(mr_update_load_balance_params/sync alloc paths) or clamp; this port dropped the clamp.
Fix validation
fix.diff adds an explicit ldCount > MAX_LOGICAL_DRIVES rejection in mrsas_sync_map_info
(release cmd, return error) and a validation-time bound in MR_ValidateMapInfo so a bogus
map never reaches fast-path code either. Not executable on this guest (no HBA) β
fix_status = not_testable; the fix is structurally minimal and obviously removes the only path
to the unbounded loop.
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
not_testablefix.diff bounds ldCount at both the sync path (mrsas.c) and validation (mrsas_fp.c); cannot be boot-tested on this guest (no HBA), so fix validation is not_testable rather than fixed. The bound provably removes the only writer of the overflow: the loop cannot execute past MAX_LOGICAL_DRIVES iterations after the guard.
fix.diff hunks; map_sync_overflow_proof.c capacity math (43050 entries capacity vs MAX_LOGICAL_DRIVES=64 bound).
Confirmed kernel references
- sys/dev/raid/mrsas/mrsas.c:3207
- sys/dev/raid/mrsas/mrsas.c:3210
- sys/dev/raid/mrsas/mrsas.c:3213
- sys/dev/raid/mrsas/mrsas.c:3220
- sys/dev/raid/mrsas/mrsas.c:3222
- sys/dev/raid/mrsas/mrsas.c:3223
- sys/dev/raid/mrsas/mrsas.c:1645
- sys/dev/raid/mrsas/mrsas_fp.c:257
- sys/dev/raid/mrsas/mrsas_fp.c:174
- sys/dev/raid/mrsas/mrsas.h:698
Detail
Exploit chain
firmware DMA-authors RAID map with ldCount K>43050 plus consistent totalSize -> attach / AEN-driven map-sync completion (mrsas.c:2965) or OCR (mrsas.c:2477) calls mrsas_sync_map_info -> linear overwrite of kernel memory adjacent to raidmap_mem[] with {u8 targetId, 0x00, u16 seqNum} x K -> heap corruption under firmware control -> kernel code execution. No local unprivileged trigger without the device.
Evidence (decisive lines)
run.log lines 'capacity in sync entries = 43050' and '=> 89944 bytes written PAST the end of the DMA allocation'; VERDICT.md full trace; map_sync_overflow_proof.c struct definitions copied verbatim from mrsas.h; env.txt shows guest has no LSI PCI device / no /dev/mrsas*.
PoC changes
No seed PoC existed; authored map_sync_overflow_proof.c standalone userland harness (verbatim mrsas.h structs) because the kernel path needs an HBA the guest does not have.
Verified recommended fix
Reject ldCount > MAX_LOGICAL_DRIVES in mrsas_sync_map_info before the copy loop (release the mfi cmd and return error) and add the same bound to MR_ValidateMapInfo so bogus maps never enable fast path.
Verdict
Source-certain unbounded firmware-driven OOB write: mrsas_sync_map_info (mrsas.c:3207,3220-3224) copies num_lds = raidMap.ldCount (full u32) 4-byte entries into a fixed 172,200-byte bus_dmamem buffer; the computed bound size_sync_info (mrsas.c:3210) is never used and MR_ValidateMapInfo (mrsas_fp.c:257-265) only checks totalSize/ldCount mutual consistency, both firmware-supplied. On-guest struct-math proof (run.log) shows ldCount=65536 with totalSize=0x9e028a8 passes validation and overwrites 89,944 bytes past the allocation with 3-of-4 firmware-chosen bytes per entry. Kernel-path execution requires a MegaRAID HBA (Thunderbolt/Invader/Fury) or crafted device DMA; the audit guest has the driver compiled in (kldstat: 80 pci/mrsas) but no LSI PCI device and no /dev/mrsas* node, so the trigger surface does not exist in the VM. Hardware-gated; malicious-firmware threat model (same gating as DF-1528/DF-1242..1244, but a write primitive of firmware-chosen length).
No comments yet.