]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blobdiff - net/mac80211/rx.c
mac80211: properly handle A-MSDUs that start with an RFC 1042 header
[mirror_ubuntu-jammy-kernel.git] / net / mac80211 / rx.c
index 62047e93e217be086cada92237b978f614eaa29e..f14d32a5001dd14537db37485d8c5165c99d5277 100644 (file)
@@ -2194,6 +2194,16 @@ ieee80211_reassemble_find(struct ieee80211_sub_if_data *sdata,
        return NULL;
 }
 
+static bool requires_sequential_pn(struct ieee80211_rx_data *rx, __le16 fc)
+{
+       return rx->key &&
+               (rx->key->conf.cipher == WLAN_CIPHER_SUITE_CCMP ||
+                rx->key->conf.cipher == WLAN_CIPHER_SUITE_CCMP_256 ||
+                rx->key->conf.cipher == WLAN_CIPHER_SUITE_GCMP ||
+                rx->key->conf.cipher == WLAN_CIPHER_SUITE_GCMP_256) &&
+               ieee80211_has_protected(fc);
+}
+
 static ieee80211_rx_result debug_noinline
 ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
 {
@@ -2238,18 +2248,14 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
                /* This is the first fragment of a new frame. */
                entry = ieee80211_reassemble_add(rx->sdata, frag, seq,
                                                 rx->seqno_idx, &(rx->skb));
-               if (rx->key &&
-                   (rx->key->conf.cipher == WLAN_CIPHER_SUITE_CCMP ||
-                    rx->key->conf.cipher == WLAN_CIPHER_SUITE_CCMP_256 ||
-                    rx->key->conf.cipher == WLAN_CIPHER_SUITE_GCMP ||
-                    rx->key->conf.cipher == WLAN_CIPHER_SUITE_GCMP_256) &&
-                   ieee80211_has_protected(fc)) {
+               if (requires_sequential_pn(rx, fc)) {
                        int queue = rx->security_idx;
 
                        /* Store CCMP/GCMP PN so that we can verify that the
                         * next fragment has a sequential PN value.
                         */
                        entry->check_sequential_pn = true;
+                       entry->key_color = rx->key->color;
                        memcpy(entry->last_pn,
                               rx->key->u.ccmp.rx_pn[queue],
                               IEEE80211_CCMP_PN_LEN);
@@ -2285,12 +2291,13 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
                u8 pn[IEEE80211_CCMP_PN_LEN], *rpn;
                int queue;
 
-               if (!rx->key ||
-                   (rx->key->conf.cipher != WLAN_CIPHER_SUITE_CCMP &&
-                    rx->key->conf.cipher != WLAN_CIPHER_SUITE_CCMP_256 &&
-                    rx->key->conf.cipher != WLAN_CIPHER_SUITE_GCMP &&
-                    rx->key->conf.cipher != WLAN_CIPHER_SUITE_GCMP_256))
+               if (!requires_sequential_pn(rx, fc))
                        return RX_DROP_UNUSABLE;
+
+               /* Prevent mixed key and fragment cache attacks */
+               if (entry->key_color != rx->key->color)
+                       return RX_DROP_UNUSABLE;
+
                memcpy(pn, entry->last_pn, IEEE80211_CCMP_PN_LEN);
                for (i = IEEE80211_CCMP_PN_LEN - 1; i >= 0; i--) {
                        pn[i]++;
@@ -2675,7 +2682,7 @@ __ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx, u8 data_offset)
        if (ieee80211_data_to_8023_exthdr(skb, &ethhdr,
                                          rx->sdata->vif.addr,
                                          rx->sdata->vif.type,
-                                         data_offset))
+                                         data_offset, true))
                return RX_DROP_UNUSABLE;
 
        ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr,