Skip to content

Commit ac85bc7

Browse files
author
Paolo Abeni
committed
Merge tag 'wireless-2022-10-13' of git://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless
Johannes Berg says: ==================== More wireless fixes for 6.1 This has only the fixes for the scan parsing issues. * tag 'wireless-2022-10-13' of git://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless: wifi: cfg80211: update hidden BSSes to avoid WARN_ON wifi: mac80211: fix crash in beacon protection for P2P-device wifi: mac80211_hwsim: avoid mac80211 warning on bad rate wifi: cfg80211: avoid nontransmitted BSS list corruption wifi: cfg80211: fix BSS refcounting bugs wifi: cfg80211: ensure length byte is present before access wifi: mac80211: fix MBSSID parsing use-after-free wifi: cfg80211/mac80211: reject bad MBSSID elements wifi: cfg80211: fix u8 overflow in cfg80211_update_notlisted_nontrans() ==================== Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Paolo Abeni <[email protected]>
2 parents fa182ea + e7ad651 commit ac85bc7

File tree

5 files changed

+84
-47
lines changed

5 files changed

+84
-47
lines changed

drivers/net/wireless/mac80211_hwsim.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4973,6 +4973,8 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2,
49734973
}
49744974

49754975
rx_status.rate_idx = nla_get_u32(info->attrs[HWSIM_ATTR_RX_RATE]);
4976+
if (rx_status.rate_idx >= data2->hw->wiphy->bands[rx_status.band]->n_bitrates)
4977+
goto out;
49764978
rx_status.signal = nla_get_u32(info->attrs[HWSIM_ATTR_SIGNAL]);
49774979

49784980
hdr = (void *)skb->data;

net/mac80211/ieee80211_i.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1709,6 +1709,14 @@ struct ieee802_11_elems {
17091709

17101710
/* whether a parse error occurred while retrieving these elements */
17111711
bool parse_error;
1712+
1713+
/*
1714+
* scratch buffer that can be used for various element parsing related
1715+
* tasks, e.g., element de-fragmentation etc.
1716+
*/
1717+
size_t scratch_len;
1718+
u8 *scratch_pos;
1719+
u8 scratch[];
17121720
};
17131721

17141722
static inline struct ieee80211_local *hw_to_local(

net/mac80211/rx.c

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1978,10 +1978,11 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
19781978

19791979
if (mmie_keyidx < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS ||
19801980
mmie_keyidx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS +
1981-
NUM_DEFAULT_BEACON_KEYS) {
1982-
cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev,
1983-
skb->data,
1984-
skb->len);
1981+
NUM_DEFAULT_BEACON_KEYS) {
1982+
if (rx->sdata->dev)
1983+
cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev,
1984+
skb->data,
1985+
skb->len);
19851986
return RX_DROP_MONITOR; /* unexpected BIP keyidx */
19861987
}
19871988

@@ -2131,7 +2132,8 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
21312132
/* either the frame has been decrypted or will be dropped */
21322133
status->flag |= RX_FLAG_DECRYPTED;
21332134

2134-
if (unlikely(ieee80211_is_beacon(fc) && result == RX_DROP_UNUSABLE))
2135+
if (unlikely(ieee80211_is_beacon(fc) && result == RX_DROP_UNUSABLE &&
2136+
rx->sdata->dev))
21352137
cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev,
21362138
skb->data, skb->len);
21372139

net/mac80211/util.c

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1445,6 +1445,8 @@ static size_t ieee802_11_find_bssid_profile(const u8 *start, size_t len,
14451445
for_each_element_id(elem, WLAN_EID_MULTIPLE_BSSID, start, len) {
14461446
if (elem->datalen < 2)
14471447
continue;
1448+
if (elem->data[0] < 1 || elem->data[0] > 8)
1449+
continue;
14481450

14491451
for_each_element(sub, elem->data + 1, elem->datalen - 1) {
14501452
u8 new_bssid[ETH_ALEN];
@@ -1504,24 +1506,26 @@ ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params)
15041506
const struct element *non_inherit = NULL;
15051507
u8 *nontransmitted_profile;
15061508
int nontransmitted_profile_len = 0;
1509+
size_t scratch_len = params->len;
15071510

1508-
elems = kzalloc(sizeof(*elems), GFP_ATOMIC);
1511+
elems = kzalloc(sizeof(*elems) + scratch_len, GFP_ATOMIC);
15091512
if (!elems)
15101513
return NULL;
15111514
elems->ie_start = params->start;
15121515
elems->total_len = params->len;
1513-
1514-
nontransmitted_profile = kmalloc(params->len, GFP_ATOMIC);
1515-
if (nontransmitted_profile) {
1516-
nontransmitted_profile_len =
1517-
ieee802_11_find_bssid_profile(params->start, params->len,
1518-
elems, params->bss,
1519-
nontransmitted_profile);
1520-
non_inherit =
1521-
cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE,
1522-
nontransmitted_profile,
1523-
nontransmitted_profile_len);
1524-
}
1516+
elems->scratch_len = scratch_len;
1517+
elems->scratch_pos = elems->scratch;
1518+
1519+
nontransmitted_profile = elems->scratch_pos;
1520+
nontransmitted_profile_len =
1521+
ieee802_11_find_bssid_profile(params->start, params->len,
1522+
elems, params->bss,
1523+
nontransmitted_profile);
1524+
elems->scratch_pos += nontransmitted_profile_len;
1525+
elems->scratch_len -= nontransmitted_profile_len;
1526+
non_inherit = cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE,
1527+
nontransmitted_profile,
1528+
nontransmitted_profile_len);
15251529

15261530
elems->crc = _ieee802_11_parse_elems_full(params, elems, non_inherit);
15271531

@@ -1555,8 +1559,6 @@ ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params)
15551559
offsetofend(struct ieee80211_bssid_index, dtim_count))
15561560
elems->dtim_count = elems->bssid_index->dtim_count;
15571561

1558-
kfree(nontransmitted_profile);
1559-
15601562
return elems;
15611563
}
15621564

net/wireless/scan.c

Lines changed: 50 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -143,18 +143,12 @@ static inline void bss_ref_get(struct cfg80211_registered_device *rdev,
143143
lockdep_assert_held(&rdev->bss_lock);
144144

145145
bss->refcount++;
146-
if (bss->pub.hidden_beacon_bss) {
147-
bss = container_of(bss->pub.hidden_beacon_bss,
148-
struct cfg80211_internal_bss,
149-
pub);
150-
bss->refcount++;
151-
}
152-
if (bss->pub.transmitted_bss) {
153-
bss = container_of(bss->pub.transmitted_bss,
154-
struct cfg80211_internal_bss,
155-
pub);
156-
bss->refcount++;
157-
}
146+
147+
if (bss->pub.hidden_beacon_bss)
148+
bss_from_pub(bss->pub.hidden_beacon_bss)->refcount++;
149+
150+
if (bss->pub.transmitted_bss)
151+
bss_from_pub(bss->pub.transmitted_bss)->refcount++;
158152
}
159153

160154
static inline void bss_ref_put(struct cfg80211_registered_device *rdev,
@@ -304,7 +298,8 @@ static size_t cfg80211_gen_new_ie(const u8 *ie, size_t ielen,
304298
tmp_old = cfg80211_find_ie(WLAN_EID_SSID, ie, ielen);
305299
tmp_old = (tmp_old) ? tmp_old + tmp_old[1] + 2 : ie;
306300

307-
while (tmp_old + tmp_old[1] + 2 - ie <= ielen) {
301+
while (tmp_old + 2 - ie <= ielen &&
302+
tmp_old + tmp_old[1] + 2 - ie <= ielen) {
308303
if (tmp_old[0] == 0) {
309304
tmp_old++;
310305
continue;
@@ -364,7 +359,8 @@ static size_t cfg80211_gen_new_ie(const u8 *ie, size_t ielen,
364359
* copied to new ie, skip ssid, capability, bssid-index ie
365360
*/
366361
tmp_new = sub_copy;
367-
while (tmp_new + tmp_new[1] + 2 - sub_copy <= subie_len) {
362+
while (tmp_new + 2 - sub_copy <= subie_len &&
363+
tmp_new + tmp_new[1] + 2 - sub_copy <= subie_len) {
368364
if (!(tmp_new[0] == WLAN_EID_NON_TX_BSSID_CAP ||
369365
tmp_new[0] == WLAN_EID_SSID)) {
370366
memcpy(pos, tmp_new, tmp_new[1] + 2);
@@ -427,6 +423,15 @@ cfg80211_add_nontrans_list(struct cfg80211_bss *trans_bss,
427423

428424
rcu_read_unlock();
429425

426+
/*
427+
* This is a bit weird - it's not on the list, but already on another
428+
* one! The only way that could happen is if there's some BSSID/SSID
429+
* shared by multiple APs in their multi-BSSID profiles, potentially
430+
* with hidden SSID mixed in ... ignore it.
431+
*/
432+
if (!list_empty(&nontrans_bss->nontrans_list))
433+
return -EINVAL;
434+
430435
/* add to the list */
431436
list_add_tail(&nontrans_bss->nontrans_list, &trans_bss->nontrans_list);
432437
return 0;
@@ -1602,6 +1607,23 @@ struct cfg80211_non_tx_bss {
16021607
u8 bssid_index;
16031608
};
16041609

1610+
static void cfg80211_update_hidden_bsses(struct cfg80211_internal_bss *known,
1611+
const struct cfg80211_bss_ies *new_ies,
1612+
const struct cfg80211_bss_ies *old_ies)
1613+
{
1614+
struct cfg80211_internal_bss *bss;
1615+
1616+
/* Assign beacon IEs to all sub entries */
1617+
list_for_each_entry(bss, &known->hidden_list, hidden_list) {
1618+
const struct cfg80211_bss_ies *ies;
1619+
1620+
ies = rcu_access_pointer(bss->pub.beacon_ies);
1621+
WARN_ON(ies != old_ies);
1622+
1623+
rcu_assign_pointer(bss->pub.beacon_ies, new_ies);
1624+
}
1625+
}
1626+
16051627
static bool
16061628
cfg80211_update_known_bss(struct cfg80211_registered_device *rdev,
16071629
struct cfg80211_internal_bss *known,
@@ -1625,7 +1647,6 @@ cfg80211_update_known_bss(struct cfg80211_registered_device *rdev,
16251647
kfree_rcu((struct cfg80211_bss_ies *)old, rcu_head);
16261648
} else if (rcu_access_pointer(new->pub.beacon_ies)) {
16271649
const struct cfg80211_bss_ies *old;
1628-
struct cfg80211_internal_bss *bss;
16291650

16301651
if (known->pub.hidden_beacon_bss &&
16311652
!list_empty(&known->hidden_list)) {
@@ -1653,16 +1674,7 @@ cfg80211_update_known_bss(struct cfg80211_registered_device *rdev,
16531674
if (old == rcu_access_pointer(known->pub.ies))
16541675
rcu_assign_pointer(known->pub.ies, new->pub.beacon_ies);
16551676

1656-
/* Assign beacon IEs to all sub entries */
1657-
list_for_each_entry(bss, &known->hidden_list, hidden_list) {
1658-
const struct cfg80211_bss_ies *ies;
1659-
1660-
ies = rcu_access_pointer(bss->pub.beacon_ies);
1661-
WARN_ON(ies != old);
1662-
1663-
rcu_assign_pointer(bss->pub.beacon_ies,
1664-
new->pub.beacon_ies);
1665-
}
1677+
cfg80211_update_hidden_bsses(known, new->pub.beacon_ies, old);
16661678

16671679
if (old)
16681680
kfree_rcu((struct cfg80211_bss_ies *)old, rcu_head);
@@ -1739,6 +1751,8 @@ cfg80211_bss_update(struct cfg80211_registered_device *rdev,
17391751
new->refcount = 1;
17401752
INIT_LIST_HEAD(&new->hidden_list);
17411753
INIT_LIST_HEAD(&new->pub.nontrans_list);
1754+
/* we'll set this later if it was non-NULL */
1755+
new->pub.transmitted_bss = NULL;
17421756

17431757
if (rcu_access_pointer(tmp->pub.proberesp_ies)) {
17441758
hidden = rb_find_bss(rdev, tmp, BSS_CMP_HIDE_ZLEN);
@@ -2021,10 +2035,15 @@ cfg80211_inform_single_bss_data(struct wiphy *wiphy,
20212035
spin_lock_bh(&rdev->bss_lock);
20222036
if (cfg80211_add_nontrans_list(non_tx_data->tx_bss,
20232037
&res->pub)) {
2024-
if (__cfg80211_unlink_bss(rdev, res))
2038+
if (__cfg80211_unlink_bss(rdev, res)) {
20252039
rdev->bss_generation++;
2040+
res = NULL;
2041+
}
20262042
}
20272043
spin_unlock_bh(&rdev->bss_lock);
2044+
2045+
if (!res)
2046+
return NULL;
20282047
}
20292048

20302049
trace_cfg80211_return_bss(&res->pub);
@@ -2143,6 +2162,8 @@ static void cfg80211_parse_mbssid_data(struct wiphy *wiphy,
21432162
for_each_element_id(elem, WLAN_EID_MULTIPLE_BSSID, ie, ielen) {
21442163
if (elem->datalen < 4)
21452164
continue;
2165+
if (elem->data[0] < 1 || (int)elem->data[0] > 8)
2166+
continue;
21462167
for_each_element(sub, elem->data + 1, elem->datalen - 1) {
21472168
u8 profile_len;
21482169

@@ -2279,7 +2300,7 @@ cfg80211_update_notlisted_nontrans(struct wiphy *wiphy,
22792300
size_t new_ie_len;
22802301
struct cfg80211_bss_ies *new_ies;
22812302
const struct cfg80211_bss_ies *old;
2282-
u8 cpy_len;
2303+
size_t cpy_len;
22832304

22842305
lockdep_assert_held(&wiphy_to_rdev(wiphy)->bss_lock);
22852306

@@ -2346,6 +2367,8 @@ cfg80211_update_notlisted_nontrans(struct wiphy *wiphy,
23462367
} else {
23472368
old = rcu_access_pointer(nontrans_bss->beacon_ies);
23482369
rcu_assign_pointer(nontrans_bss->beacon_ies, new_ies);
2370+
cfg80211_update_hidden_bsses(bss_from_pub(nontrans_bss),
2371+
new_ies, old);
23492372
rcu_assign_pointer(nontrans_bss->ies, new_ies);
23502373
if (old)
23512374
kfree_rcu((struct cfg80211_bss_ies *)old, rcu_head);

0 commit comments

Comments
 (0)