From: Johannes Berg johannes.berg@intel.com
stable inclusion from stable-v5.10.149 commit 31ce5da48a845bac48930bbde1d45e7449591728 category: bugfix bugzilla: https://gitee.com/src-openeuler/kernel/issues/I5VM7O CVE: CVE-2022-42719
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=...
--------------------------------
Commit ff05d4b45dd89b922578dac497dcabf57cf771c6 upstream. This is a different version of the commit, changed to store the non-transmitted profile in the elems, and freeing it in the few places where it's relevant, since that is only the case when the last argument for parsing (the non-tx BSSID) is non-NULL.
When we parse a multi-BSSID element, we might point some element pointers into the allocated nontransmitted_profile. However, we free this before returning, causing UAF when the relevant pointers in the parsed elements are accessed.
Fix this by not allocating the scratch buffer separately but as part of the returned structure instead, that way, there are no lifetime issues with it.
The scratch buffer introduction as part of the returned data here is taken from MLO feature work done by Ilan.
This fixes CVE-2022-42719.
Fixes: 5023b14cf4df ("mac80211: support profile split between elements") Co-developed-by: Ilan Peer ilan.peer@intel.com Signed-off-by: Ilan Peer ilan.peer@intel.com Reviewed-by: Kees Cook keescook@chromium.org Signed-off-by: Johannes Berg johannes.berg@intel.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Xu Jia xujia39@huawei.com Reviewed-by: Yue Haibing yuehaibing@huawei.com Reviewed-by: Wang Weiyang wangweiyang2@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- net/mac80211/ieee80211_i.h | 2 ++ net/mac80211/mlme.c | 6 +++++- net/mac80211/scan.c | 2 ++ net/mac80211/util.c | 7 ++++++- 4 files changed, 15 insertions(+), 2 deletions(-)
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index bcc94cc1b620..f68170a68d71 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1553,6 +1553,8 @@ struct ieee802_11_elems { u8 country_elem_len; u8 bssid_index_len;
+ void *nontx_profile; + /* whether a parse error occurred while retrieving these elements */ bool parse_error; }; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 3988403064ab..29e4d4961c37 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -3393,6 +3393,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, sdata_info(sdata, "AP bug: VHT operation missing from AssocResp\n"); } + kfree(bss_elems.nontx_profile); }
/* @@ -4044,6 +4045,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, ifmgd->assoc_data->timeout = jiffies; ifmgd->assoc_data->timeout_started = true; run_again(sdata, ifmgd->assoc_data->timeout); + kfree(elems.nontx_profile); return; }
@@ -4221,7 +4223,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, ieee80211_report_disconnect(sdata, deauth_buf, sizeof(deauth_buf), true, WLAN_REASON_DEAUTH_LEAVING); - return; + goto free; }
if (sta && elems.opmode_notif) @@ -4236,6 +4238,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, elems.cisco_dtpc_elem);
ieee80211_bss_info_change_notify(sdata, changed); +free: + kfree(elems.nontx_profile); }
void ieee80211_sta_rx_queued_ext(struct ieee80211_sub_if_data *sdata, diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 887f945bb12d..edd84f367880 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -227,6 +227,8 @@ ieee80211_bss_info_update(struct ieee80211_local *local, rx_status, beacon); }
+ kfree(elems.nontx_profile); + return bss; }
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index a1f129292ad8..c2eae5270ee5 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1485,6 +1485,11 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE, nontransmitted_profile, nontransmitted_profile_len); + if (!nontransmitted_profile_len) { + nontransmitted_profile_len = 0; + kfree(nontransmitted_profile); + nontransmitted_profile = NULL; + } }
crc = _ieee802_11_parse_elems_crc(start, len, action, elems, filter, @@ -1514,7 +1519,7 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, offsetofend(struct ieee80211_bssid_index, dtim_count)) elems->dtim_count = elems->bssid_index->dtim_count;
- kfree(nontransmitted_profile); + elems->nontx_profile = nontransmitted_profile;
return crc; }