DF-3286 / fix.diff
--- a/sys/netproto/802_11/wlan/ieee80211_mesh.c +++ b/sys/netproto/802_11/wlan/ieee80211_mesh.c @@ -652,6 +652,18 @@ ieee80211_iterate_nodes(&vap->iv_ic->ic_sta, mesh_vdetach_peers, NULL); ieee80211_mesh_rt_flush(vap); + /* DF-3288: gate entries were never freed anywhere; flush them + * here or every GANN-received gate leaks permanently. */ + { + struct ieee80211_mesh_gate_route *gr; + + MESH_RT_LOCK(ms); + while ((gr = TAILQ_FIRST(&ms->ms_known_gates)) != NULL) { + TAILQ_REMOVE(&ms->ms_known_gates, gr, gr_next); + IEEE80211_FREE(gr, M_80211_MESH_GT_RT); + } + MESH_RT_UNLOCK(ms); + } MESH_RT_LOCK_DESTROY(ms); ms->ms_ppath->mpp_vdetach(vap); IEEE80211_FREE(vap->iv_mesh, M_80211_VAP); @@ -1439,7 +1451,15 @@ /* set lifetime of addr4 (meshSA) to initial value */ rt_meshsa = ieee80211_mesh_rt_find(vap, qwh->i_addr4); - KASSERT(rt_meshsa != NULL, ("no route")); + /* + * DF-3287: when AE==AE_01 the duplicate-sequence check only + * guarantees a route for the mesh-control addr4 (proxy SA); + * the frame's i_addr4 may have none. Never dereference it + * unconditionally (KASSERT panics INVARIANTS kernels, NULL + * dereference panics production kernels). + */ + if (rt_meshsa == NULL) + return (-1); ieee80211_mesh_rt_update(rt_meshsa, ticks_to_msecs( ms->ms_ppath->mpp_inact)); @@ -1480,7 +1500,9 @@ /* set lifetime of addr4 (meshSA) to initial value */ rt = ieee80211_mesh_rt_find(vap, qwh->i_addr4); - KASSERT(rt != NULL, ("no route")); + /* DF-3287: route is only ensured for the AE-specific SA */ + if (rt == NULL) + return (-1); ieee80211_mesh_rt_update(rt, ticks_to_msecs(ms->ms_ppath->mpp_inact)); rt = NULL; @@ -1736,6 +1758,17 @@ mc = (const struct ieee80211_meshcntl *) (mtod(m, const uint8_t *) + hdrspace); ae = mc->mc_flags & IEEE80211_MESH_AE_MASK; + /* + * DF-3286: AE_11 (3) is reserved but was accepted here, + * growing meshdrlen to 24 so the mesh_decap header copy + * (56 bytes) overflows its 50-byte stack buffer. + */ + if (ae > IEEE80211_MESH_AE_10) { + IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT, + ni->ni_macaddr, "data", "reserved AE %d", ae); + vap->iv_stats.is_mesh_badae++; + goto err; + } meshdrlen = sizeof(struct ieee80211_meshcntl) + ae * IEEE80211_ADDR_LEN; hdrspace += meshdrlen; @@ -2583,6 +2616,9 @@ IEEE80211_VERIFY_LENGTH(efrm - frm, frm[1] + 2, return -1); switch (*frm) { case IEEE80211_ELEMID_MESHGANN: + /* DF-3290: only trust a full-size GANN IE */ + if (frm[1] != IEEE80211_MESHGANN_BASE_SZ) + return -1; gannie = (const struct ieee80211_meshgann_ie *) frm; memset(ie, 0, sizeof(*ie)); ie->gann_ie = gannie->gann_ie; @@ -2687,7 +2723,9 @@ MESH_RT_UNLOCK(ms); /* popagate only if decremented ttl >= 1 && forwarding is enabled */ - if ((ie.gann_ttl - 1) < 1 && !(ms->ms_flags & IEEE80211_MESHFLAGS_FWD)) + /* DF-3291: must be || or TTL-exhausted GANNs are re-broadcast + * with the uint8 ttl wrapping 0 -> 255. */ + if ((ie.gann_ttl - 1) < 1 || !(ms->ms_flags & IEEE80211_MESHFLAGS_FWD)) return 0; pgann.gann_flags = ie.gann_flags; /* Reserved */ pgann.gann_hopcount = ie.gann_hopcount + 1; @@ -3094,6 +3132,7 @@ struct ieee80211_node *ni = (struct ieee80211_node *)arg; uint16_t args[3]; + args[1] = 0; /* DF-3289: no peer link id on timeout closes */ IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_MESH, ni, "mesh link timeout, state %d, retry counter %d", ni->ni_mlstate, ni->ni_mlrcnt); |