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

mfi_pci_attach failure unwind calls mfi_free() β†’ callout_terminate() on a never-initialized watchdog callout β†’ KKASSERT kernel panic (stock INVARIANTS GENERIC)

Summary

Every attach failure unwinds through mfi_free which unconditionally terminates the watchdog callout - but it is only initialized at the END of a successful mfi_attach, so any earlier failure (DMA tag, fw not READY, bus_setup_intr, ...) terminates an all-zero callout and KKASSERTs CALLOUT_DID_INIT. The exact sink PANICKED the stock guest kernel live (primitive KLD). Boot-loop grade on INVARIANTS kernels with a failing MegaRAID card. Init-at-top-of-attach fix.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-4986 Β· 9 files
FileTypeDescriptionSize
df4986_primitive.c β€” 2.2 KB view raw
Makefile β€” 58 B ↓ download
build.sh β€” 301 B view raw
run.sh β€” 126 B view raw
build.log β€” 1.1 KB view raw
panic.txt β€” 1.2 KB view raw
env.txt β€” 232 B view raw
fix.diff β€” 1.2 KB view raw
verdict.json β€” 3.4 KB view raw

Fix verification

not_testable
baseline no→ patch + rebuild →patched clean

Hardware-gated: full mfi path cannot run on the guest (no MegaRAID card), so a patched-kernel rebuild cannot be exercised end-to-end. The panic sink itself was reproduced live (panic.txt); fix.diff moves callout_init_mp() ahead of every possible failure unwind, making the panicking state unreachable by construction (single init before any goto out / mfi_attach failure path).

↓ fix.diffper-fix-DF-4986

Confirmed kernel references

Detail

Evidence (decisive lines)

panic.txt (live guest panic: 'assertion "cc->flags & CALLOUT_DID_INIT" failed in callout_terminate at kern_timeout.c:1111' from kldload of the primitive module); build.log (module built -Werror clean); df4986_primitive.c (exact sink reproduction); VERDICT.md (full code trace mfi_pci.c:230,281,294-299 -> mfi.c:1074 -> kern_timeout.c:1104-1111)

PoC changes

n/a (authored fresh): module reproduces the sink call with the exact softc state (bzero'd callout) that the mfi_pci unwind presents to mfi_free(); built in-tree under /usr/src/sys/modules because out-of-tree kmod includes failed.

Verified recommended fix

callout_init_mp(&sc->mfi_watchdog_callout) at the top of mfi_pci_attach() right after bzero(sc) and remove the late init in mfi_attach() so every failure unwind terminates an initialized callout

Verdict

Sink primitive reproduced live on the stock guest kernel (INVARIANTS X86_64_GENERIC): callout_terminate() of a bzero'd callout panics with the exact predicted assertion (panic.txt). The full trigger β€” an mfi(4) attach failure unwinding through mfi_pci.c:296-298 into mfi_free() before mfi.c:741 initializes the watchdog callout β€” is unconditional straight-line control flow (mfi_pci.c:281 goto out; mfi_attach failures at mfi.c:413-417/428-473/672-706; mfi.c:1074 callout_terminate) and cannot execute on the guest only because no LSI MegaRAID controller exists there. On hardware: boot/kldload kernel panic whenever the card is present but attach fails before watchdog init (e.g. firmware not in READY state).