From b717251598c95bb7ce7822ffa103216598f19b67 Mon Sep 17 00:00:00 2001 From: Markus Fritsche Date: Thu, 7 May 2026 21:24:01 +0200 Subject: [PATCH 24/29] bes2600: fix concurrency UAF in bes2600_hw_scan and sched_scan MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit bes2600_bss_info_changed() and bes2600_hw_scan() can run concurrently. The probe-request SKB allocated by ieee80211_probereq_get() before scan.lock + conf_lock are taken can be touched by a concurrent bss_info_changed (via wsm_set_template_frame's path) while we hold no lock. Reorder to acquire both locks BEFORE the SKB allocation. Also reorder cleanup paths so dev_kfree_skb() runs BEFORE up() — otherwise a small window exists where the SKB has been touched but the lock has been released, allowing concurrent code to also touch it. Three sites fixed: - bes2600_hw_scan: lock-take + ENOMEM cleanup + wsm_set_template_frame error cleanup + success-path SKB free + lock release order - bes2600_sched_scan_start (#ifdef ROAM_OFFLOAD): same three sub-fixes (compiled-out at default build, fixed for consistency) - All success/error paths: dev_kfree_skb before up() Backport of cw1200 mainline commit 86760e0dfe36 ("cw1200: Fix concurrency use-after-free bugs in cw1200_hw_scan()", 2018-12-14), which fixed the identical bug in the same code shape we inherited. That commit was merged from upstream 4f68ef64cd7f. Cherry-picked from upstream Linux: 86760e0dfe36 cw1200: Fix concurrency use-after-free bugs in cw1200_hw_scan() Author: Jia-Ju Bai Link: https://lore.kernel.org/r/20181214035521.7575-1-baijiaju1990@gmail.com --- bes2600/scan.c | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/drivers/staging/bes2600/scan.c b/drivers/staging/bes2600/scan.c index ad5033b..16b5d0f 100644 --- a/drivers/staging/bes2600/scan.c +++ b/drivers/staging/bes2600/scan.c @@ -257,18 +257,21 @@ int bes2600_hw_scan(struct ieee80211_hw *hw, bes2600_pwr_set_busy_event(hw_priv, BES_PWR_LOCK_ON_SCAN); + /* will be unlocked in bes2600_scan_work() */ + down(&hw_priv->scan.lock); + down(&hw_priv->conf_lock); + frame.skb = ieee80211_probereq_get(hw, priv->vif->addr, NULL, 0, req->ie_len); - if (!frame.skb) + if (!frame.skb) { + up(&hw_priv->conf_lock); + up(&hw_priv->scan.lock); return -ENOMEM; + } if (req->ie_len) skb_put_data(frame.skb, req->ie, req->ie_len); - /* will be unlocked in bes2600_scan_work() */ - down(&hw_priv->scan.lock); - down(&hw_priv->conf_lock); - if (frame.skb) { int ret; //if (priv->if_id == 0) @@ -286,9 +289,9 @@ int bes2600_hw_scan(struct ieee80211_hw *hw, } #endif if (ret) { + dev_kfree_skb(frame.skb); up(&hw_priv->conf_lock); up(&hw_priv->scan.lock); - dev_kfree_skb(frame.skb); return ret; } } @@ -318,10 +321,10 @@ int bes2600_hw_scan(struct ieee80211_hw *hw, ++hw_priv->scan.n_ssids; } - up(&hw_priv->conf_lock); - if (frame.skb) dev_kfree_skb(frame.skb); + + up(&hw_priv->conf_lock); #ifdef WIFI_BT_COEXIST_EPTA_ENABLE bwifi_change_current_status(hw_priv, BWIFI_STATUS_SCANNING); #endif @@ -362,14 +365,18 @@ int bes2600_hw_sched_scan_start(struct ieee80211_hw *hw, if (req->n_ssids > hw->wiphy->max_scan_ssids) return -EINVAL; + /* will be unlocked in bes2600_scan_work() */ + down(&hw_priv->scan.lock); + down(&hw_priv->conf_lock); + frame.skb = ieee80211_probereq_get(hw, priv->vif->addr, NULL, 0, req->ie_len); - if (!frame.skb) + if (!frame.skb) { + up(&hw_priv->conf_lock); + up(&hw_priv->scan.lock); return -ENOMEM; + } - /* will be unlocked in bes2600_scan_work() */ - down(&hw_priv->scan.lock); - down(&hw_priv->conf_lock); if (frame.skb) { int ret; if (priv->if_id == 0) @@ -380,9 +387,9 @@ int bes2600_hw_sched_scan_start(struct ieee80211_hw *hw, ret = wsm_set_probe_responder(priv, true); } if (ret) { + dev_kfree_skb(frame.skb); up(&hw_priv->conf_lock); up(&hw_priv->scan.lock); - dev_kfree_skb(frame.skb); return ret; } } @@ -414,10 +421,10 @@ int bes2600_hw_sched_scan_start(struct ieee80211_hw *hw, } } - up(&hw_priv->conf_lock); - if (frame.skb) dev_kfree_skb(frame.skb); + + up(&hw_priv->conf_lock); queue_work(hw_priv->workqueue, &hw_priv->scan.swork); wiphy_warn(hw->wiphy, "<--[SCAN] Scheduled scan request.\n"); return 0; -- 2.54.0