A failed RX URB submission can leak the skb allocated for that attempt. rtl8xxxu_submit_rx_urb() allocates the buffer and stores it in urb.context, but if usb_submit_urb() fails, it only unanchors the URB. The RX worker queues ENOMEM/EAGAIN failures for retry with that buffer still attached. On the next attempt, rtl8xxxu_submit_rx_urb() allocates another skb and overwrites urb.context, losing the reference to the previous buffer. Stopping before the retry also leaks the buffer because pending-request cleanup frees only the URB. Fix the leak at the submission failure by making rtl8xxxu_submit_rx_urb() responsible for both allocating the skb and releasing it when submission fails. Free the newly allocated skb and clear urb.context before returning the error, so neither retry nor stop receives a pending URB that still owns a buffer. Remove the caller-side skb cleanup from start and the RX worker; those callers now handle only whether to retry or release the URB. Fixes: 26f1fad29ad9 ("New driver: rtl8xxxu (mac80211)") Assisted-by: GPT-6 Astra Signed-off-by: kimwooseok <5mghybrid@khu.ac.kr> --- drivers/net/wireless/realtek/rtl8xxxu/core.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/core.c b/drivers/net/wireless/realtek/rtl8xxxu/core.c index bddbd0990de72..795a5ec2f8cd4 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/core.c @@ -5864,7 +5864,6 @@ static void rtl8xxxu_rx_urb_work(struct work_struct *work) struct rtl8xxxu_priv *priv; struct rtl8xxxu_rx_urb *rx_urb, *tmp; struct list_head local; - struct sk_buff *skb; unsigned long flags; int ret; @@ -5896,8 +5895,6 @@ static void rtl8xxxu_rx_urb_work(struct work_struct *work) default: dev_warn(&priv->udev->dev, "failed to requeue urb with error %i\n", ret); - skb = (struct sk_buff *)rx_urb->urb.context; - dev_kfree_skb(skb); usb_free_urb(&rx_urb->urb); } } @@ -6596,8 +6593,11 @@ static int rtl8xxxu_submit_rx_urb(struct rtl8xxxu_priv *priv, skb_size, rtl8xxxu_rx_complete, skb); usb_anchor_urb(&rx_urb->urb, &priv->rx_anchor); ret = usb_submit_urb(&rx_urb->urb, GFP_ATOMIC); - if (ret) + if (ret) { usb_unanchor_urb(&rx_urb->urb); + dev_kfree_skb(skb); + rx_urb->urb.context = NULL; + } return ret; } @@ -7410,7 +7410,6 @@ static int rtl8xxxu_start(struct ieee80211_hw *hw) struct rtl8xxxu_priv *priv = hw->priv; struct rtl8xxxu_rx_urb *rx_urb; struct rtl8xxxu_tx_urb *tx_urb; - struct sk_buff *skb; unsigned long flags; int ret, i; @@ -7461,13 +7460,8 @@ static int rtl8xxxu_start(struct ieee80211_hw *hw) rx_urb->hw = hw; ret = rtl8xxxu_submit_rx_urb(priv, rx_urb); - if (ret) { - if (ret != -ENOMEM) { - skb = (struct sk_buff *)rx_urb->urb.context; - dev_kfree_skb(skb); - } + if (ret) rtl8xxxu_queue_rx_urb(priv, rx_urb); - } } schedule_delayed_work(&priv->ra_watchdog, 2 * HZ); -- 2.48.1