mac80211: backport upstream fixes for FragAttacks
[openwrt/staging/zorun.git] / package / kernel / mac80211 / patches / subsys / 380-mac80211-assure-all-fragments-are-encrypted.patch
diff --git a/package/kernel/mac80211/patches/subsys/380-mac80211-assure-all-fragments-are-encrypted.patch b/package/kernel/mac80211/patches/subsys/380-mac80211-assure-all-fragments-are-encrypted.patch
new file mode 100644 (file)
index 0000000..6939845
--- /dev/null
@@ -0,0 +1,69 @@
+From: Mathy Vanhoef <Mathy.Vanhoef@kuleuven.be>
+Date: Tue, 11 May 2021 20:02:42 +0200
+Subject: [PATCH] mac80211: assure all fragments are encrypted
+
+Do not mix plaintext and encrypted fragments in protected Wi-Fi
+networks. This fixes CVE-2020-26147.
+
+Previously, an attacker was able to first forward a legitimate encrypted
+fragment towards a victim, followed by a plaintext fragment. The
+encrypted and plaintext fragment would then be reassembled. For further
+details see Section 6.3 and Appendix D in the paper "Fragment and Forge:
+Breaking Wi-Fi Through Frame Aggregation and Fragmentation".
+
+Because of this change there are now two equivalent conditions in the
+code to determine if a received fragment requires sequential PNs, so we
+also move this test to a separate function to make the code easier to
+maintain.
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Mathy Vanhoef <Mathy.Vanhoef@kuleuven.be>
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+---
+
+--- a/net/mac80211/rx.c
++++ b/net/mac80211/rx.c
+@@ -2204,6 +2204,16 @@ ieee80211_reassemble_find(struct ieee802
+       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)
+ {
+@@ -2248,12 +2258,7 @@ ieee80211_rx_h_defragment(struct ieee802
+               /* 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
+@@ -2295,11 +2300,7 @@ ieee80211_rx_h_defragment(struct ieee802
+               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;
+               memcpy(pn, entry->last_pn, IEEE80211_CCMP_PN_LEN);
+               for (i = IEEE80211_CCMP_PN_LEN - 1; i >= 0; i--) {