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);
}

/*