mfi_disk_strategy leaks bios on hw_crit_error / issuepend_done early returns β permanent unkillable D-state (DF-2066 systemic twin, this file)
Summary
Two early returns set b_error but no B_ERROR/b_resid/biodone - the issuer sleeps in biowait forever (the entire OCR window or fatal controller fault; root-on-mfid wedges the machine). Sink-level REPRODUCED on stock guest: verbatim pattern in a kld raw-disk wedged a reader in D3/physstr surviving kill -9. Fail-label fix mirrors the 9-lines-up correct pattern.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-5012 Β· 12 files| File | Type | Description | Size | |
|---|---|---|---|---|
| df5012.c | β | 3.5 KB | view raw | |
| df5012_trigger.c | β | 828 B | view raw | |
| Makefile | β | 52 B | β download | |
| build.sh | β | 150 B | view raw | |
| run.sh | β | 154 B | view raw | |
| build.log | β | 2.2 KB | view raw | |
| run.log | β | 1.7 KB | view raw | |
| dmesg.txt | β | 231 B | view raw | |
| env.txt | β | 348 B | view raw | |
| VERDICT.md | β | 3.5 KB | β raw | |
| fix.diff | β | 675 B | view raw | |
| verdict.json | β | 3.3 KB | view raw |
DF-5012 β VERDICT
Status: REPRODUCED at sink level on the stock audit guest (the exact
completion pattern of mfi_disk.c:266-274 demonstrated live); the mfi-specific
entry conditions (hw_crit_error, issuepend_done == 0) are hardware-gated
(no MegaRAID controller on this guest) and are unconditional control flow in
the source β line-traced below.
Impact ceiling: dos β permanent unkillable D-state for any issuer with a bio in flight when the controller faults or resets (OCR). Whole-system hang when mfid carries the root filesystem.
Why the bio leaks (source trace)
mfi_disk_strategy()mfi_disk.c:249: bios arrive from the disk layer (dev_dstrategyon the mfid cdev or its slices).- mfi_disk.c:266-269:
if (controller->hw_crit_error) { bp->b_error = EBUSY; return (0); }β nobp->b_flags |= B_ERROR, nobp->b_resid, nobiodone(bio). The caller of a d_strategy owns completion; nobody else holds a reference to this bio. It is leaked into nothing. - mfi_disk.c:271-274: identical for
controller->issuepend_done == 0.issuepend_doneis a per-controller OCR gate: cleared at mfi_tbolt.c:541 when the reset starts, restored at mfi_tbolt.c:1323 when it finishes β the window is the entire OCR (seconds).hw_crit_erroris set at mfi_tbolt.c:1222/1288 on fatal PCI/firmware access failure during adapter reset and is never cleared until reattach (mfi.c:388). - The issuer (e.g.
physioβbiowait) sleeps uninterruptibly forever. Contrast the correct pattern 9 lines up (mfi_disk.c:257-263) and the userspace-facing ioctl gate that does return EBUSY (mfi.c:2901-2904).
Guest run (stock kernel, no config changes)
+ ps -o pid,stat,wchan,command -p 1109 PID STAT WCHAN COMMAND 1109 D3 physstr /tmp/poc/df5012_trigger wedge /dev/df50120 + kill -9 1109 + ps ... # after SIGKILL, 2 seconds later 1109 D3 physstr ... # STILL ALIVE + /tmp/poc/df5012_trigger poke /dev/df50120 # external completion poke: pread@1M r=512 errno=0 + ps ... -> GONE
dmesg: df5012: LEAKING bio 0xfffff8004f3dfcc0 (off 2097152) -- b_error=EBUSY,
return 0, NO biodone then df5012: poke -- completing leaked bio ....
The wedge process survived SIGKILL and terminated only when the leaked bio
was completed externally β i.e. the driver-side omission alone is sufficient
for the permanent hang. That is precisely the mfi_disk.c:266-274 behavior.
Why not a full hardware trigger
No MegaRAID controller exists on the guest (pciconf -l has no LSI 1000:1960
etc.), and mfi cannot be attached without one. QEMU does ship a megasas
device model, but the guest VM is booted from a fixed snapshot with a fixed
device set; per the DF-2066 precedent (identical bug, sibling file), the
source trace above is the standard of proof for HW-gated driver findings.
Exploit chain
Not applicable (dos class). The primitive is a permanent, unkillable kernel sleep, not memory corruption.
Fix
fix.diff: complete the bio on both paths (B_ERROR + b_resid + biodone)
via a fail: label β the same pattern the NULL-si_drv1 path already uses.
Validated git apply --check against the audit tree; not built as a
single-fix kernel (dos-class, HW-gated entry).
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_testablefix.diff (git apply --check clean) completes the bio on both paths. Single-fix kernel build not performed: the mfi entry path is hardware-gated on this guest, so a patched kernel could not exercise the trigger; the sink demo establishes the failure mode the fix removes.
fix.diff in this directory; VERDICT.md 'Fix' section
Confirmed kernel references
Detail
Evidence (decisive lines)
run.log lines '== ps before kill ==' through 'GONE' (PID 1109 D3/physstr survives kill -9, dies only after the poke completes the leaked bio); dmesg.txt 'df5012: LEAKING bio ... NO biodone' + 'poke -- completing leaked bio'; df5012.c:81-92 is the verbatim pattern; VERDICT.md has the full source trace
PoC changes
authored fresh from source analysis (no seed); module self-cleans via a recovery-poke offset so the guest is left clean
Verified recommended fix
On both early-return paths in mfi_disk_strategy(), complete the bio: set B_ERROR, b_resid = b_bcount, and call biodone() (goto fail label), mirroring the NULL-si_drv1 path 9 lines above.
Verdict
Sink-level reproduction on the stock guest kernel (DF-4986 house precedent): a kld module whose d_strategy contains the verbatim completion pattern of mfi_disk_strategy()'s hw_crit_error/issuepend_done early returns (b_error=EBUSY; return 0; no B_ERROR, no b_resid, no biodone) wedged the issuing process in an unkillable D-state (D3/physstr) that survived SIGKILL, and it terminated only when an external completion (biodone) was injected -- exactly the driver-side omission of sys/dev/raid/mfi/mfi_disk.c:266-274. The mfi-specific entry (controller->hw_crit_error set at mfi_tbolt.c:1222/1288; issuepend_done==0 for the whole OCR window, mfi_tbolt.c:541..1323) is hardware-gated on this guest (no MegaRAID controller) and is unconditional control flow in the source. Impact ceiling: dos - permanent unkillable hang for any issuer with a bio in flight when the controller faults or resets; whole-system wedge when mfid carries root.
No comments yet.