Skip to content

Commit

Permalink
UPSTREAM: wifi: cfg80211: fix BSS refcounting bugs
Browse files Browse the repository at this point in the history
commit 0b7808818cb9df6680f98996b8e9a439fa7bcc2f upstream.

There are multiple refcounting bugs related to multi-BSSID:
 - In bss_ref_get(), if the BSS has a hidden_beacon_bss, then
   the bss pointer is overwritten before checking for the
   transmitted BSS, which is clearly wrong. Fix this by using
   the bss_from_pub() macro.

 - In cfg80211_bss_update() we copy the transmitted_bss pointer
   from tmp into new, but then if we release new, we'll unref
   it erroneously. We already set the pointer and ref it, but
   need to NULL it since it was copied from the tmp data.

 - In cfg80211_inform_single_bss_data(), if adding to the non-
   transmitted list fails, we unlink the BSS and yet still we
   return it, but this results in returning an entry without
   a reference. We shouldn't return it anyway if it was broken
   enough to not get added there.

This fixes CVE-2022-42720.

Bug: 253642015
Bug: 256770696
Reported-by: Sönke Huster <[email protected]>
Tested-by: Sönke Huster <[email protected]>
Fixes: a3584f5 ("cfg80211: Properly track transmitting and non-transmitting BSS")
Signed-off-by: Johannes Berg <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
Signed-off-by: Lee Jones <[email protected]>
Change-Id: I408bf72ca59b6ffbe2aba460f3e9326bf1c94eec
(cherry picked from commit 1e18328)
  • Loading branch information
jmberg-intel authored and Robin Peng committed Nov 1, 2022
1 parent 7da68be commit 7520021
Showing 1 changed file with 14 additions and 13 deletions.
27 changes: 14 additions & 13 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 @@ -1729,6 +1723,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 @@ -1965,9 +1961,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

0 comments on commit 7520021

Please sign in to comment.