tws_passthru trusts driver_pkt.buffer_length with no bound: arbitrary-size M_ZERO kernel alloc, EFBIG ignored β command submitted with truncated SGL, protected-dmamap EINPROGRESS panic on >4GB-RAM hosts, unkillable 60s sleep + controller-wide reset
Summary
The raw u32 length drives: (1) up to ~4GiB M_ZERO allocs (NULL+copyin-EFAULT silently ignored - the command still executes with zeroed data); (2) bus_dmamap_load EFBIG only TRACE'd then SUBMITTED with a prefix SGL (partial-data firmware command); (3) >4GB-phys backing on the PROTECTED tag -> EINPROGRESS -> unconditional panic('protected dmamap callback will be defered') on any >4GB-RAM host; (4) non-completing commands sleep 60s unkillable then tws_reset the whole controller. Root-gated 0600 + hw-gated. Bound-at-entry fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4987 Β· 8 files| File | Type | Description | Size | |
|---|---|---|---|---|
| tws_pt_len.c | β | 4.6 KB | view raw | |
| build.sh | β | 94 B | view raw | |
| run.sh | β | 104 B | view raw | |
| build.log | β | 61 B | view raw | |
| run.log | β | 910 B | view raw | |
| env.txt | β | 229 B | view raw | |
| fix.diff | β | 1.7 KB | view raw | |
| verdict.json | β | 3.2 KB | view raw |
Fix verification
not_testableHardware-gated (no 3ware controller on the guest); fix.diff adds the up-front length bound and the copyin-failure abort; the bound makes the oversized kmalloc, the EFBIG-truncated-SGL submission, and the protected-dmamap EINPROGRESS panic unreachable by construction.
Confirmed kernel references
Detail
Evidence (decisive lines)
run.log (clean build + ENOENT + pciconf showing no LSI RAID device); VERDICT.md (6-step code trace with path:line); tws_pt_len.c (self-contained struct mirrors of tws_hdm.h/tws_user.h, constructs the oversized passthru command)
PoC changes
n/a (authored fresh); struct layouts mirrored from tws_hdm.h/tws_user.h into the PoC so it builds against stock guest headers
Verified recommended fix
In tws_passthru, reject driver_pkt.buffer_length > TWS_MAX_IO_SIZE with EINVAL before allocation and abort with request release when copyin fails instead of submitting the command with zeroed data
Verdict
Hardware-gated: the audit guest has no LSI 3ware controller, so /dev/tws0 does not exist and the ioctl cannot be issued (PoC builds clean and exits ENOENT, run.log). The defect itself is unconditional control flow: tws_user.c:117 assigns the raw u32 driver_pkt.buffer_length to req->length with no bound; tws_user.c:120 kmallocs that size (up to ~4 GiB, M_WAITOK|M_ZERO); the copyin error at tws_user.c:121 is ignored and the command still executes; bus_dmamap_load (maxsize 128 kB / 46 segs, tws.c:518-533) delivers EFBIG which tws_cam.c:1019-1048 only traces before SUBMITTING the command with a truncated SGL; bounce-needing buffers (>4 GB physical backing) hit reserve_bounce_pages shortfall -> EINPROGRESS -> panic('protected dmamap callback will be defered') at busdma_machdep.c:793-799 (KKASSERT above it fires first on INVARIANTS kernels); and any non-completing command sleeps 60 s uninterruptibly (no PCATCH) then triggers a controller-wide tws_reset. Expected impact on hardware: root-gated storage-stack DoS + kernel-memory exhaustion + certain kernel panic on >4 GB RAM hosts.
No comments yet.