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

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)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-4988 Β· 8 files
FileTypeDescriptionSize
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_testable
baseline no→ patch + rebuild →patched clean

Hardware-gated; fix.diff adds the destination-bound check before submission, making the out-of-packet SGL write unreachable by construction.

↓ fix.diffper-fix-DF-4988

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.