β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-1290

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)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-1290 Β· 8 files
FileTypeDescriptionSize
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
README.md readme finding summary + why not reproduced
↓ download 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 16
  • mlyvar.h:286 β€” MLY_BUS_IS_VALID(sc, bus) macro exists and is used elsewhere (e.g. mly.c:803, 825, 1379, 2187) but not in mly_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.

VERDICT.md verdict mechanism + source citations + fix
↓ download raw

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->target are 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 exceed MLY_MAX_CHANNELS; mly_btl[bus][target] indexed without MLY_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_VALID exists and is used at mly.c:803, 825, 1379, 2187 β€” but NOT in mly_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.
  • mly is compiled into GENERIC (X86_64_GENERIC:122) but mly_attach never runs; mly_process_event is 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_testable

compile 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.