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

mfi_intr bounds reply-queue contexts by mfi_max_fw_cmds but mfi_commands[] is allocated MIN(128, mfi_max_fw_cmds) -> OOB command object under firmware misbehavior

Summary

The validation uses sc->mfi_max_fw_cmds, but sc->mfi_commands is kmalloc'd with ncmds = MIN(128, mfi_max_fw_cmds). On controllers reporting max_fw_cmds>128, a reply context in [mfi_total_cmds, mfi_max_fw_cmds) indexes past the array; mfi_remove_busy performs TAILQ surgery and mfi_complete calls cm->cm_complete through out-of-bounds memory (heap corruption). Only fires if the device posts a context the driver never issued. Correct-bound one-token fix.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-3875 Β· 6 files
FileTypeDescriptionSize
README.md β€” 1.2 KB ↓ raw
VERDICT.md β€” 964 B ↓ raw
fix.diff β€” 349 B view raw
manifest.json β€” 646 B view raw
verdict.json β€” 1.1 KB view raw
env.txt β€” 283 B view raw

DF-3875 β€” mfi_intr bounds reply-queue contexts by mfi_max_fw_cmds, but mfi_commands[] is sized mfi_total_cmds

mfi.c:1227-1234:

while (ci != pi) {
    context = sc->mfi_comms->hw_reply_q[ci];
    if (context < sc->mfi_max_fw_cmds) {          /* WRONG bound */
        cm = &sc->mfi_commands[context];
        mfi_remove_busy(cm);
        cm->cm_error = 0;
        mfi_complete(sc, cm);

Allocation (mfi.c:758-786): ncmds = MIN(mfi_max_cmds=128, mfi_max_fw_cmds) sc->mfi_commands = kmalloc(sizeof(struct mfi_command) * ncmds) and mfi_total_cmds ends at ncmds, while frames/sense arrays are sized mfi_max_fw_cmds. On controllers reporting max_fw_cmds > 128 (common), any reply context in [mfi_total_cmds, mfi_max_fw_cmds) β€” written by the device into the DMA reply queue β€” indexes past mfi_commands[]: mfi_remove_busy then performs TAILQ list surgery on out-of-bounds memory (heap corruption), and mfi_complete calls through a garbage cm_complete pointer.

Well-behaved firmware only replies with issued contexts (< mfi_total_cmds), so this is a robustness hole against a faulty/hostile controller (same trust boundary as DF-3874). Correct bound: sc->mfi_total_cmds.

VERDICT.md
↓ download raw

DF-3875 VERDICT β€” inconclusive (hardware-gated), speculative

  • Mismatch verified: bound at mfi.c:1229 uses mfi_max_fw_cmds; array allocated with MIN(128, max_fw_cmds) at mfi.c:758/763; mfi_total_cmds is the true issued-context count (mfi.c:785, used correctly in mfi_free at :1081).
  • Only manifests if the device (or a DMA-capable attacker) posts a context the driver never issued -> not reachable by unprivileged users on healthy HW.
  • Impact if it fires: heap corruption via TAILQ ops + indirect call through OOB cm β€” hence worth fixing even though speculative.
  • fix.diff: one-token bound change.

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_testable
baseline no→ patch + rebuild →patched clean

trivial bound fix; not validatable without HW

fix.diff
↓ fix.diffper-fix-DF-3875

Confirmed kernel references

Detail

Evidence (decisive lines)

VERDICT.md; mfi.c:1229 vs :758-785

PoC changes

no runnable PoC

Verified recommended fix

bound context by sc->mfi_total_cmds

Verdict

Reply-queue contexts are bounds-checked against mfi_max_fw_cmds while mfi_commands[] holds only MIN(128,max_fw_cmds) entries; a firmware-posted context in between indexes OOB (list surgery + indirect call). Requires misbehaving controller; not user-reachable; fix is a one-token bound change.