aboutsummaryrefslogtreecommitdiffstats
path: root/package/kernel/mac80211/patches/subsys/385-mac80211-add-fragment-cache-to-sta_info.patch
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@nbd.name>2021-05-12 14:28:37 +0200
committerFelix Fietkau <nbd@nbd.name>2021-05-12 17:51:59 +0200
commit025bd93f36c9923127674ce127e22933592cba6c (patch)
treea25ef041247120817c4f198e829359eb03766d9f /package/kernel/mac80211/patches/subsys/385-mac80211-add-fragment-cache-to-sta_info.patch
parent5a9608102b3c444d0c963255f9d016a1d5469d5d (diff)
downloadupstream-025bd93f36c9923127674ce127e22933592cba6c.tar.gz
upstream-025bd93f36c9923127674ce127e22933592cba6c.tar.bz2
upstream-025bd93f36c9923127674ce127e22933592cba6c.zip
mac80211: backport upstream fixes for FragAttacks
From the patch series description: Several security issues in the 802.11 implementations were found by Mathy Vanhoef (New York University Abu Dhabi), who has published all the details at https://papers.mathyvanhoef.com/usenix2021.pdf Specifically, the following CVEs were assigned: * CVE-2020-24586 - Fragmentation cache not cleared on reconnection * CVE-2020-24587 - Reassembling fragments encrypted under different keys * CVE-2020-24588 - Accepting non-SPP A-MSDU frames, which leads to payload being parsed as an L2 frame under an A-MSDU bit toggling attack * CVE-2020-26139 - Forwarding EAPOL from unauthenticated sender * CVE-2020-26140 - Accepting plaintext data frames in protected networks * CVE-2020-26141 - Not verifying TKIP MIC of fragmented frames * CVE-2020-26142 - Processing fragmented frames as full frames * CVE-2020-26143 - Accepting fragmented plaintext frames in protected networks * CVE-2020-26144 - Always accepting unencrypted A-MSDU frames that start with RFC1042 header with EAPOL ethertype * CVE-2020-26145 - Accepting plaintext broadcast fragments as full frames * CVE-2020-26146 - Reassembling encrypted fragments with non-consecutive packet numbers * CVE-2020-26147 - Reassembling mixed encrypted/plaintext fragments In general, the scope of these attacks is that they may allow an attacker to * inject L2 frames that they can more or less control (depending on the vulnerability and attack method) into an otherwise protected network; * exfiltrate (some) network data under certain conditions, this is specific to the fragmentation issues. A subset of these issues is known to apply to the Linux IEEE 802.11 implementation (mac80211). Where it is affected, the attached patches fix the issues, even if not all of them reference the exact CVE IDs. In addition, driver and/or firmware updates may be necessary, as well as potentially more fixes to mac80211, depending on how drivers are using it. Specifically, for Intel devices, firmware needs to be updated to the most recently released versions (which was done without any reference to the security issues) to address some of the vulnerabilities. To have a single set of patches, I'm also including patches for the ath10k and ath11k drivers here. We currently don't have information about how other drivers are, if at all, affected. Signed-off-by: Felix Fietkau <nbd@nbd.name>
Diffstat (limited to 'package/kernel/mac80211/patches/subsys/385-mac80211-add-fragment-cache-to-sta_info.patch')
-rw-r--r--package/kernel/mac80211/patches/subsys/385-mac80211-add-fragment-cache-to-sta_info.patch313
1 files changed, 313 insertions, 0 deletions
diff --git a/package/kernel/mac80211/patches/subsys/385-mac80211-add-fragment-cache-to-sta_info.patch b/package/kernel/mac80211/patches/subsys/385-mac80211-add-fragment-cache-to-sta_info.patch
new file mode 100644
index 0000000000..b536126d38
--- /dev/null
+++ b/package/kernel/mac80211/patches/subsys/385-mac80211-add-fragment-cache-to-sta_info.patch
@@ -0,0 +1,313 @@
+From: Johannes Berg <johannes.berg@intel.com>
+Date: Tue, 11 May 2021 20:02:47 +0200
+Subject: [PATCH] mac80211: add fragment cache to sta_info
+
+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
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+---
+
+--- a/net/mac80211/ieee80211_i.h
++++ b/net/mac80211/ieee80211_i.h
+@@ -50,12 +50,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
+
+@@ -88,19 +82,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;
+
+@@ -912,9 +893,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;
+@@ -2329,4 +2308,7 @@ u32 ieee80211_calc_expected_tx_airtime(s
+ #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
+@@ -8,7 +8,7 @@
+ * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2013-2014 Intel Mobile Communications GmbH
+ * Copyright (c) 2016 Intel Deutschland GmbH
+- * Copyright (C) 2018-2020 Intel Corporation
++ * Copyright (C) 2018-2021 Intel Corporation
+ */
+ #include <linux/slab.h>
+ #include <linux/kernel.h>
+@@ -679,16 +679,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);
+@@ -2038,8 +2034,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
+@@ -2133,19 +2133,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;
+@@ -2160,14 +2175,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;
+ struct sk_buff *f_skb;
+@@ -2176,7 +2191,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)
+@@ -2217,6 +2232,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;
+@@ -2238,6 +2254,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;
+
+@@ -2256,7 +2275,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;
+@@ -2284,7 +2303,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
+@@ -4,7 +4,7 @@
+ * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
+ * Copyright 2013-2014 Intel Mobile Communications GmbH
+ * Copyright (C) 2015 - 2017 Intel Deutschland GmbH
+- * Copyright (C) 2018-2020 Intel Corporation
++ * Copyright (C) 2018-2021 Intel Corporation
+ */
+
+ #include <linux/module.h>
+@@ -393,6 +393,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 */
+@@ -1103,6 +1105,8 @@ static void __sta_info_destroy_part2(str
+
+ 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
+@@ -3,7 +3,7 @@
+ * Copyright 2002-2005, Devicescape Software, Inc.
+ * Copyright 2013-2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2015-2017 Intel Deutschland GmbH
+- * Copyright(c) 2020 Intel Corporation
++ * Copyright(c) 2020-2021 Intel Corporation
+ */
+
+ #ifndef STA_INFO_H
+@@ -439,6 +439,33 @@ struct ieee80211_sta_rx_stats {
+ };
+
+ /*
++ * 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
+ * value will be scaled by the number of active stations when it is being
+@@ -531,6 +558,7 @@ struct ieee80211_sta_rx_stats {
+ * @status_stats.last_ack_signal: last ACK signal
+ * @status_stats.ack_signal_filled: last ACK signal validity
+ * @status_stats.avg_ack_signal: average ACK signal
++ * @frags: fragment cache
+ */
+ struct sta_info {
+ /* General information, mostly static */
+@@ -639,6 +667,8 @@ struct sta_info {
+
+ struct cfg80211_chan_def tdls_chandef;
+
++ struct ieee80211_fragment_cache frags;
++
+ /* keep last! */
+ struct ieee80211_sta sta;
+ };