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

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)

No comments yet.

PoC verification

Evidence pack

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

Hardware-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.

↓ fix.diffper-fix-DF-4987

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.