Skip to content

Commit c24248e

Browse files
pchelkin91Ping-Ke Shih
authored andcommitted
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: [email protected] Signed-off-by: Fedor Pchelkin <[email protected]> Acked-by: Ping-Ke Shih <[email protected]> Signed-off-by: Ping-Ke Shih <[email protected]> Link: https://patch.msgid.link/[email protected]
1 parent 3e31a6b commit c24248e

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
@@ -1153,25 +1153,14 @@ void rtw89_core_tx_kick_off(struct rtw89_dev *rtwdev, u8 qsel)
11531153
}
11541154

11551155
int rtw89_core_tx_kick_off_and_wait(struct rtw89_dev *rtwdev, struct sk_buff *skb,
1156-
int qsel, unsigned int timeout)
1156+
struct rtw89_tx_wait_info *wait, int qsel,
1157+
unsigned int timeout)
11571158
{
1158-
struct rtw89_tx_skb_data *skb_data = RTW89_TX_SKB_CB(skb);
1159-
struct rtw89_tx_wait_info *wait;
11601159
unsigned long time_left;
11611160
int ret = 0;
11621161

11631162
lockdep_assert_wiphy(rtwdev->hw->wiphy);
11641163

1165-
wait = kzalloc(sizeof(*wait), GFP_KERNEL);
1166-
if (!wait) {
1167-
rtw89_core_tx_kick_off(rtwdev, qsel);
1168-
return 0;
1169-
}
1170-
1171-
init_completion(&wait->completion);
1172-
wait->skb = skb;
1173-
rcu_assign_pointer(skb_data->wait, wait);
1174-
11751164
rtw89_core_tx_kick_off(rtwdev, qsel);
11761165
time_left = wait_for_completion_timeout(&wait->completion,
11771166
msecs_to_jiffies(timeout));
@@ -1234,10 +1223,12 @@ int rtw89_h2c_tx(struct rtw89_dev *rtwdev,
12341223
static int rtw89_core_tx_write_link(struct rtw89_dev *rtwdev,
12351224
struct rtw89_vif_link *rtwvif_link,
12361225
struct rtw89_sta_link *rtwsta_link,
1237-
struct sk_buff *skb, int *qsel, bool sw_mld)
1226+
struct sk_buff *skb, int *qsel, bool sw_mld,
1227+
struct rtw89_tx_wait_info *wait)
12381228
{
12391229
struct ieee80211_sta *sta = rtwsta_link_to_sta_safe(rtwsta_link);
12401230
struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link);
1231+
struct rtw89_tx_skb_data *skb_data = RTW89_TX_SKB_CB(skb);
12411232
struct rtw89_vif *rtwvif = rtwvif_link->rtwvif;
12421233
struct rtw89_core_tx_request tx_req = {};
12431234
int ret;
@@ -1254,6 +1245,8 @@ static int rtw89_core_tx_write_link(struct rtw89_dev *rtwdev,
12541245
rtw89_core_tx_update_desc_info(rtwdev, &tx_req);
12551246
rtw89_core_tx_wake(rtwdev, &tx_req);
12561247

1248+
rcu_assign_pointer(skb_data->wait, wait);
1249+
12571250
ret = rtw89_hci_tx_write(rtwdev, &tx_req);
12581251
if (ret) {
12591252
rtw89_err(rtwdev, "failed to transmit skb to HCI\n");
@@ -1290,7 +1283,8 @@ int rtw89_core_tx_write(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
12901283
}
12911284
}
12921285

1293-
return rtw89_core_tx_write_link(rtwdev, rtwvif_link, rtwsta_link, skb, qsel, false);
1286+
return rtw89_core_tx_write_link(rtwdev, rtwvif_link, rtwsta_link, skb, qsel, false,
1287+
NULL);
12941288
}
12951289

12961290
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
39283922
struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link);
39293923
int link_id = ieee80211_vif_is_mld(vif) ? rtwvif_link->link_id : -1;
39303924
struct rtw89_sta_link *rtwsta_link;
3925+
struct rtw89_tx_wait_info *wait;
39313926
struct ieee80211_sta *sta;
39323927
struct ieee80211_hdr *hdr;
39333928
struct rtw89_sta *rtwsta;
@@ -3937,6 +3932,12 @@ int rtw89_core_send_nullfunc(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rt
39373932
if (vif->type != NL80211_IFTYPE_STATION || !vif->cfg.assoc)
39383933
return 0;
39393934

3935+
wait = kzalloc(sizeof(*wait), GFP_KERNEL);
3936+
if (!wait)
3937+
return -ENOMEM;
3938+
3939+
init_completion(&wait->completion);
3940+
39403941
rcu_read_lock();
39413942
sta = ieee80211_find_sta(vif, vif->cfg.ap_addr);
39423943
if (!sta) {
@@ -3951,6 +3952,8 @@ int rtw89_core_send_nullfunc(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rt
39513952
goto out;
39523953
}
39533954

3955+
wait->skb = skb;
3956+
39543957
hdr = (struct ieee80211_hdr *)skb->data;
39553958
if (ps)
39563959
hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
@@ -3961,7 +3964,8 @@ int rtw89_core_send_nullfunc(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rt
39613964
goto out;
39623965
}
39633966

3964-
ret = rtw89_core_tx_write_link(rtwdev, rtwvif_link, rtwsta_link, skb, &qsel, true);
3967+
ret = rtw89_core_tx_write_link(rtwdev, rtwvif_link, rtwsta_link, skb, &qsel, true,
3968+
wait);
39653969
if (ret) {
39663970
rtw89_warn(rtwdev, "nullfunc transmit failed: %d\n", ret);
39673971
dev_kfree_skb_any(skb);
@@ -3970,10 +3974,11 @@ int rtw89_core_send_nullfunc(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rt
39703974

39713975
rcu_read_unlock();
39723976

3973-
return rtw89_core_tx_kick_off_and_wait(rtwdev, skb, qsel,
3977+
return rtw89_core_tx_kick_off_and_wait(rtwdev, skb, wait, qsel,
39743978
timeout);
39753979
out:
39763980
rcu_read_unlock();
3981+
kfree(wait);
39773982

39783983
return ret;
39793984
}

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7476,7 +7476,8 @@ int rtw89_h2c_tx(struct rtw89_dev *rtwdev,
74767476
struct sk_buff *skb, bool fwdl);
74777477
void rtw89_core_tx_kick_off(struct rtw89_dev *rtwdev, u8 qsel);
74787478
int rtw89_core_tx_kick_off_and_wait(struct rtw89_dev *rtwdev, struct sk_buff *skb,
7479-
int qsel, unsigned int timeout);
7479+
struct rtw89_tx_wait_info *wait, int qsel,
7480+
unsigned int timeout);
74807481
void rtw89_core_fill_txdesc(struct rtw89_dev *rtwdev,
74817482
struct rtw89_tx_desc_info *desc_info,
74827483
void *txdesc);

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1494,7 +1494,6 @@ static int rtw89_pci_txwd_submit(struct rtw89_dev *rtwdev,
14941494
struct pci_dev *pdev = rtwpci->pdev;
14951495
struct sk_buff *skb = tx_req->skb;
14961496
struct rtw89_pci_tx_data *tx_data = RTW89_PCI_TX_SKB_CB(skb);
1497-
struct rtw89_tx_skb_data *skb_data = RTW89_TX_SKB_CB(skb);
14981497
bool en_wd_info = desc_info->en_wd_info;
14991498
u32 txwd_len;
15001499
u32 txwp_len;
@@ -1510,7 +1509,6 @@ static int rtw89_pci_txwd_submit(struct rtw89_dev *rtwdev,
15101509
}
15111510

15121511
tx_data->dma = dma;
1513-
rcu_assign_pointer(skb_data->wait, NULL);
15141512

15151513
txwp_len = sizeof(*txwp_info);
15161514
txwd_len = chip->txwd_body_size;

0 commit comments

Comments
 (0)