From 17402a869778f6c17b88fd360d7a96378779f97c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Pouiller?= Date: Sun, 6 Sep 2026 22:47:28 +0200 Subject: [PATCH] wifi: wfx: fix use-after-free of the cooling work on device removal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the device reports that it is too hot, wfx_suspend_hot_dev() blocks the Tx queues and arms cooling_timeout_work with a 10s delay. If the device recovers a normal temperature before the delay expires, the work is canceled. Else, the work declares the chip frozen and unblocks the Tx queues. However, this work is never canceled when the device is removed. cooling_timeout_work is queued on the system workqueue, while struct wfx_dev is released by wfx_free_common() (through ieee80211_free_hw()). So, if the device is unbound during this 10s window, the work fires after struct wfx_dev has been freed and dereferences it. Cancel the work during the teardown. It has to be done after wfx_bh_unregister(): the "device too hot" indication is processed by the bh, so canceling the work earlier would allow the bh to rearm it. On the other hand, the work calls wfx_tx_unlock(), which may in turn call wfx_bh_request_tx(). So it has to be canceled before bh_wq is destroyed. Note that the Tx queues are intentionally left blocked: the device is going away, so there is nothing to unblock. The issue was reported by the Sashiko review bot and the fix has been written by Copilot (including the commit log). The use-case is difficult to reproduce, so this code has not been tested. However, I don't believe this patch could cause any regression. Fixes: 1d52d29983e5d ("staging: wfx: add support for 'device too hot' indication") Assisted-by: Sashiko:gemini-3.1-pro-preview Assisted-by: Copilot:claude-opus-5 Signed-off-by: Jérôme Pouiller Tested-by: Alexander Sverdlin Reviewed-by: Alexander Sverdlin Link: https://patch.msgid.link/20260906204831.949692-2-jerome.pouiller@silabs.com Signed-off-by: Johannes Berg --- drivers/net/wireless/silabs/wfx/main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/silabs/wfx/main.c b/drivers/net/wireless/silabs/wfx/main.c index 4e99fe7e5bb7..b6fd9d4c1f5f 100644 --- a/drivers/net/wireless/silabs/wfx/main.c +++ b/drivers/net/wireless/silabs/wfx/main.c @@ -487,6 +487,7 @@ irq_unsubscribe: wdev->hwbus_ops->irq_unsubscribe(wdev->hwbus_priv); bh_unregister: wfx_bh_unregister(wdev); + cancel_delayed_work_sync(&wdev->cooling_timeout_work); destroy_workqueue(wdev->bh_wq); return err; } @@ -497,6 +498,7 @@ void wfx_release(struct wfx_dev *wdev) wfx_hif_shutdown(wdev); wdev->hwbus_ops->irq_unsubscribe(wdev->hwbus_priv); wfx_bh_unregister(wdev); + cancel_delayed_work_sync(&wdev->cooling_timeout_work); destroy_workqueue(wdev->bh_wq); }