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

aac_cam_fix_inquiry dereferences csio->data_ptr on successful INQUIRY completions without checking a data buffer exists (NULL-deref panic via no-data pass-through INQUIRY)

Summary

fix_inquiry reads and writes data_ptr[0] on every CAM_REQ_CMP INQUIRY with no dxfer_len/data_ptr check - a CAM_DIR_NONE passthrough INQUIRY that the adapter completes successfully NULL-derefs. Same trigger surface as DF-1822 (root /dev/passN); hw-gated. Guard fix.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-4718 Β· 4 files
FileTypeDescriptionSize
README.md β€” 1.6 KB ↓ raw
fix.diff β€” 382 B view raw
verdict.json β€” 1.5 KB view raw
manifest.json β€” 491 B view raw

DF-4718 β€” aac_cam_complete/aac_cam_fix_inquiry: INQUIRY completion dereferences csio->data_ptr without any data buffer

Root cause (code trace; hw-gated β€” no AAC adapter in the QEMU guest)

aac_cam_complete() calls aac_cam_fix_inquiry() for every XPT_SCSI_IO (sys/dev/raid/aac/aac_cam.c:626). aac_cam_fix_inquiry() matches on data[0] == INQUIRY (the CDB copy) and, when the adapter reports success, unconditionally dereferences the customer's data buffer (:551-573):

inq = (struct scsi_inquiry_data *)ccb->csio.data_ptr;
device = SID_TYPE(inq);          /* reads data_ptr[0] */
qual   = SID_QUAL(inq);
...
ccb->csio.data_ptr[0] = (qual << 5) | T_NODEVICE;   /* writes data_ptr[0] */

Nothing checks dxfer_len/data_ptr. A pass-through INQUIRY issued with CAM_DIR_NONE (dxfer_len == 0, data_ptr == NULL) β€” perfectly legal via /dev/passN (camcontrol passthrough with a CDB and no data) β€” returns SRB_STATUS_SUCCESS from the controller, making the fix-up read NULL and panic the kernel* (Fatal trap 12, fault VA 0). Kernel-internal periph INQUIRYs always attach buffers, so the trigger is a user-issued (root, pass device is 0600) or otherwise synthetic no-data INQUIRY; still a one-ioctl DoS on AAC systems and the same class DF-1822 filed for CAM_SCATTER_VALID.

Also note sense[] in struct aac_srb_response is 30 bytes (AAC_HOST_SENSE_DATA_MAX) while the copy length is bounded only by ccb->csio.sense_len β€” the 2-byte overread inside the FIB is part of DF-1823's known unbounded-sense finding.

Fix

fix.diff guards the dereference on data_ptr != NULL && dxfer_len >= 1.

Fix verification

not_testable
↓ fix.diffper-fix-DF-4718

Confirmed kernel references

Detail

Exploit chain

root (pass device 0600): camcontrol passthrough INQUIRY with no data buffer on an AAC bus -> adapter returns SUCCESS -> fix_inquiry reads *(NULL) -> kernel panic

Evidence (decisive lines)

code trace: aac_cam.c:543-549 (CDB match), :551-573 (unguarded data_ptr read+write), :626 (called for every XPT_SCSI_IO completion)

PoC changes

n/a (no seeded PoC)

Verified recommended fix

guard: status==CAM_REQ_CMP && data_ptr != NULL && dxfer_len >= 1 before touching the inquiry data (fix.diff)

Verdict

aac_cam_fix_inquiry (aac_cam.c:551-573) dereferences ccb->csio.data_ptr for successful INQUIRY completions without checking that the CCB carried a data buffer; a pass-through INQUIRY with CAM_DIR_NONE (data_ptr NULL) that the adapter completes successfully NULL-derefs in kernel mode -> panic (local DoS, same trigger class as DF-1822). Runtime verification impossible on this guest (no AAC emulation in QEMU); trace is unambiguous. fix.diff adds the buffer guard.