mt7615_suspend() takes the mt76 mutex and then waits for mac_work with cancel_delayed_work_sync(). mt7615_mac_work() takes the same mutex at the top of the worker, so the suspend path can deadlock against the delayed work it is trying to flush. This issue was found by our static analysis tool and then manually reviewed against the current tree. The grounded PoC kept the mt7615_suspend() -> cancel_delayed_work_sync(&phy->mt76->mac_work) path and the mt7615_mac_work() -> mt7615_mutex_acquire() edge. Lockdep reported: WARNING: possible circular locking dependency detected mt7615_mac_work+0x1b/0x29 [vuln_msv] __cancel_work_timer *** DEADLOCK *** Stop queueing mac_work while the mutex is held, drop the mutex, and then flush the delayed work from the sleepable post-unlock path. Fixes: c6bf20109a3f ("mt76: mt7615: add WoW support") Cc: stable@vger.kernel.org Signed-off-by: Runyu Xiao --- Notes: - Validated with a grounded Lockdep PoC that preserves the mt7615_suspend() -> cancel_delayed_work_sync(&phy->mt76->mac_work) path and the mt7615_mac_work() -> mt7615_mutex_acquire() edge. - checkpatch.pl --strict: clean. - Not tested on mt7615 hardware. drivers/net/wireless/mediatek/mt76/mt7615/main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index 15fe155ac3f3..fcb619c0f6cf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -1242,7 +1242,8 @@ static int mt7615_suspend(struct ieee80211_hw *hw, clear_bit(MT76_STATE_RUNNING, &phy->mt76->state); cancel_delayed_work_sync(&phy->scan_work); - cancel_delayed_work_sync(&phy->mt76->mac_work); + /* mac_work re-enters the mt76 mutex, so flush it after unlock. */ + cancel_delayed_work(&phy->mt76->mac_work); set_bit(MT76_STATE_SUSPEND, &phy->mt76->state); ieee80211_iterate_active_interfaces(hw, @@ -1254,6 +1255,7 @@ static int mt7615_suspend(struct ieee80211_hw *hw, err = mt76_connac_mcu_set_hif_suspend(&dev->mt76, true, true); mt7615_mutex_release(dev); + cancel_delayed_work_sync(&phy->mt76->mac_work); return err; } -- 2.34.1