untrusted comment: verify with openbsd-68-base.pub
RWQZj25CSG5R2kiUB7dvX85fJT/6luPcuAMPxgNhFbqQRNk3s4eI2zXYxMnAbZ44hdFHY4u1Pz686oMFbj9bxcuSqb8oFG95ZgY=

OpenBSD 6.8 errata 021, May 21, 2021:

Insufficient validation of A-MSDUs and fragmented 802.11 frames could
be abused to inject arbitrary frames.

Apply by doing:
    signify -Vep /etc/signify/openbsd-68-base.pub -x 021_net80211.patch.sig \
        -m - | (cd /usr/src && patch -p0)

And then rebuild and install a new kernel:
    KK=`sysctl -n kern.osversion | cut -d# -f1`
    cd /usr/src/sys/arch/`machine`/compile/$KK
    make obj
    make config
    make
    make install

Index: sys/net80211/ieee80211_input.c
===================================================================
RCS file: /cvs/src/sys/net80211/ieee80211_input.c,v
retrieving revision 1.221
diff -u -p -r1.221 ieee80211_input.c
--- sys/net80211/ieee80211_input.c	28 Aug 2020 12:01:48 -0000	1.221
+++ sys/net80211/ieee80211_input.c	19 May 2021 06:44:40 -0000
@@ -76,6 +76,8 @@ void	ieee80211_input_ba_seq(struct ieee8
 struct	mbuf *ieee80211_align_mbuf(struct mbuf *);
 void	ieee80211_decap(struct ieee80211com *, struct mbuf *,
 	    struct ieee80211_node *, int, struct mbuf_list *);
+int	ieee80211_amsdu_decap_validate(struct ieee80211com *, struct mbuf *,
+	    struct ieee80211_node *);
 void	ieee80211_amsdu_decap(struct ieee80211com *, struct mbuf *,
 	    struct ieee80211_node *, int, struct mbuf_list *);
 void	ieee80211_enqueue_data(struct ieee80211com *, struct mbuf *,
@@ -361,6 +363,20 @@ ieee80211_inputm(struct ifnet *ifp, stru
 		}
 	}
 
+	/*
+	 * We do not yet support fragments. Drop any fragmented packets.
+	 * Counter-measure against attacks where an arbitrary packet is
+	 * injected via a fragment with attacker-controlled content.
+	 * See https://papers.mathyvanhoef.com/usenix2021.pdf
+	 * Section 6.8 "Treating fragments as full frames"
+	 */
+	if (ieee80211_has_seq(wh)) {
+		uint16_t rxseq = letoh16(*(const u_int16_t *)wh->i_seq);
+		if ((wh->i_fc[1] & IEEE80211_FC1_MORE_FRAG) ||
+		    (rxseq & IEEE80211_SEQ_FRAG_MASK))
+			goto err;
+	}
+
 	/* duplicate detection (see 9.2.9) */
 	if (ieee80211_has_seq(wh) &&
 	    ic->ic_state != IEEE80211_S_SCAN) {
@@ -1130,6 +1146,50 @@ ieee80211_decap(struct ieee80211com *ic,
 	ieee80211_enqueue_data(ic, m, ni, mcast, ml);
 }
 
+int
+ieee80211_amsdu_decap_validate(struct ieee80211com *ic, struct mbuf *m,
+    struct ieee80211_node *ni)
+{
+	struct ether_header *eh = mtod(m, struct ether_header *);
+	const uint8_t llc_hdr_mac[ETHER_ADDR_LEN] = {
+		/* MAC address matching the 802.2 LLC header. */
+		LLC_SNAP_LSAP, LLC_SNAP_LSAP, LLC_UI, 0, 0, 0
+	}; 
+
+	/*
+	 * We are sorry, but this particular MAC address cannot be used.
+	 * This mitigates an attack where a single 802.11 frame is interpreted
+	 * as an A-MSDU because of a forged AMSDU-present bit in the 802.11
+	 * QoS frame header: https://papers.mathyvanhoef.com/usenix2021.pdf
+	 * See Section 7.2, 'Countermeasures for the design flaws'
+	 */
+	if (ETHER_IS_EQ(eh->ether_dhost, llc_hdr_mac))
+		return 1;
+
+	switch (ic->ic_opmode) {
+#ifndef IEEE80211_STA_ONLY
+	case IEEE80211_M_HOSTAP:
+		/*
+		 * Subframes must use the source address of the node which
+		 * transmitted the A-MSDU. Prevents MAC spoofing.
+		 */
+		if (!ETHER_IS_EQ(ni->ni_macaddr, eh->ether_shost))
+			return 1;
+		break;
+#endif
+	case IEEE80211_M_STA:
+		/* Subframes must be addressed to me. */
+		if (!ETHER_IS_EQ(ic->ic_myaddr, eh->ether_dhost))
+			return 1;
+		break;
+	default:
+		/* Ignore MONITOR/IBSS modes for now. */
+		break;
+	}
+
+	return 0;
+}
+
 /*
  * Decapsulate an Aggregate MSDU (see 7.2.2.2).
  */
@@ -1142,6 +1202,7 @@ ieee80211_amsdu_decap(struct ieee80211co
 	struct llc *llc;
 	int len, pad, mcast;
 	struct ieee80211_frame *wh;
+	struct mbuf_list subframes = MBUF_LIST_INITIALIZER();
 
 	wh = mtod(m, struct ieee80211_frame *);
 	mcast = IEEE80211_IS_MULTICAST(wh->i_addr1);
@@ -1149,15 +1210,11 @@ ieee80211_amsdu_decap(struct ieee80211co
 	/* strip 802.11 header */
 	m_adj(m, hdrlen);
 
-	for (;;) {
+	while (m->m_pkthdr.len >= ETHER_HDR_LEN + LLC_SNAPFRAMELEN) {
 		/* process an A-MSDU subframe */
-		if (m->m_len < ETHER_HDR_LEN + LLC_SNAPFRAMELEN) {
-			m = m_pullup(m, ETHER_HDR_LEN + LLC_SNAPFRAMELEN);
-			if (m == NULL) {
-				ic->ic_stats.is_rx_decap++;
-				break;
-			}
-		}
+		m = m_pullup(m, ETHER_HDR_LEN + LLC_SNAPFRAMELEN);
+		if (m == NULL)
+			break;
 		eh = mtod(m, struct ether_header *);
 		/* examine 802.3 header */
 		len = ntohs(eh->ether_type);
@@ -1165,11 +1222,12 @@ ieee80211_amsdu_decap(struct ieee80211co
 			DPRINTF(("A-MSDU subframe too short (%d)\n", len));
 			/* stop processing A-MSDU subframes */
 			ic->ic_stats.is_rx_decap++;
+			ml_purge(&subframes);
 			m_freem(m);
-			break;
+			return;
 		}
 		llc = (struct llc *)&eh[1];
-		/* examine 802.2 LLC header */
+		/* Examine the 802.2 LLC header after the A-MSDU header. */
 		if (llc->llc_dsap == LLC_SNAP_LSAP &&
 		    llc->llc_ssap == LLC_SNAP_LSAP &&
 		    llc->llc_control == LLC_UI &&
@@ -1189,8 +1247,9 @@ ieee80211_amsdu_decap(struct ieee80211co
 			/* stop processing A-MSDU subframes */
 			DPRINTF(("A-MSDU subframe too long (%d)\n", len));
 			ic->ic_stats.is_rx_decap++;
+			ml_purge(&subframes);
 			m_freem(m);
-			break;
+			return;
 		}
 
 		/* "detach" our A-MSDU subframe from the others */
@@ -1198,20 +1257,31 @@ ieee80211_amsdu_decap(struct ieee80211co
 		if (n == NULL) {
 			/* stop processing A-MSDU subframes */
 			ic->ic_stats.is_rx_decap++;
+			ml_purge(&subframes);
 			m_freem(m);
-			break;
+			return;
 		}
-		ieee80211_enqueue_data(ic, m, ni, mcast, ml);
 
-		if (n->m_pkthdr.len == 0) {
-			m_freem(n);
-			break;
+		if (ieee80211_amsdu_decap_validate(ic, m, ni)) {
+			/* stop processing A-MSDU subframes */
+			ic->ic_stats.is_rx_decap++;
+			ml_purge(&subframes);
+			m_freem(m);
+			return;
 		}
+
+		ml_enqueue(&subframes, m);
+	
 		m = n;
 		/* remove padding */
 		pad = ((len + 3) & ~3) - len;
 		m_adj(m, pad);
 	}
+	
+	while ((n = ml_dequeue(&subframes)) != NULL)
+		ieee80211_enqueue_data(ic, n, ni, mcast, ml);
+
+	m_freem(m);
 }
 
 /*
