Skip to content

Commit 200d58c

Browse files
MocLGgregkh
authored andcommitted
wifi: rtw88: usb: fix memory leaks on USB write failures
commit 6b96494 upstream. When rtw_usb_write_port() fails to submit a USB Request Block (URB) (e.g., due to device disconnect or ENOMEM), the completion callback is never executed. Currently, the driver ignores the return value of rtw_usb_write_port() in rtw_usb_write_data() and rtw_usb_tx_agg_skb(). Because these functions rely on the completion callback to free the socket buffers (skbs) and the transaction control block (txcb), a submission failure results in: 1. A memory leak of the allocated skb in rtw_usb_write_data(). 2. A memory leak of the txcb structure and all aggregated skbs in rtw_usb_tx_agg_skb(). Fix this by checking the return value of rtw_usb_write_port(). If it fails, explicitly free the skb in rtw_usb_write_data(), and properly purge the tx_ack_queue and free the txcb in rtw_usb_tx_agg_skb(). The issue was discovered in practice during device disconnect/reconnect scenarios and memory pressure conditions. Tested by verifying normal TX operation continues after the fix without regressions. Fixes: a82dfd3 ("wifi: rtw88: Add common USB chip support") Cc: stable@vger.kernel.org Acked-by: Ping-Ke Shih <pkshih@realtek.com> Tested-by: Luka Gejak <luka.gejak@linux.dev> Signed-off-by: Luka Gejak <luka.gejak@linux.dev> Signed-off-by: Ping-Ke Shih <pkshih@realtek.com> Link: https://patch.msgid.link/20260518142311.10328-2-luka.gejak@linux.dev Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 73d427d commit 200d58c

1 file changed

Lines changed: 11 additions & 2 deletions

File tree

  • drivers/net/wireless/realtek/rtw88

drivers/net/wireless/realtek/rtw88/usb.c

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,7 @@ static bool rtw_usb_tx_agg_skb(struct rtw_usb *rtwusb, struct sk_buff_head *list
399399
int agg_num = 0;
400400
unsigned int align_next = 0;
401401
u8 qsel;
402+
int ret;
402403

403404
if (skb_queue_empty(list))
404405
return false;
@@ -456,7 +457,13 @@ static bool rtw_usb_tx_agg_skb(struct rtw_usb *rtwusb, struct sk_buff_head *list
456457
tx_desc = (struct rtw_tx_desc *)skb_head->data;
457458
qsel = le32_get_bits(tx_desc->w1, RTW_TX_DESC_W1_QSEL);
458459

459-
rtw_usb_write_port(rtwdev, qsel, skb_head, rtw_usb_write_port_tx_complete, txcb);
460+
ret = rtw_usb_write_port(rtwdev, qsel, skb_head,
461+
rtw_usb_write_port_tx_complete, txcb);
462+
if (ret) {
463+
ieee80211_purge_tx_queue(rtwdev->hw, &txcb->tx_ack_queue);
464+
kfree(txcb);
465+
return false;
466+
}
460467

461468
return true;
462469
}
@@ -518,8 +525,10 @@ static int rtw_usb_write_data(struct rtw_dev *rtwdev,
518525

519526
ret = rtw_usb_write_port(rtwdev, qsel, skb,
520527
rtw_usb_write_port_complete, skb);
521-
if (unlikely(ret))
528+
if (unlikely(ret)) {
522529
rtw_err(rtwdev, "failed to do USB write, ret=%d\n", ret);
530+
dev_kfree_skb_any(skb);
531+
}
523532

524533
return ret;
525534
}

0 commit comments

Comments
 (0)