Skip to content

Commit

Permalink
Merge android13-5.10-2022-09 into android13-gs-pixel-5.10-gs101-tm-qpr1
Browse files Browse the repository at this point in the history
Merge SHA:
7eb63dc UPSTREAM: wifi: mac80211: fix MBSSID parsing use-after-free

Bug: 233569354
Bug: 253641805 (ACK)
Bug: 253642015 (ACK)
Bug: 253642087 (ACK)
Bug: 253642088 (ACK)
Bug: 253642089 (ACK)
Bug: 254180332 (ACK)
Bug: 256770696 (ACK)
Change-Id: Iaf487323af43954fb9ea27fee565a45bb865211b
Signed-off-by: Robin Peng <[email protected]>
  • Loading branch information
Robin Peng committed Nov 2, 2022
2 parents 1809731 + 7eb63dc commit beba115
Show file tree
Hide file tree
Showing 7 changed files with 84 additions and 47 deletions.
2 changes: 2 additions & 0 deletions drivers/net/wireless/mac80211_hwsim.c
Original file line number Diff line number Diff line change
Expand Up @@ -3676,6 +3676,8 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2,

rx_status.band = channel->band;
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;
Expand Down
4 changes: 2 additions & 2 deletions net/mac80211/ieee80211_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -1480,7 +1480,6 @@ struct ieee802_11_elems {
const u8 *supp_rates;
const u8 *ds_params;
const struct ieee80211_tim_ie *tim;
const u8 *challenge;
const u8 *rsn;
const u8 *rsnx;
const u8 *erp_info;
Expand Down Expand Up @@ -1533,7 +1532,6 @@ struct ieee802_11_elems {
u8 ssid_len;
u8 supp_rates_len;
u8 tim_len;
u8 challenge_len;
u8 rsn_len;
u8 rsnx_len;
u8 ext_supp_rates_len;
Expand All @@ -1548,6 +1546,8 @@ struct ieee802_11_elems {
u8 country_elem_len;
u8 bssid_index_len;

void *nontx_profile;

/* whether a parse error occurred while retrieving these elements */
bool parse_error;
};
Expand Down
21 changes: 13 additions & 8 deletions net/mac80211/mlme.c
Original file line number Diff line number Diff line change
Expand Up @@ -2899,22 +2899,23 @@ static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata,
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_mgd_auth_data *auth_data = sdata->u.mgd.auth_data;
const struct element *challenge;
u8 *pos;
struct ieee802_11_elems elems;
u32 tx_flags = 0;

pos = mgmt->u.auth.variable;
ieee802_11_parse_elems(pos, len - (pos - (u8 *)mgmt), false, &elems,
mgmt->bssid, auth_data->bss->bssid);
if (!elems.challenge)
challenge = cfg80211_find_elem(WLAN_EID_CHALLENGE, pos,
len - (pos - (u8 *)mgmt));
if (!challenge)
return;
auth_data->expected_transaction = 4;
drv_mgd_prepare_tx(sdata->local, sdata, 0);
if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS))
tx_flags = IEEE80211_TX_CTL_REQ_TX_STATUS |
IEEE80211_TX_INTFL_MLME_CONN_TX;
ieee80211_send_auth(sdata, 3, auth_data->algorithm, 0,
elems.challenge - 2, elems.challenge_len + 2,
(void *)challenge,
challenge->datalen + sizeof(*challenge),
auth_data->bss->bssid, auth_data->bss->bssid,
auth_data->key, auth_data->key_len,
auth_data->key_idx, tx_flags);
Expand Down Expand Up @@ -3299,7 +3300,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
}
capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info);
ieee802_11_parse_elems(pos, len - (pos - (u8 *)mgmt), false, elems,
mgmt->bssid, assoc_data->bss->bssid);
mgmt->bssid, NULL);

if (elems->aid_resp)
aid = le16_to_cpu(elems->aid_resp->aid);
Expand Down Expand Up @@ -3393,6 +3394,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
sdata_info(sdata,
"AP bug: VHT operation missing from AssocResp\n");
}
kfree(bss_elems.nontx_profile);
}

/*
Expand Down Expand Up @@ -3701,7 +3703,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
return;

ieee802_11_parse_elems(pos, len - (pos - (u8 *)mgmt), false, &elems,
mgmt->bssid, assoc_data->bss->bssid);
mgmt->bssid, NULL);

if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY &&
elems.timeout_int &&
Expand Down Expand Up @@ -4038,6 +4040,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
ifmgd->assoc_data->timeout = jiffies;
ifmgd->assoc_data->timeout_started = true;
run_again(sdata, ifmgd->assoc_data->timeout);
kfree(elems.nontx_profile);
return;
}

Expand Down Expand Up @@ -4215,7 +4218,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
ieee80211_report_disconnect(sdata, deauth_buf,
sizeof(deauth_buf), true,
WLAN_REASON_DEAUTH_LEAVING);
return;
goto free;
}

if (sta && elems.opmode_notif)
Expand All @@ -4230,6 +4233,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
elems.cisco_dtpc_elem);

ieee80211_bss_info_change_notify(sdata, changed);
free:
kfree(elems.nontx_profile);
}

void ieee80211_sta_rx_queued_ext(struct ieee80211_sub_if_data *sdata,
Expand Down
12 changes: 7 additions & 5 deletions net/mac80211/rx.c
Original file line number Diff line number Diff line change
Expand Up @@ -1976,10 +1976,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 */
}

Expand Down Expand Up @@ -2127,7 +2128,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);

Expand Down
2 changes: 2 additions & 0 deletions net/mac80211/scan.c
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,8 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
rx_status, beacon);
}

kfree(elems.nontx_profile);

return bss;
}

Expand Down
13 changes: 8 additions & 5 deletions net/mac80211/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -1124,10 +1124,6 @@ _ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
} else
elem_parse_failed = true;
break;
case WLAN_EID_CHALLENGE:
elems->challenge = pos;
elems->challenge_len = elen;
break;
case WLAN_EID_VENDOR_SPECIFIC:
if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 &&
pos[2] == 0xf2) {
Expand Down Expand Up @@ -1409,6 +1405,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];
Expand Down Expand Up @@ -1485,6 +1483,11 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE,
nontransmitted_profile,
nontransmitted_profile_len);
if (!nontransmitted_profile_len) {
nontransmitted_profile_len = 0;
kfree(nontransmitted_profile);
nontransmitted_profile = NULL;
}
}

crc = _ieee802_11_parse_elems_crc(start, len, action, elems, filter,
Expand Down Expand Up @@ -1514,7 +1517,7 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
offsetofend(struct ieee80211_bssid_index, dtim_count))
elems->dtim_count = elems->bssid_index->dtim_count;

kfree(nontransmitted_profile);
elems->nontx_profile = nontransmitted_profile;

return crc;
}
Expand Down
77 changes: 50 additions & 27 deletions net/wireless/scan.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -429,6 +425,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;
Expand Down Expand Up @@ -1590,6 +1595,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,
Expand All @@ -1613,7 +1635,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)) {
Expand Down Expand Up @@ -1641,16 +1662,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);
Expand Down Expand Up @@ -1727,6 +1739,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);
Expand Down Expand Up @@ -1963,9 +1977,14 @@ cfg80211_inform_single_bss_data(struct wiphy *wiphy,
*/
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;
}
}

if (!res)
return NULL;
}

trace_cfg80211_return_bss(&res->pub);
Expand Down Expand Up @@ -2084,6 +2103,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;

Expand Down Expand Up @@ -2219,7 +2240,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);

Expand Down Expand Up @@ -2286,6 +2307,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);
Expand Down

0 comments on commit beba115

Please sign in to comment.