mpr_log_evt_handler(): hexdump() of firmware event data with unvalidated device-controlled length β OOB heap read to console
Summary
hexdump(event->EventData, event->EventDataLength, NULL, 0) passes the raw device-supplied U16 (which per MPI2 counts 32-bit words) as a byte count against a ~96-128-byte reply-frame allocation; an oversized device value dumps up to 64 KiB of adjacent kernel heap to the console. Requires root-enabled MPR_EVENT debug plus a broken/malicious firmware event: kernel heap info leak to console/syslog. Convert-and-clamp fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-3817 Β· 6 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 1.6 KB | β raw | |
| VERDICT.md | β | 1.6 KB | β raw | |
| probe.log | β | 479 B | view raw | |
| fix.diff | β | 707 B | view raw | |
| manifest.json | β | 766 B | view raw | |
| verdict.json | β | 1.5 KB | view raw |
DF-3817 β mpr_log_evt_handler(): hexdump() of EventData with device-controlled length (OOB read of reply-frame buffer to console)
What
mpr_log_evt_handler() (sys/dev/raid/mpr/mpr.c:2053-2078):
case MPI2_EVENT_LOG_DATA:
mpr_dprint(sc, MPR_EVENT, "MPI2_EVENT_LOG_DATA:\n");
if (sc->mpr_debug & MPR_EVENT)
hexdump(event->EventData, event->EventDataLength, NULL, 0); /* mpr.c:2065 */
event->EventDataLength is a U16 taken verbatim from the firmware's event
notification reply (a device-controlled DMA buffer). Per the MPI2
specification it counts 32-bit words, and the driver never validates it
against the reply frame size (sc->replyframesz, mpr.c:1346 =
facts->ReplyFrameSize * 4, typically 96-128 bytes). hexdump() interprets
it as a byte count:
- semantics bug: under-dumps legitimate events (1/4 of the data);
- security bug: a firmware value > the remaining frame bytes makes hexdump
read up to 65535 bytes past the
EventDatapointer β an OOB read of the kernel heap adjacent to the reply-frames DMA allocation, printed to the console (dmesg/console log).
Gate: requires hw.mpr.N.debug_level to have MPR_EVENT set (root sysctl or
loader tunable; the default mpr.c:1672 is MPR_INFO|MPR_FAULT) and a
device that sends a LOG_DATA event with an oversized length β broken or
malicious firmware/DMA. Same device-trust family as DF-3815.
Not runnable here
No SAS3 controller on the guest (probe.log); event delivery cannot occur.
Fix
fix.diff: convert wordsβbytes and clamp to the bytes remaining in the
reply frame.
DF-3817 β VERDICT
status: inconclusive (runtime) β no controller on the guest to deliver events; source defect certain, debug-path-gated.
Trace
- Handler registration:
mpr_attach_log()mpr.c:2081-2093 sets MPI2_EVENT_LOG_DATA in the mask; events are delivered viampr_dispatch_event()(mpr.c:2451-2476) from the interrupt path withreplypointing into thesc->reply_framesDMA allocation (mpr.c:2356-2358, range-checked only against the frame-pool bounds at mpr.c:2365-2377 β not against the per-message declared length). - The dump: mpr.c:2064-2066 β
hexdump(event->EventData, event->EventDataLength, NULL, 0). EventDataLength is the raw U16 from the reply (no le16toh, no clamp); MPI2 defines it in dwords. - Best case: prints 1/4 of the event. Worst case (device value larger than the frame): reads up to 64 KiB past a ~96-128-byte DMA-coherent buffer β kernel heap contents to console/syslog.
Impact ceiling
Privileged debug flag + device cooperation β console info leak of kernel heap adjacent to the reply pool; panic unlikely (hexdump reads only). Low severity, hardening class.
Fix
fix.diff: hexdump(event->EventData, imin(le16toh(event->EventDataLength) * 4, sc->replyframesz - offsetof(MPI2_EVENT_NOTIFICATION_REPLY, EventData)), NULL, 0).
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_testableNo controller on guest; event path cannot be exercised.
fix.diff; probe.log.
Confirmed kernel references
Detail
Evidence (decisive lines)
VERDICT.md; fix.diff (words->bytes + clamp to replyframesz).
PoC changes
No runnable PoC without hardware.
Verified recommended fix
Convert EventDataLength words to bytes and clamp to the remaining reply-frame bytes before hexdump().
Verdict
Source-certain: mpr.c:2065 passes the raw device-supplied U16 EventDataLength (dwords per MPI2, never validated) to hexdump() as a byte count against a ~96-128-byte reply-frame allocation β oversized values dump up to 64 KiB of adjacent kernel heap to the console. Gated behind MPR_EVENT debug (root) plus device cooperation. Runtime inconclusive: no SAS3 controller on the guest, events cannot be delivered (probe.log).
No comments yet.