lkml.org 
[lkml]   [2022]   [Oct]   [13]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.19 24/33] wifi: cfg80211: fix BSS refcounting bugs
    Date
    From: Johannes Berg <johannes.berg@intel.com>

    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.

    Reported-by: Sönke Huster <shuster@seemoo.tu-darmstadt.de>
    Tested-by: Sönke Huster <shuster@seemoo.tu-darmstadt.de>
    Fixes: a3584f56de1c ("cfg80211: Properly track transmitting and non-transmitting BSS")
    Signed-off-by: Johannes Berg <johannes.berg@intel.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    ---
    net/wireless/scan.c | 27 ++++++++++++++-------------
    1 file changed, 14 insertions(+), 13 deletions(-)

    --- a/net/wireless/scan.c
    +++ b/net/wireless/scan.c
    @@ -143,18 +143,12 @@ static inline void bss_ref_get(struct cf
    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,
    @@ -1741,6 +1735,8 @@ cfg80211_bss_update(struct cfg80211_regi
    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);
    @@ -2023,10 +2019,15 @@ cfg80211_inform_single_bss_data(struct w
    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);

    \
     
     \ /
      Last update: 2022-10-13 20:28    [W:7.451 / U:0.716 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site