Passthru SGL write destination steered by user-controlled gcmd->size byte: up to ~860 bytes of DMA descriptors written past the request's 1024-byte command packet into neighboring requests of the shared command pool
Summary
For non-SCSI opcodes the DMA callback computes sgl_ptr = gcmd + gcmd->size (the user-supplied size byte 0..255) and writes up to 46 16-byte descriptors there with no bound vs the 1024-byte packet - size=255 lands the window at cmd_pkt+1148..1884, corrupting neighboring requests' headers/commands in the shared dma_mem pool (persisting: get_request never clears .hdr). Semi-controlled content (physical addrs). Root+hw-gated but geometry exact and unconditional. Reject-oversized-size fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4988 Β· 8 files| File | Type | Description | Size | |
|---|---|---|---|---|
| tws_pt_sgl.c | β | 3.9 KB | view raw | |
| build.sh | β | 94 B | view raw | |
| run.sh | β | 97 B | view raw | |
| build.log | β | 61 B | view raw | |
| run.log | β | 910 B | view raw | |
| env.txt | β | 229 B | view raw | |
| fix.diff | β | 1.8 KB | view raw | |
| verdict.json | β | 2.5 KB | view raw |
Fix verification
not_testableHardware-gated; fix.diff adds the destination-bound check before submission, making the out-of-packet SGL write unreachable by construction.
Confirmed kernel references
Detail
Evidence (decisive lines)
run.log (clean build + ENOENT + pciconf: no LSI device); VERDICT.md (geometry with all struct sizes cited from tws_hdm.h); tws_pt_sgl.c (constructs opcode=0x01 + gcmd.size=255 passthru command)
PoC changes
n/a (authored fresh); struct mirrors inline so the PoC builds against stock guest headers
Verified recommended fix
In tws_passthru reject non-SCSI commands whose gcmd->size would place the maximum-length SGL outside the 1024-byte command packet (128 + 4size + max_sglsentsize <= 1024)
Verdict
Hardware-gated (no 3ware controller on the audit guest; PoC builds clean and exits ENOENT, run.log). The OOB write is proven by exact size arithmetic: tws_user.c:126 copies the user's 896-byte command including the generic size byte; for non-EXECUTE_SCSI opcodes tws_cam.c:1035 computes the SGL destination as gcmd + 4*gcmd->size (gcmd->size user-controlled 0..255) and tws_cam.c:1038/1053-1100 writes up to 46 16-byte descriptors there β with size=255 the window ends at cmd_pkt+1884 vs the 1024-byte packet, i.e. up to ~860 bytes past this request's packet into the neighboring request packets of the shared dma_mem pool (tws.c:463-636). nseg is tag-bounded (46); the destination is not bounded at all. Root-gated 0600 device + hardware gate -> Low severity, CWE-787.
No comments yet.