# DF-4399 — Passthrough SGL written at user-chosen offset (gcmd->size) into the shared command DMA arena

## What
`sys/dev/raid/tws/tws_cam.c:1029-1045` (`tws_dmamap_data_load_cbfn`): for a
passthrough request whose opcode is NOT `TWS_FW_CMD_EXECUTE_SCSI`, the scatter/gather
list destination is computed as

```c
gcmd = &req->cmd_pkt->cmd.pkt_g.generic;
sgl_ptr = (u_int32_t *)(gcmd) + gcmd->size;   /* size is u_int8_t, 0..255 */
gcmd->size += sgls * ((is64bit && !use_32bit_sgls) ? 4 : 2);
tws_fill_sg_list(sc, segs, sgl_ptr, sgls);
```

`gcmd->size` is taken verbatim from the user: `tws_passthru()`
(`sys/dev/raid/tws/tws_user.c:126-127`) copies the whole
`struct tws_command_apache` (including `pkt_g.generic.size`) from the
`TWS_IOCTL_FIRMWARE_PASS_THROUGH` (`_IOWR('T',202,...)`) ioctl buffer before
submission, and nothing validates it.

`tws.c:463-464, 499-509`), so this is corruption of *unrelated in-flight
kernel command packets* (live SCSI I/O command headers/SGRs) with
semi-controlled data (bus addresses of the attacker's buffer, page-multiple
lengths) — not a wild heap write.

**Precise landing (pack(1) layout, `tws_hdm.h:287-336`):** packet size is
1024 B (128 B header + 896 B body). `size=255` ⇒ SGL starts at
`cmd_buf[2] + 128 + 1020 = arena+3196`, which is **offset 124 of packet 3** —
byte-for-byte its `header_desc` (`size_header`, `request_id` u16,
`size_sense`, header bytes 124..128) and then its command body. With a
128 kB buffer (32 segments × 16 B) it spans up to packet-3 offset 636.

## Impact
Root-only (`/dev/tws0` is 0600 root:operator, `tws.c:284-286`). A privileged user
corrupts neighboring command packets including the header through which the
firmware DMA-writes sense data (`sense_bufs[i].hdr`, `tws.c:617`), so the
firmware can be fed forged request ids / SGLs of concurrent I/O — kernel-level
memory corruption reachable from a file-descriptor ioctl.

## Trigger
`trigger.c` — root opens `/dev/tws0`, issues `TWS_IOCTL_FIRMWARE_PASS_THROUGH`
with opcode `TWS_FW_CMD_SET_PARAM` (0x13), `generic.size = 255`,
`buffer_length = 4096`. The callback then writes the SGL at `gcmd+1020`.

## Reproduce
```
cc -O2 -o trigger trigger.c   # build
sudo ./trigger /dev/tws0      # run on a host with a tws(4) controller
```
Expected: kernel log noise from corrupted neighbor commands / unstable I/O;
on a debug kernel, tws trace entries show request 3 misbehaving.

## Status on the audit QEMU guest
No 3ware HBA present → inconclusive; offset arithmetic proven from struct sizes
(`tws_hdm.h:273-336`: header 128 B, packet 1152 B, `size` u8) in VERDICT.md.
