XPT_RESET_DEV sends its FIB under a stale Header.Command (assigned only in the XPT_SCSI_IO case; aac_release_command() never clears it)
Summary
Header.Command is set only for XPT_SCSI_IO; the RESET_DEV case submits the recycled FIB with whatever opcode it last carried (release_command re-inits everything but Command) - resets are dispatched under an unrelated opcode (worst case a container ioctl) exactly during error recovery. Hw-gated; trace-certain. Set-command-on-common-path fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4717 Β· 4 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 1.9 KB | β raw | |
| fix.diff | β | 780 B | view raw | |
| verdict.json | β | 1.6 KB | view raw | |
| manifest.json | β | 520 B | view raw |
DF-4717 β aac_cam XPT_RESET_DEV sends the FIB under a stale Header.Command
Root cause (code trace; hw-gated β no Adaptec adapter in the QEMU guest, runtime verification not possible)
fib->Header.Command is assigned ONLY in the XPT_SCSI_IO case of
aac_cam_action() (sys/dev/raid/aac/aac_cam.c:452-453). The
XPT_RESET_DEV case (:488-496) falls through to the common SRB setup
(:501-521) and sends the FIB without ever setting the command opcode.
aac_release_command()'s "re-initialize" (sys/dev/raid/aac/aac.c:1395-1407)
clears XferState, StructType, Flags, SenderSize,
ReceiverFibAddress, SenderData β not Header.Command. Every FIB
therefore carries the opcode of whatever previously used it (an earlier
ScsiPortCommand, but equally a ContainerCommand, ClusterCommand, AIF or
ioctl FIB routed through the same command pool).
Result: a device reset issued by CAM (XPT_RESET_DEV β issued by periph error recovery on command timeouts, i.e. precisely when the adapter is misbehaving) is submitted to the adapter as a stale, unrelated command with a reset-SRB payload. The firmware dispatches on Header.Command, so the reset is either silently mangled into a different operation (up to container reconfiguration if the stale opcode maps to a container ioctl) or ignored; aac_cam_complete() then interprets the response as an aac_srb_response. The reset also obviously does not reset the device, defeating CAM's error recovery escalation.
Threat: requires an AAC adapter (PCI) plus a failing/target device that triggers CAM reset escalation; consequences are adapter-state corruption / failed recovery. Device-dependent; not memory-unsafe in the host.
Fix
Set Header.Command on the common path (both XPT_SCSI_IO and
XPT_RESET_DEV) β fix.diff moves the 64-bit selection before the
direction switch. Alternatively clear Header.Command in
aac_release_command().
Fix verification
not_testableConfirmed kernel references
Detail
Exploit chain
failing/target device behind an AAC controller -> CAM periph timeout -> XPT_RESET_DEV -> FIB sent under stale opcode -> reset lost / adapter command confusion
Evidence (decisive lines)
code trace: aac_cam.c:432-499 (only SCSI_IO sets Command), aac_cam.c:511-518 (XferState/Size set, Command untouched), aac.c:1395-1407 (re-init omits Header.Command)
PoC changes
n/a (no seeded PoC)
Verified recommended fix
assign fib->Header.Command on the common path before the func_code switch (fix.diff) or clear it in aac_release_command()
Verdict
XPT_RESET_DEV submits its FIB with a stale Header.Command (set only for XPT_SCSI_IO at aac_cam.c:452-453; aac_release_command's re-init at aac.c:1395-1407 never clears it), so device resets are dispatched by the firmware under an unrelated opcode (protocol confusion / failed error recovery; worst case container-ioctl misinterpretation). Runtime verification impossible on this guest: Adaptec AAC is PCI hardware not emulated by QEMU. Fix by code trace: set the command on the common path (fix.diff).
No comments yet.