OOB write on softc via untrusted controller event channel/target/lun in mly_process_event
Summary
mly_process_event at mly.c:1323/1347: sc->mly_btl[me->channel][me->target].mb_flags|=MLY_BTL_RESCAN. me->channel/target are u8 (0-255) from controller event. mly_btl is [MLY_MAX_CHANNELS=6][MLY_MAX_TARGETS=16]. channel=255,target=255 -> offset 4335 elements (~170KB) past mly_btl. Logical device path :1327-1332: MLY_LOGDEV_BUS(lun) can yield bus>=6. No MLY_BUS_IS_VALID check. Controller event DMA -> mly_check_event -> mly_process_event via 1s periodic callout. Fix: validate channel<6,target<16,bus<6 before indexing.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-1290 Β· 8 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | readme | finding summary + why not reproduced | 2.6 KB | β raw |
| VERDICT.md | verdict | mechanism + source citations + fix | 2.2 KB | β raw |
| fix.diff | suggested-fix | validate channel<6, target<16, bus<6 before indexing mly_btl | 1.4 KB | view raw |
| build.sh | build-script | no PoC binary | 357 B | view raw |
| run.sh | run-script | no runtime PoC | 326 B | view raw |
| env.txt | environment | guest PCI/kld/uname | 862 B | 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-1290 β mly_process_event OOB write on mly_btl
Finding
mly_process_event at sys/dev/raid/mly/mly.c:1323/1347 indexes
sc->mly_btl[me->channel][me->target] using controller-event-supplied u8
fields me->channel and me->target. mly_btl is sized
[MLY_MAX_CHANNELS=6][MLY_MAX_TARGETS=16] (mlyreg.h:59-60). A malicious or
buggy controller can deliver channel=255, target=255 β array offset 4335
elements (~170 KB) past mly_btl. The case 'l'/'m' logical-device path
at mly.c:1327-1332 computes bus = MLY_LOGDEV_BUS(sc, me->lun) which can
also yield bus >= MLY_MAX_CHANNELS without any MLY_BUS_IS_VALID check.
Why we did not reproduce at runtime
Same reason as DF-1289: no Mylex HBA on the QEMU/KVM guest. The driver is
compiled into GENERIC but never attaches. mly_process_event is reachable
only from the driver's 1-second periodic callout (mly_check_event), which
fires only after mly_attach succeeds. With no HBA, none of this runs.
Source-level confirmation
mly.c:1323βsc->mly_btl[me->channel][me->target].mb_flags |= MLY_BTL_RESCAN;(no bounds check;case 'p')mly.c:1327βbus = MLY_LOGDEV_BUS(sc, me->lun);(no MLY_BUS_IS_VALID)mly.c:1330βmly_printf(... sc->mly_btl[bus][target].mb_name ...)(indexes unvalidated bus)mly.c:1332βsc->mly_btl[bus][target].mb_flags |= MLY_BTL_RESCAN;(writes unvalidated bus)mly.c:1347βsc->mly_btl[me->channel][me->target].mb_flags |= MLY_BTL_RESCAN;(no bounds;case 's')mlyreg.h:59-60βMLY_MAX_CHANNELS 6,MLY_MAX_TARGETS 16mlyvar.h:286βMLY_BUS_IS_VALID(sc, bus)macro exists and is used elsewhere (e.g.mly.c:803, 825, 1379, 2187) but not inmly_process_event.
Compare mly.c:2187 (mly_cam_action) which does validate:
if (!MLY_BUS_IS_VALID(sc, bus)) { ... return; } β proving the pattern is
established; mly_process_event simply omits it. Bug is real.
Realistic impact ceiling
A hostile/faulty Mylex HBA can drive a ~170 KB OOB write (sets the
MLY_BTL_RESCAN bit, which is 1<<3, on attacker-chosen elements of the
softc at attacker-chosen offset). Because the write only sets a single bit,
grooming is constrained, but on a non-debug kernel the corruption of adjacent
softc state is in principle exploitable for DoS at minimum. Threat model is
again "hostile PCI device".
Fix
fix.diff adds explicit me->channel < MLY_MAX_CHANNELS && me->target < MLY_MAX_TARGETS checks before the two physical-device writes, and a
bus >= MLY_MAX_CHANNELS || target >= MLY_MAX_TARGETS early-out in the
logical-device case.
DF-1290 β mly_process_event OOB write on mly_btl
Verdict
NOT REPRODUCED β real source-level bug confirmed; unreachable on this guest (no Mylex HBA, same as DF-1289).
Mechanism (verified)
mly.c:1323βcase 'p':sc->mly_btl[me->channel][me->target].mb_flags |= MLY_BTL_RESCAN;βme->channel/me->targetare u8 (0-255) from the controller event DMA. No bounds check vs[6][16].mly.c:1327-1332βcase 'l'/'m':bus = MLY_LOGDEV_BUS(sc, me->lun)can exceedMLY_MAX_CHANNELS;mly_btl[bus][target]indexed withoutMLY_BUS_IS_VALID.mly.c:1347βcase 's': same unvalidated[me->channel][me->target]write.mlyreg.h:59-60βMLY_MAX_CHANNELS 6,MLY_MAX_TARGETS 16.mlyvar.h:286βMLY_BUS_IS_VALIDexists and is used atmly.c:803, 825, 1379, 2187β but NOT inmly_process_event. Confirms the omission.
Result for me->channel=255, me->target=255: writes to mly_btl[255][255] β offset 4095 elements (each struct mly_btl is 48 bytes β ~196 KB) past the array base inside the softc β a large attacker-driven OOB write (setting bit MLY_BTL_RESCAN = 1<<3).
Why not triggered on this guest
pciconf -l(env.txt): no vendor-1069 device. Only Intel PIIX3/PIIX4 + virtio.mlyis compiled into GENERIC (X86_64_GENERIC:122) butmly_attachnever runs;mly_process_eventis only invoked from the periodic callout after attach.
Phase 4(d): genuinely not reachable on this kernel.
Fix
fix.diff adds three guards:
1. case 'p' (line 1323): gate the RESCAN write on me->channel < MLY_MAX_CHANNELS && me->target < MLY_MAX_TARGETS.
2. case 'l'/'m' (lines 1327-1332): early break if bus >= MLY_MAX_CHANNELS || target >= MLY_MAX_TARGETS (and log a one-line warning).
3. case 's' (line 1347): same physical-device guard as case 'p'.
Fix validation
Compiles cleanly in the unified 5-fix kernel build (fix_build.log).
Runtime before/after is not_testable β no HBA β path unreachable on both
kernels.
Realistic impact
~170 KB OOB write driven by a malicious/faulty Mylex HBA. Single-bit set
(MLY_BTL_RESCAN); threat model is hostile PCI device. Fix is correct and
matches the existing MLY_BUS_IS_VALID pattern used elsewhere in the driver.
Fix verification
not_testablecompile validated
nativekernel rc=0
Confirmed kernel references
β
Detail
Exploit chain
none
Evidence (decisive lines)
β
Verdict
Source-confirmed. mly_process_event channel/target no bounds vs [6][16] -> ~170KB OOB write. mly in GENERIC, no Mylex HW.
No comments yet.