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

XPT_RESET_DEV dereferences softc->atadev[tid] with no NULL or bounds check

Summary

atapi_action XPT_RESET_DEV case directly dereferences softc->atadev[ccb_h->target_id]->dev without NULL guard that XPT_PATH_INQ (:385) and XPT_SCSI_IO (:490) apply. If ATAPI device removed (atadev[tid]=NULL by reinit_bus) but CAM path not yet torn down CAM dispatches XPT_RESET_DEV causing NULL deref panic. No bounds check: atadev[] has 2 slots target_id can be CAM_TARGET_WILDCARD. Reachable via atacontrol reset or hot-plug race. [VERIFIED pass2: reproduced - XPT_RESET_DEV with atadev 0 NULL panics at the exact verbatim deref Fatal trap 12 VA 0; DEV_NOT_THERE fix A/B guest survives]

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-2501 Β· 9 files
FileTypeDescriptionSize
README.md β€” 1005 B ↓ raw
VERDICT.md β€” 2.3 KB ↓ raw
build.sh β€” 99 B view raw
run.log β€” 371 B view raw
env.txt β€” 963 B view raw
fix.diff β€” 994 B view raw
manifest.json β€” 783 B view raw
verdict.json β€” 2.3 KB view raw
panic.txt β€” 370 B view raw

DF-2501 -- XPT_RESET_DEV dereferences softc->atadev[tid] with no NULL/bounds check

Verification used the shared rig tree at /root/rigs on the audit guest (see manifest). The rig for this finding: dfv_acam (rig.c = harness, gen.sh = verbatim extractor, dfv_*_extract.h = generated production text). The decisive outputs below were captured live on the guest during the 2026-10-24 verification session; full session logs are summarized per run.

Build

sh build.sh            # extracts verbatim driver text + builds the KLD

Run (guest, root)

kldload ./dfv_rig.ko

kldload dfv_acam.ko; sysctl kern.dfv_acam_run=1 # panics the stock kernel

Expected

panic.txt: Fatal trap 12 at dfv_acam_sysctl (inlined verbatim atapi_action XPT_RESET_DEV), fault VA 0x0; fixed: xpt_done(status=0x8) CAM_DEV_NOT_THERE.

Fix validation

fix.diff adds the same NULL/bounds guard XPT_SCSI_IO uses; A/B survives with CAM_DEV_NOT_THERE.

Verdict: reproduced / impact=panic (see verdict.json, VERDICT.md)

VERDICT.md
↓ download raw

DF-2501 verdict -- XPT_RESET_DEV dereferences softc->atadev[tid] with no NULL/bounds check

status: reproduced reproduced: 1 impact: panic confidence: certain attempts: 2 runtime_sec: 700

The verbatim atapi_action XPT_RESET_DEV case (atapi-cam.c:428-432) evaluates softc->atadev[tid]->dev with neither the NULL guard XPT_PATH_INQ applies at :385 nor the guard XPT_SCSI_IO applies at :490. Dispatching XPT_RESET_DEV with atadev[0] == NULL (the state reinit_bus leaves behind) panicked the kernel at the exact deref: Fatal trap 12, fault VA 0x0, stopped at the movq through the NULL atadev - the precise instruction the finding cites. Fixed source A/B: the same dispatch returns CAM_DEV_NOT_THERE (xpt_done status=0x8 logged) and the guest survives. Trigger model per the filing: CAM dispatch racing atacontrol reinit/hot-plug - privileged/physical context; the pass(4) route to XPT_RESET_DEV is also gated by raw-device permissions on this system.

Evidence (decisive lines)

(kernel serial console) Fatal user address access from kernel mode from sysctl at ffffffff82606e66 Fatal trap 12: page fault while in kernel mode fault virtual address = 0x0 Stopped at dfv_acam_sysctl+0x116: movq (%rax),%rcx <- atadev[tid]->dev, rax=0 --- fixed source A/B --- DF2501: log: xpt_done(status=0x8) <- CAM_DEV_NOT_THERE, guest survives

Panic

Fatal user address access from kernel mode from sysctl at ffffffff82606e66
Fatal trap 12: page fault while in kernel mode
fault virtual address   = 0x0
fault code      = supervisor read data, page not present
Stopped at      dfv_acam_sysctl+0x116:   movq    (%rax),%rcx
(trace: verbatim atapi_action XPT_RESET_DEV -> softc->atadev[0]->dev with atadev[0]=NULL, atapi-cam.c:432)

Exploit chain / privesc assessment

deterministic kernel NULL-deref panic; privesc ceiling: none (DoS).

Fix + A/B

fix.diff adds the same NULL/bounds guard XPT_SCSI_IO uses; A/B survives with CAM_DEV_NOT_THERE.

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

fixed
↓ fix.diffper-fix-DF-2501

Confirmed kernel references

Detail

Exploit chain

deterministic kernel NULL-deref panic; privesc ceiling: none (DoS).

Evidence (decisive lines)

panic.txt: Fatal trap 12 at dfv_acam_sysctl (inlined verbatim atapi_action XPT_RESET_DEV), fault VA 0x0; fixed: xpt_done(status=0x8) CAM_DEV_NOT_THERE.

PoC changes

verbatim atapi_action + struct extraction; ATA transport interposed; get_mplock stubs (not exported to KLDs on this kernel).

Verified recommended fix

NULL/bounds guard atadev[tid] in XPT_RESET_DEV like XPT_SCSI_IO

Verdict

The verbatim atapi_action XPT_RESET_DEV case (atapi-cam.c:428-432) evaluates softc->atadev[tid]->dev with neither the NULL guard XPT_PATH_INQ applies at :385 nor the guard XPT_SCSI_IO applies at :490. Dispatching XPT_RESET_DEV with atadev[0] == NULL (the state reinit_bus leaves behind) panicked the kernel at the exact deref: Fatal trap 12, fault VA 0x0, stopped at the movq through the NULL atadev - the precise instruction the finding cites. Fixed source A/B: the same dispatch returns CAM_DEV_NOT_THERE (xpt_done status=0x8 logged) and the guest survives. Trigger model per the filing: CAM dispatch racing atacontrol reinit/hot-plug - privileged/physical context; the pass(4) route to XPT_RESET_DEV is also gated by raw-device permissions on this system.