# 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).
