From: Ping-Ke Shih pkshih@realtek.com
[ Upstream commit f44a9b14a78f1e2e2c57dbc1f1e93889ad2f6ac0 ]
TX task can enqueue ROC skb, but other tasks dequeue the skb. Using skb_queue_walk_safe() without locking will cause potential racing. Use skb_dequeue() with lock instead.
Signed-off-by: Ping-Ke Shih pkshih@realtek.com Link: https://patch.msgid.link/20251021133402.15467-3-pkshih@realtek.com Signed-off-by: Sasha Levin sashal@kernel.org ---
LLM Generated explanations, may be completely bogus:
## Conclusion
This commit is a **legitimate bug fix** for a race condition in the rtw89 WiFi driver's ROC (Remain On Channel) packet handling. The race occurs because `skb_queue_walk_safe()` traverses the queue without holding the queue's internal lock, while concurrently the TX task may add packets via `skb_queue_tail()`.
**The fix:** - Replaces the unlocked iteration + separate unlink pattern with atomic `skb_dequeue()` - Is small (net -8 lines), contained, and obviously correct - Uses standard kernel idioms that are well-tested - Has minimal regression risk
**Stable tree applicability:** - Applies to kernel versions 6.4+ where the ROC functionality exists - Does NOT apply to 6.1.y LTS (code doesn't exist) - Code is identical in 6.6.y LTS and later versions
**Why YES despite missing stable tags:** The fix meets all the technical criteria for stable backporting: it fixes a real bug (race condition that could cause crashes), is small and surgical, doesn't add features, and has very low regression risk. While the maintainer didn't explicitly request stable backport, the bug is clearly real and the fix is clearly correct. The absence of a `Cc: stable` tag may simply indicate it wasn't considered urgent, not that it shouldn't be backported.
**YES**
drivers/net/wireless/realtek/rtw89/core.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 917b2adede61d..8b40cada4149e 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -3632,12 +3632,10 @@ void rtw89_core_free_sta_pending_roc_tx(struct rtw89_dev *rtwdev, struct ieee80211_sta *sta) { struct rtw89_sta *rtwsta = sta_to_rtwsta(sta); - struct sk_buff *skb, *tmp; + struct sk_buff *skb;
- skb_queue_walk_safe(&rtwsta->roc_queue, skb, tmp) { - skb_unlink(skb, &rtwsta->roc_queue); + while ((skb = skb_dequeue(&rtwsta->roc_queue))) dev_kfree_skb_any(skb); - } }
static void rtw89_core_stop_tx_ba_session(struct rtw89_dev *rtwdev, @@ -3881,8 +3879,8 @@ static void rtw89_core_sta_pending_tx_iter(void *data, struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); struct rtw89_vif_link *target = data; struct rtw89_vif_link *rtwvif_link; - struct sk_buff *skb, *tmp; unsigned int link_id; + struct sk_buff *skb; int qsel, ret;
rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) @@ -3895,9 +3893,7 @@ static void rtw89_core_sta_pending_tx_iter(void *data, if (skb_queue_len(&rtwsta->roc_queue) == 0) return;
- skb_queue_walk_safe(&rtwsta->roc_queue, skb, tmp) { - skb_unlink(skb, &rtwsta->roc_queue); - + while ((skb = skb_dequeue(&rtwsta->roc_queue))) { ret = rtw89_core_tx_write(rtwdev, vif, sta, skb, &qsel); if (ret) { rtw89_warn(rtwdev, "pending tx failed with %d\n", ret);