# DF-3290 — mesh_parse_meshgate_action reads the 15-byte GANN body regardless of the IE's declared length; OOB bytes re-broadcast

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

## What

`mesh_parse_meshgate_action` (:2574-2602) only guarantees that
`frm[1] + 2` bytes of each IE are present (loop VERIFY_LENGTH at :2583),
then copies the **full 17-byte GANN structure** for any
IEEE80211_ELEMID_MESHGANN element without comparing `gann_len` to
IEEE80211_MESHGANN_BASE_SZ (15):

```c
case IEEE80211_ELEMID_MESHGANN:
        gannie = (const struct ieee80211_meshgann_ie *) frm;
        /* copies gann_flags..gann_interval: 15 bytes past ie+len */
        ie->gann_seq = le32dec(&gannie->gann_seq); ...
```

A GANN IE declaring `len=0` (or <15) placed at the end of a frame that
is padded to satisfy `ieee80211_parse_action`'s *total* length check
(input.c requires only ≥17 bytes of action body) makes the parser read
up to 15 bytes beyond the IE's declared extent — stale mbuf/cluster
data. The parsed values (gate addr, seq, ttl, interval) are then
**re-broadcast** in the propagated GANN (`ieee80211_send_action` at
:2702), disclosing those bytes to every mesh node in radio range.
Distinct from DF-0286 (lmetric total-length check) and DF-0288
(meshpeering early decode): this is the per-IE length check missing in
the GANN walk.

## Reproduced (stock kernel)

Injected (harness step 21): action body = `0d 02` (cat/act) + padding
IE `00 06 PP×6` + GANN IE header `7d 00` (**declared len=0**) + 15
trailing marker bytes (00 0d B2 B3..B8 B9×4 BD BE) that the parser must
NOT attribute to the IE.

Victim re-broadcast (captured at the radio):
```
tx[29] fc0=d0 len=43: ... 0d 02 7d 0f 00 0e b1 b3 b4 b5 b6 b7 b8 b9 b9 b9 b9 be bd
```
→ propagated GANN carries gate addr **b3:b4:b5:b6:b7:b8**, seq
**0xb9b9b9b9**, ttl **0xb1**, interval **0xbebd** — every one of the 15
bytes read from beyond the len=0 IE.

## Build / run

```
sh findings/poc/DF-3286/build.sh
sh findings/poc/DF-3290/run.sh
```

## Threat

Remote (established peer) OOB read of up to 15 bytes past the IE into
stale mbuf-cluster contents, exfiltrated over the air to the whole mesh.
kernleak bucket. Severity Low (bounded stale-data read; needs mesh vap).
CWE-125. Fix: require `frm[1] == IEEE80211_MESHGANN_BASE_SZ`.
