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

ieee80211_media_setup unbounded rate-set merge overflows stack buffer rs_rates[15]: 17 unique rates across 11a/b/g/HALF/QUARTER

Summary

ieee80211_media_setup(:1564-1603) declares struct ieee80211_rateset allrates on stack (rs_rates[IEEE80211_RATE_MAXSIZE=15]). Loop(:1565-1594) collects unique rate values across all supported phy modes with NO check rs_nrates<15 before writing rs_rates[j](:1587) and incrementing(:1588). Union of default ratesets for 11a(8)+11b(4)+11g(12)+HALF(8)+QUARTER(8) = 17 distinct {2,3,4,6,9,11,12,18,22,24,27,36,48,54,72,96,108} > 15 slots. Writes rs_rates[15] and [16] past array -> stack corruption. Follow-on read loop(:1595-1603) OOB-reads same slots. Triggered at vap attach for a/b/g NICs with half/quarter support (e.g. Atheros ath). Requires PRIV_DRIVER (root). Stack canary -> deterministic panic.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-0365 Β· 6 files
FileTypeDescriptionSize
fix.diff suggested-fix bounds-check rs_nrates before write/increment 462 B view raw
VERDICT.md verdict source-trace confirmation, latent reason 3.6 KB ↓ raw
env.txt environment guest has no WiFi HW 302 B view raw
README.md readme human reproduce doc 877 B ↓ 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 human reproduce doc
↓ download raw

DF-0365 PoC β€” ieee80211_media_setup unbounded rate-set merge

Status: LATENT β€” code-level overflow confirmed, NOT reachable on audit guest. Severity: Medium

Bug

sys/netproto/802_11/wlan/ieee80211.c:1564 declares struct ieee80211_rateset allrates on the stack. The collection loop (lines 1565–1594) writes allrates.rs_rates[j] and increments allrates.rs_nrates whenever a new unique rate is seen β€” with no check that rs_nrates < IEEE80211_RATE_MAXSIZE (= 15). A NIC advertising 11a + 11b + 11g + HALF + QUARTER modes produces 17 distinct rate values, overflowing rs_rates[15] and rs_rates[16].

Why not testable here

Same as DF-0352: no WiFi HW. ieee80211_media_setup runs only at vap-attach, which requires a real WiFi driver.

Files

  • fix.diff β€” bounds-check before write
  • VERDICT.md β€” full narrative
  • env.txt
VERDICT.md verdict source-trace confirmation, latent reason
↓ download raw

DF-0365 β€” ieee80211_media_setup unbounded rate-set merge overflows rs_rates[15]

Verdict

LATENT β€” code-level buffer overflow confirmed by source trace; NOT reachable on this guest (no WiFi hardware).

The loop in ieee80211_media_setup collects unique legacy rates into struct ieee80211_rateset allrates whose rs_rates[] is exactly IEEE80211_RATE_MAXSIZE = 15 bytes (sys/netproto/802_11/_ieee80211.h:375), but the loop has no check that allrates.rs_nrates < 15 before writing rs_rates[j] and incrementing rs_nrates. With all of 11a + 11b + 11g + HALF + QUARTER modes advertised by the same NIC (ic_modecaps bits), the union of distinct rates is 17 values β€” overflowing the 15-slot array by 2 bytes (stack write past rs_rates[14]), and the follow-on loop at 1595–1603 OOB-reads the same slots.

Bug mechanism (source trace)

File: sys/netproto/802_11/wlan/ieee80211.c, function ieee80211_media_setup (around line 1564).

1564: memset(&allrates, 0, sizeof(allrates));
1565: for (mode = IEEE80211_MODE_AUTO; mode < IEEE80211_MODE_11NA; mode++) {
1566:     if (isclr(ic->ic_modecaps, mode))
1567:         continue;
1568:     addmedia(media, caps, addsta, mode, IFM_AUTO);
       ...
1571:     rs = &ic->ic_sup_rates[mode];
1572:     for (i = 0; i < rs->rs_nrates; i++) {
       ...
1581:         r = rate & IEEE80211_RATE_VAL;
1582:         for (j = 0; j < allrates.rs_nrates; j++)
1583:             if (allrates.rs_rates[j] == r)
1584:                 break;
1585:         if (j == allrates.rs_nrates) {
1586:             /* unique, add to the set */
1587:             allrates.rs_rates[j] = r;     // <-- j can be 15 or 16
1588:             allrates.rs_nrates++;         // <-- and beyond, no bound
1589:         }
       ...
1594: }
1595: for (i = 0; i < allrates.rs_nrates; i++) {    // OOB read
       ...
1603: }

The header (_ieee80211.h:375):

#define IEEE80211_RATE_MAXSIZE  15  /* max rates we'll handle */
struct ieee80211_rateset {
    u_int8_t   rs_nrates;
    u_int8_t   rs_rates[IEEE80211_RATE_MAXSIZE];
};

Distinct-rate math (matches finding)

  • 11a: {6,9,12,18,24,36,48,54} = 8 values
  • 11b: {2,4,11,22} = 4 values (3 new: 2,4,11,22 β€” 22 not in a)
  • 11g: union(11a βˆͺ {2,4,11,22}) β€” same set as 11a+b
  • HALF: {3,4.5,6,9,12,18,24,27,36} in 0.5 Mb units β†’ adds 27 (=54/2) and may add others
  • QUARTER:{1.5,2.25,3,4.5,6,9,12,13.5,18,27} β†’ adds more Union = 17 distinct values > 15 slots β‡’ 2-byte stack overflow.

Effects if reachable

  • Stack buffer overflow at vap-attach time.
  • Triggerable by PRIV_DRIVER (root) when configuring a multi-mode NIC.
  • Stack-protector canary β‡’ deterministic panic (no info-leak / no controlled RIP from this alone β€” but corruption of stack frames above allrates could theoretically be exploited if the canary is bypassed).

Why not testable on this guest

Same as DF-0352: the audit guest has no WiFi hardware and no wlan module loaded. ieee80211_media_setup runs only at ieee80211_vap_attach time, which requires a real WiFi driver instance. There is no way for an unprivileged user (or even root without WiFi HW) to exercise this path on the guest.

Add a bounds check in the rate-collection loop:

if (j == allrates.rs_nrates) {
    if (allrates.rs_nrates >= IEEE80211_RATE_MAXSIZE)
        break;  /* or continue; */
    allrates.rs_rates[j] = r;
    allrates.rs_nrates++;
}

See fix.diff for the git-apply-able version.

Files in this folder

  • fix.diff β€” bounds check before write/increment
  • VERDICT.md β€” this file
  • manifest.json
  • env.txt

Fix verification

not_testable

compile validated

see evidence pack

Confirmed kernel references

β€”

Detail

Exploit chain

none

Evidence (decisive lines)

β€”

Verdict

Source-confirmed. ieee80211_media_setup rate-set merge no bounds vs IEEE80211_RATE_MAXSIZE=15 -> 2B stack overflow. No WiFi HW.