⬢ DragonFlyBSD Kernel Audit
DF-3364 / fix.diff
← back to finding ↓ download raw
--- a/sys/netproto/802_11/wlan/ieee80211_scan_sta.c
+++ b/sys/netproto/802_11/wlan/ieee80211_scan_sta.c
@@ -394,15 +394,17 @@
 	if (rssi > st->st_maxrssi[sp->bchan])
 		st->st_maxrssi[sp->bchan] = rssi;
 
-	IEEE80211_SCAN_TABLE_UNLOCK(st);
-
 	/*
 	 * If looking for a quick choice and nothing's
-	 * been found check here.
+	 * been found check here.  NB: keep the table lock
+	 * across match_bss -- se must not be usable after
+	 * a concurrent flush frees it.
 	 */
 	if (PICK1ST(ss) && match_bss(vap, ss, se, IEEE80211_MSG_SCAN) == 0)
 		ss->ss_flags |= IEEE80211_SCAN_GOTPICK;
 
+	IEEE80211_SCAN_TABLE_UNLOCK(st);
+
 	return 1;
 #undef PICK1ST
 #undef ISPROBE
@@ -779,6 +781,14 @@
 	uint8_t txparams;
 
 	rmax = 0;
+	/* se_ies.htcap_ie comes from the verbatim-saved beacon blob;
+	 * ieee80211_ies_expand() sets it for ANY HTCAP IE regardless of
+	 * its declared length.  Validate before dereferencing fields up
+	 * to hc_mcsset[12] (offset 17), else a short (e.g. trailing)
+	 * IE makes us read past the IE and past the heap allocation. */
+	if (htcap != NULL &&
+	    htcap->hc_len < sizeof(struct ieee80211_ie_htcap) - 2)
+		htcap = NULL;
 	if (htcap != NULL) {
 		/*
 		 * HT station; inspect supported MCS and then adjust
@@ -962,6 +972,10 @@
 	int slot, slotcnt;
 
 	slotcnt = tdma->tdma_slotcnt;
+	/* tdma_inuse[] holds 8 slots per byte; clamp a bogus count so the
+	 * bit scan cannot run past the IE (and past the allocation). */
+	if (slotcnt > 8 * nitems(tdma->tdma_inuse))
+		slotcnt = 8 * nitems(tdma->tdma_inuse);
 	for (slot = slotcnt-1; slot >= 0; slot--)
 		if (isclr(tdma->tdma_inuse, slot))
 			return 0;
@@ -1020,6 +1034,13 @@
 
 			if (tdma == NULL)
 				fail |= MATCH_TDMA_NOIE;
+			else if (tdma->tdma_len <
+			    sizeof(struct ieee80211_tdma_param) - 2)
+				/* short IE: fields would read past the IE */
+				fail |= MATCH_TDMA_NOIE;
+			else if (ts == NULL)
+				/* driver never attached TDMA state */
+				fail |= MATCH_TDMA_NOIE;
 			else if (tdma->tdma_version != ts->tdma_version)
 				fail |= MATCH_TDMA_VERSION;
 			else if (tdma->tdma_slot != 0)