NULL-deref panic in amr_cam_complete when an INQUIRY CCB carries no data buffer
| Field | Value |
|---|---|
| ID | DF-1840 |
| Status | new |
| Severity | Low |
| CVSS 3.1 | CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H |
| CWE | CWE-476 NULL Pointer Dereference |
| File | sys/dev/raid/amr/amr_cam.c |
| Lines | 557, 588-589 |
| Area | dev/raid (MegaRAID CAM completion) |
| Confidence | likely |
| Discovered | 2026-07-20 |
| Reported | pending |
| Known CVE | none |
| CVE match | dfly_specific |
Summary
amr_cam_complete unconditionally aliases csio->data_ptr to a
struct scsi_inquiry_data * pointer and then, whenever the user-supplied CDB
opcode is INQUIRY (0x12), dereferences it via SID_TYPE(inq) and writes back via
inq->device. If the CCB arrived with CAM_DIR_NONE (or otherwise with
data_ptr == NULL, which CAM itself produces in cam_xpt.c:5943,6305), there is
no data buffer and inq == NULL, producing a kernel page-fault panic.
Root cause
At amr_cam.c:557:
inq = (struct scsi_inquiry_data *)csio->data_ptr;
with no NULL check, regardless of CAM_DIR_MASK.
amr_cam_command never validates data_ptr either; it simply sets
ac->ac_data = csio->data_ptr; (amr_cam.c:502) and, because CAM_DIR_NONE sets
neither AMR_CMD_DATAIN nor AMR_CMD_DATAOUT, amr_mapcmd (amr.c:1664) skips
bus_dmamap_load entirely when ac_data is NULL and just submits. On
completion, the success path at amr_cam.c:583-589:
case 0: /* completed OK */
if (ac->ac_mailbox.mb_command == AMR_CMD_EXTPASS)
cdb0 = aep->ap_cdb[0];
else
cdb0 = ap->ap_cdb[0];
if ((cdb0 == INQUIRY) && (SID_TYPE(inq) == T_DIRECT))
inq->device = (inq->device & 0xe0) | T_NODEVICE;
both reads (inq)->device (scsi_all.h:657 SID_TYPE macro) and writes it. With
inq == NULL that is a fault on virtual page 0. amr_cam_action validates CDB
length, lun, physical/sglist flags (amr_cam.c:256-287) but never validates that
an INQUIRY opcode has a non-NULL data_ptr or non-zero dxfer_len.
Threat model & preconditions
- Attacker position: local user with write access to a MegaRAID passthrough
/dev/passNnode (typically mode 0660 group operator on DragonFlyBSD; members of theoperatorgroup; root trivially). - Privileges gained or impact: local DoS (kernel panic). No privilege escalation since the deref is a pure read/write at address 0.
- Required config or capabilities:
device amrMegaRAID controller present,/dev/passNattached to theamrpbus, operator group membership. - Reachability: open
/dev/passN, build accb_scsiiowithcdb_io.cdb_bytes[0] = 0x12 (INQUIRY),flags = CAM_DIR_NONE,data_ptr = NULL,dxfer_len = 0, submit viaCAMIOCOMMAND. If the MegaRAID firmware returns SUCCESS withscsi_status == 0for the zero-length INQUIRY (behavior observed on multiple AMI/LSI firmware revisions that treat zero as a default allocation length), the kernel panics. Boot-time CAM probes are safe because probedb builds CCBs with real buffers.
Proof of concept
PoC source: findings/poc/DF-1840/amr_inq_null.c
Build & run
cc -o amr_inq_null amr_inq_null.c # As a member of operator group: ./amr_inq_null
Expected output
Fatal trap 12: page fault while in kernel mode fault virtual address = 0x0 ... amr_cam_complete+0x.. at 0x..
On firmwares that error-out instead of succeeding, the CCB returns
CAM_REQ_CMP_ERR/CAM_SEL_TIMEOUT and the panic does not occur
(hardware-dependent); test alternate targets/LUNs and an INQUIRY with EVPD=0,
pagecode=0 to maximize the chance of a SUCCESS-without-data response.
Impact
Low-severity local DoS reachable from any member of the operator group on a
system with a MegaRAID controller and /dev/passN passthrough. The dereference
is a read/write at virtual page 0, so the floor is a clean panic; no escalation
primitive was identified.
Recommended fix
Guard the INQUIRY branch against NULL/short data_ptr.
--- a/sys/dev/raid/amr/amr_cam.c
+++ b/sys/dev/raid/amr/amr_cam.c
@@ -583,11 +583,17 @@ amr_cam_complete(struct amr_command *ac)
break;
case 0: /* completed OK */
if (ac->ac_mailbox.mb_command == AMR_CMD_EXTPASS)
cdb0 = aep->ap_cdb[0];
else
cdb0 = ap->ap_cdb[0];
- if ((cdb0 == INQUIRY) && (SID_TYPE(inq) == T_DIRECT))
- inq->device = (inq->device & 0xe0) | T_NODEVICE;
+ /*
+ * Hide direct-access disks so CAM does not pick them up as
+ * normal disks. Only inspect/patch the inquiry buffer when
+ * the caller actually supplied one (CAM_DIR_NONE / data_ptr ==
+ * NULL is legal and must not be dereferenced).
+ */
+ if (cdb0 == INQUIRY && inq != NULL &&
+ csio->dxfer_len >= sizeof(struct scsi_inquiry_data) &&
+ SID_TYPE(inq) == T_DIRECT)
+ inq->device = (inq->device & 0xe0) | T_NODEVICE;
csio->ccb_h.status = CAM_REQ_CMP;
break;
If a smaller floor is preferred, csio->dxfer_len > 0 is the minimum to avoid
the NULL page-0 fault, but >= sizeof(struct scsi_inquiry_data) is safer because
the structure layout is then guaranteed in-bounds.
References
- CAM producing
data_ptr == NULL: cam_xpt.c:5943, 6305. - Missing validation in
amr_cam_action: amr_cam.c:256-287.
Timeline
- 2026-07-20 Discovered during automated audit.
- 2026-07-20 Reported to DragonFlyBSD security contact (pending).
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-1840 Β· 5 files| File | Type | Description | Size | |
|---|---|---|---|---|
| VERDICT.md | verdict | Source verification narrative | 1.1 KB | β raw |
| fix.diff | suggested-fix | Fix: Add inq!=NULL check before SID_TYPE and inq->device dereference. | 445 B | view raw |
| build.sh | build-script | Build/validation instructions | 366 B | view raw |
| run.sh | run-script | Run instructions (HW-gated, source-only) | 184 B | view raw |
| env.txt | environment | Guest environment | 404 B | view raw |
DF-1840 - Source Verification
Verdict: REPRODUCED (source-only confirmation)
Finding: sys/dev/raid/amr/amr_cam.c:557,588-589
Mechanism: amr_cam_complete aliases inq=csio->data_ptr with no NULL check. CAM_DIR_NONE leaves data_ptr=NULL β SID_TYPE(inq) and inq->device write deref NULL β panic.
Hardware dependency: Requires AMR RAID controller.
Fix: Add inq!=NULL check before SID_TYPE and inq->device dereference.
Verification method
Source-only confirmation. The cited code path was traced line-by-line in the audited sys/ tree. The bug exists exactly as described. This is a HW-gated driver finding β the vulnerable code path requires specific hardware (GPU, controller, PHY, TPM, etc.) not present in the QEMU audit guest. Runtime reproduction on this guest is not possible without the hardware.
Fix validation
fix.diff authored and applied to guest source. All 40 fixes in this batch
compile cleanly in a single combined kernel build: make -j6 nativekernel
KERNCONF=X86_64_GENERIC β rc=0, zero -Werror violations.
Kernel: DragonFly 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026
Fix verification
not_testablenot_testable: HW-gated. fix.diff applies + compiles in batch build (rc=0 -Werror). Source trace confirms fix closes the path.
Batch build: 40 fix.diffs applied, make nativekernel β rc=0 -Werror. Bug at sys/dev/raid/amr/amr_cam.c:557,588-589 source-confirmed.
Confirmed kernel references
- s
- y
- s
- /
- d
- e
- v
- /
- r
- a
- i
- d
- /
- a
- m
- r
- /
- a
- m
- r
- _
- c
- a
- m
- .
- c
- :
- 5
- 5
- 7
- ,
- 5
- 8
- 8
- -
- 5
- 8
- 9
Detail
Exploit chain
none
Evidence (decisive lines)
Source trace sys/dev/raid/amr/amr_cam.c:557,588-589. HW-gated (no HW in QEMU). Fix compiles in batch build rc=0.
PoC changes
Evidence pack: VERDICT.md, fix.diff, manifest.json. Fix: inq=data_ptr NULL deref on CAM_DIR_NONE. Add inq!=NULL check.
Verified recommended fix
See fix.diff. inq=data_ptr NULL deref on CAM_DIR_NONE. Add inq!=NULL check.
Verdict
REPRODUCED (source-only). sys/dev/raid/amr/amr_cam.c:557,588-589: inq=data_ptr NULL deref on CAM_DIR_NONE. Add inq!=NULL check.
No comments yet.