Skip to content

Commit e9fd43b

Browse files
pchelkin91gregkh
authored andcommitted
wifi: rtw89: avoid possible TX wait initialization race
[ Upstream commit c24248e ] 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] [ adapted rtw89_core_tx_write_link() modifications to rtw89_core_tx_write() ] Signed-off-by: Sasha Levin <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent c33da54 commit e9fd43b

File tree

4 files changed

+26
-23
lines changed

4 files changed

+26
-23
lines changed

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

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -978,25 +978,14 @@ void rtw89_core_tx_kick_off(struct rtw89_dev *rtwdev, u8 qsel)
978978
}
979979

980980
int rtw89_core_tx_kick_off_and_wait(struct rtw89_dev *rtwdev, struct sk_buff *skb,
981-
int qsel, unsigned int timeout)
981+
struct rtw89_tx_wait_info *wait, int qsel,
982+
unsigned int timeout)
982983
{
983-
struct rtw89_tx_skb_data *skb_data = RTW89_TX_SKB_CB(skb);
984-
struct rtw89_tx_wait_info *wait;
985984
unsigned long time_left;
986985
int ret = 0;
987986

988987
lockdep_assert_wiphy(rtwdev->hw->wiphy);
989988

990-
wait = kzalloc(sizeof(*wait), GFP_KERNEL);
991-
if (!wait) {
992-
rtw89_core_tx_kick_off(rtwdev, qsel);
993-
return 0;
994-
}
995-
996-
init_completion(&wait->completion);
997-
wait->skb = skb;
998-
rcu_assign_pointer(skb_data->wait, wait);
999-
1000989
rtw89_core_tx_kick_off(rtwdev, qsel);
1001990
time_left = wait_for_completion_timeout(&wait->completion,
1002991
msecs_to_jiffies(timeout));
@@ -1057,10 +1046,12 @@ int rtw89_h2c_tx(struct rtw89_dev *rtwdev,
10571046
}
10581047

10591048
int rtw89_core_tx_write(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
1060-
struct ieee80211_sta *sta, struct sk_buff *skb, int *qsel)
1049+
struct ieee80211_sta *sta, struct sk_buff *skb, int *qsel,
1050+
struct rtw89_tx_wait_info *wait)
10611051
{
10621052
struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta);
10631053
struct rtw89_vif *rtwvif = vif_to_rtwvif(vif);
1054+
struct rtw89_tx_skb_data *skb_data = RTW89_TX_SKB_CB(skb);
10641055
struct rtw89_core_tx_request tx_req = {0};
10651056
struct rtw89_sta_link *rtwsta_link = NULL;
10661057
struct rtw89_vif_link *rtwvif_link;
@@ -1093,6 +1084,8 @@ int rtw89_core_tx_write(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
10931084
rtw89_core_tx_update_desc_info(rtwdev, &tx_req);
10941085
rtw89_core_tx_wake(rtwdev, &tx_req);
10951086

1087+
rcu_assign_pointer(skb_data->wait, wait);
1088+
10961089
ret = rtw89_hci_tx_write(rtwdev, &tx_req);
10971090
if (ret) {
10981091
rtw89_err(rtwdev, "failed to transmit skb to HCI\n");
@@ -2908,7 +2901,7 @@ static void rtw89_core_txq_push(struct rtw89_dev *rtwdev,
29082901
goto out;
29092902
}
29102903
rtw89_core_txq_check_agg(rtwdev, rtwtxq, skb);
2911-
ret = rtw89_core_tx_write(rtwdev, vif, sta, skb, NULL);
2904+
ret = rtw89_core_tx_write(rtwdev, vif, sta, skb, NULL, NULL);
29122905
if (ret) {
29132906
rtw89_err(rtwdev, "failed to push txq: %d\n", ret);
29142907
ieee80211_free_txskb(rtwdev->hw, skb);
@@ -3084,7 +3077,7 @@ static void rtw89_core_sta_pending_tx_iter(void *data,
30843077
skb_queue_walk_safe(&rtwsta->roc_queue, skb, tmp) {
30853078
skb_unlink(skb, &rtwsta->roc_queue);
30863079

3087-
ret = rtw89_core_tx_write(rtwdev, vif, sta, skb, &qsel);
3080+
ret = rtw89_core_tx_write(rtwdev, vif, sta, skb, &qsel, NULL);
30883081
if (ret) {
30893082
rtw89_warn(rtwdev, "pending tx failed with %d\n", ret);
30903083
dev_kfree_skb_any(skb);
@@ -3106,6 +3099,7 @@ static int rtw89_core_send_nullfunc(struct rtw89_dev *rtwdev,
31063099
struct rtw89_vif_link *rtwvif_link, bool qos, bool ps)
31073100
{
31083101
struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link);
3102+
struct rtw89_tx_wait_info *wait;
31093103
struct ieee80211_sta *sta;
31103104
struct ieee80211_hdr *hdr;
31113105
struct sk_buff *skb;
@@ -3114,6 +3108,12 @@ static int rtw89_core_send_nullfunc(struct rtw89_dev *rtwdev,
31143108
if (vif->type != NL80211_IFTYPE_STATION || !vif->cfg.assoc)
31153109
return 0;
31163110

3111+
wait = kzalloc(sizeof(*wait), GFP_KERNEL);
3112+
if (!wait)
3113+
return -ENOMEM;
3114+
3115+
init_completion(&wait->completion);
3116+
31173117
rcu_read_lock();
31183118
sta = ieee80211_find_sta(vif, vif->cfg.ap_addr);
31193119
if (!sta) {
@@ -3127,11 +3127,13 @@ static int rtw89_core_send_nullfunc(struct rtw89_dev *rtwdev,
31273127
goto out;
31283128
}
31293129

3130+
wait->skb = skb;
3131+
31303132
hdr = (struct ieee80211_hdr *)skb->data;
31313133
if (ps)
31323134
hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
31333135

3134-
ret = rtw89_core_tx_write(rtwdev, vif, sta, skb, &qsel);
3136+
ret = rtw89_core_tx_write(rtwdev, vif, sta, skb, &qsel, wait);
31353137
if (ret) {
31363138
rtw89_warn(rtwdev, "nullfunc transmit failed: %d\n", ret);
31373139
dev_kfree_skb_any(skb);
@@ -3140,10 +3142,11 @@ static int rtw89_core_send_nullfunc(struct rtw89_dev *rtwdev,
31403142

31413143
rcu_read_unlock();
31423144

3143-
return rtw89_core_tx_kick_off_and_wait(rtwdev, skb, qsel,
3145+
return rtw89_core_tx_kick_off_and_wait(rtwdev, skb, wait, qsel,
31443146
RTW89_ROC_TX_TIMEOUT);
31453147
out:
31463148
rcu_read_unlock();
3149+
kfree(wait);
31473150

31483151
return ret;
31493152
}

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6818,12 +6818,14 @@ static inline bool rtw89_is_rtl885xb(struct rtw89_dev *rtwdev)
68186818
}
68196819

68206820
int rtw89_core_tx_write(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
6821-
struct ieee80211_sta *sta, struct sk_buff *skb, int *qsel);
6821+
struct ieee80211_sta *sta, struct sk_buff *skb, int *qsel,
6822+
struct rtw89_tx_wait_info *wait);
68226823
int rtw89_h2c_tx(struct rtw89_dev *rtwdev,
68236824
struct sk_buff *skb, bool fwdl);
68246825
void rtw89_core_tx_kick_off(struct rtw89_dev *rtwdev, u8 qsel);
68256826
int rtw89_core_tx_kick_off_and_wait(struct rtw89_dev *rtwdev, struct sk_buff *skb,
6826-
int qsel, unsigned int timeout);
6827+
struct rtw89_tx_wait_info *wait, int qsel,
6828+
unsigned int timeout);
68276829
void rtw89_core_fill_txdesc(struct rtw89_dev *rtwdev,
68286830
struct rtw89_tx_desc_info *desc_info,
68296831
void *txdesc);

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ static void rtw89_ops_tx(struct ieee80211_hw *hw,
3636
return;
3737
}
3838

39-
ret = rtw89_core_tx_write(rtwdev, vif, sta, skb, &qsel);
39+
ret = rtw89_core_tx_write(rtwdev, vif, sta, skb, &qsel, NULL);
4040
if (ret) {
4141
rtw89_err(rtwdev, "failed to transmit skb: %d\n", ret);
4242
ieee80211_free_txskb(hw, skb);

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1366,7 +1366,6 @@ static int rtw89_pci_txwd_submit(struct rtw89_dev *rtwdev,
13661366
struct pci_dev *pdev = rtwpci->pdev;
13671367
struct sk_buff *skb = tx_req->skb;
13681368
struct rtw89_pci_tx_data *tx_data = RTW89_PCI_TX_SKB_CB(skb);
1369-
struct rtw89_tx_skb_data *skb_data = RTW89_TX_SKB_CB(skb);
13701369
bool en_wd_info = desc_info->en_wd_info;
13711370
u32 txwd_len;
13721371
u32 txwp_len;
@@ -1382,7 +1381,6 @@ static int rtw89_pci_txwd_submit(struct rtw89_dev *rtwdev,
13821381
}
13831382

13841383
tx_data->dma = dma;
1385-
rcu_assign_pointer(skb_data->wait, NULL);
13861384

13871385
txwp_len = sizeof(*txwp_info);
13881386
txwd_len = chip->txwd_body_size;

0 commit comments

Comments
 (0)