Heap buffer overflow in USB RX frame aggregation: m_getcl (2048B) too small for m_copydata of up to 4080B
Summary
When Ralink USB device batches multiple 802.11 frames into one USB bulk transfer (DMA aggregation) driver copies each non-final aggregated frame into freshly allocated mbuf. mbuf allocated with m_getcl() providing MCLBYTES (2048-byte) cluster but m_copydata() writes dmalen+sizeof(struct rt2870_rxd) bytes into it. dmalen up to ~4076 (bounded only by RUN_MAX_RXSZ=4096) so copy overflows 2048-byte cluster by up to 2032 bytes. m_copydata does not bounds-check destination (kern/uipc_mbuf.c:1671 KASSERT only validates source). Source sc->rx_m correctly allocated m_getjcl MJUMPAGESIZE (4096). Two attack vectors: (1) Wireless adjacent-network rogue AP sends burst of large data frames firmware batches them overflow triggers (2) USB physical malicious device impersonating Ralink sends crafted bulk IN. Impact: kernel heap corruption arbitrary kernel code execution or panic DoS.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-2358 Β· 6 files| File | Type | Description | Size | |
|---|---|---|---|---|
| VERDICT.md | verdict | gate analysis + RX-aggregation dest-cluster overflow trace | 3.7 KB | β raw |
| fix.diff | suggested-fix | allocate dest mbuf with m_getjcl(MJUMPAGESIZE) like the source rx_m | 699 B | view raw |
| build.sh | build-script | documents HW gate | 159 B | view raw |
| run.sh | run-script | prints gate proof | 290 B | view raw |
| env.txt | environment | guest env | 1.1 KB | view raw |
| wifi_gate.txt | gate-proof | usbconfig empty, no wlan iface | 311 B | view raw |
DF-2358 β Heap buffer overflow in USB RX frame aggregation (sys/bus/u4b/wlan/if_run.c)
Verdict: NOT REPRODUCED (HW-gated); REAL BUG IN SOURCE (defense-in-depth fix warranted)
Hardware gate (why the PoC cannot run on this guest)
run is the Ralink RT2700U/RT2800U/RT3000U/RT3900E 802.11abgn USB wifi driver.
It attaches only when a matching Ralink USB wifi dongle is plugged in. The audit
QEMU/KVM guest has no USB device and no wifi interface:
$ usbconfig list # No device match or lack of permissions. $ ifconfig -l # vtnet0 lo0 (no wlan/run) $ pciconf -l | grep -iE "ralink|148f|1435|0789" # (no Ralink USB wifi chip) $ kldstat # kernel + ehci.ko + xhci.ko only
The RX aggregation path run_bulk_rx_callback runs only when the run driver
has attached to a Ralink USB wifi device and is receiving batched frames. With no
such device the path never executes; the unprivileged maxx user cannot plug a
USB dongle into the QEMU guest, and there is no adjacent rogue-AP threat (no
radio).
Source trace β the bug is REAL (sys/bus/u4b/wlan/if_run.c)
run_bulk_rx_callback (if_run.c:2897-...) splits an aggregated USB bulk
transfer into individual 802.11 frames. Bounds (if_runvar.h:26-27):
#define RUN_MAX_RXSZ MIN(4096, MJUMPAGESIZE) /* 4096 */
The source buffer sc->rx_m is correctly allocated with m_getcl/m_getjcl
(MJUMPAGESIZE = 4096), so the source of the copy is in bounds. The problem
is the destination:
m->m_pkthdr.len = m->m_len = xferlen; /* if_run.c:2985 */
for(;;) {
dmalen = le32toh(*mtod(m, uint32_t *)) & 0xffff; /* device-controlled 16-bit */
if ((dmalen >= (uint32_t)-8) || (dmalen == 0) || ((dmalen & 3) != 0)) break;
if ((dmalen + 8) > (uint32_t)xferlen) break; /* if_run.c:2996: bound by xferlen, not dest */
if ((xferlen -= dmalen + 8) <= 8) { ... run_rx_frame(sc, m, dmalen); break; } /* final frame uses 4096-byte src buf */
/* aggregated (non-final) frames: copy into a NEW m_getcl cluster */
m0 = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); /* if_run.c:3013: cluster = MCLBYTES = 2048 */
...
m_copydata(m, 4, dmalen + sizeof(struct rt2870_rxd), /* if_run.c:3023 */
mtod(m0, void *)); /* writes dmalen+rxd_size into 2048-byte cluster */
dmalen is bounded only by xferlen (β€ RUN_MAX_RXSZ = 4096), so for a
non-final aggregated frame dmalen + sizeof(struct rt2870_rxd) can reach ~4080
bytes β but m0 is a m_getcl cluster of only MCLBYTES = 2048 bytes.
m_copydata does not bounds-check the destination (the KASSERT at
kern/uipc_mbuf.c:1671 validates only the source), so the copy overflows the
2048-byte cluster by up to ~2032 bytes into adjacent slab memory.
Two attack vectors: (1) wireless adjacent-network rogue AP bursts large data frames the firmware aggregates; (2) a malicious USB device impersonating Ralink sends a crafted bulk IN. Impact: kernel heap corruption β arbitrary kernel code execution or panic.
Exploit chain status
Not pursuable β primitive (heap overflow of destination cluster) requires a Ralink USB wifi dongle or adjacent radio (absent) β valid Phase-6 hard blocker: dead path at runtime on this guest. On hardware this is a write-capable heap overflow.
PoC changes
None. No Ralink USB wifi dongle on guest; verified by source trace only.
Recommended fix
Use a destination mbuf large enough for dmalen + sizeof(rt2870_rxd) (e.g.
m_getjcl(MJUMPAGESIZE)) or bound dmalen against MCLBYTES -
sizeof(rt2870_rxd). See fix.diff (matches finding proposal: allocate the
destination with a cluster that can hold the maximum possible copy).
Fix verification
not_testablenot_testable: PoC cannot run on this guest (HW-gated, no target device). fix.diff validated by git apply --check (clean) + line-accurate source trace confirming it closes the cited path.
git apply --check findings/poc/DF-2358/fix.diff -> OK (clean apply). No runtime test possible (HW-gated).
Confirmed kernel references
Detail
Exploit chain
none β valid hard blocker (driver/device path dead at runtime on this guest: no target HW / no attached device). No unprivileged->root path.
Evidence (decisive lines)
usbconfig list -> No device match or lack of permissions.; pciconf -l -> no target controller HW; ifconfig -l -> vtnet0 lo0; kldstat -> kernel/ehci/xhci only; ls /dev/<target> -> No such file or directory; id maxx -> uid=1001 groups=1001 (not operator). Source confirmed at cited lines.
PoC changes
Created findings/poc/DF-2358/{VERDICT.md,fix.diff,build.sh,run.sh,env.txt,gate_proof.txt,manifest.json}. No PoC source (HW-gated).
Verified recommended fix
change m0=m_getcl to m_getjcl(MJUMPAGESIZE). Full git-apply-able diff in findings/poc/DF-2358/fix.diff (git apply --check OK).
Verdict
NOT REPRODUCED (HW-gated). The bug is REAL in source (traced line-by-line). run heap overflow in USB RX frame aggregation (non-final frame m_getcl=2048, copy up to ~4080); no Ralink USB wifi. Gate confirmed via usbconfig list (No device match / no /dev/ugen*), pciconf -l (no target controller HW), ifconfig (vtnet0 lo0 only), kldstat (no target module), and ls /dev (no target nodes). maxx (uid 1001, not in operator) cannot reach any /dev/usbctl write path.
No comments yet.