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

Unbounded CDB copy into fixed 12-byte SRB CmdBlock overwrites SRB pointer fields

Summary

trm_action XPT_SCSI_IO at trm.c:591: pSRB->ScsiCmdLen=pcsio->cdb_len (u_int8_t 0-255). bcopy at :598-599/:609-610 copies cdb_len bytes into CmdBlock[12] (trm.h:145) with NO bounds check. 16-byte CDB (READ_16/WRITE_16 from da(4) on >2TB disk) writes 4 bytes past into Segment0. pass(4) with CAM_CDB_POINTER cdb_len=200 overwrites pNextSRB/pSRBDCB/pSRBSGL/pccb pointers -> UAF/code execution. SCSI_MAX_CDBLEN=16 > CmdBlock=12. Fix: reject cdb_len>sizeof(CmdBlock).

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-1235 Β· 12 files
FileTypeDescriptionSize
VERDICT.md verdict full path:line trace, threat model, fix rationale 5.2 KB ↓ raw
README.md readme claim, verdict, runnable-PoC instructions 2.1 KB ↓ raw
trm_cdb_overflow.c trigger-source PoC: reachability check (kldstat grep trm) 2.1 KB view raw
build.sh build-script cc -O -Wall -o trm_cdb_overflow trm_cdb_overflow.c 193 B view raw
run.sh run-script ./trm_cdb_overflow 104 B view raw
build.log build-log PoC build, full output 127 B view raw
run.log run-log PoC run on this guest (trm not loaded) 451 B view raw
fix.diff suggested-fix reject cdb_len > sizeof(pSRB->CmdBlock) in trm_action with CAM_REQ_INVALID 792 B view raw
fix_build.log build-log kernel build rc=0 with all 5 fixes applied; trm.c compiled clean as trm.ko under -Werror 2.1 KB view raw
env.txt environment guest uname, cc version, PCI topology 2.0 KB view raw
../fix_build_combined.log build-log Combined 41-finding kernel build (rc=0, -Werror clean) 5.6 MB ↓ download
../fix_build_summary.txt build-summary Summary of the combined 41-finding kernel build 826 B view raw
README.md readme claim, verdict, runnable-PoC instructions
↓ download raw

DF-1235 β€” README

Finding

trm_action (XPT_SCSI_IO) at sys/dev/disk/trm/trm.c:591,598-599,609-610 copies cdb_len bytes from the CAM CDB into pSRB->CmdBlock[12] with NO bounds check. CmdBlock is 12 bytes (trm.h:145), but cdb_len is a u_int8_t (0..255). A 16-byte CDB (READ_16/WRITE_16 on >2 TB disks) overflows by 4 bytes into Segment0; pass(4) with CAM_CDB_POINTER and cdb_len=200 overwrites pNextSRB/pSRBDCB/pSRBSGL/pccb (trm.h:144-160) β†’ SRB type confusion / UAF / hijack.

Verdict

NOT REPRODUCED on this guest: trm is not in X86_64_GENERIC (sys/config/X86_64_GENERIC has no device trm) and no Tekram DC-395 controller is present in pciconf -lv. trm_action is dead code on this kernel. PoC prints the reachability status.

Confidence (bug is real): certain β€” traced line-by-line in sys/. Impact ceiling: operator-group β†’ kernel heap corruption / type confusion on any host with a Tekram DC-395U/UW adapter and the trm module loaded.

How to reproduce

./build.sh && ./run.sh

Expected on this guest: PoC builds clean, prints "trm driver NOT loaded (no 'device trm' in X86_64_GENERIC)" and "trm_action is dead code on this kernel". On a host with the trm module loaded and a Tekram adapter, issuing a CAMIOCOMMAND XPT_SCSI_IO with cdb_len > 12 through /dev/passN overflows CmdBlock.

Files

Path Purpose
trm_cdb_overflow.c PoC: reachability check (kldstat grep trm)
build.sh / run.sh exact build/run commands
fix.diff reject cdb_len > sizeof(CmdBlock) in trm_action
VERDICT.md full path:line trace, threat model, fix rationale
build.log / run.log PoC build + run outputs
fix_build.log module-build compile validation of fix.diff
env.txt guest uname / cc / device topology
VERDICT.md verdict full path:line trace, threat model, fix rationale
↓ download raw

DF-1235 β€” VERDICT

Finding: trm_action(XPT_SCSI_IO) at sys/dev/disk/trm/trm.c:591 copies the SCSI CDB into pSRB->CmdBlock[12] with no bounds check; a cdb_len larger than 12 (legitimate READ_16/WRITE_16 is 16; user cdb_len via pass(4) can be up to 255) overflows into Segment0, Segment1, pNextSRB, pSRBDCB, pSRBSGL, and pccb (the SRB layout at trm.h:144-160).

Status: NOT REPRODUCED on this guest β€” trm is not in X86_64_GENERIC (sys/config/X86_64_GENERIC has no device trm) and no Tekram DC-395 controller is present. Confidence (bug is real): certain (traced line-by-line in sys/). Impact ceiling: SRB type confusion / UAF / hijack of the pccb, pNextSRB, pSRBDCB, pSRBSGL pointers β€” exploitable by any local user with write access to /dev/passN (operator group) once a Tekram adapter and trm module are present.

Mechanism (confirmed line-by-line in sys/)

  1. struct _SRB at sys/dev/disk/trm/trm.h:144-160: c struct _SRB { u_int8_t CmdBlock[12]; /* :145 -- 12 bytes only */ u_long Segment0[2]; /* :146 -- immediate overflow target */ u_long Segment1[2]; /* :147 */ struct _SRB *pNextSRB; /* :148 -- attacker-overwritable ptr */ struct _DCB *pSRBDCB; /* :149 -- attacker-overwritable ptr */ SGentry SgSenseTemp; /* :150 */ PSEG pSRBSGL; /* :152 -- attacker-overwritable ptr */ ... union ccb *pccb; /* :160 -- attacker-overwritable ptr */ ... }; The CDB target is 12 bytes. SCSI_MAX_CDBLEN is 16. The 4-byte gap is the bug.

  2. trm_action at sys/dev/disk/trm/trm.c:591: c pSRB->ScsiCmdLen = pcsio->cdb_len; and at trm.c:596-610 (both CDB_POINTER and inline-cdb branches): c if ((pccb->ccb_h.flags & CAM_CDB_POINTER) != 0) { if ((pccb->ccb_h.flags & CAM_CDB_PHYS) == 0) { bcopy(pcsio->cdb_io.cdb_ptr, pSRB->CmdBlock, pcsio->cdb_len); /* :598-599 */ } ... } else bcopy(pcsio->cdb_io.cdb_bytes, pSRB->CmdBlock, pcsio->cdb_len); /* :609-610 */ No bounds check on cdb_len. pcsio->cdb_len is a u_int8_t in struct ccb_scsiio, so it can be 0..255.

  3. Real-world overflow sources: - Disk I/O on a > 2 TB LUN issues READ_16/WRITE_16 (16-byte CDBs). cdb_len=16 overflows by 4 bytes into Segment0. The driver does not advertise PI_MSG_EXTENDED CDB support and does not reject these CDBs, so this happens on real hardware. - pass(4) with CAM_CDB_POINTER lets any user with write access to /dev/passN set cdb_len to any value 0..255. With cdb_len=200, the bcopy overwrites pNextSRB, pSRBDCB, pSRBSGL, and pccb β€” type confusion / UAF / hijack.

  4. Subsequent code dereferences these corrupted pointers: - pSRB->pSRBDCB at trm.c:485 in trm_SendSRB, - pSRB->pNextSRB at trm.c:463, 502, 511, 514, - pSRB->pSRBSGL in the SG copy loop at trm.c:433, - pSRB->pccb at trm.c:423 and in every completion path.

Why it is NOT REPRODUCED on this guest

  • sys/config/X86_64_GENERIC does not contain device trm. The driver is built only as the loadable module trm.ko.
  • The audit guest has no Tekram DC-395U/UW controller in pciconf -lv, so even loading trm.ko would not bind the driver to any device and no /dev/passN would route through trm_action.
  • PoC trm_cdb_overflow.c confirms kldstat -v | grep trm returns empty.

Threat model & privilege boundary

/dev/passN is created by pass(4) and given default devfs perms of 0600 root:operator (only the QEMU CD-ROM shows up on the audit guest, visible as /dev/pass0). Any user in the operator group can issue CAMIOCOMMAND ioctls with XPT_SCSI_IO and a forged ccb_scsiio with arbitrary cdb_len up to 255. On a host with a Tekram adapter and the trm module loaded, this is a real operator-group β†’ kernel corruption vector. Note: loading trm.ko requires root, but loading the driver is something a real admin does once at install time on a host with the hardware β€” the exploit itself is fully unprivileged.

Fix (authored in fix.diff, applied + compile-validated)

Reject cdb_len > sizeof(pSRB->CmdBlock) immediately after the assignment at trm.c:591, returning CAM_REQ_INVALID and the SRB to the free list (matching the existing rejection pattern at trm.c:600-606 for CAM_CDB_PHYS). This is the minimum root-cause fix.

(Deepening CmdBlock to 16 would also fix the size but changes the DMA wire format the chip expects β€” out of scope for a security patch.)

Validation

  • fix.diff applies cleanly with patch -p1 --forward (verified).
  • All 5 audit fixes applied together; make -j6 nativekernel KERNCONF=X86_64_GENERIC returned rc=0 with no errors / warnings under -Werror. trm.c was compiled cleanly as the loadable module trm.ko (built as part of the kernel module set).
  • Fix is not_testable at runtime on this guest (trm not in GENERIC, no Tekram HW).

Fix verification

not_testable

compile validated

nativekernel rc=0

Confirmed kernel references

β€”

Detail

Exploit chain

none

Evidence (decisive lines)

β€”

Verdict

Source-confirmed. trm CDB copy no bounds vs CmdBlock[12] -> SRB corruption. trm NOT in GENERIC, no Tekram HW.