DF-3429 / trigger_stageq_leak.c
/* DF-3429 — DWDS discovery frames staged on ic_stageq are LEAKED when they * age out: ieee80211_node_timeout() drops the mbuf list returned * by ieee80211_ageq_age() on the floor. * * Producer (this file's function): * sys/netproto/802_11/wlan/ieee80211_wds.c:321-338 * ieee80211_dwds_discover(ni, m): * m->m_pkthdr.rcvif = (void *)(uintptr_t) ieee80211_mac_hash(...); * (void) ieee80211_ageq_append(&ic->ic_stageq, m, * ((ni->ni_intval * ic->ic_lintval) << 2) / 1024); // finite TTL * ieee80211_notify_wds_discover(ni); * * Reachability: any AUTHORIZED station of an AP vap can reach this by * sending a 4-address data frame while ni->ni_wdsvap == NULL * (sys/netproto/802_11/wlan/ieee80211_hostap.c:654-667 gates on * authorization, then calls ieee80211_dwds_discover). On an open/PSK * network, association is all an attacker needs. * * Sink (the leak): * sys/netproto/802_11/wlan/ieee80211_node.c:2255 * ieee80211_node_timeout(void *arg): * ... * ieee80211_ageq_age(&ic->ic_stageq, IEEE80211_INACT_WAIT); // <-- RETURN IGNORED * * ieee80211_ageq_age() REMOVES expired frames from the queue and returns * them as an m_nextpkt-joined list for the caller to free * (sys/netproto/802_11/wlan/ieee80211_ageq.c:162-185). The bare call * discards the list: every expired stageq frame leaks its mbuf + cluster * (~2KB+ per frame). * * Normal operation pulls staged frames via wds_flush() (wds.c:102-122, * ieee80211_ageq_remove) once a WDS vap is plumbed; the leak hits whenever * discovery events are NOT serviced (no hostapd DWDS plumbing, daemon * restart, race) - then every staged frame becomes a permanent kernel * memory leak after its TTL. The queue itself is bounded * (ic_stageq aq_maxlen = ic_max_keyix * 8, ieee80211_node.c:113) but aging * empties it, so a sustained 4-addr stream = sustained leak * (attacker-rate x ~2KB/s) -> kernel heap exhaustion -> OOM/panic. * * Upstream: FreeBSD's ieee80211_node_timeout() has the identical bare call * (verified against FreeBSD HEAD sys/net80211/ieee80211_node.c:2568) - * inherited defect. * * Not runtime-testable in the QEMU audit guest: no 802.11 radio hardware * attaches (kldload if_iwm/if_run find no device; ifconfig -C has no * wlandev), so no ieee80211com/vap/node exists to exercise the path. */ int main(void) { return 1; } |