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@vger.kernel.org Signed-off-by: Runyu Xiao --- 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