[PATCH wireless] wifi: ath12k: avoid flushing scan work under the wiphy lock
Runyu Xiao
runyu.xiao at seu.edu.cn
Thu Jun 11 20:27:01 PDT 2026
ath12k_mac_op_stop() is entered with the wiphy mutex already held. It
then takes ah->hw_mutex and ath12k_mac_stop() synchronously cancels the
scan.timeout delayed work. The timeout worker grabs the same wiphy lock
before it aborts the scan, so stop can deadlock against the pending
worker.
This issue was found by our static analysis tool and then manually
reviewed against the current tree.
The grounded PoC kept the ath12k_mac_op_stop() -> ath12k_mac_stop() ->
cancel_delayed_work_sync(&ar->scan.timeout) path and the
ath12k_scan_timeout_work() -> wiphy_lock() edge. Lockdep reported:
WARNING: possible circular locking dependency detected
ath12k_scan_timeout_work+0x25/0x42 [vuln_msv]
__cancel_work_timer
*** DEADLOCK ***
Drain scan.timeout before re-entering the stop path under the wiphy lock
and leave the rest of ath12k_mac_stop() unchanged.
Fixes: 2830bc9e784f ("wifi: ath12k: implement remain on channel for P2P mode")
Cc: stable at vger.kernel.org
Signed-off-by: Runyu Xiao <runyu.xiao at seu.edu.cn>
---
Notes:
- Validated with a grounded Lockdep PoC that preserves the
ath12k_mac_op_stop() -> ath12k_mac_stop() ->
cancel_delayed_work_sync(&ar->scan.timeout) path and the
ath12k_scan_timeout_work() -> wiphy_lock() edge.
- checkpatch.pl --strict: clean.
- Not tested on ath12k hardware.
drivers/net/wireless/ath/ath12k/mac.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index b97469dca046..cc9e8331513d 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -5263,8 +5263,6 @@ static void ath12k_mac_op_cancel_hw_scan(struct ieee80211_hw *hw,
ar = arvif->ar;
ath12k_scan_abort(ar);
-
- cancel_delayed_work_sync(&ar->scan.timeout);
}
}
@@ -9164,6 +9162,15 @@ static int ath12k_mac_op_start(struct ieee80211_hw *hw)
lockdep_assert_wiphy(hw->wiphy);
+ /*
+ * scan.timeout grabs the wiphy lock before aborting the scan, so
+ * drain it before re-entering the stop path under the wiphy lock.
+ */
+ wiphy_unlock(hw->wiphy);
+ for_each_ar(ah, ar, i)
+ cancel_delayed_work_sync(&ar->scan.timeout);
+ wiphy_lock(hw->wiphy);
+
ath12k_drain_tx(ah);
guard(mutex)(&ah->hw_mutex);
--
2.34.1
More information about the ath12k
mailing list