From nobody Thu Oct 2 06:19:46 2025 Received: from mail.ispras.ru (mail.ispras.ru [83.149.199.84]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0590027702A; Fri, 19 Sep 2025 21:09:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=83.149.199.84 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1758316175; cv=none; b=ZMY/zB8fC/p+NiFI9o1sAPoXwyJb+eJANX5eqfLCDgdTOHXAXbQmz8rZC1usbuAglRG7v7y0W9+HOhNtrNBXLwtP869gQjEhMu44Yvjpkgv+PKDMxkRj4zZAM0/RPdgzYTMLz5a5ZeI64vYxfvl9tU/C+zUQNM6OIqzgEgfwCiU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1758316175; c=relaxed/simple; bh=AzWR9yINVsv3/jho544foII4PxWX83Ya9OPk097+Zbc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=MbgGE2MTT/cPZryGhLtWPn16x7SDME5cK29tHuxC5J//dzmjaeCdFMMW3GVdtlr09G3Ob/arCQF4z+zWmwOLo+3wEiQsXPTu2A2tZuKmdyHXOeQZW27+QFoiMT9gA4KEA85j8jle78OCoOIjLN6P9ExQCfkef1oDPdM3fFufDBw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=ispras.ru; spf=pass smtp.mailfrom=ispras.ru; dkim=pass (1024-bit key) header.d=ispras.ru header.i=@ispras.ru header.b=tKfCwHlP; arc=none smtp.client-ip=83.149.199.84 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=ispras.ru Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=ispras.ru Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=ispras.ru header.i=@ispras.ru header.b="tKfCwHlP" Received: from debian.intra.ispras.ru (unknown [10.10.165.9]) by mail.ispras.ru (Postfix) with ESMTPSA id E3C394076723; Fri, 19 Sep 2025 21:09:22 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 mail.ispras.ru E3C394076723 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ispras.ru; s=default; t=1758316163; bh=+4qxICeTyd+XYx4CHFefq+jkZF3Hp0q0bI8/zHksiuM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=tKfCwHlPSRiua6MQSmB168M4VVwkNYPrrNlGFei+Wb8761LMLDXoHrzbeayHyo3+/ pf0/a4Q8qQa3Q7x4FCnSF3dxxuN+qQxLfPqaTLNHBxBZ+exbp8pQJV+WJ2kDwXewBB FwJs3BaUwp2h7Hy+cfaUBZXy/2HIe0camhl1WYkU= From: Fedor Pchelkin To: Ping-Ke Shih , Zong-Zhe Yang Cc: Fedor Pchelkin , Bitterblue Smith , Po-Hao Huang , linux-wireless@vger.kernel.org, linux-kernel@vger.kernel.org, lvc-project@linuxtesting.org, stable@vger.kernel.org Subject: [PATCH rtw-next v5 1/4] wifi: rtw89: fix use-after-free in rtw89_core_tx_kick_off_and_wait() Date: Sat, 20 Sep 2025 00:08:47 +0300 Message-ID: <20250919210852.823912-2-pchelkin@ispras.ru> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20250919210852.823912-1-pchelkin@ispras.ru> References: <20250919210852.823912-1-pchelkin@ispras.ru> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" There is a bug observed when rtw89_core_tx_kick_off_and_wait() tries to access already freed skb_data: BUG: KFENCE: use-after-free write in rtw89_core_tx_kick_off_and_wait drive= rs/net/wireless/realtek/rtw89/core.c:1110 CPU: 6 UID: 0 PID: 41377 Comm: kworker/u64:24 Not tainted 6.17.0-rc1+ #1 = PREEMPT(lazy) Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS edk2-20250523-= 14.fc42 05/23/2025 Workqueue: events_unbound cfg80211_wiphy_work [cfg80211] Use-after-free write at 0x0000000020309d9d (in kfence-#251): rtw89_core_tx_kick_off_and_wait drivers/net/wireless/realtek/rtw89/core.c:= 1110 rtw89_core_scan_complete drivers/net/wireless/realtek/rtw89/core.c:5338 rtw89_hw_scan_complete_cb drivers/net/wireless/realtek/rtw89/fw.c:7979 rtw89_chanctx_proceed_cb drivers/net/wireless/realtek/rtw89/chan.c:3165 rtw89_chanctx_proceed drivers/net/wireless/realtek/rtw89/chan.h:141 rtw89_hw_scan_complete drivers/net/wireless/realtek/rtw89/fw.c:8012 rtw89_mac_c2h_scanofld_rsp drivers/net/wireless/realtek/rtw89/mac.c:5059 rtw89_fw_c2h_work drivers/net/wireless/realtek/rtw89/fw.c:6758 process_one_work kernel/workqueue.c:3241 worker_thread kernel/workqueue.c:3400 kthread kernel/kthread.c:463 ret_from_fork arch/x86/kernel/process.c:154 ret_from_fork_asm arch/x86/entry/entry_64.S:258 kfence-#251: 0x0000000056e2393d-0x000000009943cb62, size=3D232, cache=3Dsk= buff_head_cache allocated by task 41377 on cpu 6 at 77869.159548s (0.009551s ago): __alloc_skb net/core/skbuff.c:659 __netdev_alloc_skb net/core/skbuff.c:734 ieee80211_nullfunc_get net/mac80211/tx.c:5844 rtw89_core_send_nullfunc drivers/net/wireless/realtek/rtw89/core.c:3431 rtw89_core_scan_complete drivers/net/wireless/realtek/rtw89/core.c:5338 rtw89_hw_scan_complete_cb drivers/net/wireless/realtek/rtw89/fw.c:7979 rtw89_chanctx_proceed_cb drivers/net/wireless/realtek/rtw89/chan.c:3165 rtw89_chanctx_proceed drivers/net/wireless/realtek/rtw89/chan.c:3194 rtw89_hw_scan_complete drivers/net/wireless/realtek/rtw89/fw.c:8012 rtw89_mac_c2h_scanofld_rsp drivers/net/wireless/realtek/rtw89/mac.c:5059 rtw89_fw_c2h_work drivers/net/wireless/realtek/rtw89/fw.c:6758 process_one_work kernel/workqueue.c:3241 worker_thread kernel/workqueue.c:3400 kthread kernel/kthread.c:463 ret_from_fork arch/x86/kernel/process.c:154 ret_from_fork_asm arch/x86/entry/entry_64.S:258 freed by task 1045 on cpu 9 at 77869.168393s (0.001557s ago): ieee80211_tx_status_skb net/mac80211/status.c:1117 rtw89_pci_release_txwd_skb drivers/net/wireless/realtek/rtw89/pci.c:564 rtw89_pci_release_tx_skbs.isra.0 drivers/net/wireless/realtek/rtw89/pci.c:= 651 rtw89_pci_release_tx drivers/net/wireless/realtek/rtw89/pci.c:676 rtw89_pci_napi_poll drivers/net/wireless/realtek/rtw89/pci.c:4238 __napi_poll net/core/dev.c:7495 net_rx_action net/core/dev.c:7557 net/core/dev.c:7684 handle_softirqs kernel/softirq.c:580 do_softirq.part.0 kernel/softirq.c:480 __local_bh_enable_ip kernel/softirq.c:407 rtw89_pci_interrupt_threadfn drivers/net/wireless/realtek/rtw89/pci.c:927 irq_thread_fn kernel/irq/manage.c:1133 irq_thread kernel/irq/manage.c:1257 kthread kernel/kthread.c:463 ret_from_fork arch/x86/kernel/process.c:154 ret_from_fork_asm arch/x86/entry/entry_64.S:258 It is a consequence of a race between the waiting and the signaling side of the completion: Waiting thread Completing thread rtw89_core_tx_kick_off_and_wait() rcu_assign_pointer(skb_data->wait, wait) /* start waiting */ wait_for_completion_timeout() rtw89_pci_tx_status() rtw89_core_tx_wait_comple= te() rcu_read_lock() /* signals completion a= nd * proceeds further */ complete(&wait->complet= ion) rcu_read_unlock() ... /* frees skb_data */ ieee80211_tx_status_ni() /* returns (exit status doesn't matter) */ wait_for_completion_timeout() ... /* accesses the already freed skb_data */ rcu_assign_pointer(skb_data->wait, NULL) The completing side might proceed and free the underlying skb even before the waiting side is fully awoken and run to execution. Actually the race happens regardless of wait_for_completion_timeout() exit status, e.g. the waiting side may hit a timeout and the concurrent completing side is still able to free the skb. Skbs which are sent by rtw89_core_tx_kick_off_and_wait() are owned by the driver. They don't come from core ieee80211 stack so no need to pass them to ieee80211_tx_status_ni() on completing side. Introduce a work function which will act as a garbage collector for rtw89_tx_wait_info objects and the associated skbs. Thus no potentially heavy locks are required on the completing side. Found by Linux Verification Center (linuxtesting.org). Fixes: 1ae5ca615285 ("wifi: rtw89: add function to wait for completion of T= X skbs") Cc: stable@vger.kernel.org Suggested-by: Zong-Zhe Yang Signed-off-by: Fedor Pchelkin Acked-by: Ping-Ke Shih --- v5: - use completion_done() and delayed work (Ping-Ke) v4: - fill wait's fields before publishing (Zong-Zhe) - leave dev_kfree_skb_any + kfree_rcu for tx_wait release (Zong-Zhe) v3: - decrease waiting timeout in rtw89_tx_wait_work() (Zong-Zhe) - clear tx_waits list from rtw89_hci_reset(), too (Zong-Zhe) - keep RCU updating for skb_data->wait (Zong-Zhe) - keep the old order of calls in rtw89_pci_tx_status() (Zong-Zhe) - drop wait->finished as complete_all() would make the completion be done permanently v2: - use a work function to manage release of tx_waits and associated skbs= (Zong-Zhe) drivers/net/wireless/realtek/rtw89/core.c | 30 +++++++++++++++---- drivers/net/wireless/realtek/rtw89/core.h | 35 +++++++++++++++++++++-- drivers/net/wireless/realtek/rtw89/pci.c | 3 +- drivers/net/wireless/realtek/rtw89/ser.c | 2 ++ 4 files changed, 61 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wirele= ss/realtek/rtw89/core.c index fe059c4a6b55..ec467ae0e9e6 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -1135,6 +1135,14 @@ rtw89_core_tx_update_desc_info(struct rtw89_dev *rtw= dev, } } =20 +static void rtw89_tx_wait_work(struct wiphy *wiphy, struct wiphy_work *wor= k) +{ + struct rtw89_dev *rtwdev =3D container_of(work, struct rtw89_dev, + tx_wait_work.work); + + rtw89_tx_wait_list_clear(rtwdev); +} + void rtw89_core_tx_kick_off(struct rtw89_dev *rtwdev, u8 qsel) { u8 ch_dma; @@ -1152,6 +1160,8 @@ int rtw89_core_tx_kick_off_and_wait(struct rtw89_dev = *rtwdev, struct sk_buff *sk unsigned long time_left; int ret =3D 0; =20 + lockdep_assert_wiphy(rtwdev->hw->wiphy); + wait =3D kzalloc(sizeof(*wait), GFP_KERNEL); if (!wait) { rtw89_core_tx_kick_off(rtwdev, qsel); @@ -1159,18 +1169,23 @@ int rtw89_core_tx_kick_off_and_wait(struct rtw89_de= v *rtwdev, struct sk_buff *sk } =20 init_completion(&wait->completion); + wait->skb =3D skb; rcu_assign_pointer(skb_data->wait, wait); =20 rtw89_core_tx_kick_off(rtwdev, qsel); time_left =3D wait_for_completion_timeout(&wait->completion, msecs_to_jiffies(timeout)); - if (time_left =3D=3D 0) - ret =3D -ETIMEDOUT; - else if (!wait->tx_done) - ret =3D -EAGAIN; =20 - rcu_assign_pointer(skb_data->wait, NULL); - kfree_rcu(wait, rcu_head); + if (time_left =3D=3D 0) { + ret =3D -ETIMEDOUT; + list_add_tail(&wait->list, &rtwdev->tx_waits); + wiphy_delayed_work_queue(rtwdev->hw->wiphy, &rtwdev->tx_wait_work, + RTW89_TX_WAIT_WORK_TIMEOUT); + } else { + if (!wait->tx_done) + ret =3D -EAGAIN; + rtw89_tx_wait_release(wait); + } =20 return ret; } @@ -5548,6 +5563,7 @@ void rtw89_core_stop(struct rtw89_dev *rtwdev) wiphy_work_cancel(wiphy, &btc->dhcp_notify_work); wiphy_work_cancel(wiphy, &btc->icmp_notify_work); cancel_delayed_work_sync(&rtwdev->txq_reinvoke_work); + wiphy_delayed_work_cancel(wiphy, &rtwdev->tx_wait_work); wiphy_delayed_work_cancel(wiphy, &rtwdev->track_work); wiphy_delayed_work_cancel(wiphy, &rtwdev->track_ps_work); wiphy_delayed_work_cancel(wiphy, &rtwdev->chanctx_work); @@ -5773,6 +5789,7 @@ int rtw89_core_init(struct rtw89_dev *rtwdev) INIT_LIST_HEAD(&rtwdev->scan_info.pkt_list[band]); } INIT_LIST_HEAD(&rtwdev->scan_info.chan_list); + INIT_LIST_HEAD(&rtwdev->tx_waits); INIT_WORK(&rtwdev->ba_work, rtw89_core_ba_work); INIT_WORK(&rtwdev->txq_work, rtw89_core_txq_work); INIT_DELAYED_WORK(&rtwdev->txq_reinvoke_work, rtw89_core_txq_reinvoke_wor= k); @@ -5784,6 +5801,7 @@ int rtw89_core_init(struct rtw89_dev *rtwdev) wiphy_delayed_work_init(&rtwdev->coex_rfk_chk_work, rtw89_coex_rfk_chk_wo= rk); wiphy_delayed_work_init(&rtwdev->cfo_track_work, rtw89_phy_cfo_track_work= ); wiphy_delayed_work_init(&rtwdev->mcc_prepare_done_work, rtw89_mcc_prepare= _done_work); + wiphy_delayed_work_init(&rtwdev->tx_wait_work, rtw89_tx_wait_work); INIT_DELAYED_WORK(&rtwdev->forbid_ba_work, rtw89_forbid_ba_work); wiphy_delayed_work_init(&rtwdev->antdiv_work, rtw89_phy_antdiv_work); rtwdev->txq_wq =3D alloc_workqueue("rtw89_tx_wq", WQ_UNBOUND | WQ_HIGHPRI= , 0); diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wirele= ss/realtek/rtw89/core.h index 3d4ad2ffb75c..d15fa70eb4dc 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -3507,9 +3507,12 @@ struct rtw89_phy_rate_pattern { bool enable; }; =20 +#define RTW89_TX_WAIT_WORK_TIMEOUT msecs_to_jiffies(500) struct rtw89_tx_wait_info { struct rcu_head rcu_head; + struct list_head list; struct completion completion; + struct sk_buff *skb; bool tx_done; }; =20 @@ -6000,6 +6003,9 @@ struct rtw89_dev { /* used to protect rpwm */ spinlock_t rpwm_lock; =20 + struct list_head tx_waits; + struct wiphy_delayed_work tx_wait_work; + struct rtw89_cam_info cam_info; =20 struct sk_buff_head c2h_queue; @@ -6256,6 +6262,26 @@ rtw89_assoc_link_rcu_dereference(struct rtw89_dev *r= twdev, u8 macid) list_first_entry_or_null(&p->dlink_pool, typeof(*p->links_inst), dlink_sc= hd); \ }) =20 +static inline void rtw89_tx_wait_release(struct rtw89_tx_wait_info *wait) +{ + dev_kfree_skb_any(wait->skb); + kfree_rcu(wait, rcu_head); +} + +static inline void rtw89_tx_wait_list_clear(struct rtw89_dev *rtwdev) +{ + struct rtw89_tx_wait_info *wait, *tmp; + + lockdep_assert_wiphy(rtwdev->hw->wiphy); + + list_for_each_entry_safe(wait, tmp, &rtwdev->tx_waits, list) { + if (!completion_done(&wait->completion)) + continue; + list_del(&wait->list); + rtw89_tx_wait_release(wait); + } +} + static inline int rtw89_hci_tx_write(struct rtw89_dev *rtwdev, struct rtw89_core_tx_request *tx_req) { @@ -6265,6 +6291,7 @@ static inline int rtw89_hci_tx_write(struct rtw89_dev= *rtwdev, static inline void rtw89_hci_reset(struct rtw89_dev *rtwdev) { rtwdev->hci.ops->reset(rtwdev); + rtw89_tx_wait_list_clear(rtwdev); } =20 static inline int rtw89_hci_start(struct rtw89_dev *rtwdev) @@ -7345,11 +7372,12 @@ static inline struct sk_buff *rtw89_alloc_skb_for_r= x(struct rtw89_dev *rtwdev, return dev_alloc_skb(length); } =20 -static inline void rtw89_core_tx_wait_complete(struct rtw89_dev *rtwdev, +static inline bool rtw89_core_tx_wait_complete(struct rtw89_dev *rtwdev, struct rtw89_tx_skb_data *skb_data, bool tx_done) { struct rtw89_tx_wait_info *wait; + bool ret =3D false; =20 rcu_read_lock(); =20 @@ -7357,11 +7385,14 @@ static inline void rtw89_core_tx_wait_complete(stru= ct rtw89_dev *rtwdev, if (!wait) goto out; =20 + ret =3D true; wait->tx_done =3D tx_done; - complete(&wait->completion); + /* Don't access skb anymore after completion */ + complete_all(&wait->completion); =20 out: rcu_read_unlock(); + return ret; } =20 static inline bool rtw89_is_mlo_1_1(struct rtw89_dev *rtwdev) diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireles= s/realtek/rtw89/pci.c index c8286eb84276..8dd91d867ea6 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.c +++ b/drivers/net/wireless/realtek/rtw89/pci.c @@ -464,7 +464,8 @@ static void rtw89_pci_tx_status(struct rtw89_dev *rtwde= v, struct rtw89_tx_skb_data *skb_data =3D RTW89_TX_SKB_CB(skb); struct ieee80211_tx_info *info; =20 - rtw89_core_tx_wait_complete(rtwdev, skb_data, tx_status =3D=3D RTW89_TX_D= ONE); + if (rtw89_core_tx_wait_complete(rtwdev, skb_data, tx_status =3D=3D RTW89_= TX_DONE)) + return; =20 info =3D IEEE80211_SKB_CB(skb); ieee80211_tx_info_clear_status(info); diff --git a/drivers/net/wireless/realtek/rtw89/ser.c b/drivers/net/wireles= s/realtek/rtw89/ser.c index bb39fdbcba0d..fe7beff8c424 100644 --- a/drivers/net/wireless/realtek/rtw89/ser.c +++ b/drivers/net/wireless/realtek/rtw89/ser.c @@ -502,7 +502,9 @@ static void ser_reset_trx_st_hdl(struct rtw89_ser *ser,= u8 evt) } =20 drv_stop_rx(ser); + wiphy_lock(wiphy); drv_trx_reset(ser); + wiphy_unlock(wiphy); =20 /* wait m3 */ hal_send_m2_event(ser); --=20 2.51.0 From nobody Thu Oct 2 06:19:46 2025 Received: from mail.ispras.ru (mail.ispras.ru [83.149.199.84]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0597C28689B; Fri, 19 Sep 2025 21:09:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=83.149.199.84 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1758316175; cv=none; b=AhZR50zZQseKSulI9AIzHb6LxWXVabOGjp3u6rH4p48ZR9CtOvuk793J614/FX4j/Kf4bsX1NZ24e/6wdeHy8IHfzxc6RmhKfeOUNU2dGYKaW6x0QxfHmQCOrIwHKwTVy3Jxq9ndW+gKKscjNNJyyAzadl/lTfPPzUnaDh8AGSE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1758316175; c=relaxed/simple; bh=AgnmiRl00Q+TR5lkkj3F3V6s0smD41VHyxIWPPeLXUM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Xck2Y+soO7BHGjwWevmsoktv11JAWJbySgsb5I2xNZN6qUhPW9GEYBBCKDkJtzPlMnYGJP06XNRytBGGANpKVdxsC5MOOLPM32LHlWaNfklIj5wKRm7dNTk+Jq27nWrNB0YIC7E+V+JkvJ4g76d1CGN5FB8CH0IsyneVe69HUR4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=ispras.ru; spf=pass smtp.mailfrom=ispras.ru; dkim=pass (1024-bit key) header.d=ispras.ru header.i=@ispras.ru header.b=MX/OFU3R; arc=none smtp.client-ip=83.149.199.84 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=ispras.ru Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=ispras.ru Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=ispras.ru header.i=@ispras.ru header.b="MX/OFU3R" Received: from debian.intra.ispras.ru (unknown [10.10.165.9]) by mail.ispras.ru (Postfix) with ESMTPSA id AD0124076724; Fri, 19 Sep 2025 21:09:23 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 mail.ispras.ru AD0124076724 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ispras.ru; s=default; t=1758316163; bh=TMZ1Ae4sWnLco23Cwa29HKv1iyXkHZtKG3JzaMIlqYc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=MX/OFU3RUwPikIyT6/m1bTTOACdO8oDSPQ4BagFejJ66SftTTErI0JJ3KJnTghCw4 Ms+zzVzp7Yfl+BPu29pJUmUFbbWwlB77RC8pYbR6Kl7iDIOjxku4VvxFuYb16euZah qTfl7safaO2G9b5B+FcbXoG2CiwTxEF2PwgVFV90= From: Fedor Pchelkin To: Ping-Ke Shih , Zong-Zhe Yang Cc: Fedor Pchelkin , Bitterblue Smith , Po-Hao Huang , linux-wireless@vger.kernel.org, linux-kernel@vger.kernel.org, lvc-project@linuxtesting.org, stable@vger.kernel.org Subject: [PATCH rtw-next v5 2/4] wifi: rtw89: avoid possible TX wait initialization race Date: Sat, 20 Sep 2025 00:08:48 +0300 Message-ID: <20250919210852.823912-3-pchelkin@ispras.ru> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20250919210852.823912-1-pchelkin@ispras.ru> References: <20250919210852.823912-1-pchelkin@ispras.ru> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The value of skb_data->wait indicates whether skb is passed on to the core mac80211 stack or released by the driver itself. Make sure that by the time skb is added to txwd queue and becomes visible to the completing side, it has already allocated and initialized TX wait related data (in case it's needed). This is found by code review and addresses a possible race scenario described below: Waiting thread Completing thread rtw89_core_send_nullfunc() rtw89_core_tx_write_link() ... rtw89_pci_txwd_submit() skb_data->wait =3D NULL /* add skb to the queue */ skb_queue_tail(&txwd->queue, skb) /* another thread (e.g. rtw89_ops_tx) performs TX kick off for the same q= ueue */ rtw89_pci_napi_poll() ... rtw89_pci_release_txwd_skb() /* get skb from the queue */ skb_unlink(skb, &txwd->queu= e) rtw89_pci_tx_status() rtw89_core_tx_wait_comple= te() /* use incorrect skb_data= ->wait */ rtw89_core_tx_kick_off_and_wait() /* assign skb_data->wait but too late */ Found by Linux Verification Center (linuxtesting.org). Fixes: 1ae5ca615285 ("wifi: rtw89: add function to wait for completion of T= X skbs") Cc: stable@vger.kernel.org Signed-off-by: Fedor Pchelkin Acked-by: Ping-Ke Shih --- v5: - update the changelog to reflect that the potential race scenario was found by code review - pass wait as an argument to rtw89_core_tx_kick_off_and_wait() v4: - use wiphy_dereference (Zong-Zhe) - move wait->skb assignment place=20 drivers/net/wireless/realtek/rtw89/core.c | 39 +++++++++++++---------- drivers/net/wireless/realtek/rtw89/core.h | 3 +- drivers/net/wireless/realtek/rtw89/pci.c | 2 -- 3 files changed, 24 insertions(+), 20 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wirele= ss/realtek/rtw89/core.c index ec467ae0e9e6..1f44c7fc1c5e 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -1153,25 +1153,14 @@ void rtw89_core_tx_kick_off(struct rtw89_dev *rtwde= v, u8 qsel) } =20 int rtw89_core_tx_kick_off_and_wait(struct rtw89_dev *rtwdev, struct sk_bu= ff *skb, - int qsel, unsigned int timeout) + struct rtw89_tx_wait_info *wait, int qsel, + unsigned int timeout) { - struct rtw89_tx_skb_data *skb_data =3D RTW89_TX_SKB_CB(skb); - struct rtw89_tx_wait_info *wait; unsigned long time_left; int ret =3D 0; =20 lockdep_assert_wiphy(rtwdev->hw->wiphy); =20 - wait =3D kzalloc(sizeof(*wait), GFP_KERNEL); - if (!wait) { - rtw89_core_tx_kick_off(rtwdev, qsel); - return 0; - } - - init_completion(&wait->completion); - wait->skb =3D skb; - rcu_assign_pointer(skb_data->wait, wait); - rtw89_core_tx_kick_off(rtwdev, qsel); time_left =3D wait_for_completion_timeout(&wait->completion, msecs_to_jiffies(timeout)); @@ -1234,10 +1223,12 @@ int rtw89_h2c_tx(struct rtw89_dev *rtwdev, static int rtw89_core_tx_write_link(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, struct rtw89_sta_link *rtwsta_link, - struct sk_buff *skb, int *qsel, bool sw_mld) + struct sk_buff *skb, int *qsel, bool sw_mld, + struct rtw89_tx_wait_info *wait) { struct ieee80211_sta *sta =3D rtwsta_link_to_sta_safe(rtwsta_link); struct ieee80211_vif *vif =3D rtwvif_link_to_vif(rtwvif_link); + struct rtw89_tx_skb_data *skb_data =3D RTW89_TX_SKB_CB(skb); struct rtw89_vif *rtwvif =3D rtwvif_link->rtwvif; struct rtw89_core_tx_request tx_req =3D {}; int ret; @@ -1254,6 +1245,8 @@ static int rtw89_core_tx_write_link(struct rtw89_dev = *rtwdev, rtw89_core_tx_update_desc_info(rtwdev, &tx_req); rtw89_core_tx_wake(rtwdev, &tx_req); =20 + rcu_assign_pointer(skb_data->wait, wait); + ret =3D rtw89_hci_tx_write(rtwdev, &tx_req); if (ret) { rtw89_err(rtwdev, "failed to transmit skb to HCI\n"); @@ -1290,7 +1283,8 @@ int rtw89_core_tx_write(struct rtw89_dev *rtwdev, str= uct ieee80211_vif *vif, } } =20 - return rtw89_core_tx_write_link(rtwdev, rtwvif_link, rtwsta_link, skb, qs= el, false); + return rtw89_core_tx_write_link(rtwdev, rtwvif_link, rtwsta_link, skb, qs= el, false, + NULL); } =20 static __le32 rtw89_build_txwd_body0(struct rtw89_tx_desc_info *desc_info) @@ -3928,6 +3922,7 @@ int rtw89_core_send_nullfunc(struct rtw89_dev *rtwdev= , struct rtw89_vif_link *rt struct ieee80211_vif *vif =3D rtwvif_link_to_vif(rtwvif_link); int link_id =3D ieee80211_vif_is_mld(vif) ? rtwvif_link->link_id : -1; struct rtw89_sta_link *rtwsta_link; + struct rtw89_tx_wait_info *wait; struct ieee80211_sta *sta; struct ieee80211_hdr *hdr; struct rtw89_sta *rtwsta; @@ -3937,6 +3932,12 @@ int rtw89_core_send_nullfunc(struct rtw89_dev *rtwde= v, struct rtw89_vif_link *rt if (vif->type !=3D NL80211_IFTYPE_STATION || !vif->cfg.assoc) return 0; =20 + wait =3D kzalloc(sizeof(*wait), GFP_KERNEL); + if (!wait) + return -ENOMEM; + + init_completion(&wait->completion); + rcu_read_lock(); sta =3D ieee80211_find_sta(vif, vif->cfg.ap_addr); if (!sta) { @@ -3951,6 +3952,8 @@ int rtw89_core_send_nullfunc(struct rtw89_dev *rtwdev= , struct rtw89_vif_link *rt goto out; } =20 + wait->skb =3D skb; + hdr =3D (struct ieee80211_hdr *)skb->data; if (ps) hdr->frame_control |=3D cpu_to_le16(IEEE80211_FCTL_PM); @@ -3961,7 +3964,8 @@ int rtw89_core_send_nullfunc(struct rtw89_dev *rtwdev= , struct rtw89_vif_link *rt goto out; } =20 - ret =3D rtw89_core_tx_write_link(rtwdev, rtwvif_link, rtwsta_link, skb, &= qsel, true); + ret =3D rtw89_core_tx_write_link(rtwdev, rtwvif_link, rtwsta_link, skb, &= qsel, true, + wait); if (ret) { rtw89_warn(rtwdev, "nullfunc transmit failed: %d\n", ret); dev_kfree_skb_any(skb); @@ -3970,10 +3974,11 @@ int rtw89_core_send_nullfunc(struct rtw89_dev *rtwd= ev, struct rtw89_vif_link *rt =20 rcu_read_unlock(); =20 - return rtw89_core_tx_kick_off_and_wait(rtwdev, skb, qsel, + return rtw89_core_tx_kick_off_and_wait(rtwdev, skb, wait, qsel, timeout); out: rcu_read_unlock(); + kfree(wait); =20 return ret; } diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wirele= ss/realtek/rtw89/core.h index d15fa70eb4dc..928c8c84c964 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -7476,7 +7476,8 @@ int rtw89_h2c_tx(struct rtw89_dev *rtwdev, struct sk_buff *skb, bool fwdl); void rtw89_core_tx_kick_off(struct rtw89_dev *rtwdev, u8 qsel); int rtw89_core_tx_kick_off_and_wait(struct rtw89_dev *rtwdev, struct sk_bu= ff *skb, - int qsel, unsigned int timeout); + struct rtw89_tx_wait_info *wait, int qsel, + unsigned int timeout); void rtw89_core_fill_txdesc(struct rtw89_dev *rtwdev, struct rtw89_tx_desc_info *desc_info, void *txdesc); diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireles= s/realtek/rtw89/pci.c index 8dd91d867ea6..0ee5f8579447 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.c +++ b/drivers/net/wireless/realtek/rtw89/pci.c @@ -1494,7 +1494,6 @@ static int rtw89_pci_txwd_submit(struct rtw89_dev *rt= wdev, struct pci_dev *pdev =3D rtwpci->pdev; struct sk_buff *skb =3D tx_req->skb; struct rtw89_pci_tx_data *tx_data =3D RTW89_PCI_TX_SKB_CB(skb); - struct rtw89_tx_skb_data *skb_data =3D RTW89_TX_SKB_CB(skb); bool en_wd_info =3D desc_info->en_wd_info; u32 txwd_len; u32 txwp_len; @@ -1510,7 +1509,6 @@ static int rtw89_pci_txwd_submit(struct rtw89_dev *rt= wdev, } =20 tx_data->dma =3D dma; - rcu_assign_pointer(skb_data->wait, NULL); =20 txwp_len =3D sizeof(*txwp_info); txwd_len =3D chip->txwd_body_size; --=20 2.51.0 From nobody Thu Oct 2 06:19:46 2025 Received: from mail.ispras.ru (mail.ispras.ru [83.149.199.84]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C54B028DB54; Fri, 19 Sep 2025 21:09:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=83.149.199.84 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1758316174; cv=none; b=Fl+kAqz1BwOzC7761joCRErkPg0ay7C6BIPjsQarrOEgR5tUtDRUGoE0F/cOIDAc37MPy1WuAmT4EoNmqpixUJ6Ce8qMkxSUmFIdMsIFguDjFtUVkWbBhseoPpLytDUjZVm7zf5brb0sZXU1OUFOHvsGI2naQJQy71IfvcVXLWs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1758316174; c=relaxed/simple; bh=cG3vmSe6SxklI3ueJ9M2OA0WGfCITGkIas8B4xIdNTs=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=MEaibPrMTMLQX6S3zB0h2PHD10opxLTld76MdaslyUjTRQlTqGDTNcywBAikOfW3/MBnpn5JVXLjB1Rel5tegj1uftEhFft660K4fY48H1Ib/Cf+iYOwEg9g3vseod0iZQMunt2SaK9FoWPrQ1j/LeHsYez98h3f9ord+3db0pw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=ispras.ru; spf=pass smtp.mailfrom=ispras.ru; dkim=pass (1024-bit key) header.d=ispras.ru header.i=@ispras.ru header.b=Wd87HB0u; arc=none smtp.client-ip=83.149.199.84 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=ispras.ru Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=ispras.ru Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=ispras.ru header.i=@ispras.ru header.b="Wd87HB0u" Received: from debian.intra.ispras.ru (unknown [10.10.165.9]) by mail.ispras.ru (Postfix) with ESMTPSA id 6D8AD4076729; Fri, 19 Sep 2025 21:09:24 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 mail.ispras.ru 6D8AD4076729 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ispras.ru; s=default; t=1758316164; bh=BA5tqSvBSp4kXec7WBC70HwJ6Ad9Ag1iFAokhWm+jcI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Wd87HB0uEvzQLj532giJgSbV9deUMLDJarwSXqjAK5ofYzc4/TAnZIVasLp6pJBcm RhphrtnNrHpKueTdP7sMJDNlpJcltjnB7nXyjW/+NJt9zi2gkMnLYgx07NlwmgF+CI 1mw5a2vKG57W+igXGOkpdc+pBrSsbHDvTsCpCjS4= From: Fedor Pchelkin To: Ping-Ke Shih , Zong-Zhe Yang Cc: Fedor Pchelkin , Bitterblue Smith , Po-Hao Huang , linux-wireless@vger.kernel.org, linux-kernel@vger.kernel.org, lvc-project@linuxtesting.org Subject: [PATCH rtw-next v5 3/4] wifi: rtw89: fix leak in rtw89_core_send_nullfunc() Date: Sat, 20 Sep 2025 00:08:49 +0300 Message-ID: <20250919210852.823912-4-pchelkin@ispras.ru> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20250919210852.823912-1-pchelkin@ispras.ru> References: <20250919210852.823912-1-pchelkin@ispras.ru> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" If there is no rtwsta_link found in rtw89_core_send_nullfunc(), allocated skb is leaked. Free it on the error handling path. Found by Linux Verification Center (linuxtesting.org). Fixes: a8ba4acab7db ("wifi: rtw89: send nullfunc based on the given link") Signed-off-by: Fedor Pchelkin Acked-by: Ping-Ke Shih --- v3: - use dev_kfree_skb_any() directly on error handling path without extra goto complexity (Zong-Zhe) drivers/net/wireless/realtek/rtw89/core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wirele= ss/realtek/rtw89/core.c index 1f44c7fc1c5e..917b2adede61 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -3961,6 +3961,7 @@ int rtw89_core_send_nullfunc(struct rtw89_dev *rtwdev= , struct rtw89_vif_link *rt rtwsta_link =3D rtwsta->links[rtwvif_link->link_id]; if (unlikely(!rtwsta_link)) { ret =3D -ENOLINK; + dev_kfree_skb_any(skb); goto out; } =20 --=20 2.51.0 From nobody Thu Oct 2 06:19:46 2025 Received: from mail.ispras.ru (mail.ispras.ru [83.149.199.84]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C54212877F1; Fri, 19 Sep 2025 21:09:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=83.149.199.84 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1758316174; cv=none; b=nxRiiSP8QZMlSx8aZjlshnCrwxWc2x0HW4UnYVb0pc8WTdLs1YwVjPN10gdGGoFwUa8PNjY/0EC6LDvdqyVy8TL187X/Sq5s3jrAZUTn5EkzamXFXO324CBh/FtXgtXYhYiwXMPU5DdAi9EuohM5hnY9RjoHz+SCXeEQx/3An2Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1758316174; c=relaxed/simple; bh=g7ZYLJw64Tpc7UQeFooGHkKmnWawGuwg03GOSXNAUVk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=POn+OyFKz+u6kszBX3tN7hABwxz/jggK4NulpOJnh64PLCP7M9VNwwaYPAskr/lqS9HocNBilgSO6CLS6Qnoz8vofrkbo5sXnfyLTDILOAPZJmt44Mn79g2pLAj7Pmcq42Zy+HA3gxJPUHREoC3I1XXQHeco+lJdRe9Bz2d5DYU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=ispras.ru; spf=pass smtp.mailfrom=ispras.ru; dkim=pass (1024-bit key) header.d=ispras.ru header.i=@ispras.ru header.b=YQjUp5Mr; arc=none smtp.client-ip=83.149.199.84 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=ispras.ru Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=ispras.ru Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=ispras.ru header.i=@ispras.ru header.b="YQjUp5Mr" Received: from debian.intra.ispras.ru (unknown [10.10.165.9]) by mail.ispras.ru (Postfix) with ESMTPSA id 2B09A4076733; Fri, 19 Sep 2025 21:09:25 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 mail.ispras.ru 2B09A4076733 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ispras.ru; s=default; t=1758316165; bh=NJj22fzOdYNvzEou7366Uk4NlW3zvaZWooXBR+YJ0sc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=YQjUp5MrNxQEbhjPwiZZ5MRNqM3RpLbKc0le+iALLp88jNVZYDU4g4AEL3a8DUVjn 7EVCB5t+HiiU6WNjLi6NBBmZ5xk5A1VV8bUokf9ed6r9Um0XVLoxMGcbzdiNOcPlX7 70E+fgHakyVy+VodOiyoBDAf4wB12440cKTBMcTE= From: Fedor Pchelkin To: Ping-Ke Shih , Zong-Zhe Yang Cc: Fedor Pchelkin , Bitterblue Smith , Po-Hao Huang , linux-wireless@vger.kernel.org, linux-kernel@vger.kernel.org, lvc-project@linuxtesting.org Subject: [PATCH rtw-next v5 4/4] wifi: rtw89: avoid circular locking dependency in ser_state_run() Date: Sat, 20 Sep 2025 00:08:50 +0300 Message-ID: <20250919210852.823912-5-pchelkin@ispras.ru> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20250919210852.823912-1-pchelkin@ispras.ru> References: <20250919210852.823912-1-pchelkin@ispras.ru> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Lockdep gives a splat [1] when ser_hdl_work item is executed. It is scheduled at mac80211 workqueue via ieee80211_queue_work() and takes a wiphy lock inside. However, this workqueue can be flushed when e.g. closing the interface and wiphy lock is already taken in that case. Choosing wiphy_work_queue() for SER is likely not suitable. Back on to the global workqueue. [1]: WARNING: possible circular locking dependency detected 6.17.0-rc2 #17 Not tainted ------------------------------------------------------ kworker/u32:1/61 is trying to acquire lock: ffff88811bc00768 (&rdev->wiphy.mtx){+.+.}-{4:4}, at: ser_state_run+0x5e/0x= 180 [rtw89_core] but task is already holding lock: ffffc9000048fd30 ((work_completion)(&ser->ser_hdl_work)){+.+.}-{0:0}, at: = process_one_work+0x7b5/0x1450 which lock already depends on the new lock. the existing dependency chain (in reverse order) is: -> #2 ((work_completion)(&ser->ser_hdl_work)){+.+.}-{0:0}: process_one_work+0x7c6/0x1450 worker_thread+0x49e/0xd00 kthread+0x313/0x640 ret_from_fork+0x221/0x300 ret_from_fork_asm+0x1a/0x30 -> #1 ((wq_completion)phy0){+.+.}-{0:0}: touch_wq_lockdep_map+0x8e/0x180 __flush_workqueue+0x129/0x10d0 ieee80211_stop_device+0xa8/0x110 ieee80211_do_stop+0x14ce/0x2880 ieee80211_stop+0x13a/0x2c0 __dev_close_many+0x18f/0x510 __dev_change_flags+0x25f/0x670 netif_change_flags+0x7b/0x160 do_setlink.isra.0+0x1640/0x35d0 rtnl_newlink+0xd8c/0x1d30 rtnetlink_rcv_msg+0x700/0xb80 netlink_rcv_skb+0x11d/0x350 netlink_unicast+0x49a/0x7a0 netlink_sendmsg+0x759/0xc20 ____sys_sendmsg+0x812/0xa00 ___sys_sendmsg+0xf7/0x180 __sys_sendmsg+0x11f/0x1b0 do_syscall_64+0xbb/0x360 entry_SYSCALL_64_after_hwframe+0x77/0x7f -> #0 (&rdev->wiphy.mtx){+.+.}-{4:4}: __lock_acquire+0x124c/0x1d20 lock_acquire+0x154/0x2e0 __mutex_lock+0x17b/0x12f0 ser_state_run+0x5e/0x180 [rtw89_core] rtw89_ser_hdl_work+0x119/0x220 [rtw89_core] process_one_work+0x82d/0x1450 worker_thread+0x49e/0xd00 kthread+0x313/0x640 ret_from_fork+0x221/0x300 ret_from_fork_asm+0x1a/0x30 other info that might help us debug this: Chain exists of: &rdev->wiphy.mtx --> (wq_completion)phy0 --> (work_completion)(&ser->ser= _hdl_work) Possible unsafe locking scenario: CPU0 CPU1 ---- ---- lock((work_completion)(&ser->ser_hdl_work)); lock((wq_completion)phy0); lock((work_completion)(&ser->ser_hdl_work)); lock(&rdev->wiphy.mtx); *** DEADLOCK *** 2 locks held by kworker/u32:1/61: #0: ffff888103835148 ((wq_completion)phy0){+.+.}-{0:0}, at: process_one_w= ork+0xefa/0x1450 #1: ffffc9000048fd30 ((work_completion)(&ser->ser_hdl_work)){+.+.}-{0:0},= at: process_one_work+0x7b5/0x1450 stack backtrace: CPU: 0 UID: 0 PID: 61 Comm: kworker/u32:1 Not tainted 6.17.0-rc2 #17 PREEM= PT(voluntary) Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS edk2-20250523-= 14.fc42 05/23/2025 Workqueue: phy0 rtw89_ser_hdl_work [rtw89_core] Call Trace: dump_stack_lvl+0x5d/0x80 print_circular_bug.cold+0x178/0x1be check_noncircular+0x14c/0x170 __lock_acquire+0x124c/0x1d20 lock_acquire+0x154/0x2e0 __mutex_lock+0x17b/0x12f0 ser_state_run+0x5e/0x180 [rtw89_core] rtw89_ser_hdl_work+0x119/0x220 [rtw89_core] process_one_work+0x82d/0x1450 worker_thread+0x49e/0xd00 kthread+0x313/0x640 ret_from_fork+0x221/0x300 ret_from_fork_asm+0x1a/0x30 Found by Linux Verification Center (linuxtesting.org). Fixes: ebfc9199df05 ("wifi: rtw89: add wiphy_lock() to work that isn't held= wiphy_lock() yet") Signed-off-by: Fedor Pchelkin Acked-by: Ping-Ke Shih --- drivers/net/wireless/realtek/rtw89/ser.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/ser.c b/drivers/net/wireles= s/realtek/rtw89/ser.c index fe7beff8c424..f99e179f7ff9 100644 --- a/drivers/net/wireless/realtek/rtw89/ser.c +++ b/drivers/net/wireless/realtek/rtw89/ser.c @@ -205,7 +205,6 @@ static void rtw89_ser_hdl_work(struct work_struct *work) =20 static int ser_send_msg(struct rtw89_ser *ser, u8 event) { - struct rtw89_dev *rtwdev =3D container_of(ser, struct rtw89_dev, ser); struct ser_msg *msg =3D NULL; =20 if (test_bit(RTW89_SER_DRV_STOP_RUN, ser->flags)) @@ -221,7 +220,7 @@ static int ser_send_msg(struct rtw89_ser *ser, u8 event) list_add(&msg->list, &ser->msg_q); spin_unlock_irq(&ser->msg_q_lock); =20 - ieee80211_queue_work(rtwdev->hw, &ser->ser_hdl_work); + schedule_work(&ser->ser_hdl_work); return 0; } =20 --=20 2.51.0