Heap OOB read in bwn_dma_rxeof via dr_rx_bufsize / descriptor bytecnt mismatch
Summary
bwn_dma_rxeof at if_bwn.c:5486 checks frame_len against dr->dr_rx_bufsize (=BWN_DMA0_RX_BUFFERSIZE=IEEE80211_MAX_LEN~2316) but actual RX DMA buffer is MCLBYTES=2048. Descriptor bytecnt at :5733 set to MCLBYTES-sizeof(bwn_rxhdr4)=2028. For frame_len in (2018,2316] the check passes, m_len set to len+dr_frameoffset at :5512 exceeding 2048-byte cluster, m_adj leaves m_len up to 2316 with only 2018 bytes valid backing store. ieee80211_input walks up to ~298 bytes past cluster -> heap info leak or panic. Unauthenticated wireless attacker sends large Beacon/Probe Response with many IEs. Default config. Fix: set dr_rx_bufsize = MCLBYTES - sizeof(bwn_rxhdr4) or check len against dr_rx_bufsize - dr_frameoffset.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-1131 Β· 12 files| File | Type | Description | Size | |
|---|---|---|---|---|
| harness.c | trigger-source | userspace replica of bwn_dma_rxeof length check + WITH-FIX pass | 5.6 KB | view raw |
| build.sh | build-script | cc -O2 -Wall -Wextra -o harness harness.c | 114 B | view raw |
| run.sh | run-script | ./harness | 60 B | view raw |
| build.log | build-log | final build, full output | 8 B | view raw |
| run.log | run-log | decisive run incl CONFIRMED + FIX VALIDATED | 1.8 KB | view raw |
| env.txt | environment | uname, cc, pciconf (no WiFi HW) | 241 B | view raw |
| fix.diff | suggested-fix | add len+frameoffset>MCLBYTES guard to bwn rxeof drop check | 791 B | view raw |
| fix_validation.txt | fix-validation | apply-check + compile (rc=0) + harness fix-demo | 1.7 KB | view raw |
| VERDICT.md | verdict | full narrative | 2.4 KB | β raw |
| README.md | readme | summary + repro | 2.5 KB | β 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 |
DF-1131 β bwn DMA rxeof dr_rx_bufsize / cluster-size mismatch OOB read
Verdict
CONFIRMED (source-trace + harness) β INCONCLUSIVE on-guest (HW-gated). The bug is real; it cannot be triggered on the audit QEMU guest because the guest has no Broadcom BCM43xx (bwn) WiFi adapter (virtio net only).
Bug (one line)
bwn_dma_rxeof() checks frame_len against dr->dr_rx_bufsize (=
BWN_DMA0_RX_BUFFERSIZE = IEEE80211_MAX_LEN = 2312) but the RX mbuf cluster is
only MCLBYTES (2048), so a device-reported frame_len in (2018, 2312] passes the
check yet makes m_len = len + dr_frameoffset exceed the 2048-byte cluster.
Mechanism (path:line)
if_bwn.c:2778βdr->dr_rx_bufsize = BWN_DMA0_RX_BUFFERSIZE;(BWN_DMA0_RX_BUFFERSIZE = IEEE80211_MAX_LEN;if_bwnreg.h:464).IEEE80211_MAX_LEN = 2300 + 4 + (3+1+4) = 2312(ieee80211.h:1297);MCLBYTES = 2048.if_bwn.c:5674βm = m_getcl(...)allocates an MCLBYTES (2048) cluster.if_bwn.c:5688βm->m_len = m->m_pkthdr.len = MCLBYTES;if_bwn.c:5470βlen = le16toh(rxhdr->frame_len);(device-reported).if_bwn.c:5486βif (len > dr->dr_rx_bufsize)checks against 2312, not 2048.if_bwn.c:5512βm->m_len = m->m_pkthdr.len = len + dr->dr_frameoffset;(frameoffset=30) exceeds 2048 forlen > 2018, but the cluster is only 2048 -> net80211 reads past the cluster when processing the frame.
Trigger / threat model
A malicious/rogue 802.11 frame (or a firmware bug) that makes the device report
frame_len in (2018, 2312] is kept (it would be dropped only above 2312) and
processed with an m_len larger than the cluster. net80211 then over-reads up to
(2312+30-2048)=294 bytes of adjacent kernel heap; those bytes appear in the
delivered frame payload (info leak) or hit an unmapped page (panic). Requires a
Broadcom bwn adapter; attacker is within radio range.
Reproduction on the audit guest
Not possible β no bwn WiFi hardware. harness.c is a userspace replica of the
length-check arithmetic, built and run as unprivileged maxx, proving the OOB and
that the fix (drop when len + frameoffset > MCLBYTES) yields 0 OOB.
Build / run
./build.sh && ./run.sh
Expected: DF-1131: CONFIRMED heap OOB read primitive (up to 294 bytes past cluster)
then DF-1131 FIX: VALIDATED - cluster-bound guard drops all overrun frames.
Fix
fix.diff adds (u_int)len + dr->dr_frameoffset > MCLBYTES to the existing drop
check. Applies cleanly; compiles in the GENERIC kernel build (rc=0).
DF-1131 β VERDICT
Verdict: CONFIRMED via source-trace + userspace harness. On-guest: INCONCLUSIVE (HW-gated β no Broadcom bwn WiFi adapter on the QEMU guest).
Root-cause confirmation
bwn_dma_rxeof() validates the device-reported frame_len against the wrong
constant. dr->dr_rx_bufsize is set to BWN_DMA0_RX_BUFFERSIZE = IEEE80211_MAX_LEN
= 2312 (if_bwn.c:2778, if_bwnreg.h:464, ieee80211.h:1297), but the actual
RX buffer is an mbuf cluster of MCLBYTES = 2048 allocated by m_getcl()
(if_bwn.c:5674) with m_len = MCLBYTES (if_bwn.c:5688). The check at
if_bwn.c:5486 (if (len > dr->dr_rx_bufsize)) therefore drops only len > 2312,
while any len in (2018, 2312] is kept and immediately produces
m_len = len + dr_frameoffset (if_bwn.c:5512, frameoffset=30) greater than the
2048-byte cluster. net80211 processes the mbuf reading up to m_len bytes from a
2048-byte backing cluster -> heap OOB read of up to (2312+30-2048)=294 bytes.
Evidence
harness.c(run as unprivilegedmaxx) shows 4/7frame_lenvalues (2019, 2048, 2100, 2312) pass the kernel check but overrun the 2048-byte cluster by 1..294 bytes; a concrete model withframe_len=2100reads 82 OOB bytes of an adjacent heap marker.- Full run:
run.log. Build:build.log. Environment (no WiFi HW):env.txt.
Exploit chain / impact
This is an OOB read (CWE-125), not a write primitive, so no uid=0 chain.
Realistic impact ceiling: kernel heap info leak up to ~294 bytes per malicious
frame (the over-read bytes flow into the received 802.11 frame payload), or a
panic if the overrun reaches an unmapped page. AV:A, requires bwn hardware +
radio-range attacker.
Fix validation
fix.diff extends the drop check to (u_int)len + dr->dr_frameoffset > MCLBYTES.
- git apply --check -p1 => OK.
- Compiles in the GENERIC kernel build (nativekernel rc=0; if_bwn.o built clean).
- Harness "WITH FIX" pass: 0/7 OOB cases remain.
- fix_status: not_testable (HW-gated runtime; apply-check + compile + harness fix-demo + trace all pass).
PoC changes
Evidence pack authored from scratch (seeded dir was empty): harness.c
(+ WITH-FIX pass), build.sh, run.sh, fix.diff, VERDICT.md, manifest.json, logs.
Kernel refs (confirmed during verification)
sys/dev/netif/bwn/bwn/if_bwn.c:2778, :5470, :5486, :5512, :5674, :5688;
sys/dev/netif/bwn/bwn/if_bwnreg.h:464; sys/netproto/802_11/ieee80211.h:1297.
Fix verification
not_testablecompile+harness validated
module build rc=0 + harness 0 OOB
Confirmed kernel references
β
Detail
Exploit chain
none
Evidence (decisive lines)
β
Verdict
Source-confirmed+harness. bwn_dma_rxeof frame_len 2048-2312 passes check but exceeds MCLBYTES cluster -> 294B heap OOB read. No bwn WiFi.
No comments yet.