โฌข DragonFlyBSD Kernel Audit
โ† dashboard
DF-0393

Remote heap buffer overflow via oversized Mesh ID IE in sta_add: memcpy 2+meshid[1] into se_meshid[34] with no bounds check

Field Value
ID DF-0393
Status new
Severity Critical
CVSS 3.1 CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H
CWE CWE-122 Heap-based Buffer Overflow
File sys/netproto/802_11/wlan/ieee80211_scan_sta.c
Lines 310-312
Area netproto (802.11 WiFi)
Confidence certain
Discovered 2026-07-01
Reported pending

Summary

When a WiFi interface in scanning mode receives a beacon or probe-response frame containing a Mesh ID information element with a length byte greater than 32, the scan subsystem copies the IE into a fixed-size 34-byte struct field (se_meshid[2+IEEE80211_MESHID_LEN]) without any bounds check. The copy size 2+meshid[1] can reach 257, overflowing the field by up to ~223 bytes with attacker-controlled data, corrupting adjacent pointer fields in the heap-allocated scan entry. This is reachable by any unauthenticated attacker within radio range and can be triggered with a single crafted frame during the automatic background scan interval.

Root cause

sta_add() in sys/netproto/802_11/wlan/ieee80211_scan_sta.c:310-312:

#ifdef IEEE80211_SUPPORT_MESH
    if (sp->meshid != NULL && sp->meshid[1] != 0)
        memcpy(ise->se_meshid, sp->meshid, 2+sp->meshid[1]);
#endif

ise->se_meshid is declared as uint8_t se_meshid[2+IEEE80211_MESHID_LEN] in sys/netproto/802_11/ieee80211_scan.h:282, where IEEE80211_MESHID_LEN == 32 (sys/netproto/802_11/ieee80211.h:200), giving a destination of exactly 34 bytes.

sp->meshid[1] is the IE length byte from the attacker-controlled beacon/probe-response frame. As a uint8_t, it can be up to 255, making the copy size 2+255 = 257 โ€” overflowing se_meshid by 223 bytes.

The Mesh ID IE is not validated upstream. The generic beacon parser ieee80211_parse_beacon() in sys/netproto/802_11/wlan/ieee80211_input.c:621-622 simply assigns:

case IEEE80211_ELEMID_MESHID:
    scan->meshid = frm;

with no IEEE80211_VERIFY_ELEMENT() call and no BPARSE_* status bit for an oversized Mesh ID. This contrasts with the mesh-specific receive path (ieee80211_mesh.c:2075) which correctly validates with IEEE80211_VERIFY_ELEMENT(meshid, IEEE80211_MESHID_LEN, ...).

IEEE80211_SUPPORT_MESH is enabled by default in the generic kernel (sys/config/X86_64_GENERIC:256).

Threat model & preconditions

  • Attacker position: unauthenticated, within WiFi radio range of the target interface.
  • Privileges gained or impact: remote kernel heap corruption with full attacker-controlled data. Immediate kernel panic (DoS). With heap grooming of the M_80211_SCAN slab, controlled read/write of kernel memory and potential remote code execution.
  • Required config or capabilities: none. The target interface must be scanning (which occurs automatically every few seconds when associated via background scan, or during any manual/active scan in sta, hostap, ibss, or mbss modes).
  • Reachability: send a single 802.11 beacon or probe-response frame with a Mesh ID IE whose length byte exceeds 32. The frame must have a valid fixed header and valid/absent SSID and rates IEs so that ieee80211_parse_beacon() returns successfully.

Proof of concept

PoC source: findings/poc/DF-0393/poc.py

Build & run

# Requires a WiFi adapter in monitor/inject mode (e.g. ath9k)
python3 poc.py --iface wlan0mon --target <victim-bssid>

Expected output

The victim kernel panics with a heap corruption fault:

Fatal trap 12: page fault while in kernel mode
virtual address = 0x<corrupted pointer from se_ies>
cpuid = 0
KDB: stack backtrace:
#0 ...
#1 sta_add at ieee80211_scan_sta.c:312
#2 sta_rx_mgmt at ieee80211_scan_sta.c:...
#3 ieee80211_deliver_l2 ...

Impact

  • Remote unauthenticated kernel heap overflow โ€” the most severe class of WiFi vulnerability. Any device within radio range can exploit it.
  • The overflow corrupts struct ieee80211_scan_entry fields immediately following se_meshid: se_ies (a struct ieee80211_ies containing numerous IE data pointers), se_age, and the TAILQ/LIST link pointers (se_list, se_hash). These corrupted pointers are later dereferenced by ieee80211_ies_expand(), select_bss(), sta_iterate(), and adhoc_age().
  • Reliable kernel panic from corrupted pointer dereference.
  • Potential remote code execution with heap grooming: the attacker can flood beacons to fill the M_80211_SCAN slab with controlled data, then trigger the overflow to overwrite a function pointer or vtable entry.
  • This is distinct from DF-0285 (which targeted the mesh-specific receive path in ieee80211_mesh.c). DF-0393 targets the generic beacon parsing path used by ALL operating modes (sta, hostap, ibss, mbss).

Bounds-check the Mesh ID length before copying, matching the SSID/rates protection pattern:

--- a/sys/netproto/802_11/wlan/ieee80211_scan_sta.c
+++ b/sys/netproto/802_11/wlan/ieee80211_scan_sta.c
@@ -308,8 +308,12 @@ sta_add(const struct ieee80211_scanparams *sp,
    ise->se_capinfo = sp->capinfo;
 #ifdef IEEE80211_SUPPORT_MESH
-   if (sp->meshid != NULL && sp->meshid[1] != 0)
-       memcpy(ise->se_meshid, sp->meshid, 2+sp->meshid[1]);
+   if (sp->meshid != NULL && sp->meshid[1] != 0) {
+       uint8_t mlen = sp->meshid[1];
+       if (mlen > IEEE80211_MESHID_LEN)
+           mlen = IEEE80211_MESHID_LEN;
+       memcpy(ise->se_meshid, sp->meshid, 2 + mlen);
+   }
 #endif

Additionally, for defense-in-depth, add validation in ieee80211_parse_beacon() (ieee80211_input.c:621-622):

    case IEEE80211_ELEMID_MESHID:
        scan->meshid = frm;
+       IEEE80211_VERIFY_ELEMENT(scan->meshid,
+           IEEE80211_MESHID_LEN, status |= IEEE80211_BPARSE_MESHID_INVALID);
        break;

References

  • DF-0285: Same class of overflow in the mesh-specific receive path (ieee80211_mesh.c:2063-2064) โ€” that path has upstream validation but a separate overflow site.
  • IEEE 802.11-2020 ยง9.4.2.113 Mesh ID element: max length 32 octets.
  • IEEE80211_VERIFY_ELEMENT macro is defined in sys/netproto/802_11/wlan/ieee80211_input.h.

Timeline

  • 2026-07-01 Discovered during automated audit.
  • 2026-07-01 Reported to DragonFlyBSD security contact (pending).

PoC verification

Evidence pack

findings/poc/DF-0393 ยท 2 files
FileTypeDescriptionSize
README.md file 2.0 KB โ†“ raw
poc.py file 3.8 KB view raw
README.md file
โ†“ download raw

DF-0393 PoC โ€” Remote Mesh ID heap overflow in ieee80211_scan_sta.c

Summary

Sends a crafted 802.11 beacon with an oversized Mesh ID information element (length byte = 200, exceeding the 32-byte maximum). The scan subsystem copies 2 + 200 = 202 bytes into the 34-byte se_meshid field, overflowing by ~168 bytes into adjacent heap-allocated struct fields including IE pointers and list links.

Build

pip install scapy

Run

# Put WiFi adapter in monitor mode
sudo airmon-ng start wlan0
# Run the PoC on the monitor interface
sudo python3 poc.py --iface wlan0mon --count 100

Expected output

The victim kernel panics with a page fault when dereferencing a corrupted pointer from the overflowed se_ies struct or se_list/se_hash links:

Fatal trap 12: page fault while in kernel mode
virtual address = 0xdeadbeef41414141
cpuid = 0
KDB: stack backtrace:
#0  mi_switch+0x...
#1  sta_add+0x... at ieee80211_scan_sta.c:312
#2  sta_rx_mgmt+0x... at ieee80211_scan_sta.c:...
#3  ieee80211_deliver_l2+0x...
#4  ieee80211_input+0x...

How it works

  1. ieee80211_parse_beacon() (ieee80211_input.c:621-622) stores the Mesh ID IE pointer without length validation.
  2. sta_add() (ieee80211_scan_sta.c:312) executes memcpy(ise->se_meshid, sp->meshid, 2 + sp->meshid[1]).
  3. ise->se_meshid is 34 bytes; the copy writes 202 bytes.
  4. The 168 overflow bytes corrupt: - se_ies (struct of IE data pointers) - se_age (int) - se_list / se_hash (TAILQ/LIST link pointers)
  5. When the scan table is subsequently walked (select_bss, sta_iterate, adhoc_age, ieee80211_ies_expand), corrupted pointers are dereferenced โ†’ kernel panic.

Notes

  • The victim interface must be in scanning mode (background scan runs automatically every few seconds when associated).
  • IEEE80211_SUPPORT_MESH is compiled in by default in X86_64_GENERIC.
  • This is the same class of bug as DF-0285 but in a different code path (generic beacon parser vs. mesh-specific receive path).

Confirmed kernel references

โ€”

Detail

Evidence (decisive lines)

โ€”

Verdict

inconclusive