From f82da2c1a6665588c1754ebfbb6264f8641cbbd4 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Oct 10 2022 15:21:12 +0000 Subject: Merge branch 'users/tiwai/SLE15-SP4/bsc1203770' into SLE15-SP4_EMBARGO --- diff --git a/patches.suse/mac80211-always-allocate-struct-ieee802_11_elems.patch b/patches.suse/mac80211-always-allocate-struct-ieee802_11_elems.patch new file mode 100644 index 0000000..483daa3 --- /dev/null +++ b/patches.suse/mac80211-always-allocate-struct-ieee802_11_elems.patch @@ -0,0 +1,1161 @@ +From 5d24828d05f37ad770599de00b53d5386e35aa61 Mon Sep 17 00:00:00 2001 +From: Johannes Berg +Date: Mon, 20 Sep 2021 15:40:10 +0200 +Subject: [PATCH] mac80211: always allocate struct ieee802_11_elems +Git-commit: 5d24828d05f37ad770599de00b53d5386e35aa61 +Patch-mainline: v5.16-rc1 +References: CVE-2022-42719 bsc#1204051 + +As the 802.11 spec evolves, we need to parse more and more +elements. This is causing the struct to grow, and we can no +longer get away with putting it on the stack. + +Change the API to always dynamically allocate and return an +allocated pointer that must be kfree()d later. + +As an alternative, I contemplated a scheme whereby we'd say +in the code which elements we needed, e.g. + + DECLARE_ELEMENT_PARSER(elems, + SUPPORTED_CHANNELS, + CHANNEL_SWITCH, + EXT(KEY_DELIVERY)); + + ieee802_11_parse_elems(..., &elems, ...); + +and while I think this is possible and will save us a lot +since most individual places only care about a small subset +of the elements, it ended up being a bit more work since a +lot of places do the parsing and then pass the struct to +other functions, sometimes with multiple levels. + +Link: https://lore.kernel.org/r/20210920154009.26caff6b5998.I05ae58768e990e611aee8eca8abefd9d7bc15e05@changeid +Signed-off-by: Johannes Berg +Acked-by: Takashi Iwai + +--- + net/mac80211/agg-rx.c | 11 +- + net/mac80211/ibss.c | 27 ++++-- + net/mac80211/ieee80211_i.h | 22 ++--- + net/mac80211/mesh.c | 86 ++++++++++++--------- + net/mac80211/mesh_hwmp.c | 44 ++++++----- + net/mac80211/mesh_plink.c | 11 +- + net/mac80211/mlme.c | 176 +++++++++++++++++++++++++-------------------- + net/mac80211/scan.c | 16 ++-- + net/mac80211/tdls.c | 63 +++++++++------- + net/mac80211/util.c | 20 +++-- + 10 files changed, 274 insertions(+), 202 deletions(-) + +--- a/net/mac80211/agg-rx.c ++++ b/net/mac80211/agg-rx.c +@@ -478,7 +478,7 @@ void ieee80211_process_addba_request(str + size_t len) + { + u16 capab, tid, timeout, ba_policy, buf_size, start_seq_num; +- struct ieee802_11_elems elems = { }; ++ struct ieee802_11_elems *elems = NULL; + u8 dialog_token; + int ies_len; + +@@ -496,16 +496,17 @@ void ieee80211_process_addba_request(str + ies_len = len - offsetof(struct ieee80211_mgmt, + u.action.u.addba_req.variable); + if (ies_len) { +- ieee802_11_parse_elems(mgmt->u.action.u.addba_req.variable, +- ies_len, true, &elems, mgmt->bssid, NULL); +- if (elems.parse_error) ++ elems = ieee802_11_parse_elems(mgmt->u.action.u.addba_req.variable, ++ ies_len, true, mgmt->bssid, NULL); ++ if (!elems || elems->parse_error) + return; + } + + __ieee80211_start_rx_ba_session(sta, dialog_token, timeout, + start_seq_num, ba_policy, tid, + buf_size, true, false, +- elems.addba_ext_ie); ++ elems ? elems->addba_ext_ie : NULL); ++ kfree(elems); + } + + void ieee80211_manage_rx_ba_offl(struct ieee80211_vif *vif, +--- a/net/mac80211/ibss.c ++++ b/net/mac80211/ibss.c +@@ -9,7 +9,7 @@ + * Copyright 2009, Johannes Berg + * 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 +@@ -1600,7 +1600,7 @@ void ieee80211_rx_mgmt_probe_beacon(stru + struct ieee80211_rx_status *rx_status) + { + size_t baselen; +- struct ieee802_11_elems elems; ++ struct ieee802_11_elems *elems; + + BUILD_BUG_ON(offsetof(typeof(mgmt->u.probe_resp), variable) != + offsetof(typeof(mgmt->u.beacon), variable)); +@@ -1613,10 +1613,14 @@ void ieee80211_rx_mgmt_probe_beacon(stru + if (baselen > len) + return; + +- ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen, +- false, &elems, mgmt->bssid, NULL); +- +- ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems); ++ elems = ieee802_11_parse_elems(mgmt->u.probe_resp.variable, ++ len - baselen, false, ++ mgmt->bssid, NULL); ++ ++ if (elems) { ++ ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, elems); ++ kfree(elems); ++ } + } + + void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, +@@ -1625,7 +1629,7 @@ void ieee80211_ibss_rx_queued_mgmt(struc + struct ieee80211_rx_status *rx_status; + struct ieee80211_mgmt *mgmt; + u16 fc; +- struct ieee802_11_elems elems; ++ struct ieee802_11_elems *elems; + int ies_len; + + rx_status = IEEE80211_SKB_RXCB(skb); +@@ -1662,15 +1666,16 @@ void ieee80211_ibss_rx_queued_mgmt(struc + if (ies_len < 0) + break; + +- ieee802_11_parse_elems( ++ elems = ieee802_11_parse_elems( + mgmt->u.action.u.chan_switch.variable, +- ies_len, true, &elems, mgmt->bssid, NULL); ++ ies_len, true, mgmt->bssid, NULL); + +- if (elems.parse_error) ++ if (!elems || elems->parse_error) + break; + + ieee80211_rx_mgmt_spectrum_mgmt(sdata, mgmt, skb->len, +- rx_status, &elems); ++ rx_status, elems); ++ kfree(elems); + break; + } + } +--- a/net/mac80211/ieee80211_i.h ++++ b/net/mac80211/ieee80211_i.h +@@ -2197,18 +2197,18 @@ static inline void ieee80211_tx_skb(stru + ieee80211_tx_skb_tid(sdata, skb, 7); + } + +-void ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, +- struct ieee802_11_elems *elems, +- u64 filter, u32 crc, u8 *transmitter_bssid, +- u8 *bss_bssid); +-static inline void ieee802_11_parse_elems(const u8 *start, size_t len, +- bool action, +- struct ieee802_11_elems *elems, +- u8 *transmitter_bssid, +- u8 *bss_bssid) ++struct ieee802_11_elems *ieee802_11_parse_elems_crc(const u8 *start, size_t len, ++ bool action, ++ u64 filter, u32 crc, ++ const u8 *transmitter_bssid, ++ const u8 *bss_bssid); ++static inline struct ieee802_11_elems * ++ieee802_11_parse_elems(const u8 *start, size_t len, bool action, ++ const u8 *transmitter_bssid, ++ const u8 *bss_bssid) + { +- ieee802_11_parse_elems_crc(start, len, action, elems, 0, 0, +- transmitter_bssid, bss_bssid); ++ return ieee802_11_parse_elems_crc(start, len, action, 0, 0, ++ transmitter_bssid, bss_bssid); + } + + +--- a/net/mac80211/mesh.c ++++ b/net/mac80211/mesh.c +@@ -1247,7 +1247,7 @@ ieee80211_mesh_rx_probe_req(struct ieee8 + struct sk_buff *presp; + struct beacon_data *bcn; + struct ieee80211_mgmt *hdr; +- struct ieee802_11_elems elems; ++ struct ieee802_11_elems *elems; + size_t baselen; + u8 *pos; + +@@ -1256,22 +1256,24 @@ ieee80211_mesh_rx_probe_req(struct ieee8 + if (baselen > len) + return; + +- ieee802_11_parse_elems(pos, len - baselen, false, &elems, mgmt->bssid, +- NULL); +- +- if (!elems.mesh_id) ++ elems = ieee802_11_parse_elems(pos, len - baselen, false, mgmt->bssid, ++ NULL); ++ if (!elems) + return; + ++ if (!elems->mesh_id) ++ goto free; ++ + /* 802.11-2012 10.1.4.3.2 */ + if ((!ether_addr_equal(mgmt->da, sdata->vif.addr) && + !is_broadcast_ether_addr(mgmt->da)) || +- elems.ssid_len != 0) +- return; ++ elems->ssid_len != 0) ++ goto free; + +- if (elems.mesh_id_len != 0 && +- (elems.mesh_id_len != ifmsh->mesh_id_len || +- memcmp(elems.mesh_id, ifmsh->mesh_id, ifmsh->mesh_id_len))) +- return; ++ if (elems->mesh_id_len != 0 && ++ (elems->mesh_id_len != ifmsh->mesh_id_len || ++ memcmp(elems->mesh_id, ifmsh->mesh_id, ifmsh->mesh_id_len))) ++ goto free; + + rcu_read_lock(); + bcn = rcu_dereference(ifmsh->beacon); +@@ -1295,6 +1297,8 @@ ieee80211_mesh_rx_probe_req(struct ieee8 + ieee80211_tx_skb(sdata, presp); + out: + rcu_read_unlock(); ++free: ++ kfree(elems); + } + + static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, +@@ -1305,7 +1309,7 @@ static void ieee80211_mesh_rx_bcn_presp( + { + struct ieee80211_local *local = sdata->local; + struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; +- struct ieee802_11_elems elems; ++ struct ieee802_11_elems *elems; + struct ieee80211_channel *channel; + size_t baselen; + int freq; +@@ -1320,42 +1324,48 @@ static void ieee80211_mesh_rx_bcn_presp( + if (baselen > len) + return; + +- ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen, +- false, &elems, mgmt->bssid, NULL); ++ elems = ieee802_11_parse_elems(mgmt->u.probe_resp.variable, ++ len - baselen, ++ false, mgmt->bssid, NULL); ++ if (!elems) ++ return; + + /* ignore non-mesh or secure / unsecure mismatch */ +- if ((!elems.mesh_id || !elems.mesh_config) || +- (elems.rsn && sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) || +- (!elems.rsn && sdata->u.mesh.security != IEEE80211_MESH_SEC_NONE)) +- return; ++ if ((!elems->mesh_id || !elems->mesh_config) || ++ (elems->rsn && sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) || ++ (!elems->rsn && sdata->u.mesh.security != IEEE80211_MESH_SEC_NONE)) ++ goto free; + +- if (elems.ds_params) +- freq = ieee80211_channel_to_frequency(elems.ds_params[0], band); ++ if (elems->ds_params) ++ freq = ieee80211_channel_to_frequency(elems->ds_params[0], band); + else + freq = rx_status->freq; + + channel = ieee80211_get_channel(local->hw.wiphy, freq); + + if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) +- return; ++ goto free; + +- if (mesh_matches_local(sdata, &elems)) { ++ if (mesh_matches_local(sdata, elems)) { + mpl_dbg(sdata, "rssi_threshold=%d,rx_status->signal=%d\n", + sdata->u.mesh.mshcfg.rssi_threshold, rx_status->signal); + if (!sdata->u.mesh.user_mpm || + sdata->u.mesh.mshcfg.rssi_threshold == 0 || + sdata->u.mesh.mshcfg.rssi_threshold < rx_status->signal) +- mesh_neighbour_update(sdata, mgmt->sa, &elems, ++ mesh_neighbour_update(sdata, mgmt->sa, elems, + rx_status); + + if (ifmsh->csa_role != IEEE80211_MESH_CSA_ROLE_INIT && + !sdata->vif.csa_active) +- ieee80211_mesh_process_chnswitch(sdata, &elems, true); ++ ieee80211_mesh_process_chnswitch(sdata, elems, true); + } + + if (ifmsh->sync_ops) + ifmsh->sync_ops->rx_bcn_presp(sdata, +- stype, mgmt, &elems, rx_status); ++ stype, mgmt, elems, rx_status); ++ ++free: ++ kfree(elems); + } + + int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata) +@@ -1447,7 +1457,7 @@ static void mesh_rx_csa_frame(struct iee + struct ieee80211_mgmt *mgmt, size_t len) + { + struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; +- struct ieee802_11_elems elems; ++ struct ieee802_11_elems *elems; + u16 pre_value; + bool fwd_csa = true; + size_t baselen; +@@ -1460,33 +1470,37 @@ static void mesh_rx_csa_frame(struct iee + pos = mgmt->u.action.u.chan_switch.variable; + baselen = offsetof(struct ieee80211_mgmt, + u.action.u.chan_switch.variable); +- ieee802_11_parse_elems(pos, len - baselen, true, &elems, +- mgmt->bssid, NULL); +- +- if (!mesh_matches_local(sdata, &elems)) ++ elems = ieee802_11_parse_elems(pos, len - baselen, true, ++ mgmt->bssid, NULL); ++ if (!elems) + return; + +- ifmsh->chsw_ttl = elems.mesh_chansw_params_ie->mesh_ttl; ++ if (!mesh_matches_local(sdata, elems)) ++ goto free; ++ ++ ifmsh->chsw_ttl = elems->mesh_chansw_params_ie->mesh_ttl; + if (!--ifmsh->chsw_ttl) + fwd_csa = false; + +- pre_value = le16_to_cpu(elems.mesh_chansw_params_ie->mesh_pre_value); ++ pre_value = le16_to_cpu(elems->mesh_chansw_params_ie->mesh_pre_value); + if (ifmsh->pre_value >= pre_value) +- return; ++ goto free; + + ifmsh->pre_value = pre_value; + + if (!sdata->vif.csa_active && +- !ieee80211_mesh_process_chnswitch(sdata, &elems, false)) { ++ !ieee80211_mesh_process_chnswitch(sdata, elems, false)) { + mcsa_dbg(sdata, "Failed to process CSA action frame"); +- return; ++ goto free; + } + + /* forward or re-broadcast the CSA frame */ + if (fwd_csa) { +- if (mesh_fwd_csa_frame(sdata, mgmt, len, &elems) < 0) ++ if (mesh_fwd_csa_frame(sdata, mgmt, len, elems) < 0) + mcsa_dbg(sdata, "Failed to forward the CSA frame"); + } ++free: ++ kfree(elems); + } + + static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata, +--- a/net/mac80211/mesh_hwmp.c ++++ b/net/mac80211/mesh_hwmp.c +@@ -1,7 +1,7 @@ + // SPDX-License-Identifier: GPL-2.0-only + /* + * Copyright (c) 2008, 2009 open80211s Ltd. +- * Copyright (C) 2019 Intel Corporation ++ * Copyright (C) 2019, 2021 Intel Corporation + * Author: Luis Carlos Cobo + */ + +@@ -908,7 +908,7 @@ static void hwmp_rann_frame_process(stru + void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, + struct ieee80211_mgmt *mgmt, size_t len) + { +- struct ieee802_11_elems elems; ++ struct ieee802_11_elems *elems; + size_t baselen; + u32 path_metric; + struct sta_info *sta; +@@ -926,37 +926,41 @@ void mesh_rx_path_sel_frame(struct ieee8 + rcu_read_unlock(); + + baselen = (u8 *) mgmt->u.action.u.mesh_action.variable - (u8 *) mgmt; +- ieee802_11_parse_elems(mgmt->u.action.u.mesh_action.variable, +- len - baselen, false, &elems, mgmt->bssid, NULL); ++ elems = ieee802_11_parse_elems(mgmt->u.action.u.mesh_action.variable, ++ len - baselen, false, mgmt->bssid, NULL); ++ if (!elems) ++ return; + +- if (elems.preq) { +- if (elems.preq_len != 37) ++ if (elems->preq) { ++ if (elems->preq_len != 37) + /* Right now we support just 1 destination and no AE */ +- return; +- path_metric = hwmp_route_info_get(sdata, mgmt, elems.preq, ++ goto free; ++ path_metric = hwmp_route_info_get(sdata, mgmt, elems->preq, + MPATH_PREQ); + if (path_metric) +- hwmp_preq_frame_process(sdata, mgmt, elems.preq, ++ hwmp_preq_frame_process(sdata, mgmt, elems->preq, + path_metric); + } +- if (elems.prep) { +- if (elems.prep_len != 31) ++ if (elems->prep) { ++ if (elems->prep_len != 31) + /* Right now we support no AE */ +- return; +- path_metric = hwmp_route_info_get(sdata, mgmt, elems.prep, ++ goto free; ++ path_metric = hwmp_route_info_get(sdata, mgmt, elems->prep, + MPATH_PREP); + if (path_metric) +- hwmp_prep_frame_process(sdata, mgmt, elems.prep, ++ hwmp_prep_frame_process(sdata, mgmt, elems->prep, + path_metric); + } +- if (elems.perr) { +- if (elems.perr_len != 15) ++ if (elems->perr) { ++ if (elems->perr_len != 15) + /* Right now we support only one destination per PERR */ +- return; +- hwmp_perr_frame_process(sdata, mgmt, elems.perr); ++ goto free; ++ hwmp_perr_frame_process(sdata, mgmt, elems->perr); + } +- if (elems.rann) +- hwmp_rann_frame_process(sdata, mgmt, elems.rann); ++ if (elems->rann) ++ hwmp_rann_frame_process(sdata, mgmt, elems->rann); ++free: ++ kfree(elems); + } + + /** +--- a/net/mac80211/mesh_plink.c ++++ b/net/mac80211/mesh_plink.c +@@ -1,7 +1,7 @@ + // SPDX-License-Identifier: GPL-2.0-only + /* + * Copyright (c) 2008, 2009 open80211s Ltd. +- * Copyright (C) 2019 Intel Corporation ++ * Copyright (C) 2019, 2021 Intel Corporation + * Author: Luis Carlos Cobo + */ + #include +@@ -1200,7 +1200,7 @@ void mesh_rx_plink_frame(struct ieee8021 + struct ieee80211_mgmt *mgmt, size_t len, + struct ieee80211_rx_status *rx_status) + { +- struct ieee802_11_elems elems; ++ struct ieee802_11_elems *elems; + size_t baselen; + u8 *baseaddr; + +@@ -1228,7 +1228,8 @@ void mesh_rx_plink_frame(struct ieee8021 + if (baselen > len) + return; + } +- ieee802_11_parse_elems(baseaddr, len - baselen, true, &elems, +- mgmt->bssid, NULL); +- mesh_process_plink_frame(sdata, mgmt, &elems, rx_status); ++ elems = ieee802_11_parse_elems(baseaddr, len - baselen, true, ++ mgmt->bssid, NULL); ++ mesh_process_plink_frame(sdata, mgmt, elems, rx_status); ++ kfree(elems); + } +--- a/net/mac80211/mlme.c ++++ b/net/mac80211/mlme.c +@@ -3312,8 +3312,11 @@ static bool ieee80211_assoc_success(stru + aid = 0; /* TODO */ + } + capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info); +- ieee802_11_parse_elems(pos, len - (pos - (u8 *)mgmt), false, elems, +- mgmt->bssid, assoc_data->bss->bssid); ++ elems = ieee802_11_parse_elems(pos, len - (pos - (u8 *)mgmt), false, ++ mgmt->bssid, assoc_data->bss->bssid); ++ ++ if (!elems) ++ return false; + + if (elems->aid_resp) + aid = le16_to_cpu(elems->aid_resp->aid); +@@ -3335,7 +3338,8 @@ static bool ieee80211_assoc_success(stru + + if (!is_s1g && !elems->supp_rates) { + sdata_info(sdata, "no SuppRates element in AssocResp\n"); +- return false; ++ ret = false; ++ goto out; + } + + sdata->vif.bss_conf.aid = aid; +@@ -3357,7 +3361,7 @@ static bool ieee80211_assoc_success(stru + (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT) && + (!elems->vht_cap_elem || !elems->vht_operation)))) { + const struct cfg80211_bss_ies *ies; +- struct ieee802_11_elems bss_elems; ++ struct ieee802_11_elems *bss_elems; + + rcu_read_lock(); + ies = rcu_dereference(cbss->ies); +@@ -3368,13 +3372,17 @@ static bool ieee80211_assoc_success(stru + if (!bss_ies) + return false; + +- ieee802_11_parse_elems(bss_ies->data, bss_ies->len, +- false, &bss_elems, +- mgmt->bssid, +- assoc_data->bss->bssid); ++ bss_elems = ieee802_11_parse_elems(bss_ies->data, bss_ies->len, ++ false, mgmt->bssid, ++ assoc_data->bss->bssid); ++ if (!bss_elems) { ++ ret = false; ++ goto out; ++ } ++ + if (assoc_data->wmm && +- !elems->wmm_param && bss_elems.wmm_param) { +- elems->wmm_param = bss_elems.wmm_param; ++ !elems->wmm_param && bss_elems->wmm_param) { ++ elems->wmm_param = bss_elems->wmm_param; + sdata_info(sdata, + "AP bug: WMM param missing from AssocResp\n"); + } +@@ -3383,30 +3391,32 @@ static bool ieee80211_assoc_success(stru + * Also check if we requested HT/VHT, otherwise the AP doesn't + * have to include the IEs in the (re)association response. + */ +- if (!elems->ht_cap_elem && bss_elems.ht_cap_elem && ++ if (!elems->ht_cap_elem && bss_elems->ht_cap_elem && + !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) { +- elems->ht_cap_elem = bss_elems.ht_cap_elem; ++ elems->ht_cap_elem = bss_elems->ht_cap_elem; + sdata_info(sdata, + "AP bug: HT capability missing from AssocResp\n"); + } +- if (!elems->ht_operation && bss_elems.ht_operation && ++ if (!elems->ht_operation && bss_elems->ht_operation && + !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) { +- elems->ht_operation = bss_elems.ht_operation; ++ elems->ht_operation = bss_elems->ht_operation; + sdata_info(sdata, + "AP bug: HT operation missing from AssocResp\n"); + } +- if (!elems->vht_cap_elem && bss_elems.vht_cap_elem && ++ if (!elems->vht_cap_elem && bss_elems->vht_cap_elem && + !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) { +- elems->vht_cap_elem = bss_elems.vht_cap_elem; ++ elems->vht_cap_elem = bss_elems->vht_cap_elem; + sdata_info(sdata, + "AP bug: VHT capa missing from AssocResp\n"); + } +- if (!elems->vht_operation && bss_elems.vht_operation && ++ if (!elems->vht_operation && bss_elems->vht_operation && + !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) { +- elems->vht_operation = bss_elems.vht_operation; ++ elems->vht_operation = bss_elems->vht_operation; + sdata_info(sdata, + "AP bug: VHT operation missing from AssocResp\n"); + } ++ ++ kfree(bss_elems); + } + + /* +@@ -3660,6 +3670,7 @@ static bool ieee80211_assoc_success(stru + + ret = true; + out: ++ kfree(elems); + kfree(bss_ies); + return ret; + } +@@ -3671,7 +3682,7 @@ static void ieee80211_rx_mgmt_assoc_resp + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + struct ieee80211_mgd_assoc_data *assoc_data = ifmgd->assoc_data; + u16 capab_info, status_code, aid; +- struct ieee802_11_elems elems; ++ struct ieee802_11_elems *elems; + int ac, uapsd_queues = -1; + u8 *pos; + bool reassoc; +@@ -3728,14 +3739,16 @@ static void ieee80211_rx_mgmt_assoc_resp + fils_decrypt_assoc_resp(sdata, (u8 *)mgmt, &len, assoc_data) < 0) + return; + +- ieee802_11_parse_elems(pos, len - (pos - (u8 *)mgmt), false, &elems, +- mgmt->bssid, assoc_data->bss->bssid); ++ elems = ieee802_11_parse_elems(pos, len - (pos - (u8 *)mgmt), false, ++ mgmt->bssid, assoc_data->bss->bssid); ++ if (!elems) ++ goto notify_driver; + + if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY && +- elems.timeout_int && +- elems.timeout_int->type == WLAN_TIMEOUT_ASSOC_COMEBACK) { ++ elems->timeout_int && ++ elems->timeout_int->type == WLAN_TIMEOUT_ASSOC_COMEBACK) { + u32 tu, ms; +- tu = le32_to_cpu(elems.timeout_int->value); ++ tu = le32_to_cpu(elems->timeout_int->value); + ms = tu * 1024 / 1000; + sdata_info(sdata, + "%pM rejected association temporarily; comeback duration %u TU (%u ms)\n", +@@ -3755,7 +3768,7 @@ static void ieee80211_rx_mgmt_assoc_resp + event.u.mlme.reason = status_code; + drv_event_callback(sdata->local, sdata, &event); + } else { +- if (!ieee80211_assoc_success(sdata, cbss, mgmt, len, &elems)) { ++ if (!ieee80211_assoc_success(sdata, cbss, mgmt, len, elems)) { + /* oops -- internal error -- send timeout for now */ + ieee80211_destroy_assoc_data(sdata, false, false); + cfg80211_assoc_timeout(sdata->dev, cbss); +@@ -3785,6 +3798,7 @@ static void ieee80211_rx_mgmt_assoc_resp + ifmgd->assoc_req_ies, ifmgd->assoc_req_ies_len); + notify_driver: + drv_mgd_complete_tx(sdata->local, sdata, &info); ++ kfree(elems); + } + + static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, +@@ -3989,7 +4003,7 @@ static void ieee80211_rx_mgmt_beacon(str + struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; + struct ieee80211_mgmt *mgmt = (void *) hdr; + size_t baselen; +- struct ieee802_11_elems elems; ++ struct ieee802_11_elems *elems; + struct ieee80211_local *local = sdata->local; + struct ieee80211_chanctx_conf *chanctx_conf; + struct ieee80211_channel *chan; +@@ -4035,15 +4049,16 @@ static void ieee80211_rx_mgmt_beacon(str + + if (ifmgd->assoc_data && ifmgd->assoc_data->need_beacon && + ieee80211_rx_our_beacon(bssid, ifmgd->assoc_data->bss)) { +- ieee802_11_parse_elems(variable, +- len - baselen, false, &elems, +- bssid, +- ifmgd->assoc_data->bss->bssid); ++ elems = ieee802_11_parse_elems(variable, len - baselen, false, ++ bssid, ++ ifmgd->assoc_data->bss->bssid); ++ if (!elems) ++ return; + + ieee80211_rx_bss_info(sdata, mgmt, len, rx_status); + +- if (elems.dtim_period) +- ifmgd->dtim_period = elems.dtim_period; ++ if (elems->dtim_period) ++ ifmgd->dtim_period = elems->dtim_period; + ifmgd->have_beacon = true; + ifmgd->assoc_data->need_beacon = false; + if (ieee80211_hw_check(&local->hw, TIMING_BEACON_ONLY)) { +@@ -4051,17 +4066,17 @@ static void ieee80211_rx_mgmt_beacon(str + le64_to_cpu(mgmt->u.beacon.timestamp); + sdata->vif.bss_conf.sync_device_ts = + rx_status->device_timestamp; +- sdata->vif.bss_conf.sync_dtim_count = elems.dtim_count; ++ sdata->vif.bss_conf.sync_dtim_count = elems->dtim_count; + } + +- if (elems.mbssid_config_ie) ++ if (elems->mbssid_config_ie) + bss_conf->profile_periodicity = +- elems.mbssid_config_ie->profile_periodicity; ++ elems->mbssid_config_ie->profile_periodicity; + else + bss_conf->profile_periodicity = 0; + +- if (elems.ext_capab_len >= 11 && +- (elems.ext_capab[10] & WLAN_EXT_CAPA11_EMA_SUPPORT)) ++ if (elems->ext_capab_len >= 11 && ++ (elems->ext_capab[10] & WLAN_EXT_CAPA11_EMA_SUPPORT)) + bss_conf->ema_ap = true; + else + bss_conf->ema_ap = false; +@@ -4070,6 +4085,7 @@ static void ieee80211_rx_mgmt_beacon(str + ifmgd->assoc_data->timeout = jiffies; + ifmgd->assoc_data->timeout_started = true; + run_again(sdata, ifmgd->assoc_data->timeout); ++ kfree(elems); + return; + } + +@@ -4101,14 +4117,15 @@ static void ieee80211_rx_mgmt_beacon(str + */ + if (!ieee80211_is_s1g_beacon(hdr->frame_control)) + ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4); +- ieee802_11_parse_elems_crc(variable, +- len - baselen, false, &elems, +- care_about_ies, ncrc, +- mgmt->bssid, bssid); +- ncrc = elems.crc; ++ elems = ieee802_11_parse_elems_crc(variable, len - baselen, ++ false, care_about_ies, ncrc, ++ mgmt->bssid, bssid); ++ if (!elems) ++ return; ++ ncrc = elems->crc; + + if (ieee80211_hw_check(&local->hw, PS_NULLFUNC_STACK) && +- ieee80211_check_tim(elems.tim, elems.tim_len, bss_conf->aid)) { ++ ieee80211_check_tim(elems->tim, elems->tim_len, bss_conf->aid)) { + if (local->hw.conf.dynamic_ps_timeout > 0) { + if (local->hw.conf.flags & IEEE80211_CONF_PS) { + local->hw.conf.flags &= ~IEEE80211_CONF_PS; +@@ -4178,12 +4195,12 @@ static void ieee80211_rx_mgmt_beacon(str + le64_to_cpu(mgmt->u.beacon.timestamp); + sdata->vif.bss_conf.sync_device_ts = + rx_status->device_timestamp; +- sdata->vif.bss_conf.sync_dtim_count = elems.dtim_count; ++ sdata->vif.bss_conf.sync_dtim_count = elems->dtim_count; + } + + if ((ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid) || + ieee80211_is_s1g_short_beacon(mgmt->frame_control)) +- return; ++ goto free; + ifmgd->beacon_crc = ncrc; + ifmgd->beacon_crc_valid = true; + +@@ -4191,12 +4208,12 @@ static void ieee80211_rx_mgmt_beacon(str + + ieee80211_sta_process_chanswitch(sdata, rx_status->mactime, + rx_status->device_timestamp, +- &elems, true); ++ elems, true); + + if (!(ifmgd->flags & IEEE80211_STA_DISABLE_WMM) && +- ieee80211_sta_wmm_params(local, sdata, elems.wmm_param, +- elems.wmm_param_len, +- elems.mu_edca_param_set)) ++ ieee80211_sta_wmm_params(local, sdata, elems->wmm_param, ++ elems->wmm_param_len, ++ elems->mu_edca_param_set)) + changed |= BSS_CHANGED_QOS; + + /* +@@ -4205,7 +4222,7 @@ static void ieee80211_rx_mgmt_beacon(str + */ + if (!ifmgd->have_beacon) { + /* a few bogus AP send dtim_period = 0 or no TIM IE */ +- bss_conf->dtim_period = elems.dtim_period ?: 1; ++ bss_conf->dtim_period = elems->dtim_period ?: 1; + + changed |= BSS_CHANGED_BEACON_INFO; + ifmgd->have_beacon = true; +@@ -4217,9 +4234,9 @@ static void ieee80211_rx_mgmt_beacon(str + ieee80211_recalc_ps_vif(sdata); + } + +- if (elems.erp_info) { ++ if (elems->erp_info) { + erp_valid = true; +- erp_value = elems.erp_info[0]; ++ erp_value = elems->erp_info[0]; + } else { + erp_valid = false; + } +@@ -4232,12 +4249,12 @@ static void ieee80211_rx_mgmt_beacon(str + mutex_lock(&local->sta_mtx); + sta = sta_info_get(sdata, bssid); + +- changed |= ieee80211_recalc_twt_req(sdata, sta, &elems); ++ changed |= ieee80211_recalc_twt_req(sdata, sta, elems); + +- if (ieee80211_config_bw(sdata, sta, elems.ht_cap_elem, +- elems.vht_cap_elem, elems.ht_operation, +- elems.vht_operation, elems.he_operation, +- elems.s1g_oper, bssid, &changed)) { ++ if (ieee80211_config_bw(sdata, sta, elems->ht_cap_elem, ++ elems->vht_cap_elem, elems->ht_operation, ++ elems->vht_operation, elems->he_operation, ++ elems->s1g_oper, bssid, &changed)) { + mutex_unlock(&local->sta_mtx); + sdata_info(sdata, + "failed to follow AP %pM bandwidth change, disconnect\n", +@@ -4249,21 +4266,23 @@ static void ieee80211_rx_mgmt_beacon(str + sizeof(deauth_buf), true, + WLAN_REASON_DEAUTH_LEAVING, + false); +- return; ++ goto free; + } + +- if (sta && elems.opmode_notif) +- ieee80211_vht_handle_opmode(sdata, sta, *elems.opmode_notif, ++ if (sta && elems->opmode_notif) ++ ieee80211_vht_handle_opmode(sdata, sta, *elems->opmode_notif, + rx_status->band); + mutex_unlock(&local->sta_mtx); + + changed |= ieee80211_handle_pwr_constr(sdata, chan, mgmt, +- elems.country_elem, +- elems.country_elem_len, +- elems.pwr_constr_elem, +- elems.cisco_dtpc_elem); ++ elems->country_elem, ++ elems->country_elem_len, ++ elems->pwr_constr_elem, ++ elems->cisco_dtpc_elem); + + ieee80211_bss_info_change_notify(sdata, changed); ++free: ++ kfree(elems); + } + + void ieee80211_sta_rx_queued_ext(struct ieee80211_sub_if_data *sdata, +@@ -4292,7 +4311,6 @@ void ieee80211_sta_rx_queued_mgmt(struct + struct ieee80211_rx_status *rx_status; + struct ieee80211_mgmt *mgmt; + u16 fc; +- struct ieee802_11_elems elems; + int ies_len; + + rx_status = (struct ieee80211_rx_status *) skb->cb; +@@ -4324,6 +4342,8 @@ void ieee80211_sta_rx_queued_mgmt(struct + break; + case IEEE80211_STYPE_ACTION: + if (mgmt->u.action.category == WLAN_CATEGORY_SPECTRUM_MGMT) { ++ struct ieee802_11_elems *elems; ++ + ies_len = skb->len - + offsetof(struct ieee80211_mgmt, + u.action.u.chan_switch.variable); +@@ -4332,18 +4352,21 @@ void ieee80211_sta_rx_queued_mgmt(struct + break; + + /* CSA IE cannot be overridden, no need for BSSID */ +- ieee802_11_parse_elems( +- mgmt->u.action.u.chan_switch.variable, +- ies_len, true, &elems, mgmt->bssid, NULL); ++ elems = ieee802_11_parse_elems( ++ mgmt->u.action.u.chan_switch.variable, ++ ies_len, true, mgmt->bssid, NULL); + +- if (elems.parse_error) ++ if (!elems || elems->parse_error) + break; + + ieee80211_sta_process_chanswitch(sdata, + rx_status->mactime, + rx_status->device_timestamp, +- &elems, false); ++ elems, false); ++ kfree(elems); + } else if (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) { ++ struct ieee802_11_elems *elems; ++ + ies_len = skb->len - + offsetof(struct ieee80211_mgmt, + u.action.u.ext_chan_switch.variable); +@@ -4355,21 +4378,22 @@ void ieee80211_sta_rx_queued_mgmt(struct + * extended CSA IE can't be overridden, no need for + * BSSID + */ +- ieee802_11_parse_elems( +- mgmt->u.action.u.ext_chan_switch.variable, +- ies_len, true, &elems, mgmt->bssid, NULL); ++ elems = ieee802_11_parse_elems( ++ mgmt->u.action.u.ext_chan_switch.variable, ++ ies_len, true, mgmt->bssid, NULL); + +- if (elems.parse_error) ++ if (!elems || elems->parse_error) + break; + + /* for the handling code pretend this was also an IE */ +- elems.ext_chansw_ie = ++ elems->ext_chansw_ie = + &mgmt->u.action.u.ext_chan_switch.data; + + ieee80211_sta_process_chanswitch(sdata, + rx_status->mactime, + rx_status->device_timestamp, +- &elems, false); ++ elems, false); ++ kfree(elems); + } + break; + } +--- a/net/mac80211/scan.c ++++ b/net/mac80211/scan.c +@@ -9,7 +9,7 @@ + * Copyright 2007, Michael Wu + * Copyright 2013-2015 Intel Mobile Communications GmbH + * Copyright 2016-2017 Intel Deutschland GmbH +- * Copyright (C) 2018-2020 Intel Corporation ++ * Copyright (C) 2018-2021 Intel Corporation + */ + + #include +@@ -155,7 +155,7 @@ ieee80211_bss_info_update(struct ieee802 + }; + bool signal_valid; + struct ieee80211_sub_if_data *scan_sdata; +- struct ieee802_11_elems elems; ++ struct ieee802_11_elems *elems; + size_t baselen; + u8 *elements; + +@@ -209,8 +209,10 @@ ieee80211_bss_info_update(struct ieee802 + if (baselen > len) + return NULL; + +- ieee802_11_parse_elems(elements, len - baselen, false, &elems, +- mgmt->bssid, cbss->bssid); ++ elems = ieee802_11_parse_elems(elements, len - baselen, false, ++ mgmt->bssid, cbss->bssid); ++ if (!elems) ++ return NULL; + + /* In case the signal is invalid update the status */ + signal_valid = channel == cbss->channel; +@@ -218,15 +220,17 @@ ieee80211_bss_info_update(struct ieee802 + rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL; + + bss = (void *)cbss->priv; +- ieee80211_update_bss_from_elems(local, bss, &elems, rx_status, beacon); ++ ieee80211_update_bss_from_elems(local, bss, elems, rx_status, beacon); + + list_for_each_entry(non_tx_cbss, &cbss->nontrans_list, nontrans_list) { + non_tx_bss = (void *)non_tx_cbss->priv; + +- ieee80211_update_bss_from_elems(local, non_tx_bss, &elems, ++ ieee80211_update_bss_from_elems(local, non_tx_bss, elems, + rx_status, beacon); + } + ++ kfree(elems); ++ + return bss; + } + +--- a/net/mac80211/tdls.c ++++ b/net/mac80211/tdls.c +@@ -6,7 +6,7 @@ + * Copyright 2014, Intel Corporation + * Copyright 2014 Intel Mobile Communications GmbH + * Copyright 2015 - 2016 Intel Deutschland GmbH +- * Copyright (C) 2019 Intel Corporation ++ * Copyright (C) 2019, 2021 Intel Corporation + */ + + #include +@@ -1684,7 +1684,7 @@ ieee80211_process_tdls_channel_switch_re + struct sk_buff *skb) + { + struct ieee80211_local *local = sdata->local; +- struct ieee802_11_elems elems; ++ struct ieee802_11_elems *elems = NULL; + struct sta_info *sta; + struct ieee80211_tdls_data *tf = (void *)skb->data; + bool local_initiator; +@@ -1718,16 +1718,20 @@ ieee80211_process_tdls_channel_switch_re + goto call_drv; + } + +- ieee802_11_parse_elems(tf->u.chan_switch_resp.variable, +- skb->len - baselen, false, &elems, +- NULL, NULL); +- if (elems.parse_error) { ++ elems = ieee802_11_parse_elems(tf->u.chan_switch_resp.variable, ++ skb->len - baselen, false, NULL, NULL); ++ if (!elems) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ if (elems->parse_error) { + tdls_dbg(sdata, "Invalid IEs in TDLS channel switch resp\n"); + ret = -EINVAL; + goto out; + } + +- if (!elems.ch_sw_timing || !elems.lnk_id) { ++ if (!elems->ch_sw_timing || !elems->lnk_id) { + tdls_dbg(sdata, "TDLS channel switch resp - missing IEs\n"); + ret = -EINVAL; + goto out; +@@ -1735,15 +1739,15 @@ ieee80211_process_tdls_channel_switch_re + + /* validate the initiator is set correctly */ + local_initiator = +- !memcmp(elems.lnk_id->init_sta, sdata->vif.addr, ETH_ALEN); ++ !memcmp(elems->lnk_id->init_sta, sdata->vif.addr, ETH_ALEN); + if (local_initiator == sta->sta.tdls_initiator) { + tdls_dbg(sdata, "TDLS chan switch invalid lnk-id initiator\n"); + ret = -EINVAL; + goto out; + } + +- params.switch_time = le16_to_cpu(elems.ch_sw_timing->switch_time); +- params.switch_timeout = le16_to_cpu(elems.ch_sw_timing->switch_timeout); ++ params.switch_time = le16_to_cpu(elems->ch_sw_timing->switch_time); ++ params.switch_timeout = le16_to_cpu(elems->ch_sw_timing->switch_timeout); + + params.tmpl_skb = + ieee80211_tdls_ch_sw_resp_tmpl_get(sta, ¶ms.ch_sw_tm_ie); +@@ -1763,6 +1767,7 @@ call_drv: + out: + mutex_unlock(&local->sta_mtx); + dev_kfree_skb_any(params.tmpl_skb); ++ kfree(elems); + return ret; + } + +@@ -1771,7 +1776,7 @@ ieee80211_process_tdls_channel_switch_re + struct sk_buff *skb) + { + struct ieee80211_local *local = sdata->local; +- struct ieee802_11_elems elems; ++ struct ieee802_11_elems *elems; + struct cfg80211_chan_def chandef; + struct ieee80211_channel *chan; + enum nl80211_channel_type chan_type; +@@ -1831,22 +1836,27 @@ ieee80211_process_tdls_channel_switch_re + return -EINVAL; + } + +- ieee802_11_parse_elems(tf->u.chan_switch_req.variable, +- skb->len - baselen, false, &elems, NULL, NULL); +- if (elems.parse_error) { ++ elems = ieee802_11_parse_elems(tf->u.chan_switch_req.variable, ++ skb->len - baselen, false, NULL, NULL); ++ if (!elems) ++ return -ENOMEM; ++ ++ if (elems->parse_error) { + tdls_dbg(sdata, "Invalid IEs in TDLS channel switch req\n"); +- return -EINVAL; ++ ret = -EINVAL; ++ goto free; + } + +- if (!elems.ch_sw_timing || !elems.lnk_id) { ++ if (!elems->ch_sw_timing || !elems->lnk_id) { + tdls_dbg(sdata, "TDLS channel switch req - missing IEs\n"); +- return -EINVAL; ++ ret = -EINVAL; ++ goto free; + } + +- if (!elems.sec_chan_offs) { ++ if (!elems->sec_chan_offs) { + chan_type = NL80211_CHAN_HT20; + } else { +- switch (elems.sec_chan_offs->sec_chan_offs) { ++ switch (elems->sec_chan_offs->sec_chan_offs) { + case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: + chan_type = NL80211_CHAN_HT40PLUS; + break; +@@ -1865,7 +1875,8 @@ ieee80211_process_tdls_channel_switch_re + if (!cfg80211_reg_can_beacon_relax(sdata->local->hw.wiphy, &chandef, + sdata->wdev.iftype)) { + tdls_dbg(sdata, "TDLS chan switch to forbidden channel\n"); +- return -EINVAL; ++ ret = -EINVAL; ++ goto free; + } + + mutex_lock(&local->sta_mtx); +@@ -1881,7 +1892,7 @@ ieee80211_process_tdls_channel_switch_re + + /* validate the initiator is set correctly */ + local_initiator = +- !memcmp(elems.lnk_id->init_sta, sdata->vif.addr, ETH_ALEN); ++ !memcmp(elems->lnk_id->init_sta, sdata->vif.addr, ETH_ALEN); + if (local_initiator == sta->sta.tdls_initiator) { + tdls_dbg(sdata, "TDLS chan switch invalid lnk-id initiator\n"); + ret = -EINVAL; +@@ -1889,16 +1900,16 @@ ieee80211_process_tdls_channel_switch_re + } + + /* peer should have known better */ +- if (!sta->sta.ht_cap.ht_supported && elems.sec_chan_offs && +- elems.sec_chan_offs->sec_chan_offs) { ++ if (!sta->sta.ht_cap.ht_supported && elems->sec_chan_offs && ++ elems->sec_chan_offs->sec_chan_offs) { + tdls_dbg(sdata, "TDLS chan switch - wide chan unsupported\n"); + ret = -ENOTSUPP; + goto out; + } + + params.chandef = &chandef; +- params.switch_time = le16_to_cpu(elems.ch_sw_timing->switch_time); +- params.switch_timeout = le16_to_cpu(elems.ch_sw_timing->switch_timeout); ++ params.switch_time = le16_to_cpu(elems->ch_sw_timing->switch_time); ++ params.switch_timeout = le16_to_cpu(elems->ch_sw_timing->switch_timeout); + + params.tmpl_skb = + ieee80211_tdls_ch_sw_resp_tmpl_get(sta, +@@ -1917,6 +1928,8 @@ ieee80211_process_tdls_channel_switch_re + out: + mutex_unlock(&local->sta_mtx); + dev_kfree_skb_any(params.tmpl_skb); ++free: ++ kfree(elems); + return ret; + } + +--- a/net/mac80211/util.c ++++ b/net/mac80211/util.c +@@ -1384,8 +1384,8 @@ _ieee802_11_parse_elems_crc(const u8 *st + + static size_t ieee802_11_find_bssid_profile(const u8 *start, size_t len, + struct ieee802_11_elems *elems, +- u8 *transmitter_bssid, +- u8 *bss_bssid, ++ const u8 *transmitter_bssid, ++ const u8 *bss_bssid, + u8 *nontransmitted_profile) + { + const struct element *elem, *sub; +@@ -1452,16 +1452,20 @@ static size_t ieee802_11_find_bssid_prof + return found ? profile_len : 0; + } + +-void ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, +- struct ieee802_11_elems *elems, +- u64 filter, u32 crc, u8 *transmitter_bssid, +- u8 *bss_bssid) ++struct ieee802_11_elems *ieee802_11_parse_elems_crc(const u8 *start, size_t len, ++ bool action, u64 filter, ++ u32 crc, ++ const u8 *transmitter_bssid, ++ const u8 *bss_bssid) + { ++ struct ieee802_11_elems *elems; + const struct element *non_inherit = NULL; + u8 *nontransmitted_profile; + int nontransmitted_profile_len = 0; + +- memset(elems, 0, sizeof(*elems)); ++ elems = kzalloc(sizeof(*elems), GFP_ATOMIC); ++ if (!elems) ++ return NULL; + elems->ie_start = start; + elems->total_len = len; + +@@ -1508,6 +1512,8 @@ void ieee802_11_parse_elems_crc(const u8 + kfree(nontransmitted_profile); + + elems->crc = crc; ++ ++ return elems; + } + + void ieee80211_regulatory_limit_wmm_params(struct ieee80211_sub_if_data *sdata, diff --git a/patches.suse/mac80211-fix-memory-leaks-with-element-parsing.patch b/patches.suse/mac80211-fix-memory-leaks-with-element-parsing.patch new file mode 100644 index 0000000..bbdb09d --- /dev/null +++ b/patches.suse/mac80211-fix-memory-leaks-with-element-parsing.patch @@ -0,0 +1,130 @@ +From 8223ac199a3849257e86ec27865dc63f034b1cf1 Mon Sep 17 00:00:00 2001 +From: Johannes Berg +Date: Fri, 1 Oct 2021 21:11:08 +0200 +Subject: [PATCH] mac80211: fix memory leaks with element parsing +Git-commit: 8223ac199a3849257e86ec27865dc63f034b1cf1 +Patch-mainline: v5.16-rc1 +References: CVE-2022-42719 bsc#1204051 + +My previous commit 5d24828d05f3 ("mac80211: always allocate +struct ieee802_11_elems") had a few bugs and leaked the new +allocated struct in a few error cases, fix that. + +Fixes: 5d24828d05f3 ("mac80211: always allocate struct ieee802_11_elems") +Signed-off-by: Johannes Berg +Link: https://lore.kernel.org/r/20211001211108.9839928e42e0.Ib81ca187d3d3af7ed1bfeac2e00d08a4637c8025@changeid +Acked-by: Takashi Iwai + +--- + net/mac80211/agg-rx.c | 3 ++- + net/mac80211/ibss.c | 10 +++++----- + net/mac80211/mlme.c | 36 ++++++++++++++++++------------------ + 3 files changed, 25 insertions(+), 24 deletions(-) + +diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c +index 94c65def102c..470ff0ce3dc7 100644 +--- a/net/mac80211/agg-rx.c ++++ b/net/mac80211/agg-rx.c +@@ -498,13 +498,14 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, + elems = ieee802_11_parse_elems(mgmt->u.action.u.addba_req.variable, + ies_len, true, mgmt->bssid, NULL); + if (!elems || elems->parse_error) +- return; ++ goto free; + } + + __ieee80211_start_rx_ba_session(sta, dialog_token, timeout, + start_seq_num, ba_policy, tid, + buf_size, true, false, + elems ? elems->addba_ext_ie : NULL); ++free: + kfree(elems); + } + +diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c +index 66b00046f0c2..0416c4d22292 100644 +--- a/net/mac80211/ibss.c ++++ b/net/mac80211/ibss.c +@@ -1659,11 +1659,11 @@ void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, + mgmt->u.action.u.chan_switch.variable, + ies_len, true, mgmt->bssid, NULL); + +- if (!elems || elems->parse_error) +- break; +- +- ieee80211_rx_mgmt_spectrum_mgmt(sdata, mgmt, skb->len, +- rx_status, elems); ++ if (elems && !elems->parse_error) ++ ieee80211_rx_mgmt_spectrum_mgmt(sdata, mgmt, ++ skb->len, ++ rx_status, ++ elems); + kfree(elems); + break; + } +diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c +index 0ec183a92a01..40b29cfb7cfe 100644 +--- a/net/mac80211/mlme.c ++++ b/net/mac80211/mlme.c +@@ -3353,8 +3353,10 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, + bss_ies = kmemdup(ies, sizeof(*ies) + ies->len, + GFP_ATOMIC); + rcu_read_unlock(); +- if (!bss_ies) +- return false; ++ if (!bss_ies) { ++ ret = false; ++ goto out; ++ } + + bss_elems = ieee802_11_parse_elems(bss_ies->data, bss_ies->len, + false, mgmt->bssid, +@@ -4331,13 +4333,11 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, + mgmt->u.action.u.chan_switch.variable, + ies_len, true, mgmt->bssid, NULL); + +- if (!elems || elems->parse_error) +- break; +- +- ieee80211_sta_process_chanswitch(sdata, +- rx_status->mactime, +- rx_status->device_timestamp, +- elems, false); ++ if (elems && !elems->parse_error) ++ ieee80211_sta_process_chanswitch(sdata, ++ rx_status->mactime, ++ rx_status->device_timestamp, ++ elems, false); + kfree(elems); + } else if (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) { + struct ieee802_11_elems *elems; +@@ -4357,17 +4357,17 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, + mgmt->u.action.u.ext_chan_switch.variable, + ies_len, true, mgmt->bssid, NULL); + +- if (!elems || elems->parse_error) +- break; ++ if (elems && !elems->parse_error) { ++ /* for the handling code pretend it was an IE */ ++ elems->ext_chansw_ie = ++ &mgmt->u.action.u.ext_chan_switch.data; + +- /* for the handling code pretend this was also an IE */ +- elems->ext_chansw_ie = +- &mgmt->u.action.u.ext_chan_switch.data; ++ ieee80211_sta_process_chanswitch(sdata, ++ rx_status->mactime, ++ rx_status->device_timestamp, ++ elems, false); ++ } + +- ieee80211_sta_process_chanswitch(sdata, +- rx_status->mactime, +- rx_status->device_timestamp, +- elems, false); + kfree(elems); + } + break; +-- +2.35.3 + diff --git a/patches.suse/mac80211-mlme-find-auth-challenge-directly.patch b/patches.suse/mac80211-mlme-find-auth-challenge-directly.patch new file mode 100644 index 0000000..27cd0bd --- /dev/null +++ b/patches.suse/mac80211-mlme-find-auth-challenge-directly.patch @@ -0,0 +1,97 @@ +From 49a765d6785e99157ff5091cc37485732496864e Mon Sep 17 00:00:00 2001 +From: Johannes Berg +Date: Mon, 20 Sep 2021 15:40:09 +0200 +Subject: [PATCH] mac80211: mlme: find auth challenge directly +Git-commit: 49a765d6785e99157ff5091cc37485732496864e +Patch-mainline: v5.16-rc1 +References: CVE-2022-42719 bsc#1204051 + +There's no need to parse all elements etc. just to find the +authentication challenge - use cfg80211_find_elem() instead. +This also allows us to remove WLAN_EID_CHALLENGE handling +from the element parsing entirely. + +Link: https://lore.kernel.org/r/20210920154009.45f9b3a15722.Ice3159ffad03a007d6154cbf1fb3a8c48489e86f@changeid +Signed-off-by: Johannes Berg +Acked-by: Takashi Iwai + +--- + net/mac80211/ieee80211_i.h | 2 -- + net/mac80211/mlme.c | 11 ++++++----- + net/mac80211/util.c | 4 ---- + 3 files changed, 6 insertions(+), 11 deletions(-) + +diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h +index 6a129a08bc9b..7a9e529f8366 100644 +--- a/net/mac80211/ieee80211_i.h ++++ b/net/mac80211/ieee80211_i.h +@@ -1517,7 +1517,6 @@ struct ieee802_11_elems { + const u8 *supp_rates; + const u8 *ds_params; + const struct ieee80211_tim_ie *tim; +- const u8 *challenge; + const u8 *rsn; + const u8 *rsnx; + const u8 *erp_info; +@@ -1571,7 +1570,6 @@ struct ieee802_11_elems { + u8 ssid_len; + u8 supp_rates_len; + u8 tim_len; +- u8 challenge_len; + u8 rsn_len; + u8 rsnx_len; + u8 ext_supp_rates_len; +diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c +index 39b3ed89e0da..e18bd07f6822 100644 +--- a/net/mac80211/mlme.c ++++ b/net/mac80211/mlme.c +@@ -2870,17 +2870,17 @@ static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata, + { + struct ieee80211_local *local = sdata->local; + struct ieee80211_mgd_auth_data *auth_data = sdata->u.mgd.auth_data; ++ const struct element *challenge; + u8 *pos; +- struct ieee802_11_elems elems; + u32 tx_flags = 0; + struct ieee80211_prep_tx_info info = { + .subtype = IEEE80211_STYPE_AUTH, + }; + + pos = mgmt->u.auth.variable; +- ieee802_11_parse_elems(pos, len - (pos - (u8 *)mgmt), false, &elems, +- mgmt->bssid, auth_data->bss->bssid); +- if (!elems.challenge) ++ challenge = cfg80211_find_elem(WLAN_EID_CHALLENGE, pos, ++ len - (pos - (u8 *)mgmt)); ++ if (!challenge) + return; + auth_data->expected_transaction = 4; + drv_mgd_prepare_tx(sdata->local, sdata, &info); +@@ -2888,7 +2888,8 @@ static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata, + tx_flags = IEEE80211_TX_CTL_REQ_TX_STATUS | + IEEE80211_TX_INTFL_MLME_CONN_TX; + ieee80211_send_auth(sdata, 3, auth_data->algorithm, 0, +- elems.challenge - 2, elems.challenge_len + 2, ++ (void *)challenge, ++ challenge->datalen + sizeof(*challenge), + auth_data->bss->bssid, auth_data->bss->bssid, + auth_data->key, auth_data->key_len, + auth_data->key_idx, tx_flags); +diff --git a/net/mac80211/util.c b/net/mac80211/util.c +index 43ccad8b24c7..dce841228297 100644 +--- a/net/mac80211/util.c ++++ b/net/mac80211/util.c +@@ -1112,10 +1112,6 @@ _ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, + } else + elem_parse_failed = true; + break; +- case WLAN_EID_CHALLENGE: +- elems->challenge = pos; +- elems->challenge_len = elen; +- break; + case WLAN_EID_VENDOR_SPECIFIC: + if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 && + pos[2] == 0xf2) { +-- +2.35.3 + diff --git a/patches.suse/mac80211-move-CRC-into-struct-ieee802_11_elems.patch b/patches.suse/mac80211-move-CRC-into-struct-ieee802_11_elems.patch new file mode 100644 index 0000000..1327441 --- /dev/null +++ b/patches.suse/mac80211-move-CRC-into-struct-ieee802_11_elems.patch @@ -0,0 +1,99 @@ +From c6e37ed498f958254b5459253199e816b6bfc52f Mon Sep 17 00:00:00 2001 +From: Johannes Berg +Date: Mon, 20 Sep 2021 15:40:08 +0200 +Subject: [PATCH] mac80211: move CRC into struct ieee802_11_elems +Git-commit: c6e37ed498f958254b5459253199e816b6bfc52f +Patch-mainline: v5.16-rc1 +References: CVE-2022-42719 bsc#1204051 + +We're currently returning this value, but to prepare for +returning the allocated structure, move it into there. + +Link: https://lore.kernel.org/r/20210920154009.479b8ebf999d.If0d4ba75ee38998dc3eeae25058aa748efcb2fc9@changeid +Signed-off-by: Johannes Berg +Acked-by: Takashi Iwai + +--- + net/mac80211/ieee80211_i.h | 9 +++++---- + net/mac80211/mlme.c | 9 +++++---- + net/mac80211/util.c | 10 +++++----- + 3 files changed, 15 insertions(+), 13 deletions(-) + +diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h +index d74031bb4ae6..6a129a08bc9b 100644 +--- a/net/mac80211/ieee80211_i.h ++++ b/net/mac80211/ieee80211_i.h +@@ -1507,6 +1507,7 @@ struct ieee80211_csa_ie { + struct ieee802_11_elems { + const u8 *ie_start; + size_t total_len; ++ u32 crc; + + /* pointers to IEs */ + const struct ieee80211_tdls_lnkie *lnk_id; +@@ -2193,10 +2194,10 @@ static inline void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, + ieee80211_tx_skb_tid(sdata, skb, 7); + } + +-u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, +- struct ieee802_11_elems *elems, +- u64 filter, u32 crc, u8 *transmitter_bssid, +- u8 *bss_bssid); ++void ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, ++ struct ieee802_11_elems *elems, ++ u64 filter, u32 crc, u8 *transmitter_bssid, ++ u8 *bss_bssid); + static inline void ieee802_11_parse_elems(const u8 *start, size_t len, + bool action, + struct ieee802_11_elems *elems, +diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c +index c0ea3b1aa9e1..39b3ed89e0da 100644 +--- a/net/mac80211/mlme.c ++++ b/net/mac80211/mlme.c +@@ -4070,10 +4070,11 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, + */ + if (!ieee80211_is_s1g_beacon(hdr->frame_control)) + ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4); +- ncrc = ieee802_11_parse_elems_crc(variable, +- len - baselen, false, &elems, +- care_about_ies, ncrc, +- mgmt->bssid, bssid); ++ ieee802_11_parse_elems_crc(variable, ++ len - baselen, false, &elems, ++ care_about_ies, ncrc, ++ mgmt->bssid, bssid); ++ ncrc = elems.crc; + + if (ieee80211_hw_check(&local->hw, PS_NULLFUNC_STACK) && + ieee80211_check_tim(elems.tim, elems.tim_len, bss_conf->aid)) { +diff --git a/net/mac80211/util.c b/net/mac80211/util.c +index 49cb96d25169..43ccad8b24c7 100644 +--- a/net/mac80211/util.c ++++ b/net/mac80211/util.c +@@ -1461,10 +1461,10 @@ static size_t ieee802_11_find_bssid_profile(const u8 *start, size_t len, + return found ? profile_len : 0; + } + +-u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, +- struct ieee802_11_elems *elems, +- u64 filter, u32 crc, u8 *transmitter_bssid, +- u8 *bss_bssid) ++void ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, ++ struct ieee802_11_elems *elems, ++ u64 filter, u32 crc, u8 *transmitter_bssid, ++ u8 *bss_bssid) + { + const struct element *non_inherit = NULL; + u8 *nontransmitted_profile; +@@ -1516,7 +1516,7 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, + + kfree(nontransmitted_profile); + +- return crc; ++ elems->crc = crc; + } + + void ieee80211_regulatory_limit_wmm_params(struct ieee80211_sub_if_data *sdata, +-- +2.35.3 + diff --git a/patches.suse/wifi-cfg80211-avoid-nontransmitted-BSS-list-corrupti.patch b/patches.suse/wifi-cfg80211-avoid-nontransmitted-BSS-list-corrupti.patch new file mode 100644 index 0000000..0530d8e --- /dev/null +++ b/patches.suse/wifi-cfg80211-avoid-nontransmitted-BSS-list-corrupti.patch @@ -0,0 +1,56 @@ +From: Johannes Berg +Date: Sat, 1 Oct 2022 00:01:44 +0200 +Subject: [PATCH] wifi: cfg80211: avoid nontransmitted BSS list corruption +Mime-version: 1.0 +Content-type: text/plain; charset=UTF-8 +Content-transfer-encoding: 8bit +Patch-mainline: Not yet, embargoed +References: CVE-2022-42721 bsc#1204060 + +If a non-transmitted BSS shares enough information (both +SSID and BSSID!) with another non-transmitted BSS of a +different AP, then we can find and update it, and then +try to add it to the non-transmitted BSS list. We do a +search for it on the transmitted BSS, but if it's not +there (but belongs to another transmitted BSS), the list +gets corrupted. + +Since this is an erroneous situation, simply fail the +list insertion in this case and free the non-transmitted +BSS. + +This fixes CVE-2022-42721. + +Reported-by: Sönke Huster +Tested-by: Sönke Huster +Fixes: 0b8fb8235be8 ("cfg80211: Parsing of Multiple BSSID information in scanning") +Signed-off-by: Johannes Berg +Signed-off-by: Takashi Iwai + +--- + net/wireless/scan.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/net/wireless/scan.c b/net/wireless/scan.c +index 94a8679ca388..0c3eca245e3c 100644 +--- a/net/wireless/scan.c ++++ b/net/wireless/scan.c +@@ -421,6 +421,15 @@ cfg80211_add_nontrans_list(struct cfg80211_bss *trans_bss, + + rcu_read_unlock(); + ++ /* ++ * This is a bit weird - it's not on the list, but already on another ++ * one! The only way that could happen is if there's some BSSID/SSID ++ * shared by multiple APs in their multi-BSSID profiles, potentially ++ * with hidden SSID mixed in ... ignore it. ++ */ ++ if (!list_empty(&nontrans_bss->nontrans_list)) ++ return -EINVAL; ++ + /* add to the list */ + list_add_tail(&nontrans_bss->nontrans_list, &trans_bss->nontrans_list); + return 0; +-- +2.35.3 + diff --git a/patches.suse/wifi-cfg80211-fix-BSS-refcounting-bugs.patch b/patches.suse/wifi-cfg80211-fix-BSS-refcounting-bugs.patch new file mode 100644 index 0000000..1caa594 --- /dev/null +++ b/patches.suse/wifi-cfg80211-fix-BSS-refcounting-bugs.patch @@ -0,0 +1,96 @@ +From: Johannes Berg +Date: Fri, 30 Sep 2022 23:44:23 +0200 +Subject: [PATCH] wifi: cfg80211: fix BSS refcounting bugs +Mime-version: 1.0 +Content-type: text/plain; charset=UTF-8 +Content-transfer-encoding: 8bit +Patch-mainline: Not yet, embargoed +References: CVE-2022-42720 bsc#1204059 + +There are multiple refcounting bugs related to multi-BSSID: + - In bss_ref_get(), if the BSS has a hidden_beacon_bss, then + the bss pointer is overwritten before checking for the + transmitted BSS, which is clearly wrong. Fix this by using + the bss_from_pub() macro. + + - In cfg80211_bss_update() we copy the transmitted_bss pointer + from tmp into new, but then if we release new, we'll unref + it erroneously. We already set the pointer and ref it, but + need to NULL it since it was copied from the tmp data. + + - In cfg80211_inform_single_bss_data(), if adding to the non- + transmitted list fails, we unlink the BSS and yet still we + return it, but this results in returning an entry without + a reference. We shouldn't return it anyway if it was broken + enough to not get added there. + +This fixes CVE-2022-42720. + +Reported-by: Sönke Huster +Tested-by: Sönke Huster +Fixes: a3584f56de1c ("cfg80211: Properly track transmitting and non-transmitting BSS") +Signed-off-by: Johannes Berg +Signed-off-by: Takashi Iwai + +--- + net/wireless/scan.c | 27 ++++++++++++++------------- + 1 file changed, 14 insertions(+), 13 deletions(-) + +diff --git a/net/wireless/scan.c b/net/wireless/scan.c +index 5382fc2003db..94a8679ca388 100644 +--- a/net/wireless/scan.c ++++ b/net/wireless/scan.c +@@ -143,18 +143,12 @@ static inline void bss_ref_get(struct cfg80211_registered_device *rdev, + lockdep_assert_held(&rdev->bss_lock); + + bss->refcount++; +- if (bss->pub.hidden_beacon_bss) { +- bss = container_of(bss->pub.hidden_beacon_bss, +- struct cfg80211_internal_bss, +- pub); +- bss->refcount++; +- } +- if (bss->pub.transmitted_bss) { +- bss = container_of(bss->pub.transmitted_bss, +- struct cfg80211_internal_bss, +- pub); +- bss->refcount++; +- } ++ ++ if (bss->pub.hidden_beacon_bss) ++ bss_from_pub(bss->pub.hidden_beacon_bss)->refcount++; ++ ++ if (bss->pub.transmitted_bss) ++ bss_from_pub(bss->pub.transmitted_bss)->refcount++; + } + + static inline void bss_ref_put(struct cfg80211_registered_device *rdev, +@@ -1739,6 +1733,8 @@ cfg80211_bss_update(struct cfg80211_registered_device *rdev, + new->refcount = 1; + INIT_LIST_HEAD(&new->hidden_list); + INIT_LIST_HEAD(&new->pub.nontrans_list); ++ /* we'll set this later if it was non-NULL */ ++ new->pub.transmitted_bss = NULL; + + if (rcu_access_pointer(tmp->pub.proberesp_ies)) { + hidden = rb_find_bss(rdev, tmp, BSS_CMP_HIDE_ZLEN); +@@ -2021,10 +2017,15 @@ cfg80211_inform_single_bss_data(struct wiphy *wiphy, + spin_lock_bh(&rdev->bss_lock); + if (cfg80211_add_nontrans_list(non_tx_data->tx_bss, + &res->pub)) { +- if (__cfg80211_unlink_bss(rdev, res)) ++ if (__cfg80211_unlink_bss(rdev, res)) { + rdev->bss_generation++; ++ res = NULL; ++ } + } + spin_unlock_bh(&rdev->bss_lock); ++ ++ if (!res) ++ return NULL; + } + + trace_cfg80211_return_bss(&res->pub); +-- +2.35.3 + diff --git a/patches.suse/wifi-mac80211-fix-MBSSID-parsing-use-after-free.patch b/patches.suse/wifi-mac80211-fix-MBSSID-parsing-use-after-free.patch new file mode 100644 index 0000000..bd1a4a0 --- /dev/null +++ b/patches.suse/wifi-mac80211-fix-MBSSID-parsing-use-after-free.patch @@ -0,0 +1,103 @@ +From: Johannes Berg +Date: Wed, 28 Sep 2022 22:07:15 +0200 +Subject: [PATCH 3/9] wifi: mac80211: fix MBSSID parsing use-after-free +Patch-mainline: Not yet, embargoed +References: CVE-2022-42719 bsc#1204051 + +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 +Signed-off-by: Ilan Peer +Reviewed-by: Kees Cook +Signed-off-by: Johannes Berg +Signed-off-by: Takashi Iwai + +--- + net/mac80211/ieee80211_i.h | 8 ++++++++ + net/mac80211/util.c | 32 ++++++++++++++++---------------- + 2 files changed, 24 insertions(+), 16 deletions(-) + +--- a/net/mac80211/ieee80211_i.h ++++ b/net/mac80211/ieee80211_i.h +@@ -1601,6 +1601,14 @@ struct ieee802_11_elems { + + /* whether a parse error occurred while retrieving these elements */ + bool parse_error; ++ ++ /* ++ * scratch buffer that can be used for various element parsing related ++ * tasks, e.g., element de-fragmentation etc. ++ */ ++ size_t scratch_len; ++ u8 *scratch_pos; ++ u8 scratch[]; + }; + + static inline struct ieee80211_local *hw_to_local( +--- a/net/mac80211/util.c ++++ b/net/mac80211/util.c +@@ -1459,26 +1459,28 @@ ieee802_11_parse_elems_full(struct ieee8 + const struct element *non_inherit = NULL; + u8 *nontransmitted_profile; + int nontransmitted_profile_len = 0; ++ size_t scratch_len = params->len; + +- elems = kzalloc(sizeof(*elems), GFP_ATOMIC); ++ elems = kzalloc(sizeof(*elems) + scratch_len, GFP_ATOMIC); + if (!elems) + return NULL; + elems->ie_start = params->start; + elems->total_len = params->len; ++ elems->scratch_len = scratch_len; ++ elems->scratch_pos = elems->scratch; + +- nontransmitted_profile = kmalloc(params->len, GFP_ATOMIC); +- if (nontransmitted_profile) { +- nontransmitted_profile_len = +- ieee802_11_find_bssid_profile(params->start, params->len, +- elems, +- params->transmitter_bssid, +- params->bss_bssid, +- nontransmitted_profile); +- non_inherit = +- cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE, +- nontransmitted_profile, +- nontransmitted_profile_len); +- } ++ nontransmitted_profile = elems->scratch_pos; ++ nontransmitted_profile_len = ++ ieee802_11_find_bssid_profile(params->start, params->len, ++ elems, ++ params->transmitter_bssid, ++ params->bss_bssid, ++ nontransmitted_profile); ++ elems->scratch_pos += nontransmitted_profile_len; ++ elems->scratch_len -= nontransmitted_profile_len; ++ non_inherit = cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE, ++ nontransmitted_profile, ++ nontransmitted_profile_len); + + elems->crc = _ieee802_11_parse_elems_full(params, elems, non_inherit); + +@@ -1511,8 +1513,6 @@ ieee802_11_parse_elems_full(struct ieee8 + offsetofend(struct ieee80211_bssid_index, dtim_count)) + elems->dtim_count = elems->bssid_index->dtim_count; + +- kfree(nontransmitted_profile); +- + return elems; + } + diff --git a/patches.suse/wifi-mac80211-fix-crash-in-beacon-protection-for-P2P.patch b/patches.suse/wifi-mac80211-fix-crash-in-beacon-protection-for-P2P.patch new file mode 100644 index 0000000..52c2c77 --- /dev/null +++ b/patches.suse/wifi-mac80211-fix-crash-in-beacon-protection-for-P2P.patch @@ -0,0 +1,60 @@ +From: Johannes Berg +Date: Wed, 5 Oct 2022 21:24:10 +0200 +Subject: [PATCH] wifi: mac80211: fix crash in beacon protection for P2P-device +Mime-version: 1.0 +Content-type: text/plain; charset=UTF-8 +Content-transfer-encoding: 8bit +Patch-mainline: Not yet, embargoed +References: CVE-2022-42722 bsc#1204125 + +If beacon protection is active but the beacon cannot be +decrypted or is otherwise malformed, we call the cfg80211 +API to report this to userspace, but that uses a netdev +pointer, which isn't present for P2P-Device. Fix this to +call it only conditionally to ensure cfg80211 won't crash +in the case of P2P-Device. + +This fixes CVE-2022-42722. + +Reported-by: Sönke Huster +Fixes: 9eaf183af741 ("mac80211: Report beacon protection failures to user space") +Signed-off-by: Johannes Berg +Signed-off-by: Takashi Iwai + +--- + net/mac80211/rx.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c +index bd215fe3c796..6001adc0a00e 100644 +--- a/net/mac80211/rx.c ++++ b/net/mac80211/rx.c +@@ -1978,10 +1978,11 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) + + if (mmie_keyidx < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS || + mmie_keyidx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS + +- NUM_DEFAULT_BEACON_KEYS) { +- cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev, +- skb->data, +- skb->len); ++ NUM_DEFAULT_BEACON_KEYS) { ++ if (rx->sdata->dev) ++ cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev, ++ skb->data, ++ skb->len); + return RX_DROP_MONITOR; /* unexpected BIP keyidx */ + } + +@@ -2131,7 +2132,8 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) + /* either the frame has been decrypted or will be dropped */ + status->flag |= RX_FLAG_DECRYPTED; + +- if (unlikely(ieee80211_is_beacon(fc) && result == RX_DROP_UNUSABLE)) ++ if (unlikely(ieee80211_is_beacon(fc) && result == RX_DROP_UNUSABLE && ++ rx->sdata->dev)) + cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev, + skb->data, skb->len); + +-- +2.35.3 + diff --git a/patches.suse/wifi-mac80211-refactor-elements-parsing-with-paramet.patch b/patches.suse/wifi-mac80211-refactor-elements-parsing-with-paramet.patch new file mode 100644 index 0000000..030384a --- /dev/null +++ b/patches.suse/wifi-mac80211-refactor-elements-parsing-with-paramet.patch @@ -0,0 +1,221 @@ +From fd17bf041b40e3dac705c4313854becbe07b7557 Mon Sep 17 00:00:00 2001 +From: Johannes Berg +Date: Tue, 28 Jun 2022 17:49:12 +0200 +Subject: [PATCH] wifi: mac80211: refactor elements parsing with parameter struct +Git-commit: fd17bf041b40e3dac705c4313854becbe07b7557 +Patch-mainline: v6.0-rc1 +References: CVE-2022-42719 bsc#1204051 + +Refactor the element parsing into a version that has +a parameter struct so we can add more parameters more +easily in the future. + +Signed-off-by: Johannes Berg +Acked-by: Takashi Iwai + +--- + net/mac80211/ieee80211_i.h | 50 ++++++++++++++++++++++++++++---- + net/mac80211/util.c | 58 +++++++++++++++++++------------------- + 2 files changed, 74 insertions(+), 34 deletions(-) + +diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h +index a0743c78d171..2cf13ea4c9f7 100644 +--- a/net/mac80211/ieee80211_i.h ++++ b/net/mac80211/ieee80211_i.h +@@ -2138,11 +2138,51 @@ static inline void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, + ieee80211_tx_skb_tid(sdata, skb, 7); + } + +-struct ieee802_11_elems *ieee802_11_parse_elems_crc(const u8 *start, size_t len, +- bool action, +- u64 filter, u32 crc, +- const u8 *transmitter_bssid, +- const u8 *bss_bssid); ++/** ++ * struct ieee80211_elems_parse_params - element parsing parameters ++ * @start: pointer to the elements ++ * @len: length of the elements ++ * @action: %true if the elements came from an action frame ++ * @filter: bitmap of element IDs to filter out while calculating ++ * the element CRC ++ * @crc: CRC starting value ++ * @transmitter_bssid: transmitter BSSID to parse the multi-BSSID ++ * element ++ * @bss_bssid: BSSID of the BSS we want to obtain elements for ++ * when parsing the multi-BSSID element ++ */ ++struct ieee80211_elems_parse_params { ++ const u8 *start; ++ size_t len; ++ bool action; ++ u64 filter; ++ u32 crc; ++ const u8 *transmitter_bssid; ++ const u8 *bss_bssid; ++}; ++ ++struct ieee802_11_elems * ++ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params); ++ ++static inline struct ieee802_11_elems * ++ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, ++ u64 filter, u32 crc, ++ const u8 *transmitter_bssid, ++ const u8 *bss_bssid) ++{ ++ struct ieee80211_elems_parse_params params = { ++ .start = start, ++ .len = len, ++ .action = action, ++ .filter = filter, ++ .crc = crc, ++ .transmitter_bssid = transmitter_bssid, ++ .bss_bssid = bss_bssid, ++ }; ++ ++ return ieee802_11_parse_elems_full(¶ms); ++} ++ + static inline struct ieee802_11_elems * + ieee802_11_parse_elems(const u8 *start, size_t len, bool action, + const u8 *transmitter_bssid, +diff --git a/net/mac80211/util.c b/net/mac80211/util.c +index 2b2c8e1472f3..0ff09c639c50 100644 +--- a/net/mac80211/util.c ++++ b/net/mac80211/util.c +@@ -1026,19 +1026,19 @@ static void ieee80211_parse_extension_element(u32 *crc, + } + + static u32 +-_ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, +- struct ieee802_11_elems *elems, +- u64 filter, u32 crc, +- const struct element *check_inherit) ++_ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params, ++ struct ieee802_11_elems *elems, ++ const struct element *check_inherit) + { + const struct element *elem; +- bool calc_crc = filter != 0; ++ bool calc_crc = params->filter != 0; + DECLARE_BITMAP(seen_elems, 256); ++ u32 crc = params->crc; + const u8 *ie; + + bitmap_zero(seen_elems, 256); + +- for_each_element(elem, start, len) { ++ for_each_element(elem, params->start, params->len) { + bool elem_parse_failed; + u8 id = elem->id; + u8 elen = elem->datalen; +@@ -1101,7 +1101,7 @@ _ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, + break; + } + +- if (calc_crc && id < 64 && (filter & (1ULL << id))) ++ if (calc_crc && id < 64 && (params->filter & (1ULL << id))) + crc = crc32_be(crc, pos - 2, elen + 2); + + elem_parse_failed = false; +@@ -1282,7 +1282,7 @@ _ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, + elems->mesh_chansw_params_ie = (void *)pos; + break; + case WLAN_EID_WIDE_BW_CHANNEL_SWITCH: +- if (!action || ++ if (!params->action || + elen < sizeof(*elems->wide_bw_chansw_ie)) { + elem_parse_failed = true; + break; +@@ -1290,7 +1290,7 @@ _ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, + elems->wide_bw_chansw_ie = (void *)pos; + break; + case WLAN_EID_CHANNEL_SWITCH_WRAPPER: +- if (action) { ++ if (params->action) { + elem_parse_failed = true; + break; + } +@@ -1417,7 +1417,7 @@ _ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, + __set_bit(id, seen_elems); + } + +- if (!for_each_element_completed(elem, start, len)) ++ if (!for_each_element_completed(elem, params->start, params->len)) + elems->parse_error = true; + + return crc; +@@ -1491,11 +1491,8 @@ static size_t ieee802_11_find_bssid_profile(const u8 *start, size_t len, + return found ? profile_len : 0; + } + +-struct ieee802_11_elems *ieee802_11_parse_elems_crc(const u8 *start, size_t len, +- bool action, u64 filter, +- u32 crc, +- const u8 *transmitter_bssid, +- const u8 *bss_bssid) ++struct ieee802_11_elems * ++ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params) + { + struct ieee802_11_elems *elems; + const struct element *non_inherit = NULL; +@@ -1505,15 +1502,16 @@ struct ieee802_11_elems *ieee802_11_parse_elems_crc(const u8 *start, size_t len, + elems = kzalloc(sizeof(*elems), GFP_ATOMIC); + if (!elems) + return NULL; +- elems->ie_start = start; +- elems->total_len = len; ++ elems->ie_start = params->start; ++ elems->total_len = params->len; + +- nontransmitted_profile = kmalloc(len, GFP_ATOMIC); ++ nontransmitted_profile = kmalloc(params->len, GFP_ATOMIC); + if (nontransmitted_profile) { + nontransmitted_profile_len = +- ieee802_11_find_bssid_profile(start, len, elems, +- transmitter_bssid, +- bss_bssid, ++ ieee802_11_find_bssid_profile(params->start, params->len, ++ elems, ++ params->transmitter_bssid, ++ params->bss_bssid, + nontransmitted_profile); + non_inherit = + cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE, +@@ -1521,14 +1519,18 @@ struct ieee802_11_elems *ieee802_11_parse_elems_crc(const u8 *start, size_t len, + nontransmitted_profile_len); + } + +- crc = _ieee802_11_parse_elems_crc(start, len, action, elems, filter, +- crc, non_inherit); ++ elems->crc = _ieee802_11_parse_elems_full(params, elems, non_inherit); + + /* Override with nontransmitted profile, if found */ +- if (nontransmitted_profile_len) +- _ieee802_11_parse_elems_crc(nontransmitted_profile, +- nontransmitted_profile_len, +- action, elems, 0, 0, NULL); ++ if (nontransmitted_profile_len) { ++ struct ieee80211_elems_parse_params sub = { ++ .start = nontransmitted_profile, ++ .len = nontransmitted_profile_len, ++ .action = params->action, ++ }; ++ ++ _ieee802_11_parse_elems_full(&sub, elems, NULL); ++ } + + if (elems->tim && !elems->parse_error) { + const struct ieee80211_tim_ie *tim_ie = elems->tim; +@@ -1550,8 +1552,6 @@ struct ieee802_11_elems *ieee802_11_parse_elems_crc(const u8 *start, size_t len, + + kfree(nontransmitted_profile); + +- elems->crc = crc; +- + return elems; + } + +-- +2.35.3 + diff --git a/series.conf b/series.conf index cf4ba93..78391c5 100644 --- a/series.conf +++ b/series.conf @@ -5488,7 +5488,11 @@ patches.suse/net-stats-Read-the-statistics-in-___gnet_stats_copy_.patch patches.suse/ice-Nuild-fix.patch patches.suse/mlx5-fix-build-after-merge.patch + patches.suse/mac80211-move-CRC-into-struct-ieee802_11_elems.patch + patches.suse/mac80211-mlme-find-auth-challenge-directly.patch + patches.suse/mac80211-always-allocate-struct-ieee802_11_elems.patch patches.suse/cfg80211-always-free-wiphy-specific-regdomain.patch + patches.suse/mac80211-fix-memory-leaks-with-element-parsing.patch patches.suse/b43legacy-fix-a-lower-bounds-test.patch patches.suse/b43-fix-a-lower-bounds-test.patch patches.suse/rtw89-add-Realtek-802.11ax-driver.patch @@ -13830,6 +13834,7 @@ patches.suse/Bluetooth-btusb-Add-Realtek-RTL8852C-support-ID-0x13-6ad353dfc8ee.patch patches.suse/Bluetooth-hci_bcm-Add-DT-compatible-for-CYW55572.patch patches.suse/wifi-mac80211_hwsim-use-32-bit-skb-cookie.patch + patches.suse/wifi-mac80211-refactor-elements-parsing-with-paramet.patch patches.suse/wifi-mac80211-limit-A-MSDU-subframes-for-client-too.patch patches.suse/mt76-mt76x02u-fix-possible-memory-leak-in-__mt76x02u.patch patches.suse/mt76-mt7615-do-not-update-pm-stats-in-case-of-error.patch @@ -15108,6 +15113,10 @@ patches.suse/wifi-cfg80211-fix-u8-overflow-in-cfg80211_update_not.patch patches.suse/wifi-cfg80211-mac80211-reject-bad-MBSSID-elements.patch patches.suse/wifi-cfg80211-ensure-length-byte-is-present-before-a.patch + patches.suse/wifi-cfg80211-fix-BSS-refcounting-bugs.patch + patches.suse/wifi-cfg80211-avoid-nontransmitted-BSS-list-corrupti.patch + patches.suse/wifi-mac80211-fix-MBSSID-parsing-use-after-free.patch + patches.suse/wifi-mac80211-fix-crash-in-beacon-protection-for-P2P.patch ######################################################## # BPF