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

Unconditional panic() on device-fed completion status bytes: q_status != QS_DONE (fires on legitimate QS_DONE|QS_DISC1) and unhandled host_stat codes (including codes the driver itself enumerates)

Summary

The walk panics unless the raw LRAM q_status byte is exactly QS_DONE or carries QS_ABORTED - the driver's own ABI defines QS_DISC1/DISC2 bits, so a legitimate 0x82 completion or any corrupt byte panics. adv_done's default arm panics on host_stat codes outside the handled set, including two codes the switch enumerates only in order to panic. Guest model: 14/30 tabulated values panic incl. legitimate ABI bits. Log-and-complete-with-error fix (DF-4042/4308 family).

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-4351 Β· 9 files
FileTypeDescriptionSize
df4351.c β€” 5.5 KB view raw
build.sh β€” 86 B view raw
run.sh β€” 89 B view raw
build.log β€” 496 B view raw
run.log β€” 2.6 KB view raw
env.txt β€” 966 B view raw
fix.diff β€” 1.2 KB view raw
VERDICT.md β€” 2.7 KB ↓ raw
README.md β€” 1.1 KB ↓ raw

DF-4351 β€” panic() on device-fed completion status bytes (DF-4042/DF-4308 family, narrow twin)

Build / Run (guest model)

cc -O2 -Wall -o df4351 df4351.c
./df4351

Expected: 14 of 30 tabulated device-fed values lead to kernel panic, including q_status = QS_DONE|QS_DISC1 (0x82) β€” a legitimate ABI combination (QS_DISC1/QS_DISC2 are defined queue-state bits, advlib.h:565-566) β€” and host_stat codes the driver itself enumerates (QHSTA_D_LRAM_CMP_ERROR 0x81, QHSTA_M_MICRO_CODE_ERROR_HALT 0xA1).

Root cause

  • advansys.c:1092-1094 β€” panic unless the raw LRAM q_status byte is exactly QS_DONE or has QS_ABORTED set (copied unmasked by adv_copy_lram_doneq, advlib.c:816-818).
  • advansys.c:1235-1237 β€” adv_done default arm panics on host_stat codes outside the handled set, including codes the switch itself lists only to panic on.

Hostile/corrupt SCSI peripheral or buggy firmware β†’ instant kernel panic from an ordinary completion. Same family as DF-4042 (amd.c) and DF-4308 (adwcam.c), both accepted at Low for this threat model.

Fix

fix.diff (git apply --check clean): log + complete with error instead of panicking at both sites.

VERDICT.md
↓ download raw

DF-4351 VERDICT

Status: untested (kernel path) β€” code defect certain; guest model replays the exact panic predicates.

Root cause (line-accurate)

Two unconditional panic() sites gated only on adapter-written LRAM bytes:

  1. sys/dev/disk/advansys/advansys.c:1092-1094 if ((scsiq.q_status != QS_DONE) && (scsiq.q_status & QS_ABORTED) == 0) panic("adv_qdone: completed scsiq with unknown status"); q_status is copied verbatim from LRAM by adv_copy_lram_doneq (advlib.c:816-818, no masking). The driver's own queue-state ABI (advlib.h:562-569) defines QS_DISC1 (0x02)/QS_DISC2 (0x04); a completion byte of QS_DONE|QS_DISC1 (0x82) β€” a state the firmware can legitimately write for a reconnected command β€” is an instant panic. Any corrupt LRAM byte without QS_ABORTED likewise.

  2. advansys.c:1227-1237 β€” adv_done's inner switch routes QHSTA_D_QDONE_SG_LIST_CORRUPTED (0x21), QHSTA_D_ASC_DVC_ERROR_CODE_SET (0x22), QHSTA_D_HOST_ABORT_FAILED (0x23), QHSTA_D_EXE_SCSI_Q_FAILED (0x24), QHSTA_D_ASPI_NO_BUF_POOL (0x26), QHSTA_M_BAD_TAG_CODE (0x46), and β€” although the driver's ABI enumerates them β€” QHSTA_D_LRAM_CMP_ERROR (0x81) and QHSTA_M_MICRO_CODE_ERROR_HALT (0xA1) into panic("%s: Unhandled Host status error %x"), plus every undefined value.

Consequence: an ordinary I/O completion carrying any of these device-written bytes takes the whole system down. Family precedent: DF-4042 (amd.c, MESSAGE REJECT panic) and DF-4308 (adwcam.c, four unhandled host_status codes) β€” both accepted, Low severity for the hostile-peripheral threat model.

Verification

  • Kernel path untestable on the guest (no AdvanSys HBA; env.txt).
  • Guest model df4351.c (cc 8.3; build.log/run.log) tabulates the two predicates verbatim over the device-fed value domains: 14/30 values panic, including the two "legitimate ABI bits" rows (0x82/0x84) and the two enumerated-but-panicking host codes (0x81/0xA1).

Fix validation

Kernel-level validation impossible on this guest. fix.diff (git apply --check clean) replaces both panics: site 1 logs and falls through to normal completion-with-error handling (adv_done's default: arm at :1248-1253 already maps unknown done_stat to CAM_REQ_CMP_ERR, so no control-flow hazard); site 2 reports via xpt_print_path and sets CAM_REQ_CMP_ERR, matching the handling of QHSTA_M_AUTO_REQ_SENSE_FAIL.

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 no→ patch + rebuild →patched clean

Kernel fix validation impossible on this guest (no AdvanSys HBA). fix.diff is git-apply-clean against sys/; control-flow analysis: site 1 falls through to the existing unknown-done_stat handling (:1248-1253 -> CAM_REQ_CMP_ERR), site 2 mirrors the QHSTA_M_AUTO_REQ_SENSE_FAIL arm; neither path leaves the ccb uncompleted.

fix.diff; adv_done default-arm trace in VERDICT.md (:1248-1253)
↓ fix.diffper-fix-DF-4351

Confirmed kernel references

Detail

Exploit chain

hostile/corrupt SCSI peripheral or compromised AdvanSys firmware writes any completion with q_status not in {QS_DONE, *|QS_ABORTED} or host_stat in the panic set -> adv_intr -> adv_run_doneq/adv_done -> panic() -> kernel DoS. No unprivileged-user or remote path.

Evidence (decisive lines)

run.log ('PANIC-ON-DEVICE-STATUS CONFIRMED (model)', 14/30 table incl. 0x82/0x84/0x81/0xA1 rows); VERDICT.md; env.txt; fix.diff (git apply --check clean)

PoC changes

No seed PoC. Authored df4351.c: tabulates the two panic predicates (transcribed verbatim) over the q_status byte domain and the host_stat code table from advlib.h:640-667.

Verified recommended fix

Replace both device-fed panics with log + CAM_REQ_CMP_ERR completion (see fix.diff).

Verdict

Source-certain, hardware-gated (DF-4042/DF-4308 family, narrow twin). advansys.c:1092-1094 panics unless the raw LRAM completion-status byte is exactly QS_DONE or carries QS_ABORTED - the byte is copied unmasked from the adapter (advlib.c:816-818), and the driver's own ABI defines QS_DISC1/QS_DISC2 queue-state bits, so a legitimate 0x82 (QS_DONE|QS_DISC1) or any corrupt value panics the kernel from an ordinary completion. advansys.c:1235-1237 panics on host_stat codes the switch does not handle, including codes it enumerates only to panic on (0x81 QHSTA_D_LRAM_CMP_ERROR, 0xA1 QHSTA_M_MICRO_CODE_ERROR_HALT). Hostile SCSI peripheral / buggy firmware -> instant kernel DoS; family precedent DF-4042 and DF-4308 (both Low). Kernel path untestable on the guest (no AdvanSys HBA). Guest model (cc 8.3) replays both predicates verbatim: 14/30 tabulated device-fed values panic, incl. the legitimate-bit and enumerated-code rows.