From a556d5e591aa0d9c155b20cdb0f74ced355deabc Mon Sep 17 00:00:00 2001 From: Mathy Vanhoef Date: Mon, 7 Jun 2021 22:38:53 +0800 Subject: [PATCH 01/26] mac80211: assure all fragments are encrypted commit:ddb64a7489623aeaadf212e0dec27e6078027991 CVE:CVE-2020-26147 Signed-off-by:Ywenrui commit 965a7d72e798eb7af0aa67210e37cf7ecd1c9cad upstream. 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 Link: https://lore.kernel.org/r/20210511200110.30c4394bb835.I5acfdb552cc1d20c339c262315950b3eac491397@changeid Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Yang Yingliang Signed-off-by: Ywenrui --- net/mac80211/rx.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 5e56719f999c..1907085b1272 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2078,6 +2078,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) { @@ -2122,12 +2132,7 @@ 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 @@ -2169,11 +2174,7 @@ 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; memcpy(pn, entry->last_pn, IEEE80211_CCMP_PN_LEN); for (i = IEEE80211_CCMP_PN_LEN - 1; i >= 0; i--) { -- Gitee From 55c743c40e4e5ef3fb20d5d6b51f6f90baad0ff8 Mon Sep 17 00:00:00 2001 From: yu kuai Date: Thu, 20 Feb 2020 15:19:36 +0800 Subject: [PATCH 02/26] block: rename 'q->debugfs_dir' and 'q->blk_trace->dir' in blk_unregister_queue() commit:7532f5ad14e4a0c7798752091f0f26e444d44c0c CVE:CVE-2019-19770 Signed-off-by:Ywenrui hulk inclusion category: bugfix bugzilla: 30213 CVE: CVE-2019-19770 --------------------------- syzbot is reporting use after free bug in debugfs_remove[1]. This is because in request_queue, 'q->debugfs_dir' and 'q->blk_trace->dir' could be the same dir. And in __blk_release_queue(), blk_mq_debugfs_unregister() will remove everything inside the dir. With futher investigation of the reporduce repro, the problem can be reporduced by following procedure: 1. LOOP_CTL_ADD, create a request_queue q1, blk_mq_debugfs_register() will create the dir. 2. LOOP_CTL_REMOVE, blk_release_queue() will add q1 to release queue. 3. LOOP_CTL_ADD, create another request_queue q2,blk_mq_debugfs_register() will fail because the dir aready exist. 4. BLKTRACESETUP, create two files(msg and dropped) inside the dir. 5. call __blk_release_queue() for q1, debugfs_remove_recursive() will delete the files created in step 4. 6. LOOP_CTL_REMOVE, blk_release_queue() will add q2 to release queue. And when __blk_release_queue() is called for q2, blk_trace_shutdown() will try to release the two files created in step 4, wich are aready released in step 5. thread1 |kworker |thread2 ----------------------- | ------------------------ | -------------------- loop_control_ioctl | | loop_add | | blk_mq_debugfs_register| | debugfs_create_dir | | loop_control_ioctl | | loop_remove | | blk_release_queue | | schedule_work | | | |loop_control_ioctl | | loop_add | | ... | |blk_trace_ioctl | | __blk_trace_setup | | debugfs_create_file |__blk_release_queue | | blk_mq_debugfs_unregister| | debugfs_remove_recursive| | |loop_control_ioctl | | loop_remove | | ... |__blk_release_queue | | blk_trace_shutdown | | debugfs_remove | commit dc9edc44de6c ("block: Fix a blk_exit_rl() regression") pushed the final release of request_queue to a workqueue, so, when loop_add() is called again(step 3), __blk_release_queue() might not been called yet, which causes the problem. Fix the problem by renaming 'q->debugfs_dir' or 'q->blk_trace->dir' in blk_unregister_queue() if they exist. [1] https://syzkaller.appspot.com/bug?extid=903b72a010ad6b7a40f2 References: CVE-2019-19770 Fixes: commit dc9edc44de6c ("block: Fix a blk_exit_rl() regression") Reported-by: syzbot Signed-off-by: yu kuai Reviewed-by: Jason Yan Signed-off-by: Yang Yingliang Signed-off-by: Ywenrui --- block/blk-sysfs.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c index 8286640d4d66..d249d7f45875 100644 --- a/block/blk-sysfs.c +++ b/block/blk-sysfs.c @@ -11,6 +11,7 @@ #include #include #include +#include #include "blk.h" #include "blk-mq.h" @@ -958,6 +959,48 @@ int blk_register_queue(struct gendisk *disk) } EXPORT_SYMBOL_GPL(blk_register_queue); +#ifdef CONFIG_DEBUG_FS +/* + * blk_prepare_release_queue - rename q->debugfs_dir and q->blk_trace->dir + * @q: request_queue of which the dir to be renamed belong to. + * + * Because the final release of request_queue is in a workqueue, the + * cleanup might not been finished yet while the same device start to + * create. It's not correct if q->debugfs_dir still exist while trying + * to create a new one. + */ +static void blk_prepare_release_queue(struct request_queue *q) +{ + struct dentry *new = NULL; + struct dentry **old = NULL; + char name[DNAME_INLINE_LEN]; + int i = 0; + +#ifdef CONFIG_BLK_DEBUG_FS + if (!IS_ERR_OR_NULL(q->debugfs_dir)) + old = &q->debugfs_dir; +#endif +#ifdef CONFIG_BLK_DEV_IO_TRACE + /* q->debugfs_dir and q->blk_trace->dir can't both exist */ + if (q->blk_trace && !IS_ERR_OR_NULL(q->blk_trace->dir)) + old = &q->blk_trace->dir; +#endif + if (old == NULL) + return; +#define MAX_ATTEMPT 1024 + while (new == NULL && i < MAX_ATTEMPT) { + sprintf(name, "ready_to_remove_%s_%d", + kobject_name(q->kobj.parent), i++); + new = debugfs_rename(blk_debugfs_root, *old, + blk_debugfs_root, name); + } + if (new) + *old = new; +} +#else +#define blk_prepare_release_queue(q) do { } while (0) +#endif + /** * blk_unregister_queue - counterpart of blk_register_queue() * @disk: Disk of which the request queue should be unregistered from sysfs. @@ -982,6 +1025,7 @@ void blk_unregister_queue(struct gendisk *disk) * concurrent elv_iosched_store() calls. */ mutex_lock(&q->sysfs_lock); + blk_prepare_release_queue(q); blk_queue_flag_clear(QUEUE_FLAG_REGISTERED, q); -- Gitee From 82aa930cf3af1fad4b02479bf907512621930112 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AD=94=E8=8A=9D=E6=9D=83?= Date: Mon, 4 Jul 2022 16:01:32 +0800 Subject: [PATCH 03/26] =?UTF-8?q?=E5=90=8C=E6=AD=A5OAT.xml=20Signed-off-by?= =?UTF-8?q?:Kong=20Zhiquan=20---------------------?= =?UTF-8?q?-----------------------------?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- OAT.xml | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 OAT.xml diff --git a/OAT.xml b/OAT.xml new file mode 100644 index 000000000000..79a970f3b533 --- /dev/null +++ b/OAT.xml @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file -- Gitee From 88284ece2e0ada656d6f8aa605e01cddbdfad16a Mon Sep 17 00:00:00 2001 From: Mathy Vanhoef Date: Mon, 7 Jun 2021 22:38:56 +0800 Subject: [PATCH 04/26] cfg80211: mitigate A-MSDU aggregation attacks Signed-off-by:Kong zhiquan --------------------------------------------------- commit 2b8a1fee3488c602aca8bea004a087e60806a5cf upstream. Mitigate A-MSDU injection attacks (CVE-2020-24588) by detecting if the destination address of a subframe equals an RFC1042 (i.e., LLC/SNAP) header, and if so dropping the complete A-MSDU frame. This mitigates known attacks, although new (unknown) aggregation-based attacks may remain possible. This defense works because in A-MSDU aggregation injection attacks, a normal encrypted Wi-Fi frame is turned into an A-MSDU frame. This means the first 6 bytes of the first A-MSDU subframe correspond to an RFC1042 header. In other words, the destination MAC address of the first A-MSDU subframe contains the start of an RFC1042 header during an aggregation attack. We can detect this and thereby prevent this specific attack. For details, see Section 7.2 of "Fragment and Forge: Breaking Wi-Fi Through Frame Aggregation and Fragmentation". Note that for kernel 4.9 and above this patch depends on "mac80211: properly handle A-MSDUs that start with a rfc1042 header". Otherwise this patch has no impact and attacks will remain possible. Cc: stable@vger.kernel.org Signed-off-by: Mathy Vanhoef Link: https://lore.kernel.org/r/20210511200110.25d93176ddaf.I9e265b597f2cd23eb44573f35b625947b386a9de@changeid Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Yang Yingliang --- net/wireless/util.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/wireless/util.c b/net/wireless/util.c index 1a878b84cbd0..1b3e2d37cd57 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -652,6 +652,9 @@ void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list, remaining = skb->len - offset; if (subframe_len > remaining) goto purge; + /* mitigate A-MSDU aggregation injection attacks */ + if (ether_addr_equal(eth.h_dest, rfc1042_header)) + goto purge; offset += sizeof(struct ethhdr); last = remaining <= subframe_len + padding; -- Gitee From 834309b4dd7fa3f22e058864365eb87d1856a26a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 7 Jun 2021 22:38:57 +0800 Subject: [PATCH 05/26] mac80211: drop A-MSDUs on old ciphers Signed-off-by:Kong Zhiquan ---------------------------------------------------- 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 Signed-off-by: Greg Kroah-Hartman Signed-off-by: Yang Yingliang --- net/mac80211/rx.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 5e56719f999c..e07f17dd42b9 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -5,7 +5,7 @@ * Copyright 2007-2010 Johannes Berg * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright(c) 2015 - 2017 Intel Deutschland GmbH - * Copyright (C) 2018 Intel Corporation + * Copyright (C) 2018-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 @@ -2607,6 +2607,23 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx) if (is_multicast_ether_addr(hdr->addr1)) 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; + } + } + return __ieee80211_rx_h_amsdu(rx, 0); } -- Gitee From 516d09f5fbdd2dfd0f9abb38b0ca5e26012823a1 Mon Sep 17 00:00:00 2001 From: Mathy Vanhoef Date: Mon, 7 Jun 2021 22:38:54 +0800 Subject: [PATCH 06/26] mac80211: prevent mixed key and fragment cache attacks Signed-off-by: Kong Zhiquan ----------------------------------------------------- commit 94034c40ab4a3fcf581fbc7f8fdf4e29943c4a24 upstream. Simultaneously prevent mixed key attacks (CVE-2020-24587) and fragment cache attacks (CVE-2020-24586). This is accomplished by assigning a unique color to every key (per interface) and using this to track which key was used to decrypt a fragment. When reassembling frames, it is now checked whether all fragments were decrypted using the same key. To assure that fragment cache attacks are also prevented, the ID that is assigned to keys is unique even over (re)associations and (re)connects. This means fragments separated by a (re)association or (re)connect will not be reassembled. Because mac80211 now also prevents the reassembly of mixed encrypted and plaintext fragments, all cache attacks are prevented. Cc: stable@vger.kernel.org Signed-off-by: Mathy Vanhoef Link: https://lore.kernel.org/r/20210511200110.3f8290e59823.I622a67769ed39257327a362cfc09c812320eb979@changeid Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Yang Yingliang --- net/mac80211/ieee80211_i.h | 1 + net/mac80211/key.c | 7 +++++++ net/mac80211/key.h | 2 ++ net/mac80211/rx.c | 6 ++++++ 4 files changed, 16 insertions(+) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index a879d8071712..d26fc59e8c47 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -100,6 +100,7 @@ struct ieee80211_fragment_entry { 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; }; diff --git a/net/mac80211/key.c b/net/mac80211/key.c index f20bb39f492d..6775d6cb7d3d 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -653,6 +653,7 @@ int ieee80211_key_link(struct ieee80211_key *key, struct ieee80211_sub_if_data *sdata, struct sta_info *sta) { + static atomic_t key_color = ATOMIC_INIT(0); struct ieee80211_local *local = sdata->local; struct ieee80211_key *old_key; int idx = key->conf.keyidx; @@ -688,6 +689,12 @@ int ieee80211_key_link(struct ieee80211_key *key, key->sdata = sdata; key->sta = sta; + /* + * Assign a unique ID to every key so we can easily prevent mixed + * key and fragment cache attacks. + */ + key->color = atomic_inc_return(&key_color); + increment_tailroom_need_count(sdata); ieee80211_key_replace(sdata, sta, pairwise, old_key, key); diff --git a/net/mac80211/key.h b/net/mac80211/key.h index ebdb80b85dc3..d8e187bcb751 100644 --- a/net/mac80211/key.h +++ b/net/mac80211/key.h @@ -127,6 +127,8 @@ struct ieee80211_key { } debugfs; #endif + unsigned int color; + /* * key config, must be last because it contains key * material as variable length member diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index e07f17dd42b9..221acd2f086f 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2134,6 +2134,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) * 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); @@ -2175,6 +2176,11 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) rx->key->conf.cipher != WLAN_CIPHER_SUITE_GCMP && rx->key->conf.cipher != WLAN_CIPHER_SUITE_GCMP_256)) 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]++; -- Gitee From 3c322f660108ca93dc4fa7bddcaf2d6cbda9c898 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 7 Jun 2021 22:38:58 +0800 Subject: [PATCH 07/26] mac80211: add fragment cache to sta_info Signed-off-by: Kong Zhiquan ---------------------------------------------------- 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 Signed-off-by: Greg Kroah-Hartman Signed-off-by: Yang Yingliang --- net/mac80211/ieee80211_i.h | 26 ++++-------------------- net/mac80211/iface.c | 11 +++------- net/mac80211/rx.c | 41 ++++++++++++++++++++++++++++---------- net/mac80211/sta_info.c | 6 +++++- net/mac80211/sta_info.h | 31 ++++++++++++++++++++++++++++ 5 files changed, 73 insertions(+), 42 deletions(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index d26fc59e8c47..32a5bf40d91b 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -53,12 +53,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 @@ -91,19 +85,6 @@ extern const u8 ieee80211_ac_to_qos_mask[IEEE80211_NUM_ACS]; #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; @@ -885,9 +866,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; @@ -2204,4 +2183,7 @@ extern const struct ethtool_ops ieee80211_ethtool_ops; #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 */ diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 152d4365f961..080f6ff98ce4 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -7,7 +7,7 @@ * Copyright 2008, Johannes Berg * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright (c) 2016 Intel Deutschland GmbH - * Copyright (C) 2018 Intel Corporation + * Copyright (C) 2018-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 @@ -1111,16 +1111,12 @@ static void ieee80211_set_multicast_list(struct net_device *dev) */ 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); @@ -1826,8 +1822,7 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, 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); diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 221acd2f086f..623597408f23 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2009,19 +2009,34 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) 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; @@ -2036,14 +2051,14 @@ ieee80211_reassemble_add(struct ieee80211_sub_if_data *sdata, } 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; @@ -2051,7 +2066,7 @@ ieee80211_reassemble_find(struct ieee80211_sub_if_data *sdata, 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) @@ -2081,6 +2096,7 @@ ieee80211_reassemble_find(struct ieee80211_sub_if_data *sdata, 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; @@ -2102,6 +2118,9 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) goto out_no_led; } + if (rx->sta) + cache = &rx->sta->frags; + if (likely(!ieee80211_has_morefrags(fc) && frag == 0)) goto out; @@ -2120,7 +2139,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) 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 (rx->key && (rx->key->conf.cipher == WLAN_CIPHER_SUITE_CCMP || @@ -2153,7 +2172,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) /* 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); diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 9968b8a976f1..5c345853940f 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -3,7 +3,7 @@ * Copyright 2006-2007 Jiri Benc * 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 * * 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 @@ -351,6 +351,8 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, u64_stats_init(&sta->rx_stats.syncp); + ieee80211_init_frag_cache(&sta->frags); + sta->sta_state = IEEE80211_STA_NONE; /* Mark TID as unreserved */ @@ -1020,6 +1022,8 @@ static void __sta_info_destroy_part2(struct sta_info *sta) rate_control_remove_sta_debugfs(sta); ieee80211_sta_debugfs_remove(sta); + ieee80211_destroy_frag_cache(&sta->frags); + cleanup_single_sta(sta); } diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 9a04327d71d1..b6e37af56146 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -2,6 +2,7 @@ * Copyright 2002-2005, Devicescape Software, Inc. * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright(c) 2015-2017 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 @@ -411,6 +412,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 @@ -482,6 +510,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 */ @@ -583,6 +612,8 @@ struct sta_info { struct cfg80211_chan_def tdls_chandef; + struct ieee80211_fragment_cache frags; + /* keep last! */ struct ieee80211_sta sta; }; -- Gitee From 3f85259d41202db68b2c71865b9172a1550ac3f8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 7 Jun 2021 22:39:00 +0800 Subject: [PATCH 08/26] mac80211: prevent attacks on TKIP/WEP as well Signed-off-by:Kong Zhiquan --------------------------------------------------- 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 Signed-off-by: Greg Kroah-Hartman Signed-off-by: Yang Yingliang --- net/mac80211/rx.c | 12 ++++++++++++ net/mac80211/sta_info.h | 3 ++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 623597408f23..46a75cc95663 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2153,6 +2153,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) * 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], @@ -2165,6 +2166,9 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) 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; } @@ -2211,6 +2215,14 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) 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)); diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index b6e37af56146..c33bc5fc0f2d 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -429,7 +429,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; }; -- Gitee From 3793d4b1584b97a65a414c38aabddc83399a68bc Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Mon, 7 Jun 2021 22:39:02 +0800 Subject: [PATCH 09/26] mac80211: extend protection against mixed key and fragment cache attacks Signed-off-by: Kong Zhiquan --------------------------------------------------- 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 Signed-off-by: Jouni Malinen Link: https://lore.kernel.org/r/20210511200110.037aa5ca0390.I7bb888e2965a0db02a67075fcb5deb50eb7408aa@changeid Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman Signed-off-by: Yang Yingliang --- net/mac80211/rx.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 46a75cc95663..4b17273eb6b4 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2103,6 +2103,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) 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; @@ -2166,7 +2167,9 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) 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; } @@ -2216,13 +2219,19 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) 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)); -- Gitee From 87bd2b9f170d8a21564315c8c4e518b4ea850deb Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Fri, 15 Oct 2021 12:03:49 +0800 Subject: [PATCH 10/26] ath10k: add struct for high latency PN replay protection Signed-off-by:Kong Zhiquan --------------------------------------------------- mainline inclusion from mainline-v5.3-rc1 commit e1bddde9737ac4687ca6e2fe6c95f67a9bec353b category: bugfix bugzilla: 181870 CVE: CVE-2020-26145 ------------------------------------------------- Add the struct for PN replay protection and fragment packet handler. Also fix the bitmask of HTT_RX_DESC_HL_INFO_MCAST_BCAST to match what's currently used by SDIO firmware. The defines are not used yet so it's safe to modify them. Remove the conflicting HTT_RX_DESC_HL_INFO_FRAGMENT as it's not either used in ath10k. Tested on QCA6174 SDIO with firmware WLAN.RMH.4.4.1-00007-QCARMSWP-1. Signed-off-by: Wen Gong Signed-off-by: Kalle Valo conflict: drivers/net/wireless/ath/ath10k/htt.h Signed-off-by: Wang Hai Reviewed-by: Yue Haibing Signed-off-by: Yang Yingliang --- drivers/net/wireless/ath/ath10k/core.h | 8 ++++++ drivers/net/wireless/ath/ath10k/htt.h | 40 ++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 5c9fc4070fd2..3cd49d29ac23 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -414,6 +414,14 @@ struct ath10k_peer { /* protected by ar->data_lock */ struct ieee80211_key_conf *keys[WMI_MAX_KEY_INDEX + 1]; + union htt_rx_pn_t tids_last_pn[ATH10K_TXRX_NUM_EXT_TIDS]; + bool tids_last_pn_valid[ATH10K_TXRX_NUM_EXT_TIDS]; + union htt_rx_pn_t frag_tids_last_pn[ATH10K_TXRX_NUM_EXT_TIDS]; + u32 frag_tids_seq[ATH10K_TXRX_NUM_EXT_TIDS]; + struct { + enum htt_security_types sec_type; + int pn_len; + } rx_pn[ATH10K_HTT_TXRX_PEER_SECURITY_MAX]; }; struct ath10k_txq { diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index 5d3ff80f3a1f..c1ff938d5341 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -719,6 +719,20 @@ struct htt_rx_indication { struct htt_rx_indication_mpdu_range mpdu_ranges[0]; } __packed; +struct htt_hl_rx_desc { + __le32 info; + __le32 pn_31_0; + union { + struct { + __le16 pn_47_32; + __le16 pn_63_48; + } pn16; + __le32 pn_63_32; + } u0; + __le32 pn_95_64; + __le32 pn_127_96; +} __packed; + static inline struct htt_rx_indication_mpdu_range * htt_rx_ind_get_mpdu_ranges(struct htt_rx_indication *rx_ind) { @@ -764,6 +778,21 @@ struct htt_rx_peer_unmap { __le16 peer_id; } __packed; +enum htt_txrx_sec_cast_type { + HTT_TXRX_SEC_MCAST = 0, + HTT_TXRX_SEC_UCAST +}; + +enum htt_rx_pn_check_type { + HTT_RX_NON_PN_CHECK = 0, + HTT_RX_PN_CHECK +}; + +enum htt_rx_tkip_demic_type { + HTT_RX_NON_TKIP_MIC = 0, + HTT_RX_TKIP_MIC +}; + enum htt_security_types { HTT_SECURITY_NONE, HTT_SECURITY_WEP128, @@ -777,6 +806,9 @@ enum htt_security_types { HTT_NUM_SECURITY_TYPES /* keep this last! */ }; +#define ATH10K_HTT_TXRX_PEER_SECURITY_MAX 2 +#define ATH10K_TXRX_NUM_EXT_TIDS 19 + enum htt_security_flags { #define HTT_SECURITY_TYPE_MASK 0x7F #define HTT_SECURITY_TYPE_LSB 0 @@ -887,6 +919,11 @@ struct htt_rx_fragment_indication { u8 fw_msdu_rx_desc[0]; } __packed; +#define ATH10K_IEEE80211_EXTIV BIT(5) +#define ATH10K_IEEE80211_TKIP_MICLEN 8 /* trailing MIC */ + +#define HTT_RX_FRAG_IND_INFO0_HEADER_LEN 16 + #define HTT_RX_FRAG_IND_INFO0_EXT_TID_MASK 0x1F #define HTT_RX_FRAG_IND_INFO0_EXT_TID_LSB 0 #define HTT_RX_FRAG_IND_INFO0_FLUSH_VALID_MASK 0x20 @@ -1994,6 +2031,9 @@ struct htt_rx_desc { u8 msdu_payload[0]; }; +#define HTT_RX_DESC_HL_INFO_MCAST_BCAST_MASK 0x00010000 +#define HTT_RX_DESC_HL_INFO_MCAST_BCAST_LSB 16 + #define HTT_RX_DESC_ALIGN 8 #define HTT_MAC_ADDR_LEN 6 -- Gitee From 48e0867bc92c33c5aa37397364d424850000e896 Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Fri, 15 Oct 2021 12:03:50 +0800 Subject: [PATCH 11/26] ath10k: add CCMP PN replay protection for fragmented frames for PCIe Signed-off-by: Kong Zhiquan --------------------------------------------------- mainline inclusion from mainline-v5.13-rc4 commit a1166b2653db2f3de7338b9fb8a0f6e924b904ee category: bugfix bugzilla: 181870 CVE: CVE-2020-26145 ------------------------------------------------- PN replay check for not fragmented frames is finished in the firmware, but this was not done for fragmented frames when ath10k is used with QCA6174/QCA6377 PCIe. mac80211 has the function ieee80211_rx_h_defragment() for PN replay check for fragmented frames, but this does not get checked with QCA6174 due to the ieee80211_has_protected() condition not matching the cleared Protected bit case. Validate the PN of received fragmented frames within ath10k when CCMP is used and drop the fragment if the PN is not correct (incremented by exactly one from the previous fragment). This applies only for QCA6174/QCA6377 PCIe. Tested-on: QCA6174 hw3.2 PCI WLAN.RM.4.4.1-00110-QCARMSWP-1 Cc: stable@vger.kernel.org Signed-off-by: Wen Gong Signed-off-by: Jouni Malinen Link: https://lore.kernel.org/r/20210511200110.9ba2664866a4.I756e47b67e210dba69966d989c4711ffc02dc6bc@changeid Signed-off-by: Johannes Berg Signed-off-by: Wang Hai Reviewed-by: Yue Haibing Signed-off-by: Yang Yingliang --- drivers/net/wireless/ath/ath10k/htt.h | 1 + drivers/net/wireless/ath/ath10k/htt_rx.c | 99 +++++++++++++++++++++++- 2 files changed, 96 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index c1ff938d5341..95ca591abec7 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -808,6 +808,7 @@ enum htt_security_types { #define ATH10K_HTT_TXRX_PEER_SECURITY_MAX 2 #define ATH10K_TXRX_NUM_EXT_TIDS 19 +#define ATH10K_TXRX_NON_QOS_TID 16 enum htt_security_flags { #define HTT_SECURITY_TYPE_MASK 0x7F diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 68cda1564c77..3101fb00e262 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -1524,16 +1524,87 @@ static void ath10k_htt_rx_h_csum_offload(struct sk_buff *msdu) msdu->ip_summed = ath10k_htt_rx_get_csum_state(msdu); } +static u64 ath10k_htt_rx_h_get_pn(struct ath10k *ar, struct sk_buff *skb, + u16 offset, + enum htt_rx_mpdu_encrypt_type enctype) +{ + struct ieee80211_hdr *hdr; + u64 pn = 0; + u8 *ehdr; + + hdr = (struct ieee80211_hdr *)(skb->data + offset); + ehdr = skb->data + offset + ieee80211_hdrlen(hdr->frame_control); + + if (enctype == HTT_RX_MPDU_ENCRYPT_AES_CCM_WPA2) { + pn = ehdr[0]; + pn |= (u64)ehdr[1] << 8; + pn |= (u64)ehdr[4] << 16; + pn |= (u64)ehdr[5] << 24; + pn |= (u64)ehdr[6] << 32; + pn |= (u64)ehdr[7] << 40; + } + return pn; +} + +static bool ath10k_htt_rx_h_frag_pn_check(struct ath10k *ar, + struct sk_buff *skb, + u16 peer_id, + u16 offset, + enum htt_rx_mpdu_encrypt_type enctype) +{ + struct ath10k_peer *peer; + union htt_rx_pn_t *last_pn, new_pn = {0}; + struct ieee80211_hdr *hdr; + bool more_frags; + u8 tid, frag_number; + u32 seq; + + peer = ath10k_peer_find_by_id(ar, peer_id); + if (!peer) { + ath10k_dbg(ar, ATH10K_DBG_HTT, "invalid peer for frag pn check\n"); + return false; + } + + hdr = (struct ieee80211_hdr *)(skb->data + offset); + if (ieee80211_is_data_qos(hdr->frame_control)) + tid = ieee80211_get_tid(hdr); + else + tid = ATH10K_TXRX_NON_QOS_TID; + + last_pn = &peer->frag_tids_last_pn[tid]; + new_pn.pn48 = ath10k_htt_rx_h_get_pn(ar, skb, offset, enctype); + more_frags = ieee80211_has_morefrags(hdr->frame_control); + frag_number = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG; + seq = (__le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; + + if (frag_number == 0) { + last_pn->pn48 = new_pn.pn48; + peer->frag_tids_seq[tid] = seq; + } else { + if (seq != peer->frag_tids_seq[tid]) + return false; + + if (new_pn.pn48 != last_pn->pn48 + 1) + return false; + + last_pn->pn48 = new_pn.pn48; + } + + return true; +} + static void ath10k_htt_rx_h_mpdu(struct ath10k *ar, struct sk_buff_head *amsdu, struct ieee80211_rx_status *status, bool fill_crypt_header, u8 *rx_hdr, - enum ath10k_pkt_rx_err *err) + enum ath10k_pkt_rx_err *err, + u16 peer_id, + bool frag) { struct sk_buff *first; struct sk_buff *last; - struct sk_buff *msdu; + struct sk_buff *msdu, *temp; struct htt_rx_desc *rxd; struct ieee80211_hdr *hdr; enum htt_rx_mpdu_encrypt_type enctype; @@ -1546,6 +1617,7 @@ static void ath10k_htt_rx_h_mpdu(struct ath10k *ar, bool is_decrypted; bool is_mgmt; u32 attention; + bool frag_pn_check = true; if (skb_queue_empty(amsdu)) return; @@ -1644,6 +1716,24 @@ static void ath10k_htt_rx_h_mpdu(struct ath10k *ar, } skb_queue_walk(amsdu, msdu) { + if (frag && !fill_crypt_header && is_decrypted && + enctype == HTT_RX_MPDU_ENCRYPT_AES_CCM_WPA2) + frag_pn_check = ath10k_htt_rx_h_frag_pn_check(ar, + msdu, + peer_id, + 0, + enctype); + + if (!frag_pn_check) { + /* Discard the fragment with invalid PN */ + temp = msdu->prev; + __skb_unlink(msdu, amsdu); + dev_kfree_skb_any(msdu); + msdu = temp; + frag_pn_check = true; + continue; + } + ath10k_htt_rx_h_csum_offload(msdu); ath10k_htt_rx_h_undecap(ar, msdu, status, first_hdr, enctype, is_decrypted); @@ -1849,7 +1939,8 @@ static int ath10k_htt_rx_handle_amsdu(struct ath10k_htt *htt) ath10k_htt_rx_h_unchain(ar, &amsdu, &drop_cnt, &unchain_cnt); ath10k_htt_rx_h_filter(ar, &amsdu, rx_status, &drop_cnt_filter); - ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status, true, first_hdr, &err); + ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status, true, first_hdr, &err, 0, + false); msdus_to_queue = skb_queue_len(&amsdu); ath10k_htt_rx_h_enqueue(ar, &amsdu, rx_status); @@ -2200,7 +2291,7 @@ static int ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb) ath10k_htt_rx_h_ppdu(ar, &amsdu, status, vdev_id); ath10k_htt_rx_h_filter(ar, &amsdu, status, NULL); ath10k_htt_rx_h_mpdu(ar, &amsdu, status, false, NULL, - NULL); + NULL, peer_id, frag); ath10k_htt_rx_h_enqueue(ar, &amsdu, status); break; case -EAGAIN: -- Gitee From fb797409a0b173b2a0b6e1994dfb89a35a044a56 Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Fri, 15 Oct 2021 12:03:51 +0800 Subject: [PATCH 12/26] ath10k: drop fragments with multicast DA for PCIe Signed-off-by:Kong Zhiquan ---------------------------------------------------- mainline inclusion from mainline-v5.13-rc4 commit 65c415a144ad8132b6a6d97d4a1919ffc728e2d1 category: bugfix bugzilla: 181870 CVE: CVE-2020-26145 ------------------------------------------------- Fragmentation is not used with multicast frames. Discard unexpected fragments with multicast DA. This fixes CVE-2020-26145. Tested-on: QCA6174 hw3.2 PCI WLAN.RM.4.4.1-00110-QCARMSWP-1 Cc: stable@vger.kernel.org Signed-off-by: Wen Gong Signed-off-by: Jouni Malinen Link: https://lore.kernel.org/r/20210511200110.5a0bd289bda8.Idd6ebea20038fb1cfee6de924aa595e5647c9eae@changeid Signed-off-by: Johannes Berg Signed-off-by: Wang Hai Reviewed-by: Yue Haibing Signed-off-by: Yang Yingliang --- drivers/net/wireless/ath/ath10k/htt_rx.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 3101fb00e262..435b9aacbfc3 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -1546,6 +1546,16 @@ static u64 ath10k_htt_rx_h_get_pn(struct ath10k *ar, struct sk_buff *skb, return pn; } +static bool ath10k_htt_rx_h_frag_multicast_check(struct ath10k *ar, + struct sk_buff *skb, + u16 offset) +{ + struct ieee80211_hdr *hdr; + + hdr = (struct ieee80211_hdr *)(skb->data + offset); + return !is_multicast_ether_addr(hdr->addr1); +} + static bool ath10k_htt_rx_h_frag_pn_check(struct ath10k *ar, struct sk_buff *skb, u16 peer_id, @@ -1617,7 +1627,7 @@ static void ath10k_htt_rx_h_mpdu(struct ath10k *ar, bool is_decrypted; bool is_mgmt; u32 attention; - bool frag_pn_check = true; + bool frag_pn_check = true, multicast_check = true; if (skb_queue_empty(amsdu)) return; @@ -1724,13 +1734,20 @@ static void ath10k_htt_rx_h_mpdu(struct ath10k *ar, 0, enctype); - if (!frag_pn_check) { - /* Discard the fragment with invalid PN */ + if (frag) + multicast_check = ath10k_htt_rx_h_frag_multicast_check(ar, + msdu, + 0); + + if (!frag_pn_check || !multicast_check) { + /* Discard the fragment with invalid PN or multicast DA + */ temp = msdu->prev; __skb_unlink(msdu, amsdu); dev_kfree_skb_any(msdu); msdu = temp; frag_pn_check = true; + multicast_check = true; continue; } -- Gitee From d91a299e0eabd1c8babc8647bbe75874f3e27b8b Mon Sep 17 00:00:00 2001 From: "Lin, Zhenpeng" Date: Mon, 27 Sep 2021 11:09:43 +0800 Subject: [PATCH 13/26] dccp: don't duplicate ccid when cloning dccp sock commit:11bed05eebeb0f2425ca27354d82f91c05ffb101 CVE:CVE-2020-16119 Signed-off-by: wanxiaoqing ----------------------------------------------------------- stable inclusion from linux-4.19.207 commit dfec82f3e5b8bd93ab65b7417a64886ec8c42f14 -------------------------------- commit d9ea761fdd197351890418acd462c51f241014a7 upstream. Commit 2677d2067731 ("dccp: don't free ccid2_hc_tx_sock ...") fixed a UAF but reintroduced CVE-2017-6074. When the sock is cloned, two dccps_hc_tx_ccid will reference to the same ccid. So one can free the ccid object twice from two socks after cloning. This issue was found by "Hadar Manor" as well and assigned with CVE-2020-16119, which was fixed in Ubuntu's kernel. So here I port the patch from Ubuntu to fix it. The patch prevents cloned socks from referencing the same ccid. Fixes: 2677d2067731410 ("dccp: don't free ccid2_hc_tx_sock ...") Signed-off-by: Zhenpeng Lin Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Yang Yingliang Signed-off-by: wanxiaoqing --- net/dccp/minisocks.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/dccp/minisocks.c b/net/dccp/minisocks.c index ba6fc3c1186b..e91838a7b849 100644 --- a/net/dccp/minisocks.c +++ b/net/dccp/minisocks.c @@ -98,6 +98,8 @@ struct sock *dccp_create_openreq_child(const struct sock *sk, newdp->dccps_role = DCCP_ROLE_SERVER; newdp->dccps_hc_rx_ackvec = NULL; newdp->dccps_service_list = NULL; + newdp->dccps_hc_rx_ccid = NULL; + newdp->dccps_hc_tx_ccid = NULL; newdp->dccps_service = dreq->dreq_service; newdp->dccps_timestamp_echo = dreq->dreq_timestamp_echo; newdp->dccps_timestamp_time = dreq->dreq_timestamp_time; -- Gitee From 7d6764e5f7a4189e5958c9c59c10ef9b5ea0b43e Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Fri, 30 Jul 2021 11:26:53 +0800 Subject: [PATCH 14/26] KVM: do not allow mapping valid but non-reference-counted pages commit:69ce6fd026905b8fa0339aa40ef423baac1c50e6 CVE:CVE-2021-22543 Signed-off-by: wanxiaoqing ----------------------------------------------------------- stable inclusion from linux-4.19.199 commit 117777467bc015f0dc5fc079eeba0fa80c965149 -------------------------------- commit f8be156be163a052a067306417cd0ff679068c97 upstream. It's possible to create a region which maps valid but non-refcounted pages (e.g., tail pages of non-compound higher order allocations). These host pages can then be returned by gfn_to_page, gfn_to_pfn, etc., family of APIs, which take a reference to the page, which takes it from 0 to 1. When the reference is dropped, this will free the page incorrectly. Fix this by only taking a reference on valid pages if it was non-zero, which indicates it is participating in normal refcounting (and can be released with put_page). This addresses CVE-2021-22543. Signed-off-by: Nicholas Piggin Tested-by: Paolo Bonzini Cc: stable@vger.kernel.org Signed-off-by: Paolo Bonzini Signed-off-by: Ovidiu Panait Signed-off-by: Greg Kroah-Hartman Signed-off-by: Yang Yingliang Signed-off-by: wanxiaoqing --- virt/kvm/kvm_main.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 9312c7e750ed..14ed735ca292 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -1490,6 +1490,13 @@ static bool vma_is_valid(struct vm_area_struct *vma, bool write_fault) return true; } +static int kvm_try_get_pfn(kvm_pfn_t pfn) +{ + if (kvm_is_reserved_pfn(pfn)) + return 1; + return get_page_unless_zero(pfn_to_page(pfn)); +} + static int hva_to_pfn_remapped(struct vm_area_struct *vma, unsigned long addr, bool *async, bool write_fault, bool *writable, @@ -1532,11 +1539,19 @@ static int hva_to_pfn_remapped(struct vm_area_struct *vma, * Whoever called remap_pfn_range is also going to call e.g. * unmap_mapping_range before the underlying pages are freed, * causing a call to our MMU notifier. + * + * Certain IO or PFNMAP mappings can be backed with valid + * struct pages, but be allocated without refcounting e.g., + * tail pages of non-compound higher order allocations, which + * would then underflow the refcount when the caller does the + * required put_page. Don't allow those pages here. */ - kvm_get_pfn(pfn); + if (!kvm_try_get_pfn(pfn)) + r = -EFAULT; *p_pfn = pfn; - return 0; + + return r; } /* -- Gitee From c02c085208847c2f492081523dc5d14108bffd6a Mon Sep 17 00:00:00 2001 From: Jon Maloy Date: Thu, 17 Feb 2022 14:59:04 +0800 Subject: [PATCH 15/26] tipc: improve size validations for received domain records commit:85409aaeb164ad9c03308780e28f0c7548464b37 CVE:CVE-2022-0435 Signed-off-by: wanxiaoqing ----------------------------------------------------------- mainline inclusion from mainline-v5.17-rc4 commit 9aa422ad326634b76309e8ff342c246800621216 category: bugfix issue: #I4U9Y8 CVE: CVE-2022-0435 Reference: https://github.com/torvalds/linux/commit/9aa422ad326634b76309e8ff342c246800621216 Signed-off-by: Yu Changchun -------------------------------- The function tipc_mon_rcv() allows a node to receive and process domain_record structs from peer nodes to track their views of the network topology. This patch verifies that the number of members in a received domain record does not exceed the limit defined by MAX_MON_DOMAIN, something that may otherwise lead to a stack overflow. tipc_mon_rcv() is called from the function tipc_link_proto_rcv(), where we are reading a 32 bit message data length field into a uint16. To avert any risk of bit overflow, we add an extra sanity check for this in that function. We cannot see that happen with the current code, but future designers being unaware of this risk, may introduce it by allowing delivery of very large (> 64k) sk buffers from the bearer layer. This potential problem was identified by Eric Dumazet. This fixes CVE-2022-0435 Reported-by: Samuel Page Reported-by: Eric Dumazet Fixes: 35c55c9877f8 ("tipc: add neighbor monitoring framework") Signed-off-by: Jon Maloy Reviewed-by: Xin Long Reviewed-by: Samuel Page Reviewed-by: Eric Dumazet Signed-off-by: Linus Torvalds Signed-off-by: Zhengchao Shao Reviewed-by: Yongjun Wei Reviewed-by: Yue Haibing Signed-off-by: Zheng Zengkai Signed-off-by: Yu Changchun Signed-off-by: wanxiaoqing --- net/tipc/link.c | 8 +++++++- net/tipc/monitor.c | 2 ++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/net/tipc/link.c b/net/tipc/link.c index f756b721f93e..675466ed1cbb 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -1574,13 +1574,16 @@ static int tipc_link_proto_rcv(struct tipc_link *l, struct sk_buff *skb, u16 peers_tol = msg_link_tolerance(hdr); u16 peers_prio = msg_linkprio(hdr); u16 rcv_nxt = l->rcv_nxt; - u16 dlen = msg_data_sz(hdr); + u32 dlen = msg_data_sz(hdr); int mtyp = msg_type(hdr); bool reply = msg_probe(hdr); void *data; char *if_name; int rc = 0; + if (dlen > U16_MAX) + goto exit; + if (tipc_link_is_blocked(l) || !xmitq) goto exit; @@ -1659,6 +1662,9 @@ static int tipc_link_proto_rcv(struct tipc_link *l, struct sk_buff *skb, rc = TIPC_LINK_UP_EVT; break; } + + if (glen > dlen) + break; tipc_mon_rcv(l->net, data, dlen, l->addr, &l->mon_state, l->bearer_id); diff --git a/net/tipc/monitor.c b/net/tipc/monitor.c index 23706ee16607..7b6c1c5c30dc 100644 --- a/net/tipc/monitor.c +++ b/net/tipc/monitor.c @@ -457,6 +457,8 @@ void tipc_mon_rcv(struct net *net, void *data, u16 dlen, u32 addr, state->probing = false; /* Sanity check received domain record */ + if (new_member_cnt > MAX_MON_DOMAIN) + return; if (dlen < dom_rec_len(arrv_dom, 0)) return; if (dlen != dom_rec_len(arrv_dom, new_member_cnt)) -- Gitee From cfb3c426a848214b6743247bc58e92f7f7802b4e Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Wed, 2 Mar 2022 12:19:53 +0800 Subject: [PATCH 16/26] f2fs: fix to do sanity check on inode type during garbage collection commit:90f0ef6bd30b2b1f9d92e11267a2d817e70bc7fe CVE:CVE-2021-44879 Signed-off-by: wanxiaoqing ----------------------------------------------------------- mainline inclusion from mainline-v5.16-rc1 commit 9056d6489f5a41cfbb67f719d2c0ce61ead72d9f category: bugfix issue: #I4U9Y8 CVE: CVE-2021-44879 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=9056d6489f5a41cfbb67f719d2c0ce61ead72d9f Signed-off-by: Yu Changchun -------------------------------- As report by Wenqing Liu in bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=215231 - Overview kernel NULL pointer dereference triggered in folio_mark_dirty() when mount and operate on a crafted f2fs image - Reproduce tested on kernel 5.16-rc3, 5.15.X under root 1. mkdir mnt 2. mount -t f2fs tmp1.img mnt 3. touch tmp 4. cp tmp mnt F2FS-fs (loop0): sanity_check_inode: inode (ino=49) extent info [5942, 4294180864, 4] is incorrect, run fsck to fix F2FS-fs (loop0): f2fs_check_nid_range: out-of-range nid=31340049, run fsck to fix. BUG: kernel NULL pointer dereference, address: 0000000000000000 folio_mark_dirty+0x33/0x50 move_data_page+0x2dd/0x460 [f2fs] do_garbage_collect+0xc18/0x16a0 [f2fs] f2fs_gc+0x1d3/0xd90 [f2fs] f2fs_balance_fs+0x13a/0x570 [f2fs] f2fs_create+0x285/0x840 [f2fs] path_openat+0xe6d/0x1040 do_filp_open+0xc5/0x140 do_sys_openat2+0x23a/0x310 do_sys_open+0x57/0x80 The root cause is for special file: e.g. character, block, fifo or socket file, f2fs doesn't assign address space operations pointer array for mapping->a_ops field, so, in a fuzzed image, SSA table indicates a data block belong to special file, when f2fs tries to migrate that block, it causes NULL pointer access once move_data_page() calls a_ops->set_dirty_page(). Cc: stable@vger.kernel.org Reported-by: Wenqing Liu Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim Signed-off-by: Guo Xuenan Reviewed-by: Xiu Jianfeng Reviewed-by: fang wei Signed-off-by: Zheng Zengkai Signed-off-by: Yu Changchun Signed-off-by: wanxiaoqing --- fs/f2fs/gc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index 700c39ec99f5..f4f7b8feebef 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -953,7 +953,8 @@ static void gc_data_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, if (phase == 3) { inode = f2fs_iget(sb, dni.ino); - if (IS_ERR(inode) || is_bad_inode(inode)) + if (IS_ERR(inode) || is_bad_inode(inode) || + special_file(inode->i_mode)) continue; if (!down_write_trylock( -- Gitee From b982f8117b1267939f33fc968dbf262765b5e73b Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Wed, 2 Mar 2022 12:19:55 +0800 Subject: [PATCH 17/26] f2fs: fix to do sanity check in is_alive() commit:a09d86cc3c9429e870969d2cf67798436ea85e19 CVE:CVE-2021-44879 Signed-off-by: wanxiaoqing ----------------------------------------------------------- mainline inclusion from mainline-v5.16-rc1 commit 77900c45ee5cd5da63bd4d818a41dbdf367e81cd category: bugfix issue: #I4U9Y8 CVE: CVE-2021-44879 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=77900c45ee5cd5da63bd4d818a41dbdf367e81cd Signed-off-by: Yu Changchun -------------------------------- In fuzzed image, SSA table may indicate that a data block belongs to invalid node, which node ID is out-of-range (0, 1, 2 or max_nid), in order to avoid migrating inconsistent data in such corrupted image, let's do sanity check anyway before data block migration. Cc: stable@vger.kernel.org Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim Signed-off-by: Guo Xuenan Reviewed-by: Xiu Jianfeng Reviewed-by: fang wei Signed-off-by: Zheng Zengkai Signed-off-by: Yu Changchun Signed-off-by: wanxiaoqing --- fs/f2fs/gc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index f4f7b8feebef..ca54b8639197 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -589,6 +589,9 @@ static bool is_alive(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, set_sbi_flag(sbi, SBI_NEED_FSCK); } + if (f2fs_check_nid_range(sbi, dni->ino)) + return false; + *nofs = ofs_of_node(node_page); source_blkaddr = datablock_addr(NULL, node_page, ofs_in_node); f2fs_put_page(node_page, 1); -- Gitee From 165abe2a6707c4ee144b4ee782377610b22a3561 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 22 Mar 2022 17:41:47 -0700 Subject: [PATCH 18/26] llc: fix netdevice reference leaks in llc_ui_bind() commit:f8b9df096a0a1a666fb99c4feb72ceab8aefa66a CVE:CVE-2022-28356 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: wanxiaoqing ----------------------------------------------------------- stable inclusion from stable-5.10.109 commit 571df3393f523b59cba87e2f3e80a3a624030f9c category: bugfix issue: #I51A19 CVE: CVE-2022-28356 Signed-off-by: gaochao ------------------------------------------- llc: fix netdevice reference leaks in llc_ui_bind() commit 764f4eb6846f5475f1244767d24d25dd86528a4a upstream. Whenever llc_ui_bind() and/or llc_ui_autobind() took a reference on a netdevice but subsequently fail, they must properly release their reference or risk the infamous message from unregister_netdevice() at device dismantle. unregister_netdevice: waiting for eth0 to become free. Usage count = 3 Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Eric Dumazet Reported-by: 赵子轩 Reported-by: Stoyan Manolov Link: https://lore.kernel.org/r/20220323004147.1990845-1-eric.dumazet@gmail.com Signed-off-by: Jakub Kicinski Signed-off-by: Greg Kroah-Hartman Signed-off-by: wanxiaoqing --- net/llc/af_llc.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c index bcba579e292f..05ef54f3119d 100644 --- a/net/llc/af_llc.c +++ b/net/llc/af_llc.c @@ -303,6 +303,10 @@ static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr) sock_reset_flag(sk, SOCK_ZAPPED); rc = 0; out: + if (rc) { + dev_put(llc->dev); + llc->dev = NULL; + } return rc; } @@ -402,6 +406,10 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen) out_put: llc_sap_put(sap); out: + if (rc) { + dev_put(llc->dev); + llc->dev = NULL; + } release_sock(sk); return rc; } -- Gitee From aac3430ab8c93a8c1e7679c012566870f66a1bc9 Mon Sep 17 00:00:00 2001 From: Yajun Deng Date: Thu, 5 Aug 2021 19:54:34 +0800 Subject: [PATCH 19/26] netdevice: add the case if dev is NULL commit:6e434237404877a3a522729791b96f5cd4528fee CVE:CVE-2022-28356 Signed-off-by: wanxiaoqing ----------------------------------------------------------- stable inclusion from stable-5.10.110 commit ff919a7ad90c361634f0bc5c58120252d87b887a category: bugfix issue: #I51A19 CVE: CVE-2022-28356 Signed-off-by: gaochao ------------------------------------------- netdevice: add the case if dev is NULL commit b37a466837393af72fe8bcb8f1436410f3f173f3 upstream. Add the case if dev is NULL in dev_{put, hold}, so the caller doesn't need to care whether dev is NULL or not. Signed-off-by: Yajun Deng Signed-off-by: David S. Miller Cc: Pavel Machek Signed-off-by: Greg Kroah-Hartman Signed-off-by: wanxiaoqing --- include/linux/netdevice.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 4e14926433ed..774102ad15b9 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -3659,7 +3659,8 @@ void netdev_run_todo(void); */ static inline void dev_put(struct net_device *dev) { - this_cpu_dec(*dev->pcpu_refcnt); + if (dev) + this_cpu_dec(*dev->pcpu_refcnt); } /** @@ -3670,7 +3671,8 @@ static inline void dev_put(struct net_device *dev) */ static inline void dev_hold(struct net_device *dev) { - this_cpu_inc(*dev->pcpu_refcnt); + if (dev) + this_cpu_inc(*dev->pcpu_refcnt); } /* Carrier loss detection, dial on demand. The functions netif_carrier_on -- Gitee From 93e42154bd93a4eca19ad30672add9ca9321ff2f Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 24 Mar 2022 20:58:27 -0700 Subject: [PATCH 20/26] llc: only change llc->dev when bind() succeeds commit:fa4269eba24707e69a50861a89b1dc4ff0b85578 CVE:CVE-2022-28356 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: wanxiaoqing ----------------------------------------------------------- stable inclusion from stable-5.10.109 commit 163960a7de1333514c9352deb7c80c6b9fd9abf2 category: bugfix issue: #I51A19 CVE: CVE-2022-28356 Signed-off-by: gaochao ------------------------------------------- llc: only change llc->dev when bind() succeeds commit 2d327a79ee176930dc72c131a970c891d367c1dc upstream. My latest patch, attempting to fix the refcount leak in a minimal way turned out to add a new bug. Whenever the bind operation fails before we attempt to grab a reference count on a device, we might release the device refcount of a prior successful bind() operation. syzbot was not happy about this [1]. Note to stable teams: Make sure commit b37a46683739 ("netdevice: add the case if dev is NULL") is already present in your trees. [1] general protection fault, probably for non-canonical address 0xdffffc0000000070: 0000 [#1] PREEMPT SMP KASAN KASAN: null-ptr-deref in range [0x0000000000000380-0x0000000000000387] CPU: 1 PID: 3590 Comm: syz-executor361 Tainted: G W 5.17.0-syzkaller-04796-g169e77764adc #0 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 RIP: 0010:llc_ui_connect+0x400/0xcb0 net/llc/af_llc.c:500 Code: 80 3c 02 00 0f 85 fc 07 00 00 4c 8b a5 38 05 00 00 48 b8 00 00 00 00 00 fc ff df 49 8d bc 24 80 03 00 00 48 89 fa 48 c1 ea 03 <80> 3c 02 00 0f 85 a9 07 00 00 49 8b b4 24 80 03 00 00 4c 89 f2 48 RSP: 0018:ffffc900038cfcc0 EFLAGS: 00010202 RAX: dffffc0000000000 RBX: ffff8880756eb600 RCX: 0000000000000000 RDX: 0000000000000070 RSI: ffffc900038cfe3e RDI: 0000000000000380 RBP: ffff888015ee5000 R08: 0000000000000001 R09: ffff888015ee5535 R10: ffffed1002bdcaa6 R11: 0000000000000000 R12: 0000000000000000 R13: ffffc900038cfe37 R14: ffffc900038cfe38 R15: ffff888015ee5012 FS: 0000555555acd300(0000) GS:ffff8880b9d00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000020000280 CR3: 0000000077db6000 CR4: 00000000003506e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: __sys_connect_file+0x155/0x1a0 net/socket.c:1900 __sys_connect+0x161/0x190 net/socket.c:1917 __do_sys_connect net/socket.c:1927 [inline] __se_sys_connect net/socket.c:1924 [inline] __x64_sys_connect+0x6f/0xb0 net/socket.c:1924 do_syscall_x64 arch/x86/entry/common.c:50 [inline] do_syscall_64+0x35/0xb0 arch/x86/entry/common.c:80 entry_SYSCALL_64_after_hwframe+0x44/0xae RIP: 0033:0x7f016acb90b9 Code: 28 c3 e8 2a 14 00 00 66 2e 0f 1f 84 00 00 00 00 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 c0 ff ff ff f7 d8 64 89 01 48 RSP: 002b:00007ffd417947f8 EFLAGS: 00000246 ORIG_RAX: 000000000000002a RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f016acb90b9 RDX: 0000000000000010 RSI: 0000000020000140 RDI: 0000000000000003 RBP: 00007f016ac7d0a0 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000246 R12: 00007f016ac7d130 R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000000 Modules linked in: ---[ end trace 0000000000000000 ]--- RIP: 0010:llc_ui_connect+0x400/0xcb0 net/llc/af_llc.c:500 Fixes: 764f4eb6846f ("llc: fix netdevice reference leaks in llc_ui_bind()") Signed-off-by: Eric Dumazet Reported-by: syzbot Cc: 赵子轩 Cc: Stoyan Manolov Link: https://lore.kernel.org/r/20220325035827.360418-1-eric.dumazet@gmail.com Signed-off-by: Jakub Kicinski Signed-off-by: Greg Kroah-Hartman Signed-off-by: wanxiaoqing --- net/llc/af_llc.c | 57 +++++++++++++++++++++++++++--------------------- 1 file changed, 32 insertions(+), 25 deletions(-) diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c index 05ef54f3119d..966484af60c0 100644 --- a/net/llc/af_llc.c +++ b/net/llc/af_llc.c @@ -268,6 +268,7 @@ static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr) { struct sock *sk = sock->sk; struct llc_sock *llc = llc_sk(sk); + struct net_device *dev = NULL; struct llc_sap *sap; int rc = -EINVAL; @@ -279,14 +280,14 @@ static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr) goto out; rc = -ENODEV; if (sk->sk_bound_dev_if) { - llc->dev = dev_get_by_index(&init_net, sk->sk_bound_dev_if); - if (llc->dev && addr->sllc_arphrd != llc->dev->type) { - dev_put(llc->dev); - llc->dev = NULL; + dev = dev_get_by_index(&init_net, sk->sk_bound_dev_if); + if (dev && addr->sllc_arphrd != dev->type) { + dev_put(dev); + dev = NULL; } } else - llc->dev = dev_getfirstbyhwtype(&init_net, addr->sllc_arphrd); - if (!llc->dev) + dev = dev_getfirstbyhwtype(&init_net, addr->sllc_arphrd); + if (!dev) goto out; rc = -EUSERS; llc->laddr.lsap = llc_ui_autoport(); @@ -296,6 +297,11 @@ static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr) sap = llc_sap_open(llc->laddr.lsap, NULL); if (!sap) goto out; + + /* Note: We do not expect errors from this point. */ + llc->dev = dev; + dev = NULL; + memcpy(llc->laddr.mac, llc->dev->dev_addr, IFHWADDRLEN); memcpy(&llc->addr, addr, sizeof(llc->addr)); /* assign new connection to its SAP */ @@ -303,10 +309,7 @@ static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr) sock_reset_flag(sk, SOCK_ZAPPED); rc = 0; out: - if (rc) { - dev_put(llc->dev); - llc->dev = NULL; - } + dev_put(dev); return rc; } @@ -329,6 +332,7 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen) struct sockaddr_llc *addr = (struct sockaddr_llc *)uaddr; struct sock *sk = sock->sk; struct llc_sock *llc = llc_sk(sk); + struct net_device *dev = NULL; struct llc_sap *sap; int rc = -EINVAL; @@ -345,25 +349,26 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen) rc = -ENODEV; rcu_read_lock(); if (sk->sk_bound_dev_if) { - llc->dev = dev_get_by_index_rcu(&init_net, sk->sk_bound_dev_if); - if (llc->dev) { + dev = dev_get_by_index_rcu(&init_net, sk->sk_bound_dev_if); + if (dev) { if (is_zero_ether_addr(addr->sllc_mac)) - memcpy(addr->sllc_mac, llc->dev->dev_addr, + memcpy(addr->sllc_mac, dev->dev_addr, IFHWADDRLEN); - if (addr->sllc_arphrd != llc->dev->type || + if (addr->sllc_arphrd != dev->type || !ether_addr_equal(addr->sllc_mac, - llc->dev->dev_addr)) { + dev->dev_addr)) { rc = -EINVAL; - llc->dev = NULL; + dev = NULL; } } - } else - llc->dev = dev_getbyhwaddr_rcu(&init_net, addr->sllc_arphrd, + } else { + dev = dev_getbyhwaddr_rcu(&init_net, addr->sllc_arphrd, addr->sllc_mac); - if (llc->dev) - dev_hold(llc->dev); + } + if (dev) + dev_hold(dev); rcu_read_unlock(); - if (!llc->dev) + if (!dev) goto out; if (!addr->sllc_sap) { rc = -EUSERS; @@ -396,6 +401,11 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen) goto out_put; } } + + /* Note: We do not expect errors from this point. */ + llc->dev = dev; + dev = NULL; + llc->laddr.lsap = addr->sllc_sap; memcpy(llc->laddr.mac, addr->sllc_mac, IFHWADDRLEN); memcpy(&llc->addr, addr, sizeof(llc->addr)); @@ -406,10 +416,7 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen) out_put: llc_sap_put(sap); out: - if (rc) { - dev_put(llc->dev); - llc->dev = NULL; - } + dev_put(dev); release_sock(sk); return rc; } -- Gitee From 8a136bf79c59a328d33ee0d33d0a4784c1ee1bdc Mon Sep 17 00:00:00 2001 From: Szymon Heidrich Date: Mon, 24 Jan 2022 12:14:00 +0100 Subject: [PATCH 21/26] USB: gadget: validate interface OS descriptor requests commit:8046755205677ec9e075f52ebddd0d5420806139 CVE:CVE-2022-25258 Signed-off-by: wanxiaoqing ----------------------------------------------------------- stable inclusion from stable-v5.10.101 commit 22ec1004728548598f4f5b4a079a7873409eacfd category: bugfix issue: #I4U9Y8 CVE: CVE-2022-25258 Signed-off-by: Yu Changchun --------------------------------- commit 75e5b4849b81e19e9efe1654b30d7f3151c33c2c upstream. Stall the control endpoint in case provided index exceeds array size of MAX_CONFIG_INTERFACES or when the retrieved function pointer is null. Signed-off-by: Szymon Heidrich Cc: stable@kernel.org Signed-off-by: Greg Kroah-Hartman Signed-off-by: Yu Changchun Signed-off-by: wanxiaoqing --- drivers/usb/gadget/composite.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 40b3ed93596a..139b66565ed6 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -1908,6 +1908,9 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) if (w_index != 0x5 || (w_value >> 8)) break; interface = w_value & 0xFF; + if (interface >= MAX_CONFIG_INTERFACES || + !os_desc_cfg->interface[interface]) + break; buf[6] = w_index; count = count_ext_prop(os_desc_cfg, interface); -- Gitee From e91bb401f88e42037a04111227a024efe8ad3c3f Mon Sep 17 00:00:00 2001 From: Steffen Klassert Date: Mon, 7 Mar 2022 13:11:39 +0100 Subject: [PATCH 22/26] esp: Fix possible buffer overflow in ESP transformation Signed-off-by: wufan ----------------------------------------------- mainline inclusion from mainline-v5.17-rc8 commit ebe48d368e97d007bfeb76fcb065d6cfc4c96645 category: bugfix issue: #I4YLYC CVE: CVE-2022-0886 Signed-off-by: Yu Changchun --------------------------------------- The maximum message size that can be send is bigger than the maximum site that skb_page_frag_refill can allocate. So it is possible to write beyond the allocated buffer. Fix this by doing a fallback to COW in that case. v2: Avoid get get_order() costs as suggested by Linus Torvalds. Fixes: cac2661c53f3 ("esp4: Avoid skb_cow_data whenever possible") Fixes: 03e2a30f6a27 ("esp6: Avoid skb_cow_data whenever possible") Reported-by: valis Signed-off-by: Steffen Klassert Signed-off-by: Xu Jia Reviewed-by: Wei Yongjun Reviewed-by: Xiu Jianfeng Signed-off-by: Zheng Zengkai Signed-off-by: Yu Changchun --- include/net/esp.h | 2 ++ net/ipv4/esp4.c | 5 +++++ net/ipv6/esp6.c | 5 +++++ 3 files changed, 12 insertions(+) diff --git a/include/net/esp.h b/include/net/esp.h index 117652eb6ea3..465e38890ee9 100644 --- a/include/net/esp.h +++ b/include/net/esp.h @@ -4,6 +4,8 @@ #include +#define ESP_SKB_FRAG_MAXSIZE (PAGE_SIZE << SKB_FRAG_PAGE_ORDER) + struct ip_esp_hdr; static inline struct ip_esp_hdr *ip_esp_hdr(const struct sk_buff *skb) diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index 114f9def1ec5..cde9a5fd4149 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c @@ -276,6 +276,7 @@ int esp_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info * struct page *page; struct sk_buff *trailer; int tailen = esp->tailen; + unsigned int allocsz; /* this is non-NULL only with UDP Encapsulation */ if (x->encap) { @@ -285,6 +286,10 @@ int esp_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info * return err; } + allocsz = ALIGN(skb->data_len + tailen, L1_CACHE_BYTES); + if (allocsz > ESP_SKB_FRAG_MAXSIZE) + goto cow; + if (!skb_cloned(skb)) { if (tailen <= skb_tailroom(skb)) { nfrags = 1; diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index a7d996148eed..53987b1c227c 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c @@ -242,6 +242,11 @@ int esp6_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info struct page *page; struct sk_buff *trailer; int tailen = esp->tailen; + unsigned int allocsz; + + allocsz = ALIGN(skb->data_len + tailen, L1_CACHE_BYTES); + if (allocsz > ESP_SKB_FRAG_MAXSIZE) + goto cow; if (!skb_cloned(skb)) { if (tailen <= skb_tailroom(skb)) { -- Gitee From 81da9382e75420d0062a0f8d35d52820613d4b1c Mon Sep 17 00:00:00 2001 From: Yunsheng Lin Date: Thu, 26 Aug 2021 10:49:47 +0800 Subject: [PATCH 23/26] sock: remove one redundant SKB_FRAG_PAGE_ORDER macro Signed-off-by: wufan ----------------------------------------------- mainline inclusion from mainline-v5.15-rc1 commit 723783d077e39c256a1fafebbd97cbb14207c28f category: bugfix issue: #I4YLYC CVE: CVE-2022-0886 Signed-off-by: Yu Changchun --------------------------------------- Both SKB_FRAG_PAGE_ORDER are defined to the same value in net/core/sock.c and drivers/vhost/net.c. Move the SKB_FRAG_PAGE_ORDER definition to net/core/sock.h, as both net/core/sock.c and drivers/vhost/net.c include it, and it seems a reasonable file to put the macro. Signed-off-by: Yunsheng Lin Acked-by: Jason Wang Signed-off-by: David S. Miller Signed-off-by: Xu Jia Reviewed-by: Wei Yongjun Reviewed-by: Xiu Jianfeng Signed-off-by: Zheng Zengkai Signed-off-by: Yu Changchun --- include/net/sock.h | 3 +++ net/core/sock.c | 3 +-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/include/net/sock.h b/include/net/sock.h index bc752237dff3..d280da601c25 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -2512,6 +2512,9 @@ extern int sysctl_optmem_max; extern __u32 sysctl_wmem_default; extern __u32 sysctl_rmem_default; +#define SKB_FRAG_PAGE_ORDER get_order(32768) +DECLARE_STATIC_KEY_FALSE(net_high_order_alloc_disable_key); + static inline int sk_get_wmem0(const struct sock *sk, const struct proto *proto) { /* Does this proto have per netns sysctl_wmem ? */ diff --git a/net/core/sock.c b/net/core/sock.c index d243a6f41267..b9cfe5589d38 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -2189,8 +2189,7 @@ static void sk_leave_memory_pressure(struct sock *sk) } } -/* On 32bit arches, an skb frag is limited to 2^15 */ -#define SKB_FRAG_PAGE_ORDER get_order(32768) +DEFINE_STATIC_KEY_FALSE(net_high_order_alloc_disable_key); /** * skb_page_frag_refill - check that a page_frag contains enough room -- Gitee From a49d8775750fa6cd3de006d569d32366fbc605a4 Mon Sep 17 00:00:00 2001 From: Haimin Zhang Date: Wed, 16 Feb 2022 16:40:38 +0800 Subject: [PATCH 24/26] block-map: add __GFP_ZERO flag for alloc_page in function bio_copy_kern Signed-off-by: wufan ----------------------------------------------- stable inclusion from stable-5.17-rc5 commit cc8f7fe1f5eab010191aa4570f27641876fa1267 category: bugfix issue: I51A19 CVE: CVE-2022-0494 Signed-off-by: gaochao --------------------------------------- block-map: add __GFP_ZERO flag for alloc_page in function bio_copy_kern Add __GFP_ZERO flag for alloc_page in function bio_copy_kern to initialize the buffer of a bio. Signed-off-by: Haimin Zhang Reviewed-by: Chaitanya Kulkarni Reviewed-by: Christoph Hellwig Link: https://lore.kernel.org/r/20220216084038.15635-1-tcs.kernel@gmail.com Signed-off-by: Jens Axboe --- block/bio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block/bio.c b/block/bio.c index 3d757055305f..2b4a505d2ee4 100644 --- a/block/bio.c +++ b/block/bio.c @@ -1528,7 +1528,7 @@ struct bio *bio_copy_kern(struct request_queue *q, void *data, unsigned int len, if (bytes > len) bytes = len; - page = alloc_page(q->bounce_gfp | gfp_mask); + page = alloc_page(q->bounce_gfp | __GFP_ZERO | gfp_mask); if (!page) goto cleanup; -- Gitee From 01d5a1f8e0cd3323d86fe2bed3fffd9317158bda Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Wed, 13 Apr 2022 11:09:57 +0800 Subject: [PATCH 25/26] Reinstate some of "swiotlb: rework "fix info leak with DMA_FROM_DEVICE"" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: wufan ----------------------------------------------- Signed-off-by: Kong Zhiquan ------------------------------ mainline inclusion from mainline-v5.18-rc1 commit 901c7280ca0d5e2b4a8929fbe0bfb007ac2a6544 category: bugfix bugzilla: 186478, https://gitee.com/src-openeuler/kernel/issues/I503W4 CVE: CVE-2022-0854 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=901c7280ca0d5e2b4a8929fbe0bfb007ac2a6544 -------------------------------- Halil Pasic points out [1] that the full revert of that commit (revert in bddac7c1e02b), and that a partial revert that only reverts the problematic case, but still keeps some of the cleanups is probably better.  And that partial revert [2] had already been verified by Oleksandr Natalenko to also fix the issue, I had just missed that in the long discussion. So let's reinstate the cleanups from commit aa6f8dcbab47 ("swiotlb: rework "fix info leak with DMA_FROM_DEVICE""), and effectively only revert the part that caused problems. Link: https://lore.kernel.org/all/20220328013731.017ae3e3.pasic@linux.ibm.com/ [1] Link: https://lore.kernel.org/all/20220324055732.GB12078@lst.de/ [2] Link: https://lore.kernel.org/all/4386660.LvFx2qVVIh@natalenko.name/ [3] Suggested-by: Halil Pasic Tested-by: Oleksandr Natalenko Cc: Christoph Hellwig" Signed-off-by: Linus Torvalds Conflicts: kernel/dma/swiotlb.c Signed-off-by: Liu Shixin Signed-off-by: Zheng Zengkai Reviewed-by: Kefeng Wang Reviewed-by: Weilong Chen --- kernel/dma/swiotlb.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/kernel/dma/swiotlb.c b/kernel/dma/swiotlb.c index 2a8c41f12d45..543597e33cff 100644 --- a/kernel/dma/swiotlb.c +++ b/kernel/dma/swiotlb.c @@ -583,10 +583,15 @@ phys_addr_t swiotlb_tbl_map_single(struct device *hwdev, */ for (i = 0; i < nslots; i++) io_tlb_orig_addr[index+i] = orig_addr + (i << IO_TLB_SHIFT); - if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC) && - (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL)) - swiotlb_bounce(orig_addr, tlb_addr, size, DMA_TO_DEVICE); + /* + * When dir == DMA_FROM_DEVICE we could omit the copy from the orig + * to the tlb buffer, if we knew for sure the device will + * overwirte the entire current content. But we don't. Thus + * unconditional bounce may prevent leaking swiotlb content (i.e. + * kernel memory) to user-space. + */ + swiotlb_bounce(orig_addr, tlb_addr, size, DMA_TO_DEVICE); return tlb_addr; } -- Gitee From 4ce48c36502dd45375cb67547bd134009d22f6da Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 3 Apr 2022 15:58:11 -0400 Subject: [PATCH 26/26] SUNRPC: Ensure we flush any closed sockets before xs_xprt_free() Signed-off-by: wufan ----------------------------------------------- stable inclusion from stable-v5.18-rc2 commit f00432063db1a0db484e85193eccc6845435b80e category: bugfix issue: #I51A19 CVE: CVE-2022-28893 Signed-off-by: gaochao ------------------------------------------- SUNRPC: Ensure we flush any closed sockets before xs_xprt_free() We must ensure that all sockets are closed before we call xprt_free() and release the reference to the net namespace. The problem is that calling fput() will defer closing the socket until delayed_fput() gets called. Let's fix the situation by allowing rpciod and the transport teardown code (which runs on the system wq) to call __fput_sync(), and directly close the socket. Reported-by: Felix Fu Acked-by: Al Viro Fixes: a73881c96d73 ("SUNRPC: Fix an Oops in udp_poll()") Cc: stable@vger.kernel.org # 5.1.x: 3be232f11a3c: SUNRPC: Prevent immediate close+reconnect Cc: stable@vger.kernel.org # 5.1.x: 89f42494f92f: SUNRPC: Don't call connect() more than once on a TCP socket Cc: stable@vger.kernel.org # 5.1.x Signed-off-by: Trond Myklebust --- fs/file_table.c | 1 + net/sunrpc/xprt.c | 5 +---- net/sunrpc/xprtsock.c | 12 +++++++++++- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/fs/file_table.c b/fs/file_table.c index e49af4caf15d..ba4418325c26 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -365,6 +365,7 @@ void __fput_sync(struct file *file) } EXPORT_SYMBOL(fput); +EXPORT_SYMBOL(__fput_sync); void __init files_init(void) { diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 5e7c13aa66d0..7ca4bb09c48a 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -768,10 +768,7 @@ void xprt_connect(struct rpc_task *task) if (!xprt_lock_write(xprt, task)) return; - if (test_and_clear_bit(XPRT_CLOSE_WAIT, &xprt->state)) - xprt->ops->close(xprt); - - if (!xprt_connected(xprt)) { + if (!xprt_connected(xprt) && !test_bit(XPRT_CLOSE_WAIT, &xprt->state)) { task->tk_rqstp->rq_bytes_sent = 0; task->tk_timeout = task->tk_rqstp->rq_timeout; task->tk_rqstp->rq_connect_cookie = xprt->connect_cookie; diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 9dc059dea689..917724875a64 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -557,7 +557,7 @@ static int xs_local_send_request(struct rpc_task *task) -status); /* fall through */ case -EPIPE: - xs_close(xprt); + xprt_force_disconnect(xprt); status = -ENOTCONN; } @@ -845,6 +845,16 @@ static void xs_reset_transport(struct sock_xprt *transport) if (sk == NULL) return; + /* + * Make sure we're calling this in a context from which it is safe + * to call __fput_sync(). In practice that means rpciod and the + * system workqueue. + */ + if (!(current->flags & PF_WQ_WORKER)) { + WARN_ON_ONCE(1); + set_bit(XPRT_CLOSE_WAIT, &xprt->state); + return; + } if (atomic_read(&transport->xprt.swapper)) sk_clear_memalloc(sk); -- Gitee