-From 2b8a1fee3488c602aca8bea004a087e60806a5cf Mon Sep 17 00:00:00 2001
-From: Mathy Vanhoef <Mathy.Vanhoef@kuleuven.be>
-Date: Tue, 11 May 2021 20:02:45 +0200
+From foo@baz Tue Jun 1 09:24:27 AM CEST 2021
+From: Johannes Berg <johannes@sipsolutions.net>
+Date: Mon, 31 May 2021 22:31:29 +0200
Subject: cfg80211: mitigate A-MSDU aggregation attacks
+To: linux-wireless@vger.kernel.org
+Cc: stable@vger.kernel.org, Mathy Vanhoef <Mathy.Vanhoef@kuleuven.be>
+Message-ID: <20210531203135.180427-5-johannes@sipsolutions.net>
From: Mathy Vanhoef <Mathy.Vanhoef@kuleuven.be>
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
-@@ -767,6 +767,9 @@ void ieee80211_amsdu_to_8023s(struct sk_
+@@ -768,6 +768,9 @@ void ieee80211_amsdu_to_8023s(struct sk_
remaining = skb->len - offset;
if (subframe_len > remaining)
goto purge;
--- /dev/null
+From foo@baz Tue Jun 1 09:24:27 AM CEST 2021
+From: Johannes Berg <johannes@sipsolutions.net>
+Date: Mon, 31 May 2021 22:31:31 +0200
+Subject: mac80211: add fragment cache to sta_info
+To: linux-wireless@vger.kernel.org
+Cc: stable@vger.kernel.org, Johannes Berg <johannes.berg@intel.com>
+Message-ID: <20210531203135.180427-7-johannes@sipsolutions.net>
+
+From: Johannes Berg <johannes.berg@intel.com>
+
+commit 3a11ce08c45b50d69c891d71760b7c5b92074709 upstream.
+
+Prior patches protected against fragmentation cache attacks
+by coloring keys, but this shows that it can lead to issues
+when multiple stations use the same sequence number. Add a
+fragment cache to struct sta_info (in addition to the one in
+the interface) to separate fragments for different stations
+properly.
+
+This then automatically clear most of the fragment cache when a
+station disconnects (or reassociates) from an AP, or when client
+interfaces disconnect from the network, etc.
+
+On the way, also fix the comment there since this brings us in line
+with the recommendation in 802.11-2016 ("An AP should support ...").
+Additionally, remove a useless condition (since there's no problem
+purging an already empty list).
+
+Cc: stable@vger.kernel.org
+Link: https://lore.kernel.org/r/20210511200110.fc35046b0d52.I1ef101e3784d13e8f6600d83de7ec9a3a45bcd52@changeid
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/mac80211/ieee80211_i.h | 26 ++++----------------------
+ net/mac80211/iface.c | 9 ++-------
+ net/mac80211/rx.c | 41 ++++++++++++++++++++++++++++++-----------
+ net/mac80211/sta_info.c | 4 ++++
+ net/mac80211/sta_info.h | 30 ++++++++++++++++++++++++++++++
+ 5 files changed, 70 insertions(+), 40 deletions(-)
+
+--- a/net/mac80211/ieee80211_i.h
++++ b/net/mac80211/ieee80211_i.h
+@@ -52,12 +52,6 @@ struct ieee80211_local;
+ #define IEEE80211_ENCRYPT_HEADROOM 8
+ #define IEEE80211_ENCRYPT_TAILROOM 18
+
+-/* IEEE 802.11 (Ch. 9.5 Defragmentation) requires support for concurrent
+- * reception of at least three fragmented frames. This limit can be increased
+- * by changing this define, at the cost of slower frame reassembly and
+- * increased memory use (about 2 kB of RAM per entry). */
+-#define IEEE80211_FRAGMENT_MAX 4
+-
+ /* power level hasn't been configured (or set to automatic) */
+ #define IEEE80211_UNSET_POWER_LEVEL INT_MIN
+
+@@ -90,19 +84,6 @@ extern const u8 ieee80211_ac_to_qos_mask
+
+ #define IEEE80211_MAX_NAN_INSTANCE_ID 255
+
+-struct ieee80211_fragment_entry {
+- struct sk_buff_head skb_list;
+- unsigned long first_frag_time;
+- u16 seq;
+- u16 extra_len;
+- u16 last_frag;
+- u8 rx_queue;
+- bool check_sequential_pn; /* needed for CCMP/GCMP */
+- u8 last_pn[6]; /* PN of the last fragment if CCMP was used */
+- unsigned int key_color;
+-};
+-
+-
+ struct ieee80211_bss {
+ u32 device_ts_beacon, device_ts_presp;
+
+@@ -882,9 +863,7 @@ struct ieee80211_sub_if_data {
+
+ char name[IFNAMSIZ];
+
+- /* Fragment table for host-based reassembly */
+- struct ieee80211_fragment_entry fragments[IEEE80211_FRAGMENT_MAX];
+- unsigned int fragment_next;
++ struct ieee80211_fragment_cache frags;
+
+ /* TID bitmap for NoAck policy */
+ u16 noack_map;
+@@ -2164,4 +2143,7 @@ extern const struct ethtool_ops ieee8021
+ #define debug_noinline
+ #endif
+
++void ieee80211_init_frag_cache(struct ieee80211_fragment_cache *cache);
++void ieee80211_destroy_frag_cache(struct ieee80211_fragment_cache *cache);
++
+ #endif /* IEEE80211_I_H */
+--- a/net/mac80211/iface.c
++++ b/net/mac80211/iface.c
+@@ -1127,16 +1127,12 @@ static void ieee80211_set_multicast_list
+ */
+ static void ieee80211_teardown_sdata(struct ieee80211_sub_if_data *sdata)
+ {
+- int i;
+-
+ /* free extra data */
+ ieee80211_free_keys(sdata, false);
+
+ ieee80211_debugfs_remove_netdev(sdata);
+
+- for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++)
+- __skb_queue_purge(&sdata->fragments[i].skb_list);
+- sdata->fragment_next = 0;
++ ieee80211_destroy_frag_cache(&sdata->frags);
+
+ if (ieee80211_vif_is_mesh(&sdata->vif))
+ ieee80211_mesh_teardown_sdata(sdata);
+@@ -1846,8 +1842,7 @@ int ieee80211_if_add(struct ieee80211_lo
+ sdata->wdev.wiphy = local->hw.wiphy;
+ sdata->local = local;
+
+- for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++)
+- skb_queue_head_init(&sdata->fragments[i].skb_list);
++ ieee80211_init_frag_cache(&sdata->frags);
+
+ INIT_LIST_HEAD(&sdata->key_list);
+
+--- a/net/mac80211/rx.c
++++ b/net/mac80211/rx.c
+@@ -1899,19 +1899,34 @@ ieee80211_rx_h_decrypt(struct ieee80211_
+ return result;
+ }
+
++void ieee80211_init_frag_cache(struct ieee80211_fragment_cache *cache)
++{
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(cache->entries); i++)
++ skb_queue_head_init(&cache->entries[i].skb_list);
++}
++
++void ieee80211_destroy_frag_cache(struct ieee80211_fragment_cache *cache)
++{
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(cache->entries); i++)
++ __skb_queue_purge(&cache->entries[i].skb_list);
++}
++
+ static inline struct ieee80211_fragment_entry *
+-ieee80211_reassemble_add(struct ieee80211_sub_if_data *sdata,
++ieee80211_reassemble_add(struct ieee80211_fragment_cache *cache,
+ unsigned int frag, unsigned int seq, int rx_queue,
+ struct sk_buff **skb)
+ {
+ struct ieee80211_fragment_entry *entry;
+
+- entry = &sdata->fragments[sdata->fragment_next++];
+- if (sdata->fragment_next >= IEEE80211_FRAGMENT_MAX)
+- sdata->fragment_next = 0;
++ entry = &cache->entries[cache->next++];
++ if (cache->next >= IEEE80211_FRAGMENT_MAX)
++ cache->next = 0;
+
+- if (!skb_queue_empty(&entry->skb_list))
+- __skb_queue_purge(&entry->skb_list);
++ __skb_queue_purge(&entry->skb_list);
+
+ __skb_queue_tail(&entry->skb_list, *skb); /* no need for locking */
+ *skb = NULL;
+@@ -1926,14 +1941,14 @@ ieee80211_reassemble_add(struct ieee8021
+ }
+
+ static inline struct ieee80211_fragment_entry *
+-ieee80211_reassemble_find(struct ieee80211_sub_if_data *sdata,
++ieee80211_reassemble_find(struct ieee80211_fragment_cache *cache,
+ unsigned int frag, unsigned int seq,
+ int rx_queue, struct ieee80211_hdr *hdr)
+ {
+ struct ieee80211_fragment_entry *entry;
+ int i, idx;
+
+- idx = sdata->fragment_next;
++ idx = cache->next;
+ for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++) {
+ struct ieee80211_hdr *f_hdr;
+
+@@ -1941,7 +1956,7 @@ ieee80211_reassemble_find(struct ieee802
+ if (idx < 0)
+ idx = IEEE80211_FRAGMENT_MAX - 1;
+
+- entry = &sdata->fragments[idx];
++ entry = &cache->entries[idx];
+ if (skb_queue_empty(&entry->skb_list) || entry->seq != seq ||
+ entry->rx_queue != rx_queue ||
+ entry->last_frag + 1 != frag)
+@@ -1981,6 +1996,7 @@ static bool requires_sequential_pn(struc
+ static ieee80211_rx_result debug_noinline
+ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
+ {
++ struct ieee80211_fragment_cache *cache = &rx->sdata->frags;
+ struct ieee80211_hdr *hdr;
+ u16 sc;
+ __le16 fc;
+@@ -2002,6 +2018,9 @@ ieee80211_rx_h_defragment(struct ieee802
+ goto out_no_led;
+ }
+
++ if (rx->sta)
++ cache = &rx->sta->frags;
++
+ if (likely(!ieee80211_has_morefrags(fc) && frag == 0))
+ goto out;
+
+@@ -2020,7 +2039,7 @@ ieee80211_rx_h_defragment(struct ieee802
+
+ if (frag == 0) {
+ /* This is the first fragment of a new frame. */
+- entry = ieee80211_reassemble_add(rx->sdata, frag, seq,
++ entry = ieee80211_reassemble_add(cache, frag, seq,
+ rx->seqno_idx, &(rx->skb));
+ if (requires_sequential_pn(rx, fc)) {
+ int queue = rx->security_idx;
+@@ -2048,7 +2067,7 @@ ieee80211_rx_h_defragment(struct ieee802
+ /* This is a fragment for a frame that should already be pending in
+ * fragment cache. Add this fragment to the end of the pending entry.
+ */
+- entry = ieee80211_reassemble_find(rx->sdata, frag, seq,
++ entry = ieee80211_reassemble_find(cache, frag, seq,
+ rx->seqno_idx, hdr);
+ if (!entry) {
+ I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag);
+--- a/net/mac80211/sta_info.c
++++ b/net/mac80211/sta_info.c
+@@ -367,6 +367,8 @@ struct sta_info *sta_info_alloc(struct i
+
+ u64_stats_init(&sta->rx_stats.syncp);
+
++ ieee80211_init_frag_cache(&sta->frags);
++
+ sta->sta_state = IEEE80211_STA_NONE;
+
+ /* Mark TID as unreserved */
+@@ -1005,6 +1007,8 @@ static void __sta_info_destroy_part2(str
+ rate_control_remove_sta_debugfs(sta);
+ ieee80211_sta_debugfs_remove(sta);
+
++ ieee80211_destroy_frag_cache(&sta->frags);
++
+ cleanup_single_sta(sta);
+ }
+
+--- a/net/mac80211/sta_info.h
++++ b/net/mac80211/sta_info.h
+@@ -398,6 +398,33 @@ struct ieee80211_sta_rx_stats {
+ u64 msdu[IEEE80211_NUM_TIDS + 1];
+ };
+
++/*
++ * IEEE 802.11-2016 (10.6 "Defragmentation") recommends support for "concurrent
++ * reception of at least one MSDU per access category per associated STA"
++ * on APs, or "at least one MSDU per access category" on other interface types.
++ *
++ * This limit can be increased by changing this define, at the cost of slower
++ * frame reassembly and increased memory use while fragments are pending.
++ */
++#define IEEE80211_FRAGMENT_MAX 4
++
++struct ieee80211_fragment_entry {
++ struct sk_buff_head skb_list;
++ unsigned long first_frag_time;
++ u16 seq;
++ u16 extra_len;
++ u16 last_frag;
++ u8 rx_queue;
++ bool check_sequential_pn; /* needed for CCMP/GCMP */
++ u8 last_pn[6]; /* PN of the last fragment if CCMP was used */
++ unsigned int key_color;
++};
++
++struct ieee80211_fragment_cache {
++ struct ieee80211_fragment_entry entries[IEEE80211_FRAGMENT_MAX];
++ unsigned int next;
++};
++
+ /**
+ * The bandwidth threshold below which the per-station CoDel parameters will be
+ * scaled to be more lenient (to prevent starvation of slow stations). This
+@@ -470,6 +497,7 @@ struct ieee80211_sta_rx_stats {
+ * @pcpu_rx_stats: per-CPU RX statistics, assigned only if the driver needs
+ * this (by advertising the USES_RSS hw flag)
+ * @status_stats: TX status statistics
++ * @frags: fragment cache
+ */
+ struct sta_info {
+ /* General information, mostly static */
+@@ -569,6 +597,8 @@ struct sta_info {
+
+ struct cfg80211_chan_def tdls_chandef;
+
++ struct ieee80211_fragment_cache frags;
++
+ /* keep last! */
+ struct ieee80211_sta sta;
+ };
-From 965a7d72e798eb7af0aa67210e37cf7ecd1c9cad Mon Sep 17 00:00:00 2001
-From: Mathy Vanhoef <Mathy.Vanhoef@kuleuven.be>
-Date: Tue, 11 May 2021 20:02:42 +0200
+From foo@baz Tue Jun 1 09:24:27 AM CEST 2021
+From: Johannes Berg <johannes@sipsolutions.net>
+Date: Mon, 31 May 2021 22:31:26 +0200
Subject: mac80211: assure all fragments are encrypted
+To: linux-wireless@vger.kernel.org
+Cc: stable@vger.kernel.org, Mathy Vanhoef <Mathy.Vanhoef@kuleuven.be>
+Message-ID: <20210531203135.180427-2-johannes@sipsolutions.net>
From: Mathy Vanhoef <Mathy.Vanhoef@kuleuven.be>
-From bf30ca922a0c0176007e074b0acc77ed345e9990 Mon Sep 17 00:00:00 2001
-From: Johannes Berg <johannes.berg@intel.com>
-Date: Tue, 11 May 2021 20:02:48 +0200
+From foo@baz Tue Jun 1 09:24:27 AM CEST 2021
+From: Johannes Berg <johannes@sipsolutions.net>
+Date: Mon, 31 May 2021 22:31:32 +0200
Subject: mac80211: check defrag PN against current frame
+To: linux-wireless@vger.kernel.org
+Cc: stable@vger.kernel.org, Johannes Berg <johannes.berg@intel.com>
+Message-ID: <20210531203135.180427-8-johannes@sipsolutions.net>
From: Johannes Berg <johannes.berg@intel.com>
---
net/mac80211/ieee80211_i.h | 11 +++++++++--
net/mac80211/rx.c | 5 ++---
- net/mac80211/wpa.c | 13 +++++++++----
- 3 files changed, 20 insertions(+), 9 deletions(-)
+ net/mac80211/wpa.c | 12 ++++++++----
+ 3 files changed, 19 insertions(+), 9 deletions(-)
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
-@@ -242,8 +242,15 @@ struct ieee80211_rx_data {
+@@ -223,8 +223,15 @@ struct ieee80211_rx_data {
*/
int security_idx;
struct ieee80211_csa_settings {
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
-@@ -2063,7 +2063,6 @@ ieee80211_rx_h_defragment(struct ieee802
+@@ -2082,7 +2082,6 @@ ieee80211_rx_h_defragment(struct ieee802
if (entry->check_sequential_pn) {
int i;
u8 pn[IEEE80211_CCMP_PN_LEN], *rpn;
if (!requires_sequential_pn(rx, fc))
return RX_DROP_UNUSABLE;
-@@ -2078,8 +2077,8 @@ ieee80211_rx_h_defragment(struct ieee802
+@@ -2097,8 +2096,8 @@ ieee80211_rx_h_defragment(struct ieee802
if (pn[i])
break;
}
memcpy(entry->last_pn, pn, IEEE80211_CCMP_PN_LEN);
--- a/net/mac80211/wpa.c
+++ b/net/mac80211/wpa.c
-@@ -2,6 +2,7 @@
- * Copyright 2002-2004, Instant802 Networks, Inc.
- * Copyright 2008, Jouni Malinen <j@w1.fi>
- * Copyright (C) 2016 Intel Deutschland GmbH
-+ * Copyright (C) 2020-2021 Intel Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
-@@ -162,8 +163,8 @@ ieee80211_rx_h_michael_mic_verify(struct
+@@ -162,8 +162,8 @@ ieee80211_rx_h_michael_mic_verify(struct
update_iv:
/* update IV in key information to be able to detect replays */
return RX_CONTINUE;
-@@ -289,8 +290,8 @@ ieee80211_crypto_tkip_decrypt(struct iee
+@@ -289,8 +289,8 @@ ieee80211_crypto_tkip_decrypt(struct iee
key, skb->data + hdrlen,
skb->len - hdrlen, rx->sta->sta.addr,
hdr->addr1, hwaccel, rx->security_idx,
if (res != TKIP_DECRYPT_OK)
return RX_DROP_UNUSABLE;
-@@ -548,6 +549,8 @@ ieee80211_crypto_ccmp_decrypt(struct iee
+@@ -548,6 +548,8 @@ ieee80211_crypto_ccmp_decrypt(struct iee
}
memcpy(key->u.ccmp.rx_pn[queue], pn, IEEE80211_CCMP_PN_LEN);
}
/* Remove CCMP header and MIC */
-@@ -777,6 +780,8 @@ ieee80211_crypto_gcmp_decrypt(struct iee
+@@ -777,6 +779,8 @@ ieee80211_crypto_gcmp_decrypt(struct iee
}
memcpy(key->u.gcmp.rx_pn[queue], pn, IEEE80211_GCMP_PN_LEN);
--- /dev/null
+From foo@baz Tue Jun 1 09:24:27 AM CEST 2021
+From: Johannes Berg <johannes@sipsolutions.net>
+Date: Mon, 31 May 2021 22:31:34 +0200
+Subject: mac80211: do not accept/forward invalid EAPOL frames
+To: linux-wireless@vger.kernel.org
+Cc: stable@vger.kernel.org, Johannes Berg <johannes.berg@intel.com>, Jouni Malinen <jouni@codeaurora.org>
+Message-ID: <20210531203135.180427-10-johannes@sipsolutions.net>
+
+From: Johannes Berg <johannes.berg@intel.com>
+
+commit a8c4d76a8dd4fb9666fc8919a703d85fb8f44ed8 upstream.
+
+EAPOL frames are used for authentication and key management between the
+AP and each individual STA associated in the BSS. Those frames are not
+supposed to be sent by one associated STA to another associated STA
+(either unicast for broadcast/multicast).
+
+Similarly, in 802.11 they're supposed to be sent to the authenticator
+(AP) address.
+
+Since it is possible for unexpected EAPOL frames to result in misbehavior
+in supplicant implementations, it is better for the AP to not allow such
+cases to be forwarded to other clients either directly, or indirectly if
+the AP interface is part of a bridge.
+
+Accept EAPOL (control port) frames only if they're transmitted to the
+own address, or, due to interoperability concerns, to the PAE group
+address.
+
+Disable forwarding of EAPOL (or well, the configured control port
+protocol) frames back to wireless medium in all cases. Previously, these
+frames were accepted from fully authenticated and authorized stations
+and also from unauthenticated stations for one of the cases.
+
+Additionally, to avoid forwarding by the bridge, rewrite the PAE group
+address case to the local MAC address.
+
+Cc: stable@vger.kernel.org
+Co-developed-by: Jouni Malinen <jouni@codeaurora.org>
+Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
+Link: https://lore.kernel.org/r/20210511200110.cb327ed0cabe.Ib7dcffa2a31f0913d660de65ba3c8aca75b1d10f@changeid
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/mac80211/rx.c | 34 ++++++++++++++++++++++++++++------
+ 1 file changed, 28 insertions(+), 6 deletions(-)
+
+--- a/net/mac80211/rx.c
++++ b/net/mac80211/rx.c
+@@ -2298,13 +2298,13 @@ static bool ieee80211_frame_allowed(stru
+ struct ethhdr *ehdr = (struct ethhdr *) rx->skb->data;
+
+ /*
+- * Allow EAPOL frames to us/the PAE group address regardless
+- * of whether the frame was encrypted or not.
++ * Allow EAPOL frames to us/the PAE group address regardless of
++ * whether the frame was encrypted or not, and always disallow
++ * all other destination addresses for them.
+ */
+- if (ehdr->h_proto == rx->sdata->control_port_protocol &&
+- (ether_addr_equal(ehdr->h_dest, rx->sdata->vif.addr) ||
+- ether_addr_equal(ehdr->h_dest, pae_group_addr)))
+- return true;
++ if (unlikely(ehdr->h_proto == rx->sdata->control_port_protocol))
++ return ether_addr_equal(ehdr->h_dest, rx->sdata->vif.addr) ||
++ ether_addr_equal(ehdr->h_dest, pae_group_addr);
+
+ if (ieee80211_802_1x_port_control(rx) ||
+ ieee80211_drop_unencrypted(rx, fc))
+@@ -2344,6 +2344,7 @@ ieee80211_deliver_skb(struct ieee80211_r
+ if ((sdata->vif.type == NL80211_IFTYPE_AP ||
+ sdata->vif.type == NL80211_IFTYPE_AP_VLAN) &&
+ !(sdata->flags & IEEE80211_SDATA_DONT_BRIDGE_PACKETS) &&
++ ehdr->h_proto != rx->sdata->control_port_protocol &&
+ (sdata->vif.type != NL80211_IFTYPE_AP_VLAN || !sdata->u.vlan.sta)) {
+ if (is_multicast_ether_addr(ehdr->h_dest) &&
+ ieee80211_vif_get_num_mcast_if(sdata) != 0) {
+@@ -2397,9 +2398,30 @@ ieee80211_deliver_skb(struct ieee80211_r
+ #endif
+
+ if (skb) {
++ struct ethhdr *ehdr = (void *)skb_mac_header(skb);
++
+ /* deliver to local stack */
+ skb->protocol = eth_type_trans(skb, dev);
+ memset(skb->cb, 0, sizeof(skb->cb));
++
++ /*
++ * 802.1X over 802.11 requires that the authenticator address
++ * be used for EAPOL frames. However, 802.1X allows the use of
++ * the PAE group address instead. If the interface is part of
++ * a bridge and we pass the frame with the PAE group address,
++ * then the bridge will forward it to the network (even if the
++ * client was not associated yet), which isn't supposed to
++ * happen.
++ * To avoid that, rewrite the destination address to our own
++ * address, so that the authenticator (e.g. hostapd) will see
++ * the frame, but bridge won't forward it anywhere else. Note
++ * that due to earlier filtering, the only other address can
++ * be the PAE group address.
++ */
++ if (unlikely(skb->protocol == sdata->control_port_protocol &&
++ !ether_addr_equal(ehdr->h_dest, sdata->vif.addr)))
++ ether_addr_copy(ehdr->h_dest, sdata->vif.addr);
++
+ if (rx->napi)
+ napi_gro_receive(rx->napi, skb);
+ else
--- /dev/null
+From foo@baz Tue Jun 1 09:24:27 AM CEST 2021
+From: Johannes Berg <johannes@sipsolutions.net>
+Date: Mon, 31 May 2021 22:31:30 +0200
+Subject: mac80211: drop A-MSDUs on old ciphers
+To: linux-wireless@vger.kernel.org
+Cc: stable@vger.kernel.org, Johannes Berg <johannes.berg@intel.com>
+Message-ID: <20210531203135.180427-6-johannes@sipsolutions.net>
+
+From: Johannes Berg <johannes.berg@intel.com>
+
+commit 270032a2a9c4535799736142e1e7c413ca7b836e upstream.
+
+With old ciphers (WEP and TKIP) we shouldn't be using A-MSDUs
+since A-MSDUs are only supported if we know that they are, and
+the only practical way for that is HT support which doesn't
+support old ciphers.
+
+However, we would normally accept them anyway. Since we check
+the MMIC before deaggregating A-MSDUs, and the A-MSDU bit in
+the QoS header is not protected in TKIP (or WEP), this enables
+attacks similar to CVE-2020-24588. To prevent that, drop A-MSDUs
+completely with old ciphers.
+
+Cc: stable@vger.kernel.org
+Link: https://lore.kernel.org/r/20210511200110.076543300172.I548e6e71f1ee9cad4b9a37bf212ae7db723587aa@changeid
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/mac80211/rx.c | 17 +++++++++++++++++
+ 1 file changed, 17 insertions(+)
+
+--- a/net/mac80211/rx.c
++++ b/net/mac80211/rx.c
+@@ -2455,6 +2455,23 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx
+ true))
+ return RX_DROP_UNUSABLE;
+
++ if (rx->key) {
++ /*
++ * We should not receive A-MSDUs on pre-HT connections,
++ * and HT connections cannot use old ciphers. Thus drop
++ * them, as in those cases we couldn't even have SPP
++ * A-MSDUs or such.
++ */
++ switch (rx->key->conf.cipher) {
++ case WLAN_CIPHER_SUITE_WEP40:
++ case WLAN_CIPHER_SUITE_WEP104:
++ case WLAN_CIPHER_SUITE_TKIP:
++ return RX_DROP_UNUSABLE;
++ default:
++ break;
++ }
++ }
++
+ ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr,
+ rx->sdata->vif.type,
+ rx->local->hw.extra_tx_headroom,
--- /dev/null
+From foo@baz Tue Jun 1 09:24:27 AM CEST 2021
+From: Johannes Berg <johannes@sipsolutions.net>
+Date: Mon, 31 May 2021 22:31:35 +0200
+Subject: mac80211: extend protection against mixed key and fragment cache attacks
+To: linux-wireless@vger.kernel.org
+Cc: stable@vger.kernel.org, Wen Gong <wgong@codeaurora.org>
+Message-ID: <20210531203135.180427-11-johannes@sipsolutions.net>
+
+From: Wen Gong <wgong@codeaurora.org>
+
+commit 3edc6b0d6c061a70d8ca3c3c72eb1f58ce29bfb1 upstream.
+
+For some chips/drivers, e.g., QCA6174 with ath10k, the decryption is
+done by the hardware, and the Protected bit in the Frame Control field
+is cleared in the lower level driver before the frame is passed to
+mac80211. In such cases, the condition for ieee80211_has_protected() is
+not met in ieee80211_rx_h_defragment() of mac80211 and the new security
+validation steps are not executed.
+
+Extend mac80211 to cover the case where the Protected bit has been
+cleared, but the frame is indicated as having been decrypted by the
+hardware. This extends protection against mixed key and fragment cache
+attack for additional drivers/chips. This fixes CVE-2020-24586 and
+CVE-2020-24587 for such cases.
+
+Tested-on: QCA6174 hw3.2 PCI WLAN.RM.4.4.1-00110-QCARMSWP-1
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Wen Gong <wgong@codeaurora.org>
+Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
+Link: https://lore.kernel.org/r/20210511200110.037aa5ca0390.I7bb888e2965a0db02a67075fcb5deb50eb7408aa@changeid
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/mac80211/rx.c | 13 +++++++++++--
+ 1 file changed, 11 insertions(+), 2 deletions(-)
+
+--- a/net/mac80211/rx.c
++++ b/net/mac80211/rx.c
+@@ -2003,6 +2003,7 @@ ieee80211_rx_h_defragment(struct ieee802
+ unsigned int frag, seq;
+ struct ieee80211_fragment_entry *entry;
+ struct sk_buff *skb;
++ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
+
+ hdr = (struct ieee80211_hdr *)rx->skb->data;
+ fc = hdr->frame_control;
+@@ -2061,7 +2062,9 @@ ieee80211_rx_h_defragment(struct ieee802
+ sizeof(rx->key->u.gcmp.rx_pn[queue]));
+ BUILD_BUG_ON(IEEE80211_CCMP_PN_LEN !=
+ IEEE80211_GCMP_PN_LEN);
+- } else if (rx->key && ieee80211_has_protected(fc)) {
++ } else if (rx->key &&
++ (ieee80211_has_protected(fc) ||
++ (status->flag & RX_FLAG_DECRYPTED))) {
+ entry->is_protected = true;
+ entry->key_color = rx->key->color;
+ }
+@@ -2106,13 +2109,19 @@ ieee80211_rx_h_defragment(struct ieee802
+ return RX_DROP_UNUSABLE;
+ memcpy(entry->last_pn, pn, IEEE80211_CCMP_PN_LEN);
+ } else if (entry->is_protected &&
+- (!rx->key || !ieee80211_has_protected(fc) ||
++ (!rx->key ||
++ (!ieee80211_has_protected(fc) &&
++ !(status->flag & RX_FLAG_DECRYPTED)) ||
+ rx->key->color != entry->key_color)) {
+ /* Drop this as a mixed key or fragment cache attack, even
+ * if for TKIP Michael MIC should protect us, and WEP is a
+ * lost cause anyway.
+ */
+ return RX_DROP_UNUSABLE;
++ } else if (entry->is_protected && rx->key &&
++ entry->key_color != rx->key->color &&
++ (status->flag & RX_FLAG_DECRYPTED)) {
++ return RX_DROP_UNUSABLE;
+ }
+
+ skb_pull(rx->skb, ieee80211_hdrlen(fc));
--- /dev/null
+From foo@baz Tue Jun 1 09:24:27 AM CEST 2021
+From: Johannes Berg <johannes@sipsolutions.net>
+Date: Mon, 31 May 2021 22:31:33 +0200
+Subject: mac80211: prevent attacks on TKIP/WEP as well
+To: linux-wireless@vger.kernel.org
+Cc: stable@vger.kernel.org, Johannes Berg <johannes.berg@intel.com>
+Message-ID: <20210531203135.180427-9-johannes@sipsolutions.net>
+
+From: Johannes Berg <johannes.berg@intel.com>
+
+commit 7e44a0b597f04e67eee8cdcbe7ee706c6f5de38b upstream.
+
+Similar to the issues fixed in previous patches, TKIP and WEP
+should be protected even if for TKIP we have the Michael MIC
+protecting it, and WEP is broken anyway.
+
+However, this also somewhat protects potential other algorithms
+that drivers might implement.
+
+Cc: stable@vger.kernel.org
+Link: https://lore.kernel.org/r/20210511200110.430e8c202313.Ia37e4e5b6b3eaab1a5ae050e015f6c92859dbe27@changeid
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/mac80211/rx.c | 12 ++++++++++++
+ net/mac80211/sta_info.h | 3 ++-
+ 2 files changed, 14 insertions(+), 1 deletion(-)
+
+--- a/net/mac80211/rx.c
++++ b/net/mac80211/rx.c
+@@ -2048,6 +2048,7 @@ ieee80211_rx_h_defragment(struct ieee802
+ * next fragment has a sequential PN value.
+ */
+ entry->check_sequential_pn = true;
++ entry->is_protected = true;
+ entry->key_color = rx->key->color;
+ memcpy(entry->last_pn,
+ rx->key->u.ccmp.rx_pn[queue],
+@@ -2060,6 +2061,9 @@ ieee80211_rx_h_defragment(struct ieee802
+ sizeof(rx->key->u.gcmp.rx_pn[queue]));
+ BUILD_BUG_ON(IEEE80211_CCMP_PN_LEN !=
+ IEEE80211_GCMP_PN_LEN);
++ } else if (rx->key && ieee80211_has_protected(fc)) {
++ entry->is_protected = true;
++ entry->key_color = rx->key->color;
+ }
+ return RX_QUEUED;
+ }
+@@ -2101,6 +2105,14 @@ ieee80211_rx_h_defragment(struct ieee802
+ if (memcmp(pn, rpn, IEEE80211_CCMP_PN_LEN))
+ return RX_DROP_UNUSABLE;
+ memcpy(entry->last_pn, pn, IEEE80211_CCMP_PN_LEN);
++ } else if (entry->is_protected &&
++ (!rx->key || !ieee80211_has_protected(fc) ||
++ rx->key->color != entry->key_color)) {
++ /* Drop this as a mixed key or fragment cache attack, even
++ * if for TKIP Michael MIC should protect us, and WEP is a
++ * lost cause anyway.
++ */
++ return RX_DROP_UNUSABLE;
+ }
+
+ skb_pull(rx->skb, ieee80211_hdrlen(fc));
+--- a/net/mac80211/sta_info.h
++++ b/net/mac80211/sta_info.h
+@@ -415,7 +415,8 @@ struct ieee80211_fragment_entry {
+ u16 extra_len;
+ u16 last_frag;
+ u8 rx_queue;
+- bool check_sequential_pn; /* needed for CCMP/GCMP */
++ u8 check_sequential_pn:1, /* needed for CCMP/GCMP */
++ is_protected:1;
+ u8 last_pn[6]; /* PN of the last fragment if CCMP was used */
+ unsigned int key_color;
+ };
-From 94034c40ab4a3fcf581fbc7f8fdf4e29943c4a24 Mon Sep 17 00:00:00 2001
-From: Mathy Vanhoef <Mathy.Vanhoef@kuleuven.be>
-Date: Tue, 11 May 2021 20:02:43 +0200
+From foo@baz Tue Jun 1 09:24:27 AM CEST 2021
+From: Johannes Berg <johannes@sipsolutions.net>
+Date: Mon, 31 May 2021 22:31:27 +0200
Subject: mac80211: prevent mixed key and fragment cache attacks
+To: linux-wireless@vger.kernel.org
+Cc: stable@vger.kernel.org, Mathy Vanhoef <Mathy.Vanhoef@kuleuven.be>
+Message-ID: <20210531203135.180427-3-johannes@sipsolutions.net>
From: Mathy Vanhoef <Mathy.Vanhoef@kuleuven.be>
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
-@@ -647,6 +647,7 @@ int ieee80211_key_link(struct ieee80211_
- struct ieee80211_sub_if_data *sdata,
+@@ -648,6 +648,7 @@ int ieee80211_key_link(struct ieee80211_
struct sta_info *sta)
{
-+ static atomic_t key_color = ATOMIC_INIT(0);
struct ieee80211_local *local = sdata->local;
++ static atomic_t key_color = ATOMIC_INIT(0);
struct ieee80211_key *old_key;
int idx = key->conf.keyidx;
-@@ -682,6 +683,12 @@ int ieee80211_key_link(struct ieee80211_
- key->sdata = sdata;
- key->sta = sta;
+ bool pairwise = key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE;
+@@ -659,6 +660,12 @@ int ieee80211_key_link(struct ieee80211_
+ bool delay_tailroom = sdata->vif.type == NL80211_IFTYPE_STATION;
+ int ret;
+ /*
+ * Assign a unique ID to every key so we can easily prevent mixed
+ */
+ key->color = atomic_inc_return(&key_color);
+
- increment_tailroom_need_count(sdata);
+ mutex_lock(&sdata->local->key_mtx);
- ieee80211_key_replace(sdata, sta, pairwise, old_key, key);
+ if (sta && pairwise)
--- a/net/mac80211/key.h
+++ b/net/mac80211/key.h
@@ -127,6 +127,8 @@ struct ieee80211_key {
--- /dev/null
+From foo@baz Tue Jun 1 09:24:27 AM CEST 2021
+From: Johannes Berg <johannes@sipsolutions.net>
+Date: Mon, 31 May 2021 22:31:28 +0200
+Subject: mac80211: properly handle A-MSDUs that start with an RFC 1042 header
+To: linux-wireless@vger.kernel.org
+Cc: stable@vger.kernel.org, Mathy Vanhoef <Mathy.Vanhoef@kuleuven.be>
+Message-ID: <20210531203135.180427-4-johannes@sipsolutions.net>
+
+From: Mathy Vanhoef <Mathy.Vanhoef@kuleuven.be>
+
+commit a1d5ff5651ea592c67054233b14b30bf4452999c upstream.
+
+Properly parse A-MSDUs whose first 6 bytes happen to equal a rfc1042
+header. This can occur in practice when the destination MAC address
+equals AA:AA:03:00:00:00. More importantly, this simplifies the next
+patch to mitigate A-MSDU injection attacks.
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Mathy Vanhoef <Mathy.Vanhoef@kuleuven.be>
+Link: https://lore.kernel.org/r/20210511200110.0b2b886492f0.I23dd5d685fe16d3b0ec8106e8f01b59f499dffed@changeid
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/net/cfg80211.h | 5 +++--
+ net/mac80211/rx.c | 3 ++-
+ net/wireless/util.c | 5 +++--
+ 3 files changed, 8 insertions(+), 5 deletions(-)
+
+--- a/include/net/cfg80211.h
++++ b/include/net/cfg80211.h
+@@ -4338,7 +4338,8 @@ unsigned int ieee80211_get_mesh_hdrlen(s
+ * Return: 0 on success. Non-zero on error.
+ */
+ int ieee80211_data_to_8023_exthdr(struct sk_buff *skb, struct ethhdr *ehdr,
+- const u8 *addr, enum nl80211_iftype iftype);
++ const u8 *addr, enum nl80211_iftype iftype,
++ bool is_amsdu);
+
+ /**
+ * ieee80211_data_to_8023 - convert an 802.11 data frame to 802.3
+@@ -4350,7 +4351,7 @@ int ieee80211_data_to_8023_exthdr(struct
+ static inline int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
+ enum nl80211_iftype iftype)
+ {
+- return ieee80211_data_to_8023_exthdr(skb, NULL, addr, iftype);
++ return ieee80211_data_to_8023_exthdr(skb, NULL, addr, iftype, false);
+ }
+
+ /**
+--- a/net/mac80211/rx.c
++++ b/net/mac80211/rx.c
+@@ -2451,7 +2451,8 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx
+
+ if (ieee80211_data_to_8023_exthdr(skb, ðhdr,
+ rx->sdata->vif.addr,
+- rx->sdata->vif.type))
++ rx->sdata->vif.type,
++ true))
+ return RX_DROP_UNUSABLE;
+
+ ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr,
+--- a/net/wireless/util.c
++++ b/net/wireless/util.c
+@@ -422,7 +422,8 @@ unsigned int ieee80211_get_mesh_hdrlen(s
+ EXPORT_SYMBOL(ieee80211_get_mesh_hdrlen);
+
+ int ieee80211_data_to_8023_exthdr(struct sk_buff *skb, struct ethhdr *ehdr,
+- const u8 *addr, enum nl80211_iftype iftype)
++ const u8 *addr, enum nl80211_iftype iftype,
++ bool is_amsdu)
+ {
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ struct {
+@@ -510,7 +511,7 @@ int ieee80211_data_to_8023_exthdr(struct
+ skb_copy_bits(skb, hdrlen, &payload, sizeof(payload));
+ tmp.h_proto = payload.proto;
+
+- if (likely((ether_addr_equal(payload.hdr, rfc1042_header) &&
++ if (likely((!is_amsdu && ether_addr_equal(payload.hdr, rfc1042_header) &&
+ tmp.h_proto != htons(ETH_P_AARP) &&
+ tmp.h_proto != htons(ETH_P_IPX)) ||
+ ether_addr_equal(payload.hdr, bridge_tunnel_header)))
net-hso-fix-control-request-directions.patch
mac80211-assure-all-fragments-are-encrypted.patch
mac80211-prevent-mixed-key-and-fragment-cache-attacks.patch
+mac80211-properly-handle-a-msdus-that-start-with-an-rfc-1042-header.patch
cfg80211-mitigate-a-msdu-aggregation-attacks.patch
+mac80211-drop-a-msdus-on-old-ciphers.patch
+mac80211-add-fragment-cache-to-sta_info.patch
mac80211-check-defrag-pn-against-current-frame.patch
+mac80211-prevent-attacks-on-tkip-wep-as-well.patch
+mac80211-do-not-accept-forward-invalid-eapol-frames.patch
+mac80211-extend-protection-against-mixed-key-and-fragment-cache-attacks.patch
ath10k-validate-first-subframe-of-a-msdu-before-processing-the-list.patch
dm-snapshot-properly-fix-a-crash-when-an-origin-has-no-snapshots.patch
kgdb-fix-gcc-11-warnings-harder.patch