rxeof trusts the device-fed 12-bit RX frame length against a 2048-byte cluster: m_len up to 4095 β up to 2047-byte OOB read past the mbuf cluster into ieee80211_input (kernel heap disclosure / parser crash)
Summary
rt2661_rx_intr finalizes the RX mbuf with the 12-bit descriptor length straight from the DMA'd descriptor - up to 4095 - while the mbuf is a 2048-byte cluster. No clamp exists anywhere on the path; ieee80211_input then parses up to 2047 bytes past the cluster as frame content, deliverable to the stack/userland (monitor-mode capture) or crashing net80211 parsers. rt2860 sibling knowns do not cover rxeof length trust. DF-3604 family wifi instance. Clamp-to-MCLBYTES fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-3966 Β· 11 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 1.2 KB | β raw | |
| VERDICT.md | β | 1.8 KB | β raw | |
| trigger.c | β | 1.9 KB | view raw | |
| build.sh | β | 67 B | view raw | |
| run.sh | β | 91 B | view raw | |
| run.log | β | 12 B | view raw | |
| env.txt | β | 1021 B | view raw | |
| fix.diff | β | 604 B | view raw | |
| build.log | β | 37.9 KB | view raw | |
| manifest.json | β | 370 B | view raw | |
| verdict.json | β | 3.4 KB | view raw |
DF-3966 β rt2661_rx_intr trusts the device-fed 12-bit frame length against a 2 KB cluster: up to 2047-byte OOB read into ieee80211_input
File: sys/dev/netif/ral/rt2661.c (pass 2; no known findings on this file; rt2860 sibling knowns DF-3748..3753 do not cover rxeof length trust)
What
rt2661.c:1101β1102 sets m->m_pkthdr.len = m->m_len = (flags>>16)&0xfff
straight from the DMA'd RX descriptor β up to 4095 β while the mbuf is a
2048-byte cluster (m_getcl at 1055; MCLBYTES=2048, sys/sys/param.h:497).
There is no clamp. The over-long mbuf is passed to ieee80211_input
(1132β1138), so up to 2047 bytes beyond the cluster are parsed as frame
content and can be delivered to the stack/userland (monitor-mode capture,
UDP payload) β a device-gated kernel heap info leak; malformed OOB header
fields can equally panic the parsers.
Build / Run (hardware recipe)
Requires a Ralink RT2561/RT2661 NIC (guest has none β env.txt; if_ral.ko ships in /boot/kernel). See trigger.c steps: monitor mode + one crafted descriptor (flags[27:16] > 2048) + tcpdump capture.
Expected
Captured frames contain bytes from beyond the mbuf cluster (kernel heap), or a parser panic on garbage OOB bytes.
DF-3966 verdict β source-certain OOB read, hardware-gated
Reproduced?
No: the audit guest has no Ralink device (pciconf: no vendor 0x1814; env.txt). if_ral.ko is present in /boot/kernel (1.59 MB) and one kldload away on any host with the NIC.
Why the bug is real
- rt2661.c:1017-1021:
desc = &sc->rxq.desc[sc->rxq.cur]; flags read from the DMA'd descriptor (device-written). - rt2661.c:1101-1102:
m->m_pkthdr.len = m->m_len = (le32toh(desc->flags) >> 16) & 0xfffβ the ONLY bound is the 12-bit field mask (4095). - rt2661.c:1055/706: the RX mbufs are
m_getcl(...)clusters β MCLBYTES = 1<<11 = 2048 (sys/sys/param.h:494-497, x86_64). - rt2661.c:1129-1138:
mtod(m, ...)+ieee80211_input(ni, m, ...)/ieee80211_input_allβ net80211 walks the frame using m_len: everything in (2048, 4095] is read past the cluster. - No intermediate clamp exists anywhere on the path (checked: rt2661_rx_intr is the only consumer of the descriptor length).
Threat model / severity
Device-fed: requires malicious/compromised NIC firmware or a DMA platform attack (same class as DF-3748..3753 for the rt2860 sibling β those covered AID truncation, wcid UAF, TXWI pool, wcid byte, retrycnt, rate lookups; none of them is this rxeof length trust). A merely buggy NIC that sets the 12-bit length above 2048 also triggers it. Medium: kernel heap disclosure up to 2047 B/frame, repeatable per descriptor.
Fix
fix.diff clamps the finalized length to MCLBYTES before ieee80211_input.
Fix status (batch validation)
Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest make -j6 nativekernel KERNCONF=X86_64_GENERIC completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.
Fix verification
not_testablefix.diff clamps the finalized m_len/m_pkthdr.len to MCLBYTES; git apply --check clean. Runtime validation impossible without the NIC fix.diff applied to the guest /usr/src copy and the if_ral.ko module rebuilt clean with -Werror (build.log; combined with the other two rt2661 fix.diffs of this batch); runtime validation still impossible without the NIC.
fix.diff; fix.diff applied to the guest /usr/src copy and the if_ral.ko module rebuilt clean with -Werror (build.log; combined with the other two rt2661 fix.diffs of this batch); runtime validation still impossible without the NIC.
Confirmed kernel references
Detail
Exploit chain
device writes an RX descriptor with flags[27:16] in (2048,4095] and a short frame in the cluster -> m_len=m_pkthdr.len=N>2048 -> ieee80211_input parses headers/payload OOB past the 2KB cluster -> leaked kernel heap bytes travel as frame payload to userland (monitor mode capture / UDP) or crash net80211 parsers.
Evidence (decisive lines)
VERDICT.md (length/cluster math + path:line), trigger.c (hardware recipe), env.txt (no vendor 0x1814 on guest; if_ral.ko present), fix.diff (MCLBYTES clamp, git apply --check clean)
PoC changes
No runnable PoC: needs RT2561/RT2661 hardware or a PCIe device emulator posting a crafted descriptor; trigger.c documents the on-hardware steps.
Verified recommended fix
Clamp the device-fed length to MCLBYTES before handing the mbuf to ieee80211_input (fix.diff).
Verdict
Source-certain device-fed OOB read: rt2661_rx_intr finalizes the RX mbuf with m->m_pkthdr.len = m->m_len = (le32toh(desc->flags)>>16)&0xfff (rt2661.c:1101-1102) β up to 4095 from the DMA'd descriptor β while the mbuf is a 2048-byte m_getcl cluster (rt2661.c:1055; MCLBYTES=1<<11, sys/sys/param.h:497); no clamp exists anywhere on the path, so ieee80211_input/ieee80211_input_all (rt2661.c:1132-1138) parse up to 2047 bytes past the cluster and can deliver them to the stack/userland (monitor capture, UDP payload) or panic parsers on garbage OOB fields. Device-gated (malicious/compromised NIC or DMA attack; a buggy NIC setting the 12-bit field above 2048 also qualifies). Not reproduced: no Ralink NIC on the audit guest (env.txt); if_ral.ko ships in /boot/kernel. rt2860 sibling knowns DF-3748..3753 do not cover rxeof length trust.
No comments yet.