⬢ DragonFlyBSD Kernel Audit
DF-3286 / fix.diff
← back to finding ↓ download raw
--- 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);