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

RX mbuf m_len set from device-controlled RX descriptor flags with no bound -> heap OOB read

Summary

rum_bulk_read_callback at if_rum.c:1208 usbd_copy_out copies exactly len bytes (bounded by MCLBYTES). :1221 m->m_pkthdr.len = m->m_len = (flags>>16)&0xfff from device-controlled sc->sc_rx_desc.flags. NO check that descriptor length <= len or <= MCLBYTES. Malicious USB device (RT2573 VID/PID) sets flags bits[16..27] to 4095 -> m_len=4095 past 2048-byte cluster -> net80211/BPF reads 2047 bytes past cluster into kernel heap. Monitor mode + tcpdump = info leak to userspace. Most likely panic in ieee80211_input. Fix: if(((flags>>16)&0xfff)>len || >MCLBYTES) drop.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-0997 Β· 7 files
FileTypeDescriptionSize
fix.diff suggested-fix bounds-check descriptor pktlen against len and MCLBYTES 1.1 KB view raw
module_build.log build-log if_rum.ko compiles cleanly with the fix applied 1.3 KB view raw
VERDICT.md verdict full narrative 3.6 KB ↓ raw
README.md readme summary 957 B ↓ raw
manifest.json manifest this catalog 2.1 KB view raw
../fix_build_combined.log build-log Combined 41-finding kernel build (rc=0, -Werror clean) 5.6 MB ↓ download
../fix_build_summary.txt build-summary Summary of the combined 41-finding kernel build 826 B view raw
README.md readme summary
↓ download raw

DF-0997 β€” rum RX mbuf m_len heap OOB read

Summary

rum_bulk_read_callback at sys/bus/u4b/wlan/if_rum.c:1221 sets m->m_pkthdr.len = m->m_len = (flags >> 16) & 0xfff from a device-controlled RX descriptor field. A malicious/faulty RT2573 USB adapter can advertise a 12-bit length up to 4095 even though only ≀2048 bytes were actually received into the cluster. Subsequent readers walk off the cluster into kernel heap.

Why not tested on default guest

No Ralink RT2573 USB WiFi adapter is attached to the QEMU guest and if_rum.ko is not loaded. Reproduction requires USB HW passthrough or a USB-gadget fuzzer β€” not available here.

Fix

fix.diff bounds-checks the descriptor pktlen against both len (host-controller-bounded actual transfer length) and MCLBYTES, dropping the frame if bogus.

Compilation check

The fix (applied together with DF-0998 and DF-0999) compiles cleanly into if_rum.ko β€” see module_build.log.

VERDICT.md verdict full narrative
↓ download raw

DF-0997 β€” rum RX mbuf m_len set from device-controlled descriptor (heap OOB read)

Verdict

NOT TESTABLE on default guest (requires Ralink RT2573 USB WiFi adapter or USB-fuzzer emulation, neither present in the QEMU guest). Bug is real and confirmed by source review; the fix.diff compiles cleanly as a KLD module (see module_build.log).

Mechanism (cited)

rum_bulk_read_callback() at sys/bus/u4b/wlan/if_rum.c:1140:

  1. Line 1146 bounds-checks only the lower bound of len (the host-controller-reported actual transfer length): if (len < RT2573_RX_DESC_SIZE + IEEE80211_MIN_LEN) goto tr_setup; No upper bound on len. (In practice the USB layer caps len at the bufsize = MCLBYTES + RT2573_RX_DESC_SIZE, so the immediate write at line 1208 is bounded β€” the bug is the separate m_len assignment below.)

  2. Line 1208–1209: usbd_copy_out(pc, RT2573_RX_DESC_SIZE, mtod(m, ...), len); copies len bytes of received frame data into a freshly-allocated mbuf cluster (m_getcl β†’ MCLBYTES = 2048 bytes).

  3. Line 1221: m->m_pkthdr.len = m->m_len = (flags >> 16) & 0xfff; sets the mbuf length from a 12-bit field of the device-controlled RX descriptor flags β€” NOT from len. The descriptor is parsed at line 1162 from the USB transfer via usbd_copy_out(pc, 0, &sc->sc_rx_desc, RT2573_RX_DESC_SIZE).

The 12-bit field allows values up to 4095. A malicious or faulty USB device (the RT2573 announces its own RX descriptor contents) can advertise e.g. (flags >> 16) & 0xfff == 4095 while delivering only len (≀ MCLBYTES) actual frame bytes. The mbuf's m_len is then 4095 while only ≀2048 bytes were actually written into the cluster.

Any subsequent reader that walks m_len bytes from mtod(m, ...) walks past the 2048-byte cluster into kernel heap β€” a heap OOB read. The finding cites ieee80211_input (which panics on the bogus data) and BPF/monitor-mode tcpdump as the user-readable leak path.

Impact

  • Heap OOB read of up to ~2047 bytes per packet past the cluster boundary.
  • Reachable by a malicious USB device (considerable physical/access precondition) or by USB-fuzz on emulated device β€” CVSS:3.1/AV:P/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:H.
  • Most likely observed effect is a panic in ieee80211_input from OOB payload; an attacker who controls a BPF listener on the interface can exfiltrate leaked bytes via monitor-mode capture.

Why not tested on the guest

  • The QEMU guest has no rum device attached (no USB WiFi passthrough).
  • The if_rum.ko module is not loaded on the default kernel.
  • Reproduction requires either: (a) a physical RT2573 USB WiFi adapter passed through to the guest, or (b) a USB-fuzzer/gadget framework that emulates an RT2573 sending crafted RX descriptors. Neither is available on this audit guest.
  • The fix.diff was validated to compile cleanly as a KLD module (see module_build.log) β€” the three rum fixes (DF-0997/0998/0999) were applied simultaneously to /usr/src/sys/bus/u4b/wlan/if_rum.c and make in /usr/src/sys/bus/u4b/wlan/rum produced if_rum.ko with rc=0.

Fix

fix.diff β€” at line 1221, extract pktlen = (flags >> 16) & 0xfff and verify pktlen <= len && pktlen <= MCLBYTES; drop the frame (m_freem, ++ic->ic_ierrors, goto tr_setup) if the descriptor length is bogus. This prevents the OOB read regardless of what the device puts in the descriptor.

Files

  • fix.diff β€” bounds-check pktlen against len and MCLBYTES
  • module_build.log β€” proof the patched if_rum.c compiles
  • VERDICT.md β€” this narrative
  • README.md β€” summary
  • manifest.json β€” artifact catalog

Fix verification

not_testable

compile validated

see evidence pack

Confirmed kernel references

β€”

Detail

Exploit chain

none

Evidence (decisive lines)

β€”

Verdict

Source-confirmed. rum RX m_len from device 12-bit flags -> OOB read. No if_rum HW. Fix compiles.