Mirror only - Please move to https://github.com/immortalwrt/immortalwrt
修订版 | bd2dc958ad68a345410ff05bc55884fa35367708 (tree) |
---|---|
时间 | 2022-10-13 23:24:11 |
作者 | Felix Fietkau <nbd@nbd....> |
Commiter | Tianling Shen |
mac80211: backport security fixes
This mainly affects scanning and beacon parsing, especially with MBSSID enabled
Fixes: CVE-2022-41674
Fixes: CVE-2022-42719
Fixes: CVE-2022-42720
Fixes: CVE-2022-42721
Fixes: CVE-2022-42722
Signed-off-by: Felix Fietkau <nbd@nbd.name>
(cherry picked from commit 26f400210d6b3780fcc0deb89b9741837df9c8b8)
@@ -0,0 +1,110 @@ | ||
1 | +From: Johannes Berg <johannes.berg@intel.com> | |
2 | +Date: Mon, 20 Sep 2021 15:40:07 +0200 | |
3 | +Subject: [PATCH] mac80211: mesh: clean up rx_bcn_presp API | |
4 | + | |
5 | +commit a5b983c6073140b624f64e79fea6d33c3e4315a0 upstream. | |
6 | + | |
7 | +We currently pass the entire elements to the rx_bcn_presp() | |
8 | +method, but only need mesh_config. Additionally, we use the | |
9 | +length of the elements to calculate back the entire frame's | |
10 | +length, but that's confusing - just pass the length of the | |
11 | +frame instead. | |
12 | + | |
13 | +Link: https://lore.kernel.org/r/20210920154009.a18ed3d2da6c.I1824b773a0fbae4453e1433c184678ca14e8df45@changeid | |
14 | +Signed-off-by: Johannes Berg <johannes.berg@intel.com> | |
15 | +--- | |
16 | + | |
17 | +--- a/net/mac80211/ieee80211_i.h | |
18 | ++++ b/net/mac80211/ieee80211_i.h | |
19 | +@@ -645,10 +645,9 @@ struct ieee80211_if_ocb { | |
20 | + */ | |
21 | + struct ieee802_11_elems; | |
22 | + struct ieee80211_mesh_sync_ops { | |
23 | +- void (*rx_bcn_presp)(struct ieee80211_sub_if_data *sdata, | |
24 | +- u16 stype, | |
25 | +- struct ieee80211_mgmt *mgmt, | |
26 | +- struct ieee802_11_elems *elems, | |
27 | ++ void (*rx_bcn_presp)(struct ieee80211_sub_if_data *sdata, u16 stype, | |
28 | ++ struct ieee80211_mgmt *mgmt, unsigned int len, | |
29 | ++ const struct ieee80211_meshconf_ie *mesh_cfg, | |
30 | + struct ieee80211_rx_status *rx_status); | |
31 | + | |
32 | + /* should be called with beacon_data under RCU read lock */ | |
33 | +--- a/net/mac80211/mesh.c | |
34 | ++++ b/net/mac80211/mesh.c | |
35 | +@@ -1354,8 +1354,8 @@ static void ieee80211_mesh_rx_bcn_presp( | |
36 | + } | |
37 | + | |
38 | + if (ifmsh->sync_ops) | |
39 | +- ifmsh->sync_ops->rx_bcn_presp(sdata, | |
40 | +- stype, mgmt, &elems, rx_status); | |
41 | ++ ifmsh->sync_ops->rx_bcn_presp(sdata, stype, mgmt, len, | |
42 | ++ elems.mesh_config, rx_status); | |
43 | + } | |
44 | + | |
45 | + int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata) | |
46 | +--- a/net/mac80211/mesh_sync.c | |
47 | ++++ b/net/mac80211/mesh_sync.c | |
48 | +@@ -3,6 +3,7 @@ | |
49 | + * Copyright 2011-2012, Pavel Zubarev <pavel.zubarev@gmail.com> | |
50 | + * Copyright 2011-2012, Marco Porsch <marco.porsch@s2005.tu-chemnitz.de> | |
51 | + * Copyright 2011-2012, cozybit Inc. | |
52 | ++ * Copyright (C) 2021 Intel Corporation | |
53 | + */ | |
54 | + | |
55 | + #include "ieee80211_i.h" | |
56 | +@@ -35,12 +36,12 @@ struct sync_method { | |
57 | + /** | |
58 | + * mesh_peer_tbtt_adjusting - check if an mp is currently adjusting its TBTT | |
59 | + * | |
60 | +- * @ie: information elements of a management frame from the mesh peer | |
61 | ++ * @cfg: mesh config element from the mesh peer (or %NULL) | |
62 | + */ | |
63 | +-static bool mesh_peer_tbtt_adjusting(struct ieee802_11_elems *ie) | |
64 | ++static bool mesh_peer_tbtt_adjusting(const struct ieee80211_meshconf_ie *cfg) | |
65 | + { | |
66 | +- return (ie->mesh_config->meshconf_cap & | |
67 | +- IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING) != 0; | |
68 | ++ return cfg && | |
69 | ++ (cfg->meshconf_cap & IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING); | |
70 | + } | |
71 | + | |
72 | + void mesh_sync_adjust_tsf(struct ieee80211_sub_if_data *sdata) | |
73 | +@@ -76,11 +77,11 @@ void mesh_sync_adjust_tsf(struct ieee802 | |
74 | + } | |
75 | + } | |
76 | + | |
77 | +-static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, | |
78 | +- u16 stype, | |
79 | +- struct ieee80211_mgmt *mgmt, | |
80 | +- struct ieee802_11_elems *elems, | |
81 | +- struct ieee80211_rx_status *rx_status) | |
82 | ++static void | |
83 | ++mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, u16 stype, | |
84 | ++ struct ieee80211_mgmt *mgmt, unsigned int len, | |
85 | ++ const struct ieee80211_meshconf_ie *mesh_cfg, | |
86 | ++ struct ieee80211_rx_status *rx_status) | |
87 | + { | |
88 | + struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | |
89 | + struct ieee80211_local *local = sdata->local; | |
90 | +@@ -101,10 +102,7 @@ static void mesh_sync_offset_rx_bcn_pres | |
91 | + */ | |
92 | + if (ieee80211_have_rx_timestamp(rx_status)) | |
93 | + t_r = ieee80211_calculate_rx_timestamp(local, rx_status, | |
94 | +- 24 + 12 + | |
95 | +- elems->total_len + | |
96 | +- FCS_LEN, | |
97 | +- 24); | |
98 | ++ len + FCS_LEN, 24); | |
99 | + else | |
100 | + t_r = drv_get_tsf(local, sdata); | |
101 | + | |
102 | +@@ -119,7 +117,7 @@ static void mesh_sync_offset_rx_bcn_pres | |
103 | + * dot11MeshNbrOffsetMaxNeighbor non-peer non-MBSS neighbors | |
104 | + */ | |
105 | + | |
106 | +- if (elems->mesh_config && mesh_peer_tbtt_adjusting(elems)) { | |
107 | ++ if (mesh_peer_tbtt_adjusting(mesh_cfg)) { | |
108 | + msync_dbg(sdata, "STA %pM : is adjusting TBTT\n", | |
109 | + sta->sta.addr); | |
110 | + goto no_sync; |
@@ -0,0 +1,82 @@ | ||
1 | +From: Johannes Berg <johannes.berg@intel.com> | |
2 | +Date: Mon, 20 Sep 2021 15:40:08 +0200 | |
3 | +Subject: [PATCH] mac80211: move CRC into struct ieee802_11_elems | |
4 | + | |
5 | +commit c6e37ed498f958254b5459253199e816b6bfc52f upstream. | |
6 | + | |
7 | +We're currently returning this value, but to prepare for | |
8 | +returning the allocated structure, move it into there. | |
9 | + | |
10 | +Link: https://lore.kernel.org/r/20210920154009.479b8ebf999d.If0d4ba75ee38998dc3eeae25058aa748efcb2fc9@changeid | |
11 | +Signed-off-by: Johannes Berg <johannes.berg@intel.com> | |
12 | +--- | |
13 | + | |
14 | +--- a/net/mac80211/ieee80211_i.h | |
15 | ++++ b/net/mac80211/ieee80211_i.h | |
16 | +@@ -1530,6 +1530,7 @@ struct ieee80211_csa_ie { | |
17 | + struct ieee802_11_elems { | |
18 | + const u8 *ie_start; | |
19 | + size_t total_len; | |
20 | ++ u32 crc; | |
21 | + | |
22 | + /* pointers to IEs */ | |
23 | + const struct ieee80211_tdls_lnkie *lnk_id; | |
24 | +@@ -2089,10 +2090,10 @@ static inline void ieee80211_tx_skb(stru | |
25 | + ieee80211_tx_skb_tid(sdata, skb, 7); | |
26 | + } | |
27 | + | |
28 | +-u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, | |
29 | +- struct ieee802_11_elems *elems, | |
30 | +- u64 filter, u32 crc, u8 *transmitter_bssid, | |
31 | +- u8 *bss_bssid); | |
32 | ++void ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, | |
33 | ++ struct ieee802_11_elems *elems, | |
34 | ++ u64 filter, u32 crc, u8 *transmitter_bssid, | |
35 | ++ u8 *bss_bssid); | |
36 | + static inline void ieee802_11_parse_elems(const u8 *start, size_t len, | |
37 | + bool action, | |
38 | + struct ieee802_11_elems *elems, | |
39 | +--- a/net/mac80211/mlme.c | |
40 | ++++ b/net/mac80211/mlme.c | |
41 | +@@ -4102,10 +4102,11 @@ static void ieee80211_rx_mgmt_beacon(str | |
42 | + */ | |
43 | + if (!ieee80211_is_s1g_beacon(hdr->frame_control)) | |
44 | + ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4); | |
45 | +- ncrc = ieee802_11_parse_elems_crc(variable, | |
46 | +- len - baselen, false, &elems, | |
47 | +- care_about_ies, ncrc, | |
48 | +- mgmt->bssid, bssid); | |
49 | ++ ieee802_11_parse_elems_crc(variable, | |
50 | ++ len - baselen, false, &elems, | |
51 | ++ care_about_ies, ncrc, | |
52 | ++ mgmt->bssid, bssid); | |
53 | ++ ncrc = elems.crc; | |
54 | + | |
55 | + if (ieee80211_hw_check(&local->hw, PS_NULLFUNC_STACK) && | |
56 | + ieee80211_check_tim(elems.tim, elems.tim_len, bss_conf->aid)) { | |
57 | +--- a/net/mac80211/util.c | |
58 | ++++ b/net/mac80211/util.c | |
59 | +@@ -1469,10 +1469,10 @@ static size_t ieee802_11_find_bssid_prof | |
60 | + return found ? profile_len : 0; | |
61 | + } | |
62 | + | |
63 | +-u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, | |
64 | +- struct ieee802_11_elems *elems, | |
65 | +- u64 filter, u32 crc, u8 *transmitter_bssid, | |
66 | +- u8 *bss_bssid) | |
67 | ++void ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, | |
68 | ++ struct ieee802_11_elems *elems, | |
69 | ++ u64 filter, u32 crc, u8 *transmitter_bssid, | |
70 | ++ u8 *bss_bssid) | |
71 | + { | |
72 | + const struct element *non_inherit = NULL; | |
73 | + u8 *nontransmitted_profile; | |
74 | +@@ -1524,7 +1524,7 @@ u32 ieee802_11_parse_elems_crc(const u8 | |
75 | + | |
76 | + kfree(nontransmitted_profile); | |
77 | + | |
78 | +- return crc; | |
79 | ++ elems->crc = crc; | |
80 | + } | |
81 | + | |
82 | + void ieee80211_regulatory_limit_wmm_params(struct ieee80211_sub_if_data *sdata, |
@@ -0,0 +1,80 @@ | ||
1 | +From: Johannes Berg <johannes.berg@intel.com> | |
2 | +Date: Mon, 20 Sep 2021 15:40:09 +0200 | |
3 | +Subject: [PATCH] mac80211: mlme: find auth challenge directly | |
4 | + | |
5 | +commit 49a765d6785e99157ff5091cc37485732496864e upstream. | |
6 | + | |
7 | +There's no need to parse all elements etc. just to find the | |
8 | +authentication challenge - use cfg80211_find_elem() instead. | |
9 | +This also allows us to remove WLAN_EID_CHALLENGE handling | |
10 | +from the element parsing entirely. | |
11 | + | |
12 | +Link: https://lore.kernel.org/r/20210920154009.45f9b3a15722.Ice3159ffad03a007d6154cbf1fb3a8c48489e86f@changeid | |
13 | +Signed-off-by: Johannes Berg <johannes.berg@intel.com> | |
14 | +--- | |
15 | + | |
16 | +--- a/net/mac80211/ieee80211_i.h | |
17 | ++++ b/net/mac80211/ieee80211_i.h | |
18 | +@@ -1540,7 +1540,6 @@ struct ieee802_11_elems { | |
19 | + const u8 *supp_rates; | |
20 | + const u8 *ds_params; | |
21 | + const struct ieee80211_tim_ie *tim; | |
22 | +- const u8 *challenge; | |
23 | + const u8 *rsn; | |
24 | + const u8 *rsnx; | |
25 | + const u8 *erp_info; | |
26 | +@@ -1594,7 +1593,6 @@ struct ieee802_11_elems { | |
27 | + u8 ssid_len; | |
28 | + u8 supp_rates_len; | |
29 | + u8 tim_len; | |
30 | +- u8 challenge_len; | |
31 | + u8 rsn_len; | |
32 | + u8 rsnx_len; | |
33 | + u8 ext_supp_rates_len; | |
34 | +--- a/net/mac80211/mlme.c | |
35 | ++++ b/net/mac80211/mlme.c | |
36 | +@@ -2889,17 +2889,17 @@ static void ieee80211_auth_challenge(str | |
37 | + { | |
38 | + struct ieee80211_local *local = sdata->local; | |
39 | + struct ieee80211_mgd_auth_data *auth_data = sdata->u.mgd.auth_data; | |
40 | ++ const struct element *challenge; | |
41 | + u8 *pos; | |
42 | +- struct ieee802_11_elems elems; | |
43 | + u32 tx_flags = 0; | |
44 | + struct ieee80211_prep_tx_info info = { | |
45 | + .subtype = IEEE80211_STYPE_AUTH, | |
46 | + }; | |
47 | + | |
48 | + pos = mgmt->u.auth.variable; | |
49 | +- ieee802_11_parse_elems(pos, len - (pos - (u8 *)mgmt), false, &elems, | |
50 | +- mgmt->bssid, auth_data->bss->bssid); | |
51 | +- if (!elems.challenge) | |
52 | ++ challenge = cfg80211_find_elem(WLAN_EID_CHALLENGE, pos, | |
53 | ++ len - (pos - (u8 *)mgmt)); | |
54 | ++ if (!challenge) | |
55 | + return; | |
56 | + auth_data->expected_transaction = 4; | |
57 | + drv_mgd_prepare_tx(sdata->local, sdata, &info); | |
58 | +@@ -2907,7 +2907,8 @@ static void ieee80211_auth_challenge(str | |
59 | + tx_flags = IEEE80211_TX_CTL_REQ_TX_STATUS | | |
60 | + IEEE80211_TX_INTFL_MLME_CONN_TX; | |
61 | + ieee80211_send_auth(sdata, 3, auth_data->algorithm, 0, | |
62 | +- elems.challenge - 2, elems.challenge_len + 2, | |
63 | ++ (void *)challenge, | |
64 | ++ challenge->datalen + sizeof(*challenge), | |
65 | + auth_data->bss->bssid, auth_data->bss->bssid, | |
66 | + auth_data->key, auth_data->key_len, | |
67 | + auth_data->key_idx, tx_flags); | |
68 | +--- a/net/mac80211/util.c | |
69 | ++++ b/net/mac80211/util.c | |
70 | +@@ -1120,10 +1120,6 @@ _ieee802_11_parse_elems_crc(const u8 *st | |
71 | + } else | |
72 | + elem_parse_failed = true; | |
73 | + break; | |
74 | +- case WLAN_EID_CHALLENGE: | |
75 | +- elems->challenge = pos; | |
76 | +- elems->challenge_len = elen; | |
77 | +- break; | |
78 | + case WLAN_EID_VENDOR_SPECIFIC: | |
79 | + if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 && | |
80 | + pos[2] == 0xf2) { |
@@ -0,0 +1,1143 @@ | ||
1 | +From: Johannes Berg <johannes.berg@intel.com> | |
2 | +Date: Mon, 20 Sep 2021 15:40:10 +0200 | |
3 | +Subject: [PATCH] mac80211: always allocate struct ieee802_11_elems | |
4 | + | |
5 | +As the 802.11 spec evolves, we need to parse more and more | |
6 | +elements. This is causing the struct to grow, and we can no | |
7 | +longer get away with putting it on the stack. | |
8 | + | |
9 | +Change the API to always dynamically allocate and return an | |
10 | +allocated pointer that must be kfree()d later. | |
11 | + | |
12 | +As an alternative, I contemplated a scheme whereby we'd say | |
13 | +in the code which elements we needed, e.g. | |
14 | + | |
15 | + DECLARE_ELEMENT_PARSER(elems, | |
16 | + SUPPORTED_CHANNELS, | |
17 | + CHANNEL_SWITCH, | |
18 | + EXT(KEY_DELIVERY)); | |
19 | + | |
20 | + ieee802_11_parse_elems(..., &elems, ...); | |
21 | + | |
22 | +and while I think this is possible and will save us a lot | |
23 | +since most individual places only care about a small subset | |
24 | +of the elements, it ended up being a bit more work since a | |
25 | +lot of places do the parsing and then pass the struct to | |
26 | +other functions, sometimes with multiple levels. | |
27 | + | |
28 | +Link: https://lore.kernel.org/r/20210920154009.26caff6b5998.I05ae58768e990e611aee8eca8abefd9d7bc15e05@changeid | |
29 | +Signed-off-by: Johannes Berg <johannes.berg@intel.com> | |
30 | +--- | |
31 | + | |
32 | +--- a/net/mac80211/agg-rx.c | |
33 | ++++ b/net/mac80211/agg-rx.c | |
34 | +@@ -478,7 +478,7 @@ void ieee80211_process_addba_request(str | |
35 | + size_t len) | |
36 | + { | |
37 | + u16 capab, tid, timeout, ba_policy, buf_size, start_seq_num; | |
38 | +- struct ieee802_11_elems elems = { }; | |
39 | ++ struct ieee802_11_elems *elems = NULL; | |
40 | + u8 dialog_token; | |
41 | + int ies_len; | |
42 | + | |
43 | +@@ -496,16 +496,17 @@ void ieee80211_process_addba_request(str | |
44 | + ies_len = len - offsetof(struct ieee80211_mgmt, | |
45 | + u.action.u.addba_req.variable); | |
46 | + if (ies_len) { | |
47 | +- ieee802_11_parse_elems(mgmt->u.action.u.addba_req.variable, | |
48 | +- ies_len, true, &elems, mgmt->bssid, NULL); | |
49 | +- if (elems.parse_error) | |
50 | ++ elems = ieee802_11_parse_elems(mgmt->u.action.u.addba_req.variable, | |
51 | ++ ies_len, true, mgmt->bssid, NULL); | |
52 | ++ if (!elems || elems->parse_error) | |
53 | + return; | |
54 | + } | |
55 | + | |
56 | + __ieee80211_start_rx_ba_session(sta, dialog_token, timeout, | |
57 | + start_seq_num, ba_policy, tid, | |
58 | + buf_size, true, false, | |
59 | +- elems.addba_ext_ie); | |
60 | ++ elems ? elems->addba_ext_ie : NULL); | |
61 | ++ kfree(elems); | |
62 | + } | |
63 | + | |
64 | + void ieee80211_manage_rx_ba_offl(struct ieee80211_vif *vif, | |
65 | +--- a/net/mac80211/ibss.c | |
66 | ++++ b/net/mac80211/ibss.c | |
67 | +@@ -9,7 +9,7 @@ | |
68 | + * Copyright 2009, Johannes Berg <johannes@sipsolutions.net> | |
69 | + * Copyright 2013-2014 Intel Mobile Communications GmbH | |
70 | + * Copyright(c) 2016 Intel Deutschland GmbH | |
71 | +- * Copyright(c) 2018-2020 Intel Corporation | |
72 | ++ * Copyright(c) 2018-2021 Intel Corporation | |
73 | + */ | |
74 | + | |
75 | + #include <linux/delay.h> | |
76 | +@@ -1589,7 +1589,7 @@ void ieee80211_rx_mgmt_probe_beacon(stru | |
77 | + struct ieee80211_rx_status *rx_status) | |
78 | + { | |
79 | + size_t baselen; | |
80 | +- struct ieee802_11_elems elems; | |
81 | ++ struct ieee802_11_elems *elems; | |
82 | + | |
83 | + BUILD_BUG_ON(offsetof(typeof(mgmt->u.probe_resp), variable) != | |
84 | + offsetof(typeof(mgmt->u.beacon), variable)); | |
85 | +@@ -1602,10 +1602,14 @@ void ieee80211_rx_mgmt_probe_beacon(stru | |
86 | + if (baselen > len) | |
87 | + return; | |
88 | + | |
89 | +- ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen, | |
90 | +- false, &elems, mgmt->bssid, NULL); | |
91 | +- | |
92 | +- ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems); | |
93 | ++ elems = ieee802_11_parse_elems(mgmt->u.probe_resp.variable, | |
94 | ++ len - baselen, false, | |
95 | ++ mgmt->bssid, NULL); | |
96 | ++ | |
97 | ++ if (elems) { | |
98 | ++ ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, elems); | |
99 | ++ kfree(elems); | |
100 | ++ } | |
101 | + } | |
102 | + | |
103 | + void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |
104 | +@@ -1614,7 +1618,7 @@ void ieee80211_ibss_rx_queued_mgmt(struc | |
105 | + struct ieee80211_rx_status *rx_status; | |
106 | + struct ieee80211_mgmt *mgmt; | |
107 | + u16 fc; | |
108 | +- struct ieee802_11_elems elems; | |
109 | ++ struct ieee802_11_elems *elems; | |
110 | + int ies_len; | |
111 | + | |
112 | + rx_status = IEEE80211_SKB_RXCB(skb); | |
113 | +@@ -1651,15 +1655,16 @@ void ieee80211_ibss_rx_queued_mgmt(struc | |
114 | + if (ies_len < 0) | |
115 | + break; | |
116 | + | |
117 | +- ieee802_11_parse_elems( | |
118 | ++ elems = ieee802_11_parse_elems( | |
119 | + mgmt->u.action.u.chan_switch.variable, | |
120 | +- ies_len, true, &elems, mgmt->bssid, NULL); | |
121 | ++ ies_len, true, mgmt->bssid, NULL); | |
122 | + | |
123 | +- if (elems.parse_error) | |
124 | ++ if (!elems || elems->parse_error) | |
125 | + break; | |
126 | + | |
127 | + ieee80211_rx_mgmt_spectrum_mgmt(sdata, mgmt, skb->len, | |
128 | +- rx_status, &elems); | |
129 | ++ rx_status, elems); | |
130 | ++ kfree(elems); | |
131 | + break; | |
132 | + } | |
133 | + } | |
134 | +--- a/net/mac80211/ieee80211_i.h | |
135 | ++++ b/net/mac80211/ieee80211_i.h | |
136 | +@@ -2088,18 +2088,18 @@ static inline void ieee80211_tx_skb(stru | |
137 | + ieee80211_tx_skb_tid(sdata, skb, 7); | |
138 | + } | |
139 | + | |
140 | +-void ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, | |
141 | +- struct ieee802_11_elems *elems, | |
142 | +- u64 filter, u32 crc, u8 *transmitter_bssid, | |
143 | +- u8 *bss_bssid); | |
144 | +-static inline void ieee802_11_parse_elems(const u8 *start, size_t len, | |
145 | +- bool action, | |
146 | +- struct ieee802_11_elems *elems, | |
147 | +- u8 *transmitter_bssid, | |
148 | +- u8 *bss_bssid) | |
149 | ++struct ieee802_11_elems *ieee802_11_parse_elems_crc(const u8 *start, size_t len, | |
150 | ++ bool action, | |
151 | ++ u64 filter, u32 crc, | |
152 | ++ const u8 *transmitter_bssid, | |
153 | ++ const u8 *bss_bssid); | |
154 | ++static inline struct ieee802_11_elems * | |
155 | ++ieee802_11_parse_elems(const u8 *start, size_t len, bool action, | |
156 | ++ const u8 *transmitter_bssid, | |
157 | ++ const u8 *bss_bssid) | |
158 | + { | |
159 | +- ieee802_11_parse_elems_crc(start, len, action, elems, 0, 0, | |
160 | +- transmitter_bssid, bss_bssid); | |
161 | ++ return ieee802_11_parse_elems_crc(start, len, action, 0, 0, | |
162 | ++ transmitter_bssid, bss_bssid); | |
163 | + } | |
164 | + | |
165 | + | |
166 | +--- a/net/mac80211/mesh.c | |
167 | ++++ b/net/mac80211/mesh.c | |
168 | +@@ -1247,7 +1247,7 @@ ieee80211_mesh_rx_probe_req(struct ieee8 | |
169 | + struct sk_buff *presp; | |
170 | + struct beacon_data *bcn; | |
171 | + struct ieee80211_mgmt *hdr; | |
172 | +- struct ieee802_11_elems elems; | |
173 | ++ struct ieee802_11_elems *elems; | |
174 | + size_t baselen; | |
175 | + u8 *pos; | |
176 | + | |
177 | +@@ -1256,22 +1256,24 @@ ieee80211_mesh_rx_probe_req(struct ieee8 | |
178 | + if (baselen > len) | |
179 | + return; | |
180 | + | |
181 | +- ieee802_11_parse_elems(pos, len - baselen, false, &elems, mgmt->bssid, | |
182 | +- NULL); | |
183 | +- | |
184 | +- if (!elems.mesh_id) | |
185 | ++ elems = ieee802_11_parse_elems(pos, len - baselen, false, mgmt->bssid, | |
186 | ++ NULL); | |
187 | ++ if (!elems) | |
188 | + return; | |
189 | + | |
190 | ++ if (!elems->mesh_id) | |
191 | ++ goto free; | |
192 | ++ | |
193 | + /* 802.11-2012 10.1.4.3.2 */ | |
194 | + if ((!ether_addr_equal(mgmt->da, sdata->vif.addr) && | |
195 | + !is_broadcast_ether_addr(mgmt->da)) || | |
196 | +- elems.ssid_len != 0) | |
197 | +- return; | |
198 | ++ elems->ssid_len != 0) | |
199 | ++ goto free; | |
200 | + | |
201 | +- if (elems.mesh_id_len != 0 && | |
202 | +- (elems.mesh_id_len != ifmsh->mesh_id_len || | |
203 | +- memcmp(elems.mesh_id, ifmsh->mesh_id, ifmsh->mesh_id_len))) | |
204 | +- return; | |
205 | ++ if (elems->mesh_id_len != 0 && | |
206 | ++ (elems->mesh_id_len != ifmsh->mesh_id_len || | |
207 | ++ memcmp(elems->mesh_id, ifmsh->mesh_id, ifmsh->mesh_id_len))) | |
208 | ++ goto free; | |
209 | + | |
210 | + rcu_read_lock(); | |
211 | + bcn = rcu_dereference(ifmsh->beacon); | |
212 | +@@ -1295,6 +1297,8 @@ ieee80211_mesh_rx_probe_req(struct ieee8 | |
213 | + ieee80211_tx_skb(sdata, presp); | |
214 | + out: | |
215 | + rcu_read_unlock(); | |
216 | ++free: | |
217 | ++ kfree(elems); | |
218 | + } | |
219 | + | |
220 | + static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, | |
221 | +@@ -1305,7 +1309,7 @@ static void ieee80211_mesh_rx_bcn_presp( | |
222 | + { | |
223 | + struct ieee80211_local *local = sdata->local; | |
224 | + struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | |
225 | +- struct ieee802_11_elems elems; | |
226 | ++ struct ieee802_11_elems *elems; | |
227 | + struct ieee80211_channel *channel; | |
228 | + size_t baselen; | |
229 | + int freq; | |
230 | +@@ -1320,42 +1324,47 @@ static void ieee80211_mesh_rx_bcn_presp( | |
231 | + if (baselen > len) | |
232 | + return; | |
233 | + | |
234 | +- ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen, | |
235 | +- false, &elems, mgmt->bssid, NULL); | |
236 | ++ elems = ieee802_11_parse_elems(mgmt->u.probe_resp.variable, | |
237 | ++ len - baselen, | |
238 | ++ false, mgmt->bssid, NULL); | |
239 | ++ if (!elems) | |
240 | ++ return; | |
241 | + | |
242 | + /* ignore non-mesh or secure / unsecure mismatch */ | |
243 | +- if ((!elems.mesh_id || !elems.mesh_config) || | |
244 | +- (elems.rsn && sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) || | |
245 | +- (!elems.rsn && sdata->u.mesh.security != IEEE80211_MESH_SEC_NONE)) | |
246 | +- return; | |
247 | ++ if ((!elems->mesh_id || !elems->mesh_config) || | |
248 | ++ (elems->rsn && sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) || | |
249 | ++ (!elems->rsn && sdata->u.mesh.security != IEEE80211_MESH_SEC_NONE)) | |
250 | ++ goto free; | |
251 | + | |
252 | +- if (elems.ds_params) | |
253 | +- freq = ieee80211_channel_to_frequency(elems.ds_params[0], band); | |
254 | ++ if (elems->ds_params) | |
255 | ++ freq = ieee80211_channel_to_frequency(elems->ds_params[0], band); | |
256 | + else | |
257 | + freq = rx_status->freq; | |
258 | + | |
259 | + channel = ieee80211_get_channel(local->hw.wiphy, freq); | |
260 | + | |
261 | + if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) | |
262 | +- return; | |
263 | ++ goto free; | |
264 | + | |
265 | +- if (mesh_matches_local(sdata, &elems)) { | |
266 | ++ if (mesh_matches_local(sdata, elems)) { | |
267 | + mpl_dbg(sdata, "rssi_threshold=%d,rx_status->signal=%d\n", | |
268 | + sdata->u.mesh.mshcfg.rssi_threshold, rx_status->signal); | |
269 | + if (!sdata->u.mesh.user_mpm || | |
270 | + sdata->u.mesh.mshcfg.rssi_threshold == 0 || | |
271 | + sdata->u.mesh.mshcfg.rssi_threshold < rx_status->signal) | |
272 | +- mesh_neighbour_update(sdata, mgmt->sa, &elems, | |
273 | ++ mesh_neighbour_update(sdata, mgmt->sa, elems, | |
274 | + rx_status); | |
275 | + | |
276 | + if (ifmsh->csa_role != IEEE80211_MESH_CSA_ROLE_INIT && | |
277 | + !sdata->vif.csa_active) | |
278 | +- ieee80211_mesh_process_chnswitch(sdata, &elems, true); | |
279 | ++ ieee80211_mesh_process_chnswitch(sdata, elems, true); | |
280 | + } | |
281 | + | |
282 | + if (ifmsh->sync_ops) | |
283 | + ifmsh->sync_ops->rx_bcn_presp(sdata, stype, mgmt, len, | |
284 | +- elems.mesh_config, rx_status); | |
285 | ++ elems->mesh_config, rx_status); | |
286 | ++free: | |
287 | ++ kfree(elems); | |
288 | + } | |
289 | + | |
290 | + int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata) | |
291 | +@@ -1447,7 +1456,7 @@ static void mesh_rx_csa_frame(struct iee | |
292 | + struct ieee80211_mgmt *mgmt, size_t len) | |
293 | + { | |
294 | + struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | |
295 | +- struct ieee802_11_elems elems; | |
296 | ++ struct ieee802_11_elems *elems; | |
297 | + u16 pre_value; | |
298 | + bool fwd_csa = true; | |
299 | + size_t baselen; | |
300 | +@@ -1460,33 +1469,37 @@ static void mesh_rx_csa_frame(struct iee | |
301 | + pos = mgmt->u.action.u.chan_switch.variable; | |
302 | + baselen = offsetof(struct ieee80211_mgmt, | |
303 | + u.action.u.chan_switch.variable); | |
304 | +- ieee802_11_parse_elems(pos, len - baselen, true, &elems, | |
305 | +- mgmt->bssid, NULL); | |
306 | +- | |
307 | +- if (!mesh_matches_local(sdata, &elems)) | |
308 | ++ elems = ieee802_11_parse_elems(pos, len - baselen, true, | |
309 | ++ mgmt->bssid, NULL); | |
310 | ++ if (!elems) | |
311 | + return; | |
312 | + | |
313 | +- ifmsh->chsw_ttl = elems.mesh_chansw_params_ie->mesh_ttl; | |
314 | ++ if (!mesh_matches_local(sdata, elems)) | |
315 | ++ goto free; | |
316 | ++ | |
317 | ++ ifmsh->chsw_ttl = elems->mesh_chansw_params_ie->mesh_ttl; | |
318 | + if (!--ifmsh->chsw_ttl) | |
319 | + fwd_csa = false; | |
320 | + | |
321 | +- pre_value = le16_to_cpu(elems.mesh_chansw_params_ie->mesh_pre_value); | |
322 | ++ pre_value = le16_to_cpu(elems->mesh_chansw_params_ie->mesh_pre_value); | |
323 | + if (ifmsh->pre_value >= pre_value) | |
324 | +- return; | |
325 | ++ goto free; | |
326 | + | |
327 | + ifmsh->pre_value = pre_value; | |
328 | + | |
329 | + if (!sdata->vif.csa_active && | |
330 | +- !ieee80211_mesh_process_chnswitch(sdata, &elems, false)) { | |
331 | ++ !ieee80211_mesh_process_chnswitch(sdata, elems, false)) { | |
332 | + mcsa_dbg(sdata, "Failed to process CSA action frame"); | |
333 | +- return; | |
334 | ++ goto free; | |
335 | + } | |
336 | + | |
337 | + /* forward or re-broadcast the CSA frame */ | |
338 | + if (fwd_csa) { | |
339 | +- if (mesh_fwd_csa_frame(sdata, mgmt, len, &elems) < 0) | |
340 | ++ if (mesh_fwd_csa_frame(sdata, mgmt, len, elems) < 0) | |
341 | + mcsa_dbg(sdata, "Failed to forward the CSA frame"); | |
342 | + } | |
343 | ++free: | |
344 | ++ kfree(elems); | |
345 | + } | |
346 | + | |
347 | + static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata, | |
348 | +--- a/net/mac80211/mesh_hwmp.c | |
349 | ++++ b/net/mac80211/mesh_hwmp.c | |
350 | +@@ -1,7 +1,7 @@ | |
351 | + // SPDX-License-Identifier: GPL-2.0-only | |
352 | + /* | |
353 | + * Copyright (c) 2008, 2009 open80211s Ltd. | |
354 | +- * Copyright (C) 2019 Intel Corporation | |
355 | ++ * Copyright (C) 2019, 2021 Intel Corporation | |
356 | + * Author: Luis Carlos Cobo <luisca@cozybit.com> | |
357 | + */ | |
358 | + | |
359 | +@@ -908,7 +908,7 @@ static void hwmp_rann_frame_process(stru | |
360 | + void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, | |
361 | + struct ieee80211_mgmt *mgmt, size_t len) | |
362 | + { | |
363 | +- struct ieee802_11_elems elems; | |
364 | ++ struct ieee802_11_elems *elems; | |
365 | + size_t baselen; | |
366 | + u32 path_metric; | |
367 | + struct sta_info *sta; | |
368 | +@@ -926,37 +926,41 @@ void mesh_rx_path_sel_frame(struct ieee8 | |
369 | + rcu_read_unlock(); | |
370 | + | |
371 | + baselen = (u8 *) mgmt->u.action.u.mesh_action.variable - (u8 *) mgmt; | |
372 | +- ieee802_11_parse_elems(mgmt->u.action.u.mesh_action.variable, | |
373 | +- len - baselen, false, &elems, mgmt->bssid, NULL); | |
374 | ++ elems = ieee802_11_parse_elems(mgmt->u.action.u.mesh_action.variable, | |
375 | ++ len - baselen, false, mgmt->bssid, NULL); | |
376 | ++ if (!elems) | |
377 | ++ return; | |
378 | + | |
379 | +- if (elems.preq) { | |
380 | +- if (elems.preq_len != 37) | |
381 | ++ if (elems->preq) { | |
382 | ++ if (elems->preq_len != 37) | |
383 | + /* Right now we support just 1 destination and no AE */ | |
384 | +- return; | |
385 | +- path_metric = hwmp_route_info_get(sdata, mgmt, elems.preq, | |
386 | ++ goto free; | |
387 | ++ path_metric = hwmp_route_info_get(sdata, mgmt, elems->preq, | |
388 | + MPATH_PREQ); | |
389 | + if (path_metric) | |
390 | +- hwmp_preq_frame_process(sdata, mgmt, elems.preq, | |
391 | ++ hwmp_preq_frame_process(sdata, mgmt, elems->preq, | |
392 | + path_metric); | |
393 | + } | |
394 | +- if (elems.prep) { | |
395 | +- if (elems.prep_len != 31) | |
396 | ++ if (elems->prep) { | |
397 | ++ if (elems->prep_len != 31) | |
398 | + /* Right now we support no AE */ | |
399 | +- return; | |
400 | +- path_metric = hwmp_route_info_get(sdata, mgmt, elems.prep, | |
401 | ++ goto free; | |
402 | ++ path_metric = hwmp_route_info_get(sdata, mgmt, elems->prep, | |
403 | + MPATH_PREP); | |
404 | + if (path_metric) | |
405 | +- hwmp_prep_frame_process(sdata, mgmt, elems.prep, | |
406 | ++ hwmp_prep_frame_process(sdata, mgmt, elems->prep, | |
407 | + path_metric); | |
408 | + } | |
409 | +- if (elems.perr) { | |
410 | +- if (elems.perr_len != 15) | |
411 | ++ if (elems->perr) { | |
412 | ++ if (elems->perr_len != 15) | |
413 | + /* Right now we support only one destination per PERR */ | |
414 | +- return; | |
415 | +- hwmp_perr_frame_process(sdata, mgmt, elems.perr); | |
416 | ++ goto free; | |
417 | ++ hwmp_perr_frame_process(sdata, mgmt, elems->perr); | |
418 | + } | |
419 | +- if (elems.rann) | |
420 | +- hwmp_rann_frame_process(sdata, mgmt, elems.rann); | |
421 | ++ if (elems->rann) | |
422 | ++ hwmp_rann_frame_process(sdata, mgmt, elems->rann); | |
423 | ++free: | |
424 | ++ kfree(elems); | |
425 | + } | |
426 | + | |
427 | + /** | |
428 | +--- a/net/mac80211/mesh_plink.c | |
429 | ++++ b/net/mac80211/mesh_plink.c | |
430 | +@@ -1,7 +1,7 @@ | |
431 | + // SPDX-License-Identifier: GPL-2.0-only | |
432 | + /* | |
433 | + * Copyright (c) 2008, 2009 open80211s Ltd. | |
434 | +- * Copyright (C) 2019 Intel Corporation | |
435 | ++ * Copyright (C) 2019, 2021 Intel Corporation | |
436 | + * Author: Luis Carlos Cobo <luisca@cozybit.com> | |
437 | + */ | |
438 | + #include <linux/gfp.h> | |
439 | +@@ -1200,7 +1200,7 @@ void mesh_rx_plink_frame(struct ieee8021 | |
440 | + struct ieee80211_mgmt *mgmt, size_t len, | |
441 | + struct ieee80211_rx_status *rx_status) | |
442 | + { | |
443 | +- struct ieee802_11_elems elems; | |
444 | ++ struct ieee802_11_elems *elems; | |
445 | + size_t baselen; | |
446 | + u8 *baseaddr; | |
447 | + | |
448 | +@@ -1228,7 +1228,8 @@ void mesh_rx_plink_frame(struct ieee8021 | |
449 | + if (baselen > len) | |
450 | + return; | |
451 | + } | |
452 | +- ieee802_11_parse_elems(baseaddr, len - baselen, true, &elems, | |
453 | +- mgmt->bssid, NULL); | |
454 | +- mesh_process_plink_frame(sdata, mgmt, &elems, rx_status); | |
455 | ++ elems = ieee802_11_parse_elems(baseaddr, len - baselen, true, | |
456 | ++ mgmt->bssid, NULL); | |
457 | ++ mesh_process_plink_frame(sdata, mgmt, elems, rx_status); | |
458 | ++ kfree(elems); | |
459 | + } | |
460 | +--- a/net/mac80211/mlme.c | |
461 | ++++ b/net/mac80211/mlme.c | |
462 | +@@ -3317,8 +3317,11 @@ static bool ieee80211_assoc_success(stru | |
463 | + aid = 0; /* TODO */ | |
464 | + } | |
465 | + capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info); | |
466 | +- ieee802_11_parse_elems(pos, len - (pos - (u8 *)mgmt), false, elems, | |
467 | +- mgmt->bssid, assoc_data->bss->bssid); | |
468 | ++ elems = ieee802_11_parse_elems(pos, len - (pos - (u8 *)mgmt), false, | |
469 | ++ mgmt->bssid, assoc_data->bss->bssid); | |
470 | ++ | |
471 | ++ if (!elems) | |
472 | ++ return false; | |
473 | + | |
474 | + if (elems->aid_resp) | |
475 | + aid = le16_to_cpu(elems->aid_resp->aid); | |
476 | +@@ -3340,7 +3343,8 @@ static bool ieee80211_assoc_success(stru | |
477 | + | |
478 | + if (!is_s1g && !elems->supp_rates) { | |
479 | + sdata_info(sdata, "no SuppRates element in AssocResp\n"); | |
480 | +- return false; | |
481 | ++ ret = false; | |
482 | ++ goto out; | |
483 | + } | |
484 | + | |
485 | + sdata->vif.bss_conf.aid = aid; | |
486 | +@@ -3362,7 +3366,7 @@ static bool ieee80211_assoc_success(stru | |
487 | + (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT) && | |
488 | + (!elems->vht_cap_elem || !elems->vht_operation)))) { | |
489 | + const struct cfg80211_bss_ies *ies; | |
490 | +- struct ieee802_11_elems bss_elems; | |
491 | ++ struct ieee802_11_elems *bss_elems; | |
492 | + | |
493 | + rcu_read_lock(); | |
494 | + ies = rcu_dereference(cbss->ies); | |
495 | +@@ -3373,13 +3377,17 @@ static bool ieee80211_assoc_success(stru | |
496 | + if (!bss_ies) | |
497 | + return false; | |
498 | + | |
499 | +- ieee802_11_parse_elems(bss_ies->data, bss_ies->len, | |
500 | +- false, &bss_elems, | |
501 | +- mgmt->bssid, | |
502 | +- assoc_data->bss->bssid); | |
503 | ++ bss_elems = ieee802_11_parse_elems(bss_ies->data, bss_ies->len, | |
504 | ++ false, mgmt->bssid, | |
505 | ++ assoc_data->bss->bssid); | |
506 | ++ if (!bss_elems) { | |
507 | ++ ret = false; | |
508 | ++ goto out; | |
509 | ++ } | |
510 | ++ | |
511 | + if (assoc_data->wmm && | |
512 | +- !elems->wmm_param && bss_elems.wmm_param) { | |
513 | +- elems->wmm_param = bss_elems.wmm_param; | |
514 | ++ !elems->wmm_param && bss_elems->wmm_param) { | |
515 | ++ elems->wmm_param = bss_elems->wmm_param; | |
516 | + sdata_info(sdata, | |
517 | + "AP bug: WMM param missing from AssocResp\n"); | |
518 | + } | |
519 | +@@ -3388,30 +3396,32 @@ static bool ieee80211_assoc_success(stru | |
520 | + * Also check if we requested HT/VHT, otherwise the AP doesn't | |
521 | + * have to include the IEs in the (re)association response. | |
522 | + */ | |
523 | +- if (!elems->ht_cap_elem && bss_elems.ht_cap_elem && | |
524 | ++ if (!elems->ht_cap_elem && bss_elems->ht_cap_elem && | |
525 | + !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) { | |
526 | +- elems->ht_cap_elem = bss_elems.ht_cap_elem; | |
527 | ++ elems->ht_cap_elem = bss_elems->ht_cap_elem; | |
528 | + sdata_info(sdata, | |
529 | + "AP bug: HT capability missing from AssocResp\n"); | |
530 | + } | |
531 | +- if (!elems->ht_operation && bss_elems.ht_operation && | |
532 | ++ if (!elems->ht_operation && bss_elems->ht_operation && | |
533 | + !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) { | |
534 | +- elems->ht_operation = bss_elems.ht_operation; | |
535 | ++ elems->ht_operation = bss_elems->ht_operation; | |
536 | + sdata_info(sdata, | |
537 | + "AP bug: HT operation missing from AssocResp\n"); | |
538 | + } | |
539 | +- if (!elems->vht_cap_elem && bss_elems.vht_cap_elem && | |
540 | ++ if (!elems->vht_cap_elem && bss_elems->vht_cap_elem && | |
541 | + !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) { | |
542 | +- elems->vht_cap_elem = bss_elems.vht_cap_elem; | |
543 | ++ elems->vht_cap_elem = bss_elems->vht_cap_elem; | |
544 | + sdata_info(sdata, | |
545 | + "AP bug: VHT capa missing from AssocResp\n"); | |
546 | + } | |
547 | +- if (!elems->vht_operation && bss_elems.vht_operation && | |
548 | ++ if (!elems->vht_operation && bss_elems->vht_operation && | |
549 | + !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) { | |
550 | +- elems->vht_operation = bss_elems.vht_operation; | |
551 | ++ elems->vht_operation = bss_elems->vht_operation; | |
552 | + sdata_info(sdata, | |
553 | + "AP bug: VHT operation missing from AssocResp\n"); | |
554 | + } | |
555 | ++ | |
556 | ++ kfree(bss_elems); | |
557 | + } | |
558 | + | |
559 | + /* | |
560 | +@@ -3662,6 +3672,7 @@ static bool ieee80211_assoc_success(stru | |
561 | + | |
562 | + ret = true; | |
563 | + out: | |
564 | ++ kfree(elems); | |
565 | + kfree(bss_ies); | |
566 | + return ret; | |
567 | + } | |
568 | +@@ -3673,7 +3684,7 @@ static void ieee80211_rx_mgmt_assoc_resp | |
569 | + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | |
570 | + struct ieee80211_mgd_assoc_data *assoc_data = ifmgd->assoc_data; | |
571 | + u16 capab_info, status_code, aid; | |
572 | +- struct ieee802_11_elems elems; | |
573 | ++ struct ieee802_11_elems *elems; | |
574 | + int ac, uapsd_queues = -1; | |
575 | + u8 *pos; | |
576 | + bool reassoc; | |
577 | +@@ -3730,14 +3741,16 @@ static void ieee80211_rx_mgmt_assoc_resp | |
578 | + fils_decrypt_assoc_resp(sdata, (u8 *)mgmt, &len, assoc_data) < 0) | |
579 | + return; | |
580 | + | |
581 | +- ieee802_11_parse_elems(pos, len - (pos - (u8 *)mgmt), false, &elems, | |
582 | +- mgmt->bssid, assoc_data->bss->bssid); | |
583 | ++ elems = ieee802_11_parse_elems(pos, len - (pos - (u8 *)mgmt), false, | |
584 | ++ mgmt->bssid, assoc_data->bss->bssid); | |
585 | ++ if (!elems) | |
586 | ++ goto notify_driver; | |
587 | + | |
588 | + if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY && | |
589 | +- elems.timeout_int && | |
590 | +- elems.timeout_int->type == WLAN_TIMEOUT_ASSOC_COMEBACK) { | |
591 | ++ elems->timeout_int && | |
592 | ++ elems->timeout_int->type == WLAN_TIMEOUT_ASSOC_COMEBACK) { | |
593 | + u32 tu, ms; | |
594 | +- tu = le32_to_cpu(elems.timeout_int->value); | |
595 | ++ tu = le32_to_cpu(elems->timeout_int->value); | |
596 | + ms = tu * 1024 / 1000; | |
597 | + sdata_info(sdata, | |
598 | + "%pM rejected association temporarily; comeback duration %u TU (%u ms)\n", | |
599 | +@@ -3757,7 +3770,7 @@ static void ieee80211_rx_mgmt_assoc_resp | |
600 | + event.u.mlme.reason = status_code; | |
601 | + drv_event_callback(sdata->local, sdata, &event); | |
602 | + } else { | |
603 | +- if (!ieee80211_assoc_success(sdata, cbss, mgmt, len, &elems)) { | |
604 | ++ if (!ieee80211_assoc_success(sdata, cbss, mgmt, len, elems)) { | |
605 | + /* oops -- internal error -- send timeout for now */ | |
606 | + ieee80211_destroy_assoc_data(sdata, false, false); | |
607 | + cfg80211_assoc_timeout(sdata->dev, cbss); | |
608 | +@@ -3787,6 +3800,7 @@ static void ieee80211_rx_mgmt_assoc_resp | |
609 | + ifmgd->assoc_req_ies, ifmgd->assoc_req_ies_len); | |
610 | + notify_driver: | |
611 | + drv_mgd_complete_tx(sdata->local, sdata, &info); | |
612 | ++ kfree(elems); | |
613 | + } | |
614 | + | |
615 | + static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |
616 | +@@ -3991,7 +4005,7 @@ static void ieee80211_rx_mgmt_beacon(str | |
617 | + struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; | |
618 | + struct ieee80211_mgmt *mgmt = (void *) hdr; | |
619 | + size_t baselen; | |
620 | +- struct ieee802_11_elems elems; | |
621 | ++ struct ieee802_11_elems *elems; | |
622 | + struct ieee80211_local *local = sdata->local; | |
623 | + struct ieee80211_chanctx_conf *chanctx_conf; | |
624 | + struct ieee80211_channel *chan; | |
625 | +@@ -4037,15 +4051,16 @@ static void ieee80211_rx_mgmt_beacon(str | |
626 | + | |
627 | + if (ifmgd->assoc_data && ifmgd->assoc_data->need_beacon && | |
628 | + ieee80211_rx_our_beacon(bssid, ifmgd->assoc_data->bss)) { | |
629 | +- ieee802_11_parse_elems(variable, | |
630 | +- len - baselen, false, &elems, | |
631 | +- bssid, | |
632 | +- ifmgd->assoc_data->bss->bssid); | |
633 | ++ elems = ieee802_11_parse_elems(variable, len - baselen, false, | |
634 | ++ bssid, | |
635 | ++ ifmgd->assoc_data->bss->bssid); | |
636 | ++ if (!elems) | |
637 | ++ return; | |
638 | + | |
639 | + ieee80211_rx_bss_info(sdata, mgmt, len, rx_status); | |
640 | + | |
641 | +- if (elems.dtim_period) | |
642 | +- ifmgd->dtim_period = elems.dtim_period; | |
643 | ++ if (elems->dtim_period) | |
644 | ++ ifmgd->dtim_period = elems->dtim_period; | |
645 | + ifmgd->have_beacon = true; | |
646 | + ifmgd->assoc_data->need_beacon = false; | |
647 | + if (ieee80211_hw_check(&local->hw, TIMING_BEACON_ONLY)) { | |
648 | +@@ -4053,17 +4068,17 @@ static void ieee80211_rx_mgmt_beacon(str | |
649 | + le64_to_cpu(mgmt->u.beacon.timestamp); | |
650 | + sdata->vif.bss_conf.sync_device_ts = | |
651 | + rx_status->device_timestamp; | |
652 | +- sdata->vif.bss_conf.sync_dtim_count = elems.dtim_count; | |
653 | ++ sdata->vif.bss_conf.sync_dtim_count = elems->dtim_count; | |
654 | + } | |
655 | + | |
656 | +- if (elems.mbssid_config_ie) | |
657 | ++ if (elems->mbssid_config_ie) | |
658 | + bss_conf->profile_periodicity = | |
659 | +- elems.mbssid_config_ie->profile_periodicity; | |
660 | ++ elems->mbssid_config_ie->profile_periodicity; | |
661 | + else | |
662 | + bss_conf->profile_periodicity = 0; | |
663 | + | |
664 | +- if (elems.ext_capab_len >= 11 && | |
665 | +- (elems.ext_capab[10] & WLAN_EXT_CAPA11_EMA_SUPPORT)) | |
666 | ++ if (elems->ext_capab_len >= 11 && | |
667 | ++ (elems->ext_capab[10] & WLAN_EXT_CAPA11_EMA_SUPPORT)) | |
668 | + bss_conf->ema_ap = true; | |
669 | + else | |
670 | + bss_conf->ema_ap = false; | |
671 | +@@ -4072,6 +4087,7 @@ static void ieee80211_rx_mgmt_beacon(str | |
672 | + ifmgd->assoc_data->timeout = jiffies; | |
673 | + ifmgd->assoc_data->timeout_started = true; | |
674 | + run_again(sdata, ifmgd->assoc_data->timeout); | |
675 | ++ kfree(elems); | |
676 | + return; | |
677 | + } | |
678 | + | |
679 | +@@ -4103,14 +4119,15 @@ static void ieee80211_rx_mgmt_beacon(str | |
680 | + */ | |
681 | + if (!ieee80211_is_s1g_beacon(hdr->frame_control)) | |
682 | + ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4); | |
683 | +- ieee802_11_parse_elems_crc(variable, | |
684 | +- len - baselen, false, &elems, | |
685 | +- care_about_ies, ncrc, | |
686 | +- mgmt->bssid, bssid); | |
687 | +- ncrc = elems.crc; | |
688 | ++ elems = ieee802_11_parse_elems_crc(variable, len - baselen, | |
689 | ++ false, care_about_ies, ncrc, | |
690 | ++ mgmt->bssid, bssid); | |
691 | ++ if (!elems) | |
692 | ++ return; | |
693 | ++ ncrc = elems->crc; | |
694 | + | |
695 | + if (ieee80211_hw_check(&local->hw, PS_NULLFUNC_STACK) && | |
696 | +- ieee80211_check_tim(elems.tim, elems.tim_len, bss_conf->aid)) { | |
697 | ++ ieee80211_check_tim(elems->tim, elems->tim_len, bss_conf->aid)) { | |
698 | + if (local->hw.conf.dynamic_ps_timeout > 0) { | |
699 | + if (local->hw.conf.flags & IEEE80211_CONF_PS) { | |
700 | + local->hw.conf.flags &= ~IEEE80211_CONF_PS; | |
701 | +@@ -4180,12 +4197,12 @@ static void ieee80211_rx_mgmt_beacon(str | |
702 | + le64_to_cpu(mgmt->u.beacon.timestamp); | |
703 | + sdata->vif.bss_conf.sync_device_ts = | |
704 | + rx_status->device_timestamp; | |
705 | +- sdata->vif.bss_conf.sync_dtim_count = elems.dtim_count; | |
706 | ++ sdata->vif.bss_conf.sync_dtim_count = elems->dtim_count; | |
707 | + } | |
708 | + | |
709 | + if ((ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid) || | |
710 | + ieee80211_is_s1g_short_beacon(mgmt->frame_control)) | |
711 | +- return; | |
712 | ++ goto free; | |
713 | + ifmgd->beacon_crc = ncrc; | |
714 | + ifmgd->beacon_crc_valid = true; | |
715 | + | |
716 | +@@ -4193,12 +4210,12 @@ static void ieee80211_rx_mgmt_beacon(str | |
717 | + | |
718 | + ieee80211_sta_process_chanswitch(sdata, rx_status->mactime, | |
719 | + rx_status->device_timestamp, | |
720 | +- &elems, true); | |
721 | ++ elems, true); | |
722 | + | |
723 | + if (!(ifmgd->flags & IEEE80211_STA_DISABLE_WMM) && | |
724 | +- ieee80211_sta_wmm_params(local, sdata, elems.wmm_param, | |
725 | +- elems.wmm_param_len, | |
726 | +- elems.mu_edca_param_set)) | |
727 | ++ ieee80211_sta_wmm_params(local, sdata, elems->wmm_param, | |
728 | ++ elems->wmm_param_len, | |
729 | ++ elems->mu_edca_param_set)) | |
730 | + changed |= BSS_CHANGED_QOS; | |
731 | + | |
732 | + /* | |
733 | +@@ -4207,7 +4224,7 @@ static void ieee80211_rx_mgmt_beacon(str | |
734 | + */ | |
735 | + if (!ifmgd->have_beacon) { | |
736 | + /* a few bogus AP send dtim_period = 0 or no TIM IE */ | |
737 | +- bss_conf->dtim_period = elems.dtim_period ?: 1; | |
738 | ++ bss_conf->dtim_period = elems->dtim_period ?: 1; | |
739 | + | |
740 | + changed |= BSS_CHANGED_BEACON_INFO; | |
741 | + ifmgd->have_beacon = true; | |
742 | +@@ -4219,9 +4236,9 @@ static void ieee80211_rx_mgmt_beacon(str | |
743 | + ieee80211_recalc_ps_vif(sdata); | |
744 | + } | |
745 | + | |
746 | +- if (elems.erp_info) { | |
747 | ++ if (elems->erp_info) { | |
748 | + erp_valid = true; | |
749 | +- erp_value = elems.erp_info[0]; | |
750 | ++ erp_value = elems->erp_info[0]; | |
751 | + } else { | |
752 | + erp_valid = false; | |
753 | + } | |
754 | +@@ -4234,12 +4251,12 @@ static void ieee80211_rx_mgmt_beacon(str | |
755 | + mutex_lock(&local->sta_mtx); | |
756 | + sta = sta_info_get(sdata, bssid); | |
757 | + | |
758 | +- changed |= ieee80211_recalc_twt_req(sdata, sta, &elems); | |
759 | ++ changed |= ieee80211_recalc_twt_req(sdata, sta, elems); | |
760 | + | |
761 | +- if (ieee80211_config_bw(sdata, sta, elems.ht_cap_elem, | |
762 | +- elems.vht_cap_elem, elems.ht_operation, | |
763 | +- elems.vht_operation, elems.he_operation, | |
764 | +- elems.s1g_oper, bssid, &changed)) { | |
765 | ++ if (ieee80211_config_bw(sdata, sta, elems->ht_cap_elem, | |
766 | ++ elems->vht_cap_elem, elems->ht_operation, | |
767 | ++ elems->vht_operation, elems->he_operation, | |
768 | ++ elems->s1g_oper, bssid, &changed)) { | |
769 | + mutex_unlock(&local->sta_mtx); | |
770 | + sdata_info(sdata, | |
771 | + "failed to follow AP %pM bandwidth change, disconnect\n", | |
772 | +@@ -4251,21 +4268,23 @@ static void ieee80211_rx_mgmt_beacon(str | |
773 | + sizeof(deauth_buf), true, | |
774 | + WLAN_REASON_DEAUTH_LEAVING, | |
775 | + false); | |
776 | +- return; | |
777 | ++ goto free; | |
778 | + } | |
779 | + | |
780 | +- if (sta && elems.opmode_notif) | |
781 | +- ieee80211_vht_handle_opmode(sdata, sta, *elems.opmode_notif, | |
782 | ++ if (sta && elems->opmode_notif) | |
783 | ++ ieee80211_vht_handle_opmode(sdata, sta, *elems->opmode_notif, | |
784 | + rx_status->band); | |
785 | + mutex_unlock(&local->sta_mtx); | |
786 | + | |
787 | + changed |= ieee80211_handle_pwr_constr(sdata, chan, mgmt, | |
788 | +- elems.country_elem, | |
789 | +- elems.country_elem_len, | |
790 | +- elems.pwr_constr_elem, | |
791 | +- elems.cisco_dtpc_elem); | |
792 | ++ elems->country_elem, | |
793 | ++ elems->country_elem_len, | |
794 | ++ elems->pwr_constr_elem, | |
795 | ++ elems->cisco_dtpc_elem); | |
796 | + | |
797 | + ieee80211_bss_info_change_notify(sdata, changed); | |
798 | ++free: | |
799 | ++ kfree(elems); | |
800 | + } | |
801 | + | |
802 | + void ieee80211_sta_rx_queued_ext(struct ieee80211_sub_if_data *sdata, | |
803 | +@@ -4294,7 +4313,6 @@ void ieee80211_sta_rx_queued_mgmt(struct | |
804 | + struct ieee80211_rx_status *rx_status; | |
805 | + struct ieee80211_mgmt *mgmt; | |
806 | + u16 fc; | |
807 | +- struct ieee802_11_elems elems; | |
808 | + int ies_len; | |
809 | + | |
810 | + rx_status = (struct ieee80211_rx_status *) skb->cb; | |
811 | +@@ -4326,6 +4344,8 @@ void ieee80211_sta_rx_queued_mgmt(struct | |
812 | + break; | |
813 | + case IEEE80211_STYPE_ACTION: | |
814 | + if (mgmt->u.action.category == WLAN_CATEGORY_SPECTRUM_MGMT) { | |
815 | ++ struct ieee802_11_elems *elems; | |
816 | ++ | |
817 | + ies_len = skb->len - | |
818 | + offsetof(struct ieee80211_mgmt, | |
819 | + u.action.u.chan_switch.variable); | |
820 | +@@ -4334,18 +4354,21 @@ void ieee80211_sta_rx_queued_mgmt(struct | |
821 | + break; | |
822 | + | |
823 | + /* CSA IE cannot be overridden, no need for BSSID */ | |
824 | +- ieee802_11_parse_elems( | |
825 | +- mgmt->u.action.u.chan_switch.variable, | |
826 | +- ies_len, true, &elems, mgmt->bssid, NULL); | |
827 | ++ elems = ieee802_11_parse_elems( | |
828 | ++ mgmt->u.action.u.chan_switch.variable, | |
829 | ++ ies_len, true, mgmt->bssid, NULL); | |
830 | + | |
831 | +- if (elems.parse_error) | |
832 | ++ if (!elems || elems->parse_error) | |
833 | + break; | |
834 | + | |
835 | + ieee80211_sta_process_chanswitch(sdata, | |
836 | + rx_status->mactime, | |
837 | + rx_status->device_timestamp, | |
838 | +- &elems, false); | |
839 | ++ elems, false); | |
840 | ++ kfree(elems); | |
841 | + } else if (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) { | |
842 | ++ struct ieee802_11_elems *elems; | |
843 | ++ | |
844 | + ies_len = skb->len - | |
845 | + offsetof(struct ieee80211_mgmt, | |
846 | + u.action.u.ext_chan_switch.variable); | |
847 | +@@ -4357,21 +4380,22 @@ void ieee80211_sta_rx_queued_mgmt(struct | |
848 | + * extended CSA IE can't be overridden, no need for | |
849 | + * BSSID | |
850 | + */ | |
851 | +- ieee802_11_parse_elems( | |
852 | +- mgmt->u.action.u.ext_chan_switch.variable, | |
853 | +- ies_len, true, &elems, mgmt->bssid, NULL); | |
854 | ++ elems = ieee802_11_parse_elems( | |
855 | ++ mgmt->u.action.u.ext_chan_switch.variable, | |
856 | ++ ies_len, true, mgmt->bssid, NULL); | |
857 | + | |
858 | +- if (elems.parse_error) | |
859 | ++ if (!elems || elems->parse_error) | |
860 | + break; | |
861 | + | |
862 | + /* for the handling code pretend this was also an IE */ | |
863 | +- elems.ext_chansw_ie = | |
864 | ++ elems->ext_chansw_ie = | |
865 | + &mgmt->u.action.u.ext_chan_switch.data; | |
866 | + | |
867 | + ieee80211_sta_process_chanswitch(sdata, | |
868 | + rx_status->mactime, | |
869 | + rx_status->device_timestamp, | |
870 | +- &elems, false); | |
871 | ++ elems, false); | |
872 | ++ kfree(elems); | |
873 | + } | |
874 | + break; | |
875 | + } | |
876 | +--- a/net/mac80211/scan.c | |
877 | ++++ b/net/mac80211/scan.c | |
878 | +@@ -9,7 +9,7 @@ | |
879 | + * Copyright 2007, Michael Wu <flamingice@sourmilk.net> | |
880 | + * Copyright 2013-2015 Intel Mobile Communications GmbH | |
881 | + * Copyright 2016-2017 Intel Deutschland GmbH | |
882 | +- * Copyright (C) 2018-2020 Intel Corporation | |
883 | ++ * Copyright (C) 2018-2021 Intel Corporation | |
884 | + */ | |
885 | + | |
886 | + #include <linux/if_arp.h> | |
887 | +@@ -155,7 +155,7 @@ ieee80211_bss_info_update(struct ieee802 | |
888 | + }; | |
889 | + bool signal_valid; | |
890 | + struct ieee80211_sub_if_data *scan_sdata; | |
891 | +- struct ieee802_11_elems elems; | |
892 | ++ struct ieee802_11_elems *elems; | |
893 | + size_t baselen; | |
894 | + u8 *elements; | |
895 | + | |
896 | +@@ -209,8 +209,10 @@ ieee80211_bss_info_update(struct ieee802 | |
897 | + if (baselen > len) | |
898 | + return NULL; | |
899 | + | |
900 | +- ieee802_11_parse_elems(elements, len - baselen, false, &elems, | |
901 | +- mgmt->bssid, cbss->bssid); | |
902 | ++ elems = ieee802_11_parse_elems(elements, len - baselen, false, | |
903 | ++ mgmt->bssid, cbss->bssid); | |
904 | ++ if (!elems) | |
905 | ++ return NULL; | |
906 | + | |
907 | + /* In case the signal is invalid update the status */ | |
908 | + signal_valid = channel == cbss->channel; | |
909 | +@@ -218,15 +220,17 @@ ieee80211_bss_info_update(struct ieee802 | |
910 | + rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL; | |
911 | + | |
912 | + bss = (void *)cbss->priv; | |
913 | +- ieee80211_update_bss_from_elems(local, bss, &elems, rx_status, beacon); | |
914 | ++ ieee80211_update_bss_from_elems(local, bss, elems, rx_status, beacon); | |
915 | + | |
916 | + list_for_each_entry(non_tx_cbss, &cbss->nontrans_list, nontrans_list) { | |
917 | + non_tx_bss = (void *)non_tx_cbss->priv; | |
918 | + | |
919 | +- ieee80211_update_bss_from_elems(local, non_tx_bss, &elems, | |
920 | ++ ieee80211_update_bss_from_elems(local, non_tx_bss, elems, | |
921 | + rx_status, beacon); | |
922 | + } | |
923 | + | |
924 | ++ kfree(elems); | |
925 | ++ | |
926 | + return bss; | |
927 | + } | |
928 | + | |
929 | +--- a/net/mac80211/tdls.c | |
930 | ++++ b/net/mac80211/tdls.c | |
931 | +@@ -6,7 +6,7 @@ | |
932 | + * Copyright 2014, Intel Corporation | |
933 | + * Copyright 2014 Intel Mobile Communications GmbH | |
934 | + * Copyright 2015 - 2016 Intel Deutschland GmbH | |
935 | +- * Copyright (C) 2019 Intel Corporation | |
936 | ++ * Copyright (C) 2019, 2021 Intel Corporation | |
937 | + */ | |
938 | + | |
939 | + #include <linux/ieee80211.h> | |
940 | +@@ -1684,7 +1684,7 @@ ieee80211_process_tdls_channel_switch_re | |
941 | + struct sk_buff *skb) | |
942 | + { | |
943 | + struct ieee80211_local *local = sdata->local; | |
944 | +- struct ieee802_11_elems elems; | |
945 | ++ struct ieee802_11_elems *elems = NULL; | |
946 | + struct sta_info *sta; | |
947 | + struct ieee80211_tdls_data *tf = (void *)skb->data; | |
948 | + bool local_initiator; | |
949 | +@@ -1718,16 +1718,20 @@ ieee80211_process_tdls_channel_switch_re | |
950 | + goto call_drv; | |
951 | + } | |
952 | + | |
953 | +- ieee802_11_parse_elems(tf->u.chan_switch_resp.variable, | |
954 | +- skb->len - baselen, false, &elems, | |
955 | +- NULL, NULL); | |
956 | +- if (elems.parse_error) { | |
957 | ++ elems = ieee802_11_parse_elems(tf->u.chan_switch_resp.variable, | |
958 | ++ skb->len - baselen, false, NULL, NULL); | |
959 | ++ if (!elems) { | |
960 | ++ ret = -ENOMEM; | |
961 | ++ goto out; | |
962 | ++ } | |
963 | ++ | |
964 | ++ if (elems->parse_error) { | |
965 | + tdls_dbg(sdata, "Invalid IEs in TDLS channel switch resp\n"); | |
966 | + ret = -EINVAL; | |
967 | + goto out; | |
968 | + } | |
969 | + | |
970 | +- if (!elems.ch_sw_timing || !elems.lnk_id) { | |
971 | ++ if (!elems->ch_sw_timing || !elems->lnk_id) { | |
972 | + tdls_dbg(sdata, "TDLS channel switch resp - missing IEs\n"); | |
973 | + ret = -EINVAL; | |
974 | + goto out; | |
975 | +@@ -1735,15 +1739,15 @@ ieee80211_process_tdls_channel_switch_re | |
976 | + | |
977 | + /* validate the initiator is set correctly */ | |
978 | + local_initiator = | |
979 | +- !memcmp(elems.lnk_id->init_sta, sdata->vif.addr, ETH_ALEN); | |
980 | ++ !memcmp(elems->lnk_id->init_sta, sdata->vif.addr, ETH_ALEN); | |
981 | + if (local_initiator == sta->sta.tdls_initiator) { | |
982 | + tdls_dbg(sdata, "TDLS chan switch invalid lnk-id initiator\n"); | |
983 | + ret = -EINVAL; | |
984 | + goto out; | |
985 | + } | |
986 | + | |
987 | +- params.switch_time = le16_to_cpu(elems.ch_sw_timing->switch_time); | |
988 | +- params.switch_timeout = le16_to_cpu(elems.ch_sw_timing->switch_timeout); | |
989 | ++ params.switch_time = le16_to_cpu(elems->ch_sw_timing->switch_time); | |
990 | ++ params.switch_timeout = le16_to_cpu(elems->ch_sw_timing->switch_timeout); | |
991 | + | |
992 | + params.tmpl_skb = | |
993 | + ieee80211_tdls_ch_sw_resp_tmpl_get(sta, ¶ms.ch_sw_tm_ie); | |
994 | +@@ -1763,6 +1767,7 @@ call_drv: | |
995 | + out: | |
996 | + mutex_unlock(&local->sta_mtx); | |
997 | + dev_kfree_skb_any(params.tmpl_skb); | |
998 | ++ kfree(elems); | |
999 | + return ret; | |
1000 | + } | |
1001 | + | |
1002 | +@@ -1771,7 +1776,7 @@ ieee80211_process_tdls_channel_switch_re | |
1003 | + struct sk_buff *skb) | |
1004 | + { | |
1005 | + struct ieee80211_local *local = sdata->local; | |
1006 | +- struct ieee802_11_elems elems; | |
1007 | ++ struct ieee802_11_elems *elems; | |
1008 | + struct cfg80211_chan_def chandef; | |
1009 | + struct ieee80211_channel *chan; | |
1010 | + enum nl80211_channel_type chan_type; | |
1011 | +@@ -1831,22 +1836,27 @@ ieee80211_process_tdls_channel_switch_re | |
1012 | + return -EINVAL; | |
1013 | + } | |
1014 | + | |
1015 | +- ieee802_11_parse_elems(tf->u.chan_switch_req.variable, | |
1016 | +- skb->len - baselen, false, &elems, NULL, NULL); | |
1017 | +- if (elems.parse_error) { | |
1018 | ++ elems = ieee802_11_parse_elems(tf->u.chan_switch_req.variable, | |
1019 | ++ skb->len - baselen, false, NULL, NULL); | |
1020 | ++ if (!elems) | |
1021 | ++ return -ENOMEM; | |
1022 | ++ | |
1023 | ++ if (elems->parse_error) { | |
1024 | + tdls_dbg(sdata, "Invalid IEs in TDLS channel switch req\n"); | |
1025 | +- return -EINVAL; | |
1026 | ++ ret = -EINVAL; | |
1027 | ++ goto free; | |
1028 | + } | |
1029 | + | |
1030 | +- if (!elems.ch_sw_timing || !elems.lnk_id) { | |
1031 | ++ if (!elems->ch_sw_timing || !elems->lnk_id) { | |
1032 | + tdls_dbg(sdata, "TDLS channel switch req - missing IEs\n"); | |
1033 | +- return -EINVAL; | |
1034 | ++ ret = -EINVAL; | |
1035 | ++ goto free; | |
1036 | + } | |
1037 | + | |
1038 | +- if (!elems.sec_chan_offs) { | |
1039 | ++ if (!elems->sec_chan_offs) { | |
1040 | + chan_type = NL80211_CHAN_HT20; | |
1041 | + } else { | |
1042 | +- switch (elems.sec_chan_offs->sec_chan_offs) { | |
1043 | ++ switch (elems->sec_chan_offs->sec_chan_offs) { | |
1044 | + case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: | |
1045 | + chan_type = NL80211_CHAN_HT40PLUS; | |
1046 | + break; | |
1047 | +@@ -1865,7 +1875,8 @@ ieee80211_process_tdls_channel_switch_re | |
1048 | + if (!cfg80211_reg_can_beacon_relax(sdata->local->hw.wiphy, &chandef, | |
1049 | + sdata->wdev.iftype)) { | |
1050 | + tdls_dbg(sdata, "TDLS chan switch to forbidden channel\n"); | |
1051 | +- return -EINVAL; | |
1052 | ++ ret = -EINVAL; | |
1053 | ++ goto free; | |
1054 | + } | |
1055 | + | |
1056 | + mutex_lock(&local->sta_mtx); | |
1057 | +@@ -1881,7 +1892,7 @@ ieee80211_process_tdls_channel_switch_re | |
1058 | + | |
1059 | + /* validate the initiator is set correctly */ | |
1060 | + local_initiator = | |
1061 | +- !memcmp(elems.lnk_id->init_sta, sdata->vif.addr, ETH_ALEN); | |
1062 | ++ !memcmp(elems->lnk_id->init_sta, sdata->vif.addr, ETH_ALEN); | |
1063 | + if (local_initiator == sta->sta.tdls_initiator) { | |
1064 | + tdls_dbg(sdata, "TDLS chan switch invalid lnk-id initiator\n"); | |
1065 | + ret = -EINVAL; | |
1066 | +@@ -1889,16 +1900,16 @@ ieee80211_process_tdls_channel_switch_re | |
1067 | + } | |
1068 | + | |
1069 | + /* peer should have known better */ | |
1070 | +- if (!sta->sta.ht_cap.ht_supported && elems.sec_chan_offs && | |
1071 | +- elems.sec_chan_offs->sec_chan_offs) { | |
1072 | ++ if (!sta->sta.ht_cap.ht_supported && elems->sec_chan_offs && | |
1073 | ++ elems->sec_chan_offs->sec_chan_offs) { | |
1074 | + tdls_dbg(sdata, "TDLS chan switch - wide chan unsupported\n"); | |
1075 | + ret = -ENOTSUPP; | |
1076 | + goto out; | |
1077 | + } | |
1078 | + | |
1079 | + params.chandef = &chandef; | |
1080 | +- params.switch_time = le16_to_cpu(elems.ch_sw_timing->switch_time); | |
1081 | +- params.switch_timeout = le16_to_cpu(elems.ch_sw_timing->switch_timeout); | |
1082 | ++ params.switch_time = le16_to_cpu(elems->ch_sw_timing->switch_time); | |
1083 | ++ params.switch_timeout = le16_to_cpu(elems->ch_sw_timing->switch_timeout); | |
1084 | + | |
1085 | + params.tmpl_skb = | |
1086 | + ieee80211_tdls_ch_sw_resp_tmpl_get(sta, | |
1087 | +@@ -1917,6 +1928,8 @@ ieee80211_process_tdls_channel_switch_re | |
1088 | + out: | |
1089 | + mutex_unlock(&local->sta_mtx); | |
1090 | + dev_kfree_skb_any(params.tmpl_skb); | |
1091 | ++free: | |
1092 | ++ kfree(elems); | |
1093 | + return ret; | |
1094 | + } | |
1095 | + | |
1096 | +--- a/net/mac80211/util.c | |
1097 | ++++ b/net/mac80211/util.c | |
1098 | +@@ -1399,8 +1399,8 @@ _ieee802_11_parse_elems_crc(const u8 *st | |
1099 | + | |
1100 | + static size_t ieee802_11_find_bssid_profile(const u8 *start, size_t len, | |
1101 | + struct ieee802_11_elems *elems, | |
1102 | +- u8 *transmitter_bssid, | |
1103 | +- u8 *bss_bssid, | |
1104 | ++ const u8 *transmitter_bssid, | |
1105 | ++ const u8 *bss_bssid, | |
1106 | + u8 *nontransmitted_profile) | |
1107 | + { | |
1108 | + const struct element *elem, *sub; | |
1109 | +@@ -1465,16 +1465,20 @@ static size_t ieee802_11_find_bssid_prof | |
1110 | + return found ? profile_len : 0; | |
1111 | + } | |
1112 | + | |
1113 | +-void ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, | |
1114 | +- struct ieee802_11_elems *elems, | |
1115 | +- u64 filter, u32 crc, u8 *transmitter_bssid, | |
1116 | +- u8 *bss_bssid) | |
1117 | ++struct ieee802_11_elems *ieee802_11_parse_elems_crc(const u8 *start, size_t len, | |
1118 | ++ bool action, u64 filter, | |
1119 | ++ u32 crc, | |
1120 | ++ const u8 *transmitter_bssid, | |
1121 | ++ const u8 *bss_bssid) | |
1122 | + { | |
1123 | ++ struct ieee802_11_elems *elems; | |
1124 | + const struct element *non_inherit = NULL; | |
1125 | + u8 *nontransmitted_profile; | |
1126 | + int nontransmitted_profile_len = 0; | |
1127 | + | |
1128 | +- memset(elems, 0, sizeof(*elems)); | |
1129 | ++ elems = kzalloc(sizeof(*elems), GFP_ATOMIC); | |
1130 | ++ if (!elems) | |
1131 | ++ return NULL; | |
1132 | + elems->ie_start = start; | |
1133 | + elems->total_len = len; | |
1134 | + | |
1135 | +@@ -1521,6 +1525,8 @@ void ieee802_11_parse_elems_crc(const u8 | |
1136 | + kfree(nontransmitted_profile); | |
1137 | + | |
1138 | + elems->crc = crc; | |
1139 | ++ | |
1140 | ++ return elems; | |
1141 | + } | |
1142 | + | |
1143 | + void ieee80211_regulatory_limit_wmm_params(struct ieee80211_sub_if_data *sdata, |
@@ -0,0 +1,115 @@ | ||
1 | +From: Johannes Berg <johannes.berg@intel.com> | |
2 | +Date: Fri, 1 Oct 2021 21:11:08 +0200 | |
3 | +Subject: [PATCH] mac80211: fix memory leaks with element parsing | |
4 | + | |
5 | +commit 8223ac199a3849257e86ec27865dc63f034b1cf1 upstream. | |
6 | + | |
7 | +My previous commit 5d24828d05f3 ("mac80211: always allocate | |
8 | +struct ieee802_11_elems") had a few bugs and leaked the new | |
9 | +allocated struct in a few error cases, fix that. | |
10 | + | |
11 | +Fixes: 5d24828d05f3 ("mac80211: always allocate struct ieee802_11_elems") | |
12 | +Signed-off-by: Johannes Berg <johannes.berg@intel.com> | |
13 | +Link: https://lore.kernel.org/r/20211001211108.9839928e42e0.Ib81ca187d3d3af7ed1bfeac2e00d08a4637c8025@changeid | |
14 | +Signed-off-by: Johannes Berg <johannes.berg@intel.com> | |
15 | +--- | |
16 | + | |
17 | +--- a/net/mac80211/agg-rx.c | |
18 | ++++ b/net/mac80211/agg-rx.c | |
19 | +@@ -499,13 +499,14 @@ void ieee80211_process_addba_request(str | |
20 | + elems = ieee802_11_parse_elems(mgmt->u.action.u.addba_req.variable, | |
21 | + ies_len, true, mgmt->bssid, NULL); | |
22 | + if (!elems || elems->parse_error) | |
23 | +- return; | |
24 | ++ goto free; | |
25 | + } | |
26 | + | |
27 | + __ieee80211_start_rx_ba_session(sta, dialog_token, timeout, | |
28 | + start_seq_num, ba_policy, tid, | |
29 | + buf_size, true, false, | |
30 | + elems ? elems->addba_ext_ie : NULL); | |
31 | ++free: | |
32 | + kfree(elems); | |
33 | + } | |
34 | + | |
35 | +--- a/net/mac80211/ibss.c | |
36 | ++++ b/net/mac80211/ibss.c | |
37 | +@@ -1659,11 +1659,11 @@ void ieee80211_ibss_rx_queued_mgmt(struc | |
38 | + mgmt->u.action.u.chan_switch.variable, | |
39 | + ies_len, true, mgmt->bssid, NULL); | |
40 | + | |
41 | +- if (!elems || elems->parse_error) | |
42 | +- break; | |
43 | +- | |
44 | +- ieee80211_rx_mgmt_spectrum_mgmt(sdata, mgmt, skb->len, | |
45 | +- rx_status, elems); | |
46 | ++ if (elems && !elems->parse_error) | |
47 | ++ ieee80211_rx_mgmt_spectrum_mgmt(sdata, mgmt, | |
48 | ++ skb->len, | |
49 | ++ rx_status, | |
50 | ++ elems); | |
51 | + kfree(elems); | |
52 | + break; | |
53 | + } | |
54 | +--- a/net/mac80211/mlme.c | |
55 | ++++ b/net/mac80211/mlme.c | |
56 | +@@ -3374,8 +3374,10 @@ static bool ieee80211_assoc_success(stru | |
57 | + bss_ies = kmemdup(ies, sizeof(*ies) + ies->len, | |
58 | + GFP_ATOMIC); | |
59 | + rcu_read_unlock(); | |
60 | +- if (!bss_ies) | |
61 | +- return false; | |
62 | ++ if (!bss_ies) { | |
63 | ++ ret = false; | |
64 | ++ goto out; | |
65 | ++ } | |
66 | + | |
67 | + bss_elems = ieee802_11_parse_elems(bss_ies->data, bss_ies->len, | |
68 | + false, mgmt->bssid, | |
69 | +@@ -4358,13 +4360,11 @@ void ieee80211_sta_rx_queued_mgmt(struct | |
70 | + mgmt->u.action.u.chan_switch.variable, | |
71 | + ies_len, true, mgmt->bssid, NULL); | |
72 | + | |
73 | +- if (!elems || elems->parse_error) | |
74 | +- break; | |
75 | +- | |
76 | +- ieee80211_sta_process_chanswitch(sdata, | |
77 | +- rx_status->mactime, | |
78 | +- rx_status->device_timestamp, | |
79 | +- elems, false); | |
80 | ++ if (elems && !elems->parse_error) | |
81 | ++ ieee80211_sta_process_chanswitch(sdata, | |
82 | ++ rx_status->mactime, | |
83 | ++ rx_status->device_timestamp, | |
84 | ++ elems, false); | |
85 | + kfree(elems); | |
86 | + } else if (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) { | |
87 | + struct ieee802_11_elems *elems; | |
88 | +@@ -4384,17 +4384,17 @@ void ieee80211_sta_rx_queued_mgmt(struct | |
89 | + mgmt->u.action.u.ext_chan_switch.variable, | |
90 | + ies_len, true, mgmt->bssid, NULL); | |
91 | + | |
92 | +- if (!elems || elems->parse_error) | |
93 | +- break; | |
94 | ++ if (elems && !elems->parse_error) { | |
95 | ++ /* for the handling code pretend it was an IE */ | |
96 | ++ elems->ext_chansw_ie = | |
97 | ++ &mgmt->u.action.u.ext_chan_switch.data; | |
98 | ++ | |
99 | ++ ieee80211_sta_process_chanswitch(sdata, | |
100 | ++ rx_status->mactime, | |
101 | ++ rx_status->device_timestamp, | |
102 | ++ elems, false); | |
103 | ++ } | |
104 | + | |
105 | +- /* for the handling code pretend this was also an IE */ | |
106 | +- elems->ext_chansw_ie = | |
107 | +- &mgmt->u.action.u.ext_chan_switch.data; | |
108 | +- | |
109 | +- ieee80211_sta_process_chanswitch(sdata, | |
110 | +- rx_status->mactime, | |
111 | +- rx_status->device_timestamp, | |
112 | +- elems, false); | |
113 | + kfree(elems); | |
114 | + } | |
115 | + break; |
@@ -0,0 +1,41 @@ | ||
1 | +From: Johannes Berg <johannes.berg@intel.com> | |
2 | +Date: Wed, 28 Sep 2022 21:56:15 +0200 | |
3 | +Subject: [PATCH] wifi: cfg80211: fix u8 overflow in | |
4 | + cfg80211_update_notlisted_nontrans() | |
5 | + | |
6 | +commit aebe9f4639b13a1f4e9a6b42cdd2e38c617b442d upstream. | |
7 | + | |
8 | +In the copy code of the elements, we do the following calculation | |
9 | +to reach the end of the MBSSID element: | |
10 | + | |
11 | + /* copy the IEs after MBSSID */ | |
12 | + cpy_len = mbssid[1] + 2; | |
13 | + | |
14 | +This looks fine, however, cpy_len is a u8, the same as mbssid[1], | |
15 | +so the addition of two can overflow. In this case the subsequent | |
16 | +memcpy() will overflow the allocated buffer, since it copies 256 | |
17 | +bytes too much due to the way the allocation and memcpy() sizes | |
18 | +are calculated. | |
19 | + | |
20 | +Fix this by using size_t for the cpy_len variable. | |
21 | + | |
22 | +This fixes CVE-2022-41674. | |
23 | + | |
24 | +Reported-by: Soenke Huster <shuster@seemoo.tu-darmstadt.de> | |
25 | +Tested-by: Soenke Huster <shuster@seemoo.tu-darmstadt.de> | |
26 | +Fixes: 0b8fb8235be8 ("cfg80211: Parsing of Multiple BSSID information in scanning") | |
27 | +Reviewed-by: Kees Cook <keescook@chromium.org> | |
28 | +Signed-off-by: Johannes Berg <johannes.berg@intel.com> | |
29 | +--- | |
30 | + | |
31 | +--- a/net/wireless/scan.c | |
32 | ++++ b/net/wireless/scan.c | |
33 | +@@ -2238,7 +2238,7 @@ cfg80211_update_notlisted_nontrans(struc | |
34 | + size_t new_ie_len; | |
35 | + struct cfg80211_bss_ies *new_ies; | |
36 | + const struct cfg80211_bss_ies *old; | |
37 | +- u8 cpy_len; | |
38 | ++ size_t cpy_len; | |
39 | + | |
40 | + lockdep_assert_held(&wiphy_to_rdev(wiphy)->bss_lock); | |
41 | + |
@@ -0,0 +1,47 @@ | ||
1 | +From: Johannes Berg <johannes.berg@intel.com> | |
2 | +Date: Wed, 28 Sep 2022 22:01:37 +0200 | |
3 | +Subject: [PATCH] wifi: cfg80211/mac80211: reject bad MBSSID elements | |
4 | + | |
5 | +commit 8f033d2becc24aa6bfd2a5c104407963560caabc upstream | |
6 | + | |
7 | +Per spec, the maximum value for the MaxBSSID ('n') indicator is 8, | |
8 | +and the minimum is 1 since a multiple BSSID set with just one BSSID | |
9 | +doesn't make sense (the # of BSSIDs is limited by 2^n). | |
10 | + | |
11 | +Limit this in the parsing in both cfg80211 and mac80211, rejecting | |
12 | +any elements with an invalid value. | |
13 | + | |
14 | +This fixes potentially bad shifts in the processing of these inside | |
15 | +the cfg80211_gen_new_bssid() function later. | |
16 | + | |
17 | +I found this during the investigation of CVE-2022-41674 fixed by the | |
18 | +previous patch. | |
19 | + | |
20 | +Fixes: 0b8fb8235be8 ("cfg80211: Parsing of Multiple BSSID information in scanning") | |
21 | +Fixes: 78ac51f81532 ("mac80211: support multi-bssid") | |
22 | +Reviewed-by: Kees Cook <keescook@chromium.org> | |
23 | +Signed-off-by: Johannes Berg <johannes.berg@intel.com> | |
24 | +--- | |
25 | + | |
26 | +--- a/net/mac80211/util.c | |
27 | ++++ b/net/mac80211/util.c | |
28 | +@@ -1413,6 +1413,8 @@ static size_t ieee802_11_find_bssid_prof | |
29 | + for_each_element_id(elem, WLAN_EID_MULTIPLE_BSSID, start, len) { | |
30 | + if (elem->datalen < 2) | |
31 | + continue; | |
32 | ++ if (elem->data[0] < 1 || elem->data[0] > 8) | |
33 | ++ continue; | |
34 | + | |
35 | + for_each_element(sub, elem->data + 1, elem->datalen - 1) { | |
36 | + u8 new_bssid[ETH_ALEN]; | |
37 | +--- a/net/wireless/scan.c | |
38 | ++++ b/net/wireless/scan.c | |
39 | +@@ -2103,6 +2103,8 @@ static void cfg80211_parse_mbssid_data(s | |
40 | + for_each_element_id(elem, WLAN_EID_MULTIPLE_BSSID, ie, ielen) { | |
41 | + if (elem->datalen < 4) | |
42 | + continue; | |
43 | ++ if (elem->data[0] < 1 || (int)elem->data[0] > 8) | |
44 | ++ continue; | |
45 | + for_each_element(sub, elem->data + 1, elem->datalen - 1) { | |
46 | + u8 profile_len; | |
47 | + |
@@ -0,0 +1,94 @@ | ||
1 | +From: Johannes Berg <johannes.berg@intel.com> | |
2 | +Date: Wed, 28 Sep 2022 22:07:15 +0200 | |
3 | +Subject: [PATCH] wifi: mac80211: fix MBSSID parsing use-after-free | |
4 | + | |
5 | +commit ff05d4b45dd89b922578dac497dcabf57cf771c6 | |
6 | + | |
7 | +When we parse a multi-BSSID element, we might point some | |
8 | +element pointers into the allocated nontransmitted_profile. | |
9 | +However, we free this before returning, causing UAF when the | |
10 | +relevant pointers in the parsed elements are accessed. | |
11 | + | |
12 | +Fix this by not allocating the scratch buffer separately but | |
13 | +as part of the returned structure instead, that way, there | |
14 | +are no lifetime issues with it. | |
15 | + | |
16 | +The scratch buffer introduction as part of the returned data | |
17 | +here is taken from MLO feature work done by Ilan. | |
18 | + | |
19 | +This fixes CVE-2022-42719. | |
20 | + | |
21 | +Fixes: 5023b14cf4df ("mac80211: support profile split between elements") | |
22 | +Co-developed-by: Ilan Peer <ilan.peer@intel.com> | |
23 | +Signed-off-by: Ilan Peer <ilan.peer@intel.com> | |
24 | +Reviewed-by: Kees Cook <keescook@chromium.org> | |
25 | +Signed-off-by: Johannes Berg <johannes.berg@intel.com> | |
26 | +--- | |
27 | + | |
28 | +--- a/net/mac80211/ieee80211_i.h | |
29 | ++++ b/net/mac80211/ieee80211_i.h | |
30 | +@@ -1611,6 +1611,14 @@ struct ieee802_11_elems { | |
31 | + | |
32 | + /* whether a parse error occurred while retrieving these elements */ | |
33 | + bool parse_error; | |
34 | ++ | |
35 | ++ /* | |
36 | ++ * scratch buffer that can be used for various element parsing related | |
37 | ++ * tasks, e.g., element de-fragmentation etc. | |
38 | ++ */ | |
39 | ++ size_t scratch_len; | |
40 | ++ u8 *scratch_pos; | |
41 | ++ u8 scratch[]; | |
42 | + }; | |
43 | + | |
44 | + static inline struct ieee80211_local *hw_to_local( | |
45 | +--- a/net/mac80211/util.c | |
46 | ++++ b/net/mac80211/util.c | |
47 | +@@ -1478,24 +1478,25 @@ struct ieee802_11_elems *ieee802_11_pars | |
48 | + u8 *nontransmitted_profile; | |
49 | + int nontransmitted_profile_len = 0; | |
50 | + | |
51 | +- elems = kzalloc(sizeof(*elems), GFP_ATOMIC); | |
52 | ++ elems = kzalloc(sizeof(*elems) + len, GFP_ATOMIC); | |
53 | + if (!elems) | |
54 | + return NULL; | |
55 | + elems->ie_start = start; | |
56 | + elems->total_len = len; | |
57 | + | |
58 | +- nontransmitted_profile = kmalloc(len, GFP_ATOMIC); | |
59 | +- if (nontransmitted_profile) { | |
60 | +- nontransmitted_profile_len = | |
61 | +- ieee802_11_find_bssid_profile(start, len, elems, | |
62 | +- transmitter_bssid, | |
63 | +- bss_bssid, | |
64 | +- nontransmitted_profile); | |
65 | +- non_inherit = | |
66 | +- cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE, | |
67 | +- nontransmitted_profile, | |
68 | +- nontransmitted_profile_len); | |
69 | +- } | |
70 | ++ elems->scratch_len = len; | |
71 | ++ elems->scratch_pos = elems->scratch; | |
72 | ++ | |
73 | ++ nontransmitted_profile = elems->scratch_pos; | |
74 | ++ nontransmitted_profile_len = | |
75 | ++ ieee802_11_find_bssid_profile(start, len, elems, | |
76 | ++ transmitter_bssid, | |
77 | ++ bss_bssid, | |
78 | ++ nontransmitted_profile); | |
79 | ++ non_inherit = | |
80 | ++ cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE, | |
81 | ++ nontransmitted_profile, | |
82 | ++ nontransmitted_profile_len); | |
83 | + | |
84 | + crc = _ieee802_11_parse_elems_crc(start, len, action, elems, filter, | |
85 | + crc, non_inherit); | |
86 | +@@ -1524,8 +1525,6 @@ struct ieee802_11_elems *ieee802_11_pars | |
87 | + offsetofend(struct ieee80211_bssid_index, dtim_count)) | |
88 | + elems->dtim_count = elems->bssid_index->dtim_count; | |
89 | + | |
90 | +- kfree(nontransmitted_profile); | |
91 | +- | |
92 | + elems->crc = crc; | |
93 | + | |
94 | + return elems; |
@@ -0,0 +1,41 @@ | ||
1 | +From: Johannes Berg <johannes.berg@intel.com> | |
2 | +Date: Thu, 29 Sep 2022 21:50:44 +0200 | |
3 | +Subject: [PATCH] wifi: cfg80211: ensure length byte is present before | |
4 | + access | |
5 | + | |
6 | +commit 567e14e39e8f8c6997a1378bc3be615afca86063 upstream. | |
7 | + | |
8 | +When iterating the elements here, ensure the length byte is | |
9 | +present before checking it to see if the entire element will | |
10 | +fit into the buffer. | |
11 | + | |
12 | +Longer term, we should rewrite this code using the type-safe | |
13 | +element iteration macros that check all of this. | |
14 | + | |
15 | +Fixes: 0b8fb8235be8 ("cfg80211: Parsing of Multiple BSSID information in scanning") | |
16 | +Reported-by: Soenke Huster <shuster@seemoo.tu-darmstadt.de> | |
17 | +Signed-off-by: Johannes Berg <johannes.berg@intel.com> | |
18 | +--- | |
19 | + | |
20 | +--- a/net/wireless/scan.c | |
21 | ++++ b/net/wireless/scan.c | |
22 | +@@ -304,7 +304,8 @@ static size_t cfg80211_gen_new_ie(const | |
23 | + tmp_old = cfg80211_find_ie(WLAN_EID_SSID, ie, ielen); | |
24 | + tmp_old = (tmp_old) ? tmp_old + tmp_old[1] + 2 : ie; | |
25 | + | |
26 | +- while (tmp_old + tmp_old[1] + 2 - ie <= ielen) { | |
27 | ++ while (tmp_old + 2 - ie <= ielen && | |
28 | ++ tmp_old + tmp_old[1] + 2 - ie <= ielen) { | |
29 | + if (tmp_old[0] == 0) { | |
30 | + tmp_old++; | |
31 | + continue; | |
32 | +@@ -364,7 +365,8 @@ static size_t cfg80211_gen_new_ie(const | |
33 | + * copied to new ie, skip ssid, capability, bssid-index ie | |
34 | + */ | |
35 | + tmp_new = sub_copy; | |
36 | +- while (tmp_new + tmp_new[1] + 2 - sub_copy <= subie_len) { | |
37 | ++ while (tmp_new + 2 - sub_copy <= subie_len && | |
38 | ++ tmp_new + tmp_new[1] + 2 - sub_copy <= subie_len) { | |
39 | + if (!(tmp_new[0] == WLAN_EID_NON_TX_BSSID_CAP || | |
40 | + tmp_new[0] == WLAN_EID_SSID)) { | |
41 | + memcpy(pos, tmp_new, tmp_new[1] + 2); |
@@ -0,0 +1,87 @@ | ||
1 | +From: Johannes Berg <johannes.berg@intel.com> | |
2 | +Date: Fri, 30 Sep 2022 23:44:23 +0200 | |
3 | +Subject: [PATCH] wifi: cfg80211: fix BSS refcounting bugs | |
4 | +MIME-Version: 1.0 | |
5 | +Content-Type: text/plain; charset=UTF-8 | |
6 | +Content-Transfer-Encoding: 8bit | |
7 | + | |
8 | +commit 0b7808818cb9df6680f98996b8e9a439fa7bcc2f upstream. | |
9 | + | |
10 | +There are multiple refcounting bugs related to multi-BSSID: | |
11 | + - In bss_ref_get(), if the BSS has a hidden_beacon_bss, then | |
12 | + the bss pointer is overwritten before checking for the | |
13 | + transmitted BSS, which is clearly wrong. Fix this by using | |
14 | + the bss_from_pub() macro. | |
15 | + | |
16 | + - In cfg80211_bss_update() we copy the transmitted_bss pointer | |
17 | + from tmp into new, but then if we release new, we'll unref | |
18 | + it erroneously. We already set the pointer and ref it, but | |
19 | + need to NULL it since it was copied from the tmp data. | |
20 | + | |
21 | + - In cfg80211_inform_single_bss_data(), if adding to the non- | |
22 | + transmitted list fails, we unlink the BSS and yet still we | |
23 | + return it, but this results in returning an entry without | |
24 | + a reference. We shouldn't return it anyway if it was broken | |
25 | + enough to not get added there. | |
26 | + | |
27 | +This fixes CVE-2022-42720. | |
28 | + | |
29 | +Reported-by: Sönke Huster <shuster@seemoo.tu-darmstadt.de> | |
30 | +Tested-by: Sönke Huster <shuster@seemoo.tu-darmstadt.de> | |
31 | +Fixes: a3584f56de1c ("cfg80211: Properly track transmitting and non-transmitting BSS") | |
32 | +Signed-off-by: Johannes Berg <johannes.berg@intel.com> | |
33 | +--- | |
34 | + | |
35 | +--- a/net/wireless/scan.c | |
36 | ++++ b/net/wireless/scan.c | |
37 | +@@ -143,18 +143,12 @@ static inline void bss_ref_get(struct cf | |
38 | + lockdep_assert_held(&rdev->bss_lock); | |
39 | + | |
40 | + bss->refcount++; | |
41 | +- if (bss->pub.hidden_beacon_bss) { | |
42 | +- bss = container_of(bss->pub.hidden_beacon_bss, | |
43 | +- struct cfg80211_internal_bss, | |
44 | +- pub); | |
45 | +- bss->refcount++; | |
46 | +- } | |
47 | +- if (bss->pub.transmitted_bss) { | |
48 | +- bss = container_of(bss->pub.transmitted_bss, | |
49 | +- struct cfg80211_internal_bss, | |
50 | +- pub); | |
51 | +- bss->refcount++; | |
52 | +- } | |
53 | ++ | |
54 | ++ if (bss->pub.hidden_beacon_bss) | |
55 | ++ bss_from_pub(bss->pub.hidden_beacon_bss)->refcount++; | |
56 | ++ | |
57 | ++ if (bss->pub.transmitted_bss) | |
58 | ++ bss_from_pub(bss->pub.transmitted_bss)->refcount++; | |
59 | + } | |
60 | + | |
61 | + static inline void bss_ref_put(struct cfg80211_registered_device *rdev, | |
62 | +@@ -1743,6 +1737,8 @@ cfg80211_bss_update(struct cfg80211_regi | |
63 | + new->refcount = 1; | |
64 | + INIT_LIST_HEAD(&new->hidden_list); | |
65 | + INIT_LIST_HEAD(&new->pub.nontrans_list); | |
66 | ++ /* we'll set this later if it was non-NULL */ | |
67 | ++ new->pub.transmitted_bss = NULL; | |
68 | + | |
69 | + if (rcu_access_pointer(tmp->pub.proberesp_ies)) { | |
70 | + hidden = rb_find_bss(rdev, tmp, BSS_CMP_HIDE_ZLEN); | |
71 | +@@ -1983,10 +1979,15 @@ cfg80211_inform_single_bss_data(struct w | |
72 | + spin_lock_bh(&rdev->bss_lock); | |
73 | + if (cfg80211_add_nontrans_list(non_tx_data->tx_bss, | |
74 | + &res->pub)) { | |
75 | +- if (__cfg80211_unlink_bss(rdev, res)) | |
76 | ++ if (__cfg80211_unlink_bss(rdev, res)) { | |
77 | + rdev->bss_generation++; | |
78 | ++ res = NULL; | |
79 | ++ } | |
80 | + } | |
81 | + spin_unlock_bh(&rdev->bss_lock); | |
82 | ++ | |
83 | ++ if (!res) | |
84 | ++ return NULL; | |
85 | + } | |
86 | + | |
87 | + trace_cfg80211_return_bss(&res->pub); |
@@ -0,0 +1,48 @@ | ||
1 | +From: Johannes Berg <johannes.berg@intel.com> | |
2 | +Date: Sat, 1 Oct 2022 00:01:44 +0200 | |
3 | +Subject: [PATCH] wifi: cfg80211: avoid nontransmitted BSS list | |
4 | + corruption | |
5 | +MIME-Version: 1.0 | |
6 | +Content-Type: text/plain; charset=UTF-8 | |
7 | +Content-Transfer-Encoding: 8bit | |
8 | + | |
9 | +commit bcca852027e5878aec911a347407ecc88d6fff7f upstream. | |
10 | + | |
11 | +If a non-transmitted BSS shares enough information (both | |
12 | +SSID and BSSID!) with another non-transmitted BSS of a | |
13 | +different AP, then we can find and update it, and then | |
14 | +try to add it to the non-transmitted BSS list. We do a | |
15 | +search for it on the transmitted BSS, but if it's not | |
16 | +there (but belongs to another transmitted BSS), the list | |
17 | +gets corrupted. | |
18 | + | |
19 | +Since this is an erroneous situation, simply fail the | |
20 | +list insertion in this case and free the non-transmitted | |
21 | +BSS. | |
22 | + | |
23 | +This fixes CVE-2022-42721. | |
24 | + | |
25 | +Reported-by: Sönke Huster <shuster@seemoo.tu-darmstadt.de> | |
26 | +Tested-by: Sönke Huster <shuster@seemoo.tu-darmstadt.de> | |
27 | +Fixes: 0b8fb8235be8 ("cfg80211: Parsing of Multiple BSSID information in scanning") | |
28 | +Signed-off-by: Johannes Berg <johannes.berg@intel.com> | |
29 | +--- | |
30 | + | |
31 | +--- a/net/wireless/scan.c | |
32 | ++++ b/net/wireless/scan.c | |
33 | +@@ -425,6 +425,15 @@ cfg80211_add_nontrans_list(struct cfg802 | |
34 | + | |
35 | + rcu_read_unlock(); | |
36 | + | |
37 | ++ /* | |
38 | ++ * This is a bit weird - it's not on the list, but already on another | |
39 | ++ * one! The only way that could happen is if there's some BSSID/SSID | |
40 | ++ * shared by multiple APs in their multi-BSSID profiles, potentially | |
41 | ++ * with hidden SSID mixed in ... ignore it. | |
42 | ++ */ | |
43 | ++ if (!list_empty(&nontrans_bss->nontrans_list)) | |
44 | ++ return -EINVAL; | |
45 | ++ | |
46 | + /* add to the list */ | |
47 | + list_add_tail(&nontrans_bss->nontrans_list, &trans_bss->nontrans_list); | |
48 | + return 0; |
@@ -0,0 +1,31 @@ | ||
1 | +From: Johannes Berg <johannes.berg@intel.com> | |
2 | +Date: Wed, 5 Oct 2022 15:10:09 +0200 | |
3 | +Subject: [PATCH] wifi: mac80211_hwsim: avoid mac80211 warning on bad | |
4 | + rate | |
5 | +MIME-Version: 1.0 | |
6 | +Content-Type: text/plain; charset=UTF-8 | |
7 | +Content-Transfer-Encoding: 8bit | |
8 | + | |
9 | +commit 1833b6f46d7e2830251a063935ab464256defe22 upstream. | |
10 | + | |
11 | +If the tool on the other side (e.g. wmediumd) gets confused | |
12 | +about the rate, we hit a warning in mac80211. Silence that | |
13 | +by effectively duplicating the check here and dropping the | |
14 | +frame silently (in mac80211 it's dropped with the warning). | |
15 | + | |
16 | +Reported-by: Sönke Huster <shuster@seemoo.tu-darmstadt.de> | |
17 | +Tested-by: Sönke Huster <shuster@seemoo.tu-darmstadt.de> | |
18 | +Signed-off-by: Johannes Berg <johannes.berg@intel.com> | |
19 | +--- | |
20 | + | |
21 | +--- a/drivers/net/wireless/mac80211_hwsim.c | |
22 | ++++ b/drivers/net/wireless/mac80211_hwsim.c | |
23 | +@@ -3760,6 +3760,8 @@ static int hwsim_cloned_frame_received_n | |
24 | + | |
25 | + rx_status.band = channel->band; | |
26 | + rx_status.rate_idx = nla_get_u32(info->attrs[HWSIM_ATTR_RX_RATE]); | |
27 | ++ if (rx_status.rate_idx >= data2->hw->wiphy->bands[rx_status.band]->n_bitrates) | |
28 | ++ goto out; | |
29 | + rx_status.signal = nla_get_u32(info->attrs[HWSIM_ATTR_SIGNAL]); | |
30 | + | |
31 | + hdr = (void *)skb->data; |
@@ -0,0 +1,52 @@ | ||
1 | +From: Johannes Berg <johannes.berg@intel.com> | |
2 | +Date: Wed, 5 Oct 2022 21:24:10 +0200 | |
3 | +Subject: [PATCH] wifi: mac80211: fix crash in beacon protection for | |
4 | + P2P-device | |
5 | +MIME-Version: 1.0 | |
6 | +Content-Type: text/plain; charset=UTF-8 | |
7 | +Content-Transfer-Encoding: 8bit | |
8 | + | |
9 | +commit b2d03cabe2b2e150ff5a381731ea0355459be09f upstream. | |
10 | + | |
11 | +If beacon protection is active but the beacon cannot be | |
12 | +decrypted or is otherwise malformed, we call the cfg80211 | |
13 | +API to report this to userspace, but that uses a netdev | |
14 | +pointer, which isn't present for P2P-Device. Fix this to | |
15 | +call it only conditionally to ensure cfg80211 won't crash | |
16 | +in the case of P2P-Device. | |
17 | + | |
18 | +This fixes CVE-2022-42722. | |
19 | + | |
20 | +Reported-by: Sönke Huster <shuster@seemoo.tu-darmstadt.de> | |
21 | +Fixes: 9eaf183af741 ("mac80211: Report beacon protection failures to user space") | |
22 | +Signed-off-by: Johannes Berg <johannes.berg@intel.com> | |
23 | +--- | |
24 | + | |
25 | +--- a/net/mac80211/rx.c | |
26 | ++++ b/net/mac80211/rx.c | |
27 | +@@ -1986,10 +1986,11 @@ ieee80211_rx_h_decrypt(struct ieee80211_ | |
28 | + | |
29 | + if (mmie_keyidx < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS || | |
30 | + mmie_keyidx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS + | |
31 | +- NUM_DEFAULT_BEACON_KEYS) { | |
32 | +- cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev, | |
33 | +- skb->data, | |
34 | +- skb->len); | |
35 | ++ NUM_DEFAULT_BEACON_KEYS) { | |
36 | ++ if (rx->sdata->dev) | |
37 | ++ cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev, | |
38 | ++ skb->data, | |
39 | ++ skb->len); | |
40 | + return RX_DROP_MONITOR; /* unexpected BIP keyidx */ | |
41 | + } | |
42 | + | |
43 | +@@ -2137,7 +2138,8 @@ ieee80211_rx_h_decrypt(struct ieee80211_ | |
44 | + /* either the frame has been decrypted or will be dropped */ | |
45 | + status->flag |= RX_FLAG_DECRYPTED; | |
46 | + | |
47 | +- if (unlikely(ieee80211_is_beacon(fc) && result == RX_DROP_UNUSABLE)) | |
48 | ++ if (unlikely(ieee80211_is_beacon(fc) && result == RX_DROP_UNUSABLE && | |
49 | ++ rx->sdata->dev)) | |
50 | + cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev, | |
51 | + skb->data, skb->len); | |
52 | + |
@@ -0,0 +1,85 @@ | ||
1 | +From: Johannes Berg <johannes.berg@intel.com> | |
2 | +Date: Wed, 5 Oct 2022 23:11:43 +0200 | |
3 | +Subject: [PATCH] wifi: cfg80211: update hidden BSSes to avoid WARN_ON | |
4 | +MIME-Version: 1.0 | |
5 | +Content-Type: text/plain; charset=UTF-8 | |
6 | +Content-Transfer-Encoding: 8bit | |
7 | + | |
8 | +commit c90b93b5b782891ebfda49d4e5da36632fefd5d1 upstream. | |
9 | + | |
10 | +When updating beacon elements in a non-transmitted BSS, | |
11 | +also update the hidden sub-entries to the same beacon | |
12 | +elements, so that a future update through other paths | |
13 | +won't trigger a WARN_ON(). | |
14 | + | |
15 | +The warning is triggered because the beacon elements in | |
16 | +the hidden BSSes that are children of the BSS should | |
17 | +always be the same as in the parent. | |
18 | + | |
19 | +Reported-by: Sönke Huster <shuster@seemoo.tu-darmstadt.de> | |
20 | +Tested-by: Sönke Huster <shuster@seemoo.tu-darmstadt.de> | |
21 | +Fixes: 0b8fb8235be8 ("cfg80211: Parsing of Multiple BSSID information in scanning") | |
22 | +Signed-off-by: Johannes Berg <johannes.berg@intel.com> | |
23 | +--- | |
24 | + | |
25 | +--- a/net/wireless/scan.c | |
26 | ++++ b/net/wireless/scan.c | |
27 | +@@ -1609,6 +1609,23 @@ struct cfg80211_non_tx_bss { | |
28 | + u8 bssid_index; | |
29 | + }; | |
30 | + | |
31 | ++static void cfg80211_update_hidden_bsses(struct cfg80211_internal_bss *known, | |
32 | ++ const struct cfg80211_bss_ies *new_ies, | |
33 | ++ const struct cfg80211_bss_ies *old_ies) | |
34 | ++{ | |
35 | ++ struct cfg80211_internal_bss *bss; | |
36 | ++ | |
37 | ++ /* Assign beacon IEs to all sub entries */ | |
38 | ++ list_for_each_entry(bss, &known->hidden_list, hidden_list) { | |
39 | ++ const struct cfg80211_bss_ies *ies; | |
40 | ++ | |
41 | ++ ies = rcu_access_pointer(bss->pub.beacon_ies); | |
42 | ++ WARN_ON(ies != old_ies); | |
43 | ++ | |
44 | ++ rcu_assign_pointer(bss->pub.beacon_ies, new_ies); | |
45 | ++ } | |
46 | ++} | |
47 | ++ | |
48 | + static bool | |
49 | + cfg80211_update_known_bss(struct cfg80211_registered_device *rdev, | |
50 | + struct cfg80211_internal_bss *known, | |
51 | +@@ -1632,7 +1649,6 @@ cfg80211_update_known_bss(struct cfg8021 | |
52 | + kfree_rcu((struct cfg80211_bss_ies *)old, rcu_head); | |
53 | + } else if (rcu_access_pointer(new->pub.beacon_ies)) { | |
54 | + const struct cfg80211_bss_ies *old; | |
55 | +- struct cfg80211_internal_bss *bss; | |
56 | + | |
57 | + if (known->pub.hidden_beacon_bss && | |
58 | + !list_empty(&known->hidden_list)) { | |
59 | +@@ -1660,16 +1676,7 @@ cfg80211_update_known_bss(struct cfg8021 | |
60 | + if (old == rcu_access_pointer(known->pub.ies)) | |
61 | + rcu_assign_pointer(known->pub.ies, new->pub.beacon_ies); | |
62 | + | |
63 | +- /* Assign beacon IEs to all sub entries */ | |
64 | +- list_for_each_entry(bss, &known->hidden_list, hidden_list) { | |
65 | +- const struct cfg80211_bss_ies *ies; | |
66 | +- | |
67 | +- ies = rcu_access_pointer(bss->pub.beacon_ies); | |
68 | +- WARN_ON(ies != old); | |
69 | +- | |
70 | +- rcu_assign_pointer(bss->pub.beacon_ies, | |
71 | +- new->pub.beacon_ies); | |
72 | +- } | |
73 | ++ cfg80211_update_hidden_bsses(known, new->pub.beacon_ies, old); | |
74 | + | |
75 | + if (old) | |
76 | + kfree_rcu((struct cfg80211_bss_ies *)old, rcu_head); | |
77 | +@@ -2319,6 +2326,8 @@ cfg80211_update_notlisted_nontrans(struc | |
78 | + } else { | |
79 | + old = rcu_access_pointer(nontrans_bss->beacon_ies); | |
80 | + rcu_assign_pointer(nontrans_bss->beacon_ies, new_ies); | |
81 | ++ cfg80211_update_hidden_bsses(bss_from_pub(nontrans_bss), | |
82 | ++ new_ies, old); | |
83 | + rcu_assign_pointer(nontrans_bss->ies, new_ies); | |
84 | + if (old) | |
85 | + kfree_rcu((struct cfg80211_bss_ies *)old, rcu_head); |
@@ -29,7 +29,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | ||
29 | 29 | |
30 | 30 | --- a/net/mac80211/scan.c |
31 | 31 | +++ b/net/mac80211/scan.c |
32 | -@@ -461,16 +461,19 @@ static void __ieee80211_scan_completed(s | |
32 | +@@ -465,16 +465,19 @@ static void __ieee80211_scan_completed(s | |
33 | 33 | scan_req = rcu_dereference_protected(local->scan_req, |
34 | 34 | lockdep_is_held(&local->mtx)); |
35 | 35 |
@@ -56,7 +56,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com> | ||
56 | 56 | |
57 | 57 | --- a/net/mac80211/rx.c |
58 | 58 | +++ b/net/mac80211/rx.c |
59 | -@@ -3180,6 +3180,49 @@ static void ieee80211_process_sa_query_r | |
59 | +@@ -3182,6 +3182,49 @@ static void ieee80211_process_sa_query_r | |
60 | 60 | ieee80211_tx_skb(sdata, skb); |
61 | 61 | } |
62 | 62 |
@@ -106,7 +106,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com> | ||
106 | 106 | static ieee80211_rx_result debug_noinline |
107 | 107 | ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx) |
108 | 108 | { |
109 | -@@ -3205,6 +3248,9 @@ ieee80211_rx_h_mgmt_check(struct ieee802 | |
109 | +@@ -3207,6 +3250,9 @@ ieee80211_rx_h_mgmt_check(struct ieee802 | |
110 | 110 | !(rx->flags & IEEE80211_RX_BEACON_REPORTED)) { |
111 | 111 | int sig = 0; |
112 | 112 |