Skip to content

Commit d882eed

Browse files
committed
wifi: rtw89: avoid possible TX wait initialization race
JIRA: https://issues.redhat.com/browse/RHEL-114889 commit c24248e Author: Fedor Pchelkin <pchelkin@ispras.ru> Date: Sat Sep 20 00:08:48 2025 +0300 wifi: rtw89: avoid possible TX wait initialization race 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 = 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 queue */ rtw89_pci_napi_poll() ... rtw89_pci_release_txwd_skb() /* get skb from the queue */ skb_unlink(skb, &txwd->queue) rtw89_pci_tx_status() rtw89_core_tx_wait_complete() /* 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: 1ae5ca6 ("wifi: rtw89: add function to wait for completion of TX skbs") Cc: stable@vger.kernel.org Signed-off-by: Fedor Pchelkin <pchelkin@ispras.ru> Acked-by: Ping-Ke Shih <pkshih@realtek.com> Signed-off-by: Ping-Ke Shih <pkshih@realtek.com> Link: https://patch.msgid.link/20250919210852.823912-3-pchelkin@ispras.ru Signed-off-by: Jose Ignacio Tornos Martinez <jtornosm@redhat.com>
1 parent 0373512 commit d882eed

File tree

3 files changed

+24
-20
lines changed

3 files changed

+24
-20
lines changed

drivers/net/wireless/realtek/rtw89/core.c

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1091,25 +1091,14 @@ void rtw89_core_tx_kick_off(struct rtw89_dev *rtwdev, u8 qsel)
10911091
}
10921092

10931093
int rtw89_core_tx_kick_off_and_wait(struct rtw89_dev *rtwdev, struct sk_buff *skb,
1094-
int qsel, unsigned int timeout)
1094+
struct rtw89_tx_wait_info *wait, int qsel,
1095+
unsigned int timeout)
10951096
{
1096-
struct rtw89_tx_skb_data *skb_data = RTW89_TX_SKB_CB(skb);
1097-
struct rtw89_tx_wait_info *wait;
10981097
unsigned long time_left;
10991098
int ret = 0;
11001099

11011100
lockdep_assert_wiphy(rtwdev->hw->wiphy);
11021101

1103-
wait = kzalloc(sizeof(*wait), GFP_KERNEL);
1104-
if (!wait) {
1105-
rtw89_core_tx_kick_off(rtwdev, qsel);
1106-
return 0;
1107-
}
1108-
1109-
init_completion(&wait->completion);
1110-
wait->skb = skb;
1111-
rcu_assign_pointer(skb_data->wait, wait);
1112-
11131102
rtw89_core_tx_kick_off(rtwdev, qsel);
11141103
time_left = wait_for_completion_timeout(&wait->completion,
11151104
msecs_to_jiffies(timeout));
@@ -1172,10 +1161,12 @@ int rtw89_h2c_tx(struct rtw89_dev *rtwdev,
11721161
static int rtw89_core_tx_write_link(struct rtw89_dev *rtwdev,
11731162
struct rtw89_vif_link *rtwvif_link,
11741163
struct rtw89_sta_link *rtwsta_link,
1175-
struct sk_buff *skb, int *qsel, bool sw_mld)
1164+
struct sk_buff *skb, int *qsel, bool sw_mld,
1165+
struct rtw89_tx_wait_info *wait)
11761166
{
11771167
struct ieee80211_sta *sta = rtwsta_link_to_sta_safe(rtwsta_link);
11781168
struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link);
1169+
struct rtw89_tx_skb_data *skb_data = RTW89_TX_SKB_CB(skb);
11791170
struct rtw89_vif *rtwvif = rtwvif_link->rtwvif;
11801171
struct rtw89_core_tx_request tx_req = {};
11811172
int ret;
@@ -1192,6 +1183,8 @@ static int rtw89_core_tx_write_link(struct rtw89_dev *rtwdev,
11921183
rtw89_core_tx_update_desc_info(rtwdev, &tx_req);
11931184
rtw89_core_tx_wake(rtwdev, &tx_req);
11941185

1186+
rcu_assign_pointer(skb_data->wait, wait);
1187+
11951188
ret = rtw89_hci_tx_write(rtwdev, &tx_req);
11961189
if (ret) {
11971190
rtw89_err(rtwdev, "failed to transmit skb to HCI\n");
@@ -1228,7 +1221,8 @@ int rtw89_core_tx_write(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
12281221
}
12291222
}
12301223

1231-
return rtw89_core_tx_write_link(rtwdev, rtwvif_link, rtwsta_link, skb, qsel, false);
1224+
return rtw89_core_tx_write_link(rtwdev, rtwvif_link, rtwsta_link, skb, qsel, false,
1225+
NULL);
12321226
}
12331227

12341228
static __le32 rtw89_build_txwd_body0(struct rtw89_tx_desc_info *desc_info)
@@ -3426,6 +3420,7 @@ int rtw89_core_send_nullfunc(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rt
34263420
struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link);
34273421
int link_id = ieee80211_vif_is_mld(vif) ? rtwvif_link->link_id : -1;
34283422
struct rtw89_sta_link *rtwsta_link;
3423+
struct rtw89_tx_wait_info *wait;
34293424
struct ieee80211_sta *sta;
34303425
struct ieee80211_hdr *hdr;
34313426
struct rtw89_sta *rtwsta;
@@ -3435,6 +3430,12 @@ int rtw89_core_send_nullfunc(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rt
34353430
if (vif->type != NL80211_IFTYPE_STATION || !vif->cfg.assoc)
34363431
return 0;
34373432

3433+
wait = kzalloc(sizeof(*wait), GFP_KERNEL);
3434+
if (!wait)
3435+
return -ENOMEM;
3436+
3437+
init_completion(&wait->completion);
3438+
34383439
rcu_read_lock();
34393440
sta = ieee80211_find_sta(vif, vif->cfg.ap_addr);
34403441
if (!sta) {
@@ -3449,6 +3450,8 @@ int rtw89_core_send_nullfunc(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rt
34493450
goto out;
34503451
}
34513452

3453+
wait->skb = skb;
3454+
34523455
hdr = (struct ieee80211_hdr *)skb->data;
34533456
if (ps)
34543457
hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
@@ -3460,7 +3463,8 @@ int rtw89_core_send_nullfunc(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rt
34603463
goto out;
34613464
}
34623465

3463-
ret = rtw89_core_tx_write_link(rtwdev, rtwvif_link, rtwsta_link, skb, &qsel, true);
3466+
ret = rtw89_core_tx_write_link(rtwdev, rtwvif_link, rtwsta_link, skb, &qsel, true,
3467+
wait);
34643468
if (ret) {
34653469
rtw89_warn(rtwdev, "nullfunc transmit failed: %d\n", ret);
34663470
dev_kfree_skb_any(skb);
@@ -3469,10 +3473,11 @@ int rtw89_core_send_nullfunc(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rt
34693473

34703474
rcu_read_unlock();
34713475

3472-
return rtw89_core_tx_kick_off_and_wait(rtwdev, skb, qsel,
3476+
return rtw89_core_tx_kick_off_and_wait(rtwdev, skb, wait, qsel,
34733477
timeout);
34743478
out:
34753479
rcu_read_unlock();
3480+
kfree(wait);
34763481

34773482
return ret;
34783483
}

drivers/net/wireless/realtek/rtw89/core.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7389,7 +7389,8 @@ int rtw89_h2c_tx(struct rtw89_dev *rtwdev,
73897389
struct sk_buff *skb, bool fwdl);
73907390
void rtw89_core_tx_kick_off(struct rtw89_dev *rtwdev, u8 qsel);
73917391
int rtw89_core_tx_kick_off_and_wait(struct rtw89_dev *rtwdev, struct sk_buff *skb,
7392-
int qsel, unsigned int timeout);
7392+
struct rtw89_tx_wait_info *wait, int qsel,
7393+
unsigned int timeout);
73937394
void rtw89_core_fill_txdesc(struct rtw89_dev *rtwdev,
73947395
struct rtw89_tx_desc_info *desc_info,
73957396
void *txdesc);

drivers/net/wireless/realtek/rtw89/pci.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1372,7 +1372,6 @@ static int rtw89_pci_txwd_submit(struct rtw89_dev *rtwdev,
13721372
struct pci_dev *pdev = rtwpci->pdev;
13731373
struct sk_buff *skb = tx_req->skb;
13741374
struct rtw89_pci_tx_data *tx_data = RTW89_PCI_TX_SKB_CB(skb);
1375-
struct rtw89_tx_skb_data *skb_data = RTW89_TX_SKB_CB(skb);
13761375
bool en_wd_info = desc_info->en_wd_info;
13771376
u32 txwd_len;
13781377
u32 txwp_len;
@@ -1388,7 +1387,6 @@ static int rtw89_pci_txwd_submit(struct rtw89_dev *rtwdev,
13881387
}
13891388

13901389
tx_data->dma = dma;
1391-
rcu_assign_pointer(skb_data->wait, NULL);
13921390

13931391
txwp_len = sizeof(*txwp_info);
13941392
txwd_len = chip->txwd_body_size;

0 commit comments

Comments
 (0)