More wireless fixes for 6.1
This has only the fixes for the scan parsing issues. -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEH1e1rEeCd0AIMq6MB8qZga/fl8QFAmNH4nUACgkQB8qZga/f l8RFHRAAlskV3quBEnFgrOyuIcWVKq4DOFFKXXQ89cwD3ZK6auYm5gyM2obE+HkD JQZjZoJc57qh3/IoYrOlC1PO0oAHiBReQ+5xKD0d1Ye04euFuV3Boe25rH3+7wya u8uVJQqlV0sqG0DhoOPhDV/A17owtQlN/0j3yVFukPAvBjZHRduWF/lk+ozwmAsE xwByw1K/v9BqOSx3aZjFhb3snT/4IiV8yYLiHE0KMBC+p5Zk6iwOWbCHFstWFbku U6rTmWSvTDLaR+koTq4WGo/fRI68Sh4eRhcZsMnSRR8rj1LQWrRehPc+IQ9TXsgS Li0z+HeLUEUrJ8bouJV0wzizvLG473qWm5PyemomKfYA68VvplheBpL3ClLIpbW+ On3VKnyZESIKsRYoJzJ3HhG7lnay74yKC1F4GMj4GCdzkXchSBoF7z0QGM14a7+E gby4WHDSxK5kdC01vQqDCk3PBgGw+Qte6ipIvcVXnRVWCn8O0Z1lIdOkEZkODp5s F1Sg9YpFRqR1h8Uw664xm/RulhPx2o8iritPjQyv0trmFWsdRpll/EXqIUPMiT0n yJI+jD+1hDXnRt2dhTTtpG46F9oru+DbBWK+iN0GHISAlIUMXlKocIyCIKxBUUAq 0kzJrqJGPbXoodEDxvLMnAObVavo4RHux+jQVBlEkjHDpj0N7WA= =yEqx -----END PGP SIGNATURE----- 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/20221013100522.46346-1-johannes@sipsolutions.net Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
commit
ac85bc717c
@ -4973,6 +4973,8 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2,
|
||||
}
|
||||
|
||||
rx_status.rate_idx = nla_get_u32(info->attrs[HWSIM_ATTR_RX_RATE]);
|
||||
if (rx_status.rate_idx >= data2->hw->wiphy->bands[rx_status.band]->n_bitrates)
|
||||
goto out;
|
||||
rx_status.signal = nla_get_u32(info->attrs[HWSIM_ATTR_SIGNAL]);
|
||||
|
||||
hdr = (void *)skb->data;
|
||||
|
@ -1709,6 +1709,14 @@ struct ieee802_11_elems {
|
||||
|
||||
/* whether a parse error occurred while retrieving these elements */
|
||||
bool parse_error;
|
||||
|
||||
/*
|
||||
* scratch buffer that can be used for various element parsing related
|
||||
* tasks, e.g., element de-fragmentation etc.
|
||||
*/
|
||||
size_t scratch_len;
|
||||
u8 *scratch_pos;
|
||||
u8 scratch[];
|
||||
};
|
||||
|
||||
static inline struct ieee80211_local *hw_to_local(
|
||||
|
@ -1978,10 +1978,11 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
|
||||
|
||||
if (mmie_keyidx < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS ||
|
||||
mmie_keyidx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS +
|
||||
NUM_DEFAULT_BEACON_KEYS) {
|
||||
cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev,
|
||||
skb->data,
|
||||
skb->len);
|
||||
NUM_DEFAULT_BEACON_KEYS) {
|
||||
if (rx->sdata->dev)
|
||||
cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev,
|
||||
skb->data,
|
||||
skb->len);
|
||||
return RX_DROP_MONITOR; /* unexpected BIP keyidx */
|
||||
}
|
||||
|
||||
@ -2131,7 +2132,8 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
|
||||
/* either the frame has been decrypted or will be dropped */
|
||||
status->flag |= RX_FLAG_DECRYPTED;
|
||||
|
||||
if (unlikely(ieee80211_is_beacon(fc) && result == RX_DROP_UNUSABLE))
|
||||
if (unlikely(ieee80211_is_beacon(fc) && result == RX_DROP_UNUSABLE &&
|
||||
rx->sdata->dev))
|
||||
cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev,
|
||||
skb->data, skb->len);
|
||||
|
||||
|
@ -1445,6 +1445,8 @@ static size_t ieee802_11_find_bssid_profile(const u8 *start, size_t len,
|
||||
for_each_element_id(elem, WLAN_EID_MULTIPLE_BSSID, start, len) {
|
||||
if (elem->datalen < 2)
|
||||
continue;
|
||||
if (elem->data[0] < 1 || elem->data[0] > 8)
|
||||
continue;
|
||||
|
||||
for_each_element(sub, elem->data + 1, elem->datalen - 1) {
|
||||
u8 new_bssid[ETH_ALEN];
|
||||
@ -1504,24 +1506,26 @@ ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params)
|
||||
const struct element *non_inherit = NULL;
|
||||
u8 *nontransmitted_profile;
|
||||
int nontransmitted_profile_len = 0;
|
||||
size_t scratch_len = params->len;
|
||||
|
||||
elems = kzalloc(sizeof(*elems), GFP_ATOMIC);
|
||||
elems = kzalloc(sizeof(*elems) + scratch_len, GFP_ATOMIC);
|
||||
if (!elems)
|
||||
return NULL;
|
||||
elems->ie_start = params->start;
|
||||
elems->total_len = params->len;
|
||||
elems->scratch_len = scratch_len;
|
||||
elems->scratch_pos = elems->scratch;
|
||||
|
||||
nontransmitted_profile = kmalloc(params->len, GFP_ATOMIC);
|
||||
if (nontransmitted_profile) {
|
||||
nontransmitted_profile_len =
|
||||
ieee802_11_find_bssid_profile(params->start, params->len,
|
||||
elems, params->bss,
|
||||
nontransmitted_profile);
|
||||
non_inherit =
|
||||
cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE,
|
||||
nontransmitted_profile,
|
||||
nontransmitted_profile_len);
|
||||
}
|
||||
nontransmitted_profile = elems->scratch_pos;
|
||||
nontransmitted_profile_len =
|
||||
ieee802_11_find_bssid_profile(params->start, params->len,
|
||||
elems, params->bss,
|
||||
nontransmitted_profile);
|
||||
elems->scratch_pos += nontransmitted_profile_len;
|
||||
elems->scratch_len -= nontransmitted_profile_len;
|
||||
non_inherit = cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE,
|
||||
nontransmitted_profile,
|
||||
nontransmitted_profile_len);
|
||||
|
||||
elems->crc = _ieee802_11_parse_elems_full(params, elems, non_inherit);
|
||||
|
||||
@ -1555,8 +1559,6 @@ ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params)
|
||||
offsetofend(struct ieee80211_bssid_index, dtim_count))
|
||||
elems->dtim_count = elems->bssid_index->dtim_count;
|
||||
|
||||
kfree(nontransmitted_profile);
|
||||
|
||||
return elems;
|
||||
}
|
||||
|
||||
|
@ -143,18 +143,12 @@ static inline void bss_ref_get(struct cfg80211_registered_device *rdev,
|
||||
lockdep_assert_held(&rdev->bss_lock);
|
||||
|
||||
bss->refcount++;
|
||||
if (bss->pub.hidden_beacon_bss) {
|
||||
bss = container_of(bss->pub.hidden_beacon_bss,
|
||||
struct cfg80211_internal_bss,
|
||||
pub);
|
||||
bss->refcount++;
|
||||
}
|
||||
if (bss->pub.transmitted_bss) {
|
||||
bss = container_of(bss->pub.transmitted_bss,
|
||||
struct cfg80211_internal_bss,
|
||||
pub);
|
||||
bss->refcount++;
|
||||
}
|
||||
|
||||
if (bss->pub.hidden_beacon_bss)
|
||||
bss_from_pub(bss->pub.hidden_beacon_bss)->refcount++;
|
||||
|
||||
if (bss->pub.transmitted_bss)
|
||||
bss_from_pub(bss->pub.transmitted_bss)->refcount++;
|
||||
}
|
||||
|
||||
static inline void bss_ref_put(struct cfg80211_registered_device *rdev,
|
||||
@ -304,7 +298,8 @@ static size_t cfg80211_gen_new_ie(const u8 *ie, size_t ielen,
|
||||
tmp_old = cfg80211_find_ie(WLAN_EID_SSID, ie, ielen);
|
||||
tmp_old = (tmp_old) ? tmp_old + tmp_old[1] + 2 : ie;
|
||||
|
||||
while (tmp_old + tmp_old[1] + 2 - ie <= ielen) {
|
||||
while (tmp_old + 2 - ie <= ielen &&
|
||||
tmp_old + tmp_old[1] + 2 - ie <= ielen) {
|
||||
if (tmp_old[0] == 0) {
|
||||
tmp_old++;
|
||||
continue;
|
||||
@ -364,7 +359,8 @@ static size_t cfg80211_gen_new_ie(const u8 *ie, size_t ielen,
|
||||
* copied to new ie, skip ssid, capability, bssid-index ie
|
||||
*/
|
||||
tmp_new = sub_copy;
|
||||
while (tmp_new + tmp_new[1] + 2 - sub_copy <= subie_len) {
|
||||
while (tmp_new + 2 - sub_copy <= subie_len &&
|
||||
tmp_new + tmp_new[1] + 2 - sub_copy <= subie_len) {
|
||||
if (!(tmp_new[0] == WLAN_EID_NON_TX_BSSID_CAP ||
|
||||
tmp_new[0] == WLAN_EID_SSID)) {
|
||||
memcpy(pos, tmp_new, tmp_new[1] + 2);
|
||||
@ -427,6 +423,15 @@ cfg80211_add_nontrans_list(struct cfg80211_bss *trans_bss,
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
/*
|
||||
* This is a bit weird - it's not on the list, but already on another
|
||||
* one! The only way that could happen is if there's some BSSID/SSID
|
||||
* shared by multiple APs in their multi-BSSID profiles, potentially
|
||||
* with hidden SSID mixed in ... ignore it.
|
||||
*/
|
||||
if (!list_empty(&nontrans_bss->nontrans_list))
|
||||
return -EINVAL;
|
||||
|
||||
/* add to the list */
|
||||
list_add_tail(&nontrans_bss->nontrans_list, &trans_bss->nontrans_list);
|
||||
return 0;
|
||||
@ -1602,6 +1607,23 @@ struct cfg80211_non_tx_bss {
|
||||
u8 bssid_index;
|
||||
};
|
||||
|
||||
static void cfg80211_update_hidden_bsses(struct cfg80211_internal_bss *known,
|
||||
const struct cfg80211_bss_ies *new_ies,
|
||||
const struct cfg80211_bss_ies *old_ies)
|
||||
{
|
||||
struct cfg80211_internal_bss *bss;
|
||||
|
||||
/* Assign beacon IEs to all sub entries */
|
||||
list_for_each_entry(bss, &known->hidden_list, hidden_list) {
|
||||
const struct cfg80211_bss_ies *ies;
|
||||
|
||||
ies = rcu_access_pointer(bss->pub.beacon_ies);
|
||||
WARN_ON(ies != old_ies);
|
||||
|
||||
rcu_assign_pointer(bss->pub.beacon_ies, new_ies);
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
cfg80211_update_known_bss(struct cfg80211_registered_device *rdev,
|
||||
struct cfg80211_internal_bss *known,
|
||||
@ -1625,7 +1647,6 @@ cfg80211_update_known_bss(struct cfg80211_registered_device *rdev,
|
||||
kfree_rcu((struct cfg80211_bss_ies *)old, rcu_head);
|
||||
} else if (rcu_access_pointer(new->pub.beacon_ies)) {
|
||||
const struct cfg80211_bss_ies *old;
|
||||
struct cfg80211_internal_bss *bss;
|
||||
|
||||
if (known->pub.hidden_beacon_bss &&
|
||||
!list_empty(&known->hidden_list)) {
|
||||
@ -1653,16 +1674,7 @@ cfg80211_update_known_bss(struct cfg80211_registered_device *rdev,
|
||||
if (old == rcu_access_pointer(known->pub.ies))
|
||||
rcu_assign_pointer(known->pub.ies, new->pub.beacon_ies);
|
||||
|
||||
/* Assign beacon IEs to all sub entries */
|
||||
list_for_each_entry(bss, &known->hidden_list, hidden_list) {
|
||||
const struct cfg80211_bss_ies *ies;
|
||||
|
||||
ies = rcu_access_pointer(bss->pub.beacon_ies);
|
||||
WARN_ON(ies != old);
|
||||
|
||||
rcu_assign_pointer(bss->pub.beacon_ies,
|
||||
new->pub.beacon_ies);
|
||||
}
|
||||
cfg80211_update_hidden_bsses(known, new->pub.beacon_ies, old);
|
||||
|
||||
if (old)
|
||||
kfree_rcu((struct cfg80211_bss_ies *)old, rcu_head);
|
||||
@ -1739,6 +1751,8 @@ cfg80211_bss_update(struct cfg80211_registered_device *rdev,
|
||||
new->refcount = 1;
|
||||
INIT_LIST_HEAD(&new->hidden_list);
|
||||
INIT_LIST_HEAD(&new->pub.nontrans_list);
|
||||
/* we'll set this later if it was non-NULL */
|
||||
new->pub.transmitted_bss = NULL;
|
||||
|
||||
if (rcu_access_pointer(tmp->pub.proberesp_ies)) {
|
||||
hidden = rb_find_bss(rdev, tmp, BSS_CMP_HIDE_ZLEN);
|
||||
@ -2021,10 +2035,15 @@ cfg80211_inform_single_bss_data(struct wiphy *wiphy,
|
||||
spin_lock_bh(&rdev->bss_lock);
|
||||
if (cfg80211_add_nontrans_list(non_tx_data->tx_bss,
|
||||
&res->pub)) {
|
||||
if (__cfg80211_unlink_bss(rdev, res))
|
||||
if (__cfg80211_unlink_bss(rdev, res)) {
|
||||
rdev->bss_generation++;
|
||||
res = NULL;
|
||||
}
|
||||
}
|
||||
spin_unlock_bh(&rdev->bss_lock);
|
||||
|
||||
if (!res)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
trace_cfg80211_return_bss(&res->pub);
|
||||
@ -2143,6 +2162,8 @@ static void cfg80211_parse_mbssid_data(struct wiphy *wiphy,
|
||||
for_each_element_id(elem, WLAN_EID_MULTIPLE_BSSID, ie, ielen) {
|
||||
if (elem->datalen < 4)
|
||||
continue;
|
||||
if (elem->data[0] < 1 || (int)elem->data[0] > 8)
|
||||
continue;
|
||||
for_each_element(sub, elem->data + 1, elem->datalen - 1) {
|
||||
u8 profile_len;
|
||||
|
||||
@ -2279,7 +2300,7 @@ cfg80211_update_notlisted_nontrans(struct wiphy *wiphy,
|
||||
size_t new_ie_len;
|
||||
struct cfg80211_bss_ies *new_ies;
|
||||
const struct cfg80211_bss_ies *old;
|
||||
u8 cpy_len;
|
||||
size_t cpy_len;
|
||||
|
||||
lockdep_assert_held(&wiphy_to_rdev(wiphy)->bss_lock);
|
||||
|
||||
@ -2346,6 +2367,8 @@ cfg80211_update_notlisted_nontrans(struct wiphy *wiphy,
|
||||
} else {
|
||||
old = rcu_access_pointer(nontrans_bss->beacon_ies);
|
||||
rcu_assign_pointer(nontrans_bss->beacon_ies, new_ies);
|
||||
cfg80211_update_hidden_bsses(bss_from_pub(nontrans_bss),
|
||||
new_ies, old);
|
||||
rcu_assign_pointer(nontrans_bss->ies, new_ies);
|
||||
if (old)
|
||||
kfree_rcu((struct cfg80211_bss_ies *)old, rcu_head);
|
||||
|
Loading…
x
Reference in New Issue
Block a user