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

ms_known_gates gate entries are never freed: unauthenticated GANN spam exhausts kernel heap and leaks across vap destroy

Summary

Every accepted GANN from a new gate address kmallocs a struct ieee80211_mesh_gate_route into ms_known_gates; the list has no removal path anywhere in sys/ (only INSERT_TAIL), no aging, and mesh_vdetach frees vap->iv_mesh without walking it. Any mesh peer injects GANNs with fresh gann_addr values for unbounded permanent kernel heap growth (~40 bytes per 19-byte frame); vap destroy/recreate cycles accumulate. VERIFIED: 500 GANN frames -> 80211mesh_gt zone 503 in-use/19.6K; destroy -> still 503; second vap cycle +100 -> 603, leaked again (control zone correctly returns to 0). Remote unauthenticated (post-auto-peering) memory exhaustion; permanent leak across vap churn. Fix validated (flush in mesh_vdetach under MESH_RT_LOCK): 201 -> 0 after destroy.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-3288 Β· 5 files
FileTypeDescriptionSize
README.md β€” 2.2 KB ↓ raw
run.sh β€” 111 B view raw
run.log β€” 732 B view raw
verdict.json β€” 2.4 KB view raw
manifest.json β€” 538 B view raw

DF-3288 β€” ms_known_gates gate entries are never freed: unauthenticated GANN spam grows kernel heap without bound and leaks across vap destroy

File: sys/netproto/802_11/wlan/ieee80211_mesh.c (pass 2 audit)

What

Every accepted GANN action frame from a new gate address allocates a struct ieee80211_mesh_gate_route (:2662-2676) and links it into ms->ms_known_gates:

if (found == 0) {
        gr = kmalloc(ALIGN(sizeof(struct ieee80211_mesh_gate_route)),
            M_80211_MESH_GT_RT, M_INTWAIT | M_ZERO);
        IEEE80211_ADDR_COPY(gr->gr_addr, ie.gann_addr);
        TAILQ_INSERT_TAIL(&ms->ms_known_gates, gr, gr_next);
}

ms_known_gates has no removal path anywhere in sys/ (only INSERT_TAIL at :907 and :2675; verified by grep), no aging, and mesh_vdetach (:646-659) frees vap->iv_mesh without walking the gate list. Consequences:

  1. any mesh peer (established = one beacon + 2 action frames) injects GANNs with fresh gann_addr values β†’ one ~40-byte kmalloc each, forever β€” unauthenticated remote kernel memory exhaustion;
  2. destroying the mesh vap leaks the whole table β€” the entries outlive the vap; recreate/destroy cycles accumulate.

(Note: DF-0289 already covers the gr_route dangling-pointer aspect of the gate table; this finding is the missing free / unbounded growth, a different defect at different lines.)

Reproduced (stock kernel, vmstat -m)

# after 500 injected GANNs (sysctl kern.fwm_count=500; kern.fwm_step=20)
80211mesh_gt     503   19.6K       0    390M      503
# after `ifconfig wlan0 destroy`
after vap destroy:
80211mesh_gt     503   19.6K       0    390M      503      <-- LEAKED
# recreate vap, 100 more GANNs, destroy again:
80211mesh_gt     603   23.6K       0    390M      603
80211mesh_gt     603   23.6K       0    390M      603      <-- accumulates forever

Meanwhile 80211mesh_rt returns to 0 on destroy β€” only the gate table leaks.

Build / run

sh findings/poc/DF-3286/build.sh    # shared harness
sh findings/poc/DF-3288/run.sh      # 500 GANNs, destroy, vmstat -m

Threat

Remote unauthenticated (post-peering) kernel heap exhaustion; ~40 bytes per 19-byte action frame, no ceiling, permanent across vap churn. CWE-401. Severity Medium.

Fix verification

fixed
baseline reproduced→ patch + rebuild →patched clean

200 GANNs -> 201 in-use; ifconfig wlan0 destroy -> in-use 0 (baseline: 503 persisted); mesh_vdetach now flushes ms_known_gates

['fix.log: vmstat -m 201 -> 0 after destroy']
DragonFly dfbsd 6.5-DEVELOPMENT #1: Thu Sep 10 05:34:08 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64 (fix kernel)

Confirmed kernel references

Detail

Exploit chain

attacker peers (1 beacon + OPEN + CONFIRM) -> floods 19-byte GANN action frames with unique gann_addr -> one kmalloc per frame, never freed -> kernel memory exhaustion -> OOM/degradation of the mesh node (and of any later vap that shares the zone accounting)

Evidence (decisive lines)

run.log: vmstat -m 503 -> destroy -> 503 -> +100 -> 603 -> destroy -> 603

PoC changes

harness step 20 (count-configurable GANN flood with fresh gate addrs); observation via vmstat -m zone 80211mesh_gt

Verified recommended fix

flush ms_known_gates in mesh_vdetach (fix.diff hunk 7); consider aging entries when their route expires

Verdict

ms_known_gates gate entries (kmalloc M_80211_MESH_GT_RT) have no free path anywhere in sys/ and are not flushed in mesh_vdetach. 500 injected GANN action frames with fresh gate addresses grew the 80211mesh_gt zone to 503 entries / 19.6K; ifconfig wlan0 destroy freed none of them; a second vap cycle added 100 more (603/23.6K) and leaked them again. Unauthenticated (post-auto-peering) remote unbounded kernel heap growth, permanent across vap churn.