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

XPT_RESET_DEV device reset is silently converted to a malformed opcode-0 CCB by btexecuteccb's no-data opcode clobber β€” HBA error reply then panics the kernel

Summary

btaction sets hccb->opcode = INITIATOR_BUS_DEV_RESET for XPT_RESET_DEV and immediately calls btexecuteccb(bccb, NULL, 0, 0); the nseg==0 path unconditionally overwrites the opcode with INITIATOR_CCB. Every CAM device reset is transmitted as an ordinary initiator CCB with cmd_len=0, sense_len=0 and both datain/dataout set. A conforming MultiMaster firmware rejects that CCB with BTSTAT_INVALID_OPCODE/INVALID_CCB_OR_SG_PARAM, and btdone panics on both. At minimum device-reset error recovery is silently broken. camcontrol reset (privileged admin op that must not panic) triggers it. Preserve-reset-opcode fix.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-4097 Β· 15 files
FileTypeDescriptionSize
README.md β€” 1.3 KB ↓ raw
VERDICT.md β€” 2.8 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_clean.sh β€” 3.9 KB view raw
run_panic.sh β€” 424 B view raw
run1_clean.log β€” 11.6 KB view raw
run_panic.log β€” 783 B view raw
panic.txt β€” 2.5 KB view raw
env.txt β€” 249 B view raw
fix.diff β€” 6.0 KB view raw
manifest.json β€” 786 B view raw
verdict.json β€” 2.6 KB view raw

DF-4097 β€” XPT_RESET_DEV clobbered into a malformed opcode-0 CCB

Verdict: REPRODUCED (clobber observed live + terminal kernel panic)

Same rig class as DF-2429 (see DF-2429/README.md): the REAL production btaction/btdone, dispatched through the real CAM XPT layer (xpt_action) over a fabricated post-attach softc.

Build

./push_rig.sh

Run

sh run_clean.sh    # non-panicking half: the clobber observation
sh run_panic.sh    # panicking half: firmware rejection -> btdone panic

Expected output

  1. queue io (control): post-dispatch hccb snapshot op=0x00 cmd_len=6 β€” a normal no-data TUR.
  2. queue rst (XPT_RESET_DEV through the same production path): post-dispatch hccb snapshot op=0x00 cmd_len=0 sense_len=0 β€” the INITIATOR_BUS_DEV_RESET (0x81) that btaction stored at bt.c:1062 was overwritten with INITIATOR_CCB (0x00) by btexecuteccb's unconditional nseg==0 path (bt.c:1285). The adapter is handed a reset request encoded as an ordinary CCB with a zero-length CDB.
  3. Panic run: the virtual firmware rejects that malformed CCB the way conforming MultiMaster firmware does β€” completion BMBI_ERROR with btstat=BTSTAT_INVALID_OPCODE (0x16) written into the CCB β€” and production btdone panics: panic: bt9: Invalid CCB Opcode code (bt.c:1520), full backtrace in panic.txt.
VERDICT.md
↓ download raw

DF-4097 VERDICT β€” XPT_RESET_DEV converted to a malformed opcode-0 CCB

Bottom line

REPRODUCED, both halves. (1) A CAM device reset dispatched through the real xpt_action/production btaction path arrives at the host adapter mailbox as an opcode 0x00 (INITIATOR_CCB) CCB with cmd_len == 0, sense_len == 0 β€” the INITIATOR_BUS_DEV_RESET (0x81) stored at bt.c:1062 is unconditionally overwritten by btexecuteccb's nseg == 0 branch (bt.c:1285). (2) Conforming MultiMaster firmware rejects such a CCB (BTSTAT_INVALID_OPCODE, 0x16) and production btdone turns that device-fed status into panic: bt9: Invalid CCB Opcode code (bt.c:1520) β€” captured with backtrace in panic.txt.

Live evidence

Clean run (run1_clean.log lines 3-10):

[snap] id=0 (XPT_SCSI_IO TUR):     hccb(op=0x00 cmd_len=6 ...) flags=0x1 timer=1
[snap] id=1 (XPT_RESET_DEV):       hccb(op=0x00 cmd_len=0 sense_len=0 ...)

Both CCBs went through the identical production path (xpt_action β†’ devq β†’ sim->sim_action = production btaction). The reset CCB's opcode is 0x00 with an empty CDB β€” exactly the clobber.

Panic run (run_panic.log, panic.txt):

[rig] QUEUE done: id=0 bccb=0xfffff801167df620 opcode=0x00 cmd_len=0 ...
[rig] COMP: firmware writes completion: bccb=0xfffff801167df620
       comp_code=0x04 btstat=0x16 sdstat=0x00 -> production btdone()
panic: bt9: Invalid CCB Opcode code
btdone() at btdone+0x6cd 0xffffffff8042e95d
rig_ioctl() at rig_ioctl+0x1ee ...

Root cause (path:line)

  • sys/dev/disk/buslogic/bt.c:1062 β€” sets hccb->opcode = INITIATOR_BUS_DEV_RESET for XPT_RESET_DEV.
  • sys/dev/disk/buslogic/bt.c:1284-1287 β€” btexecuteccb's nseg == 0 branch unconditionally overwrites the opcode with INITIATOR_CCB; XPT_RESET_DEV passes btexecuteccb(bccb, NULL, 0, 0) (bt.c:1070), so the reset path always lands here.
  • Terminal consequence: bt.c:1520 panic on the firmware's rejection.

Impact

On real bt(4) hardware, every CAM device reset (e.g. camcontrol reset) is transmitted as a malformed CCB; error recovery is broken, and a standards-conforming firmware reply panics the kernel. Privileged admin-triggerable panic + broken recovery.

Fix validation

fix.diff preserves INITIATOR_BUS_DEV_RESET across the nseg==0 path. 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_testable
baseline reproduced→ patch + rebuild →patched clean

object-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
↓ fix.diffper-fix-DF-4097

Confirmed kernel references

Detail

Exploit chain

camcontrol reset / CAM error recovery -> xpt_action(XPT_RESET_DEV) -> production btaction stores opcode 0x81 (bt.c:1062) -> btexecuteccb(bccb,NULL,0,0) (bt.c:1070) -> nseg==0 path overwrites opcode to 0x00 (bt.c:1285) -> firmware returns BTSTAT_INVALID_OPCODE (0x16) -> btdone panic at bt.c:1520

Evidence (decisive lines)

run1_clean.log (id=0 op=0x00 cmd_len=6 vs id=1 op=0x00 cmd_len=0 sense_len=0 through the identical production path); run_panic.log + panic.txt (panic: bt9: Invalid CCB Opcode code, btdone+0x6cd backtrace)

PoC changes

rig-built finding: XPT func_code constants corrected to 0x0901/0x0912 (XPT_FC_DEV_QUEUED is 0x900); queue->dispatch is asynchronous through the devq so each queue is followed by sleep+snap

Verified recommended fix

Preserve INITIATOR_BUS_DEV_RESET across btexecuteccb's nseg==0 path (fix.diff, object-compile validated)

Verdict

REPRODUCED both halves: (1) XPT_RESET_DEV through the real xpt_action/production btaction path transmits an opcode-0x00 INITIATOR_CCB with cmd_len=0 sense_len=0 -- the INITIATOR_BUS_DEV_RESET stored at bt.c:1062 is clobbered by btexecuteccb's unconditional nseg==0 branch at bt.c:1285; (2) conforming firmware rejects that malformed CCB with BTSTAT_INVALID_OPCODE and production btdone panics ('panic: bt9: Invalid CCB Opcode code', bt.c:1520) with backtrace captured. Device-reset error recovery is broken and admin-triggerable panic on real bt(4) hardware.