mrsas_get_pd_list indexes local_pd_list with unchecked firmware deviceId (OOB write)
Summary
mrsas_get_pd_list at mrsas.c:3310-3312: sc->local_pd_list[pd_addr->deviceId].tid/driveType/driveState with deviceId from firmware u16 (0-65535). local_pd_list is MRSAS_MAX_PD=256 entries (mrsas.h:2417). deviceId>=256 writes 3 fields past array into ld_ids/ev_tq/reset_flags/load_balance_info. Guard at :3307 only bounds count<256, not deviceId value. Triggered at attach and re-triggered on PD_INSERTED/PD_REMOVED AEN. Malicious/buggy HBA. Fix: check deviceId<MRSAS_MAX_PD.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-1243 Β· 8 files| File | Type | Description | Size | |
|---|---|---|---|---|
| fix.diff | suggested-fix | bounds-check deviceId (< MRSAS_MAX_PD) before indexing local_pd_list; skip out-of-range | 1.3 KB | view raw |
| VERDICT.md | verdict | source-level trace of OOB write into softc (ev_tq ptr) + dead-code analysis | 3.3 KB | β raw |
| build.sh | build-script | applies fix, builds single-fix kernel | 772 B | view raw |
| run.sh | run-script | explains no-trigger on this guest | 594 B | view raw |
| env.txt | environment | uname, cc version, PCI inventory | 553 B | view raw |
| build.log | build-log | kernel build log excerpt proving -Werror clean compile of patched source | 9.2 KB | view raw |
| ../fix_build_combined.log | build-log | Combined 41-finding kernel build (rc=0, -Werror clean) | 5.6 MB | β download |
| ../fix_build_summary.txt | build-summary | Summary of the combined 41-finding kernel build | 826 B | view raw |
DF-1243 β mrsas_get_pd_list unchecked deviceId (OOB write into softc)
Verdict: NOT REPRODUCED (dead code at runtime β no hardware)
Mechanism (source-level, confirmed real)
mrsas_get_pd_list() at sys/dev/raid/mrsas/mrsas.c:3270 queries the
firmware for the physical-drive list and populates
sc->local_pd_list[deviceId]. The deviceId is firmware-supplied and
unchecked against the array bounds:
// line 3307-3314
if (retcode == 0 && pd_list_mem->count < pd_count) { // checks count, NOT deviceId
memset(sc->local_pd_list, 0, MRSAS_MAX_PD * sizeof(struct mrsas_pd_list));
for (pd_index = 0; pd_index < pd_list_mem->count; pd_index++) {
sc->local_pd_list[pd_addr->deviceId].tid = pd_addr->deviceId;
sc->local_pd_list[pd_addr->deviceId].driveType = pd_addr->scsiDevType;
sc->local_pd_list[pd_addr->deviceId].driveState = MR_PD_STATE_SYSTEM;
pd_addr++;
}
}
deviceId is u_int16_t (0β65535, mrsas.h:1351), but local_pd_list
has only MRSAS_MAX_PD = 256 entries (mrsas.h:2417, 1830). The guard
at line 3307 only bounds the count (< 256), not the deviceId values.
The softc layout after local_pd_list[256] (mrsas.h:2417-2424):
struct mrsas_pd_list local_pd_list[256]; // <-- the array u_int8_t ld_ids[MRSAS_MAX_LD]; // overwritten struct taskqueue *ev_tq; // <-- KERNEL FUNCTION POINTER struct task ev_task; u_int32_t CurLdCount; u_int64_t reset_flags; LD_LOAD_BALANCE_INFO load_balance_info[MAX_LOGICAL_DRIVES];
A deviceId >= 256 writes .tid, .driveType, .driveState (3 fields of
a struct mrsas_pd_list) past the array into ld_ids, and for large
deviceId values, potentially into ev_tq β a kernel taskqueue
pointer. Corrupting a function pointer and triggering the event task
could redirect kernel execution.
The bug is real in source. A malicious firmware can set deviceId to
any u16 value, causing an OOB write of 3 fields per entry past the
256-entry array, corrupting adjacent softc fields including a taskqueue
pointer. Triggered at attach and re-triggered on PD_INSERTION events.
Why it cannot reproduce on this guest
Same as DF-1242: mrsas is in GENERIC but no LSI MegaRAID SAS
hardware on the QEMU guest β driver never attaches β
mrsas_get_pd_list (called from mrsas_init_adapter during attach) is
never reached.
Valid hard blocker: dead/unreachable at runtime. Threat model is malicious firmware or a malicious PCIe device on a real MegaRAID SAS system.
Fix
fix.diff adds if (pd_addr->deviceId >= MRSAS_MAX_PD) { skip; continue; }
inside the loop, so out-of-range deviceIds are logged and skipped rather
than writing OOB. Validated by a successful single-fix kernel build
(make -j6 nativekernel rc=0).
Impact
- On this guest: none (driver never attaches, no hardware).
- On a real system: OOB write of 3 fields per malicious PD entry past
local_pd_list[256], corruptingld_ids,ev_tq(taskqueue pointer),reset_flags,load_balance_info. From malicious firmware this is kernel memory corruption in the RAID driver β a crash (DoS) from buggy firmware, or a controlled corruption primitive (including potential function-pointer overwrite ofev_tq) from a malicious PCIe device. Triggered at attach and on PD events.
Fix verification
not_testablecompile validated
module/kernel build rc=0
Confirmed kernel references
β
Detail
Exploit chain
none
Evidence (decisive lines)
β
Verdict
Source-confirmed. mrsas_get_pd_list deviceId no bounds vs [256] -> softc OOB write. mrsas in GENERIC, no MegaRAID HW.
No comments yet.