btdone/btreset panic() on HBA-supplied btstat and reset-state bytes (hostile-controller panic family)
Summary
btdone switches on bccb->hccb.btstat - a byte written into CCB/mailbox DMA memory by the host adapter - and calls panic() for INVALID_ACTION_CODE, INVALID_OPCODE, LINKED_CCB_LUN_MISMATCH and INVALID_CCB_OR_SG_PARAM. btreset likewise panics when a device holding DIAG_ACTIVE never drops it within 10s. All five sites turn device-fed state into an immediate kernel panic while holding bt->lock. Same class as the amd.c hostile-target family (DF-4042/4043), reachable from the shared interrupt path. Error-complete-instead-of-panic fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4098 Β· 16 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 1.4 KB | β raw | |
| VERDICT.md | β | 3.0 KB | β raw | |
| dfbt_rig.c | β | 26.9 KB | view raw | |
| dfbt_ctl.c | β | 8.0 KB | view raw | |
| Makefile | β | 127 B | β download | |
| push_rig.sh | β | 975 B | view raw | |
| run_panic_btdone.sh | β | 393 B | view raw | |
| run_panic_btreset.sh | β | 390 B | view raw | |
| run_panic_btdone.log | β | 724 B | view raw | |
| run_panic_btreset.log | β | 160 B | view raw | |
| panic_btdone.txt | β | 2.4 KB | view raw | |
| panic_btreset.txt | β | 789 B | view raw | |
| env.txt | β | 249 B | view raw | |
| fix.diff | β | 6.0 KB | view raw | |
| manifest.json | β | 839 B | view raw | |
| verdict.json | β | 2.8 KB | view raw |
DF-4098 β btdone/btreset panic() on host-adapter-fed bytes
Verdict: REPRODUCED (two independent panic sites, both captured)
Same rig class as DF-2429 (see DF-2429/README.md): production handlers resolved from the running kernel image and dispatched over a fabricated post-attach softc; the virtual firmware writes status bytes into the CCB DMA memory and the register file exactly as a MultiMaster HBA would.
Build
./push_rig.sh
Run (each on a fresh boot)
sh run_panic_btdone.sh # site 1: btdone btstat panic sh run_panic_btreset.sh # site 2: btreset DIAG_ACTIVE panic
Expected output
run_panic_btdone.sh: a perfectly valid I/O CCB (normal TUR, cmd_len=6, queued ACTIVE through the real XPT path) is completed by the HBA with BMBI_ERROR + btstat=BTSTAT_INVALID_ACTION_CODE (0x15) β a single device-fed byte β and production btdone executespanic("bt9: Invalid Action code")at bt.c:1517 while holding bt->lock. panic_btdone.txt has the backtrace (btdone+0x4d3).run_panic_btreset.sh: with the virtual STATUS_REG holding DIAG_ACTIVE (0x80) stuck, production btreset(hard) waits 5s for diagnostics to start (passes), then 10s for DIAG_ACTIVE to drop, and panics at bt.c:1650-1651:panic: bt9: btreset - Diagnostic Active failed to drop. status = 0x80(panic_btreset.txt, btreset+0x266). ~15s of DELAY polling then panic.
DF-4098 VERDICT β hostile/wedged-controller panic family in btdone/btreset
Bottom line
REPRODUCED at both cited panic sites, with the production code executing from the shipped kernel image:
- btdone site (bt.c:1517): a valid, normally-queued I/O CCB whose
completion mailbox carries
btstat = BTSTAT_INVALID_ACTION_CODE(0x15) β one host-adapter-fed byte β panics the kernel while the driver holdsbt->lock:panic: bt9: Invalid Action code, backtracebtdone+0x4d3(panic_btdone.txt). The sibling panics at bt.c:1520 (INVALID_OPCODE, exercised in DF-4097), bt.c:1524 and bt.c:1527 are the same pattern (fourpanic()calls switching onbccb->hccb.btstat, a byte in CCB DMA memory the adapter owns). - btreset site (bt.c:1650-1651): with STATUS_REG scripting
DIAG_ACTIVE stuck (wedged/hardware-failing controller β exactly the
situation a reset is meant to recover from), production
btreset(hard)panics after the 10s wait:panic: bt9: btreset - Diagnostic Active failed to drop. status = 0x80, backtracebtreset+0x266(panic_btreset.txt).
Live evidence
run_panic_btdone.log + panic_btdone.txt:
[rig] COMP: firmware writes completion: bccb=0xfffff801167df620
comp_code=0x04 btstat=0x15 sdstat=0x00 -> production btdone()
panic: bt9: Invalid Action code
btdone() at btdone+0x4d3 0xffffffff8042e763
run_panic_btreset.log + panic_btreset.txt:
[rig] BTRESET: production btreset(hard=1) panic: bt9: btreset - Diagnostic Active failed to drop. status = 0x80 btreset() at btreset+0x266 0xffffffff8042f606
Root cause (path:line)
- bt.c:1517, 1520, 1524, 1527 β
panic()onbccb->hccb.btstatvalues written into CCB DMA memory by the host adapter. - bt.c:1650-1651 β
panic()when DIAG_ACTIVE never drops within 10s. - Both reachable from the shared interrupt path (
bt_intrβbt_intr_lockedβbtdone) and from timeout recovery (bttimeoutβbtreset).
Impact
Any BusLogic controller that misbehaves (PCI error, wedged firmware, or a malicious/compromised HBA β the DF-4042/4043 amd hostile-target family analogue) converts one status byte into an immediate kernel panic. Local DoS from device-fed state; recovery is impossible because the driver dies instead of completing the command with an error.
Fix validation
fix.diff converts all five panic sites into device_printf +
error completion (CAM_REQ_CMP_ERR / ETIMEDOUT). Patched bt.c+btreg.h
compile clean with the X86_64_GENERIC kernel flags under -Werror
(FIXED-COMPILES-CLEAN, bt.fixed.o). No runtime A/B kernel build
(panic class, not memory corruption; not mandated).
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_testableobject-compile validation only (panic class, kernel A/B not mandated): patched bt.c compiles clean under -Werror with kernel headers
fix.diff; 'FIXED-COMPILES-CLEAN' with bt.fixed.o on the guest
Confirmed kernel references
Detail
Exploit chain
compromised/wedged BusLogic HBA (or target-induced error) writes btstat 0x15/0x16 into the CCB completion or holds DIAG_ACTIVE -> bt_intr->bt_intr_locked->btdone panic at bt.c:1517 (or bttimeout->btreset panic at bt.c:1650) -> kernel DoS while holding bt->lock
Evidence (decisive lines)
panic_btdone.txt (panic + btdone+0x4d3 backtrace after comp_code=0x04 btstat=0x15); panic_btreset.txt (panic + btreset+0x266 after 10s DIAG_ACTIVE stuck); run_panic_*.log for the dispatch context
PoC changes
rig stands in for missing PCI hardware only; the virtual HBA scripts STATUS_REG=0x80 stuck (vhba_enable=0) for the btreset variant; both panics needed separate boots (one panic per boot)
Verified recommended fix
Replace all five panic() sites with device_printf + error completion (CAM_REQ_CMP_ERR / ETIMEDOUT) -- never trust HBA-fed bytes or reset state with the kernel's life (fix.diff, object-compile validated)
Verdict
REPRODUCED at both cited panic sites with production code from the shipped kernel image: (1) btdone panics ('panic: bt9: Invalid Action code', bt.c:1517, btdone+0x4d3) on a valid I/O CCB completed with the single device-fed btstat byte BTSTAT_INVALID_ACTION_CODE (0x15) -- three sibling panics at bt.c:1520/1524/1527 switch on the same HBA-owned byte (1520 exercised live in DF-4097); (2) btreset panics ('btreset - Diagnostic Active failed to drop', bt.c:1650, btreset+0x266) when the wedged controller holds DIAG_ACTIVE -- precisely the condition a reset exists to recover from. Hostile/wedged-controller -> immediate kernel panic, interrupt-path reachable.
No comments yet.