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)
PoC verification
Evidence pack
findings/poc/DF-4986 Β· 9 files| File | Type | Description | Size | |
|---|---|---|---|---|
| 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_testableHardware-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).
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).
No comments yet.