* [PATCH v3 1/2] wifi: mt76: mt792x: fix UAF in SDIO TX path when out of memory
2026-08-19 8:21 [PATCH v3 0/2] wifi: mt76: refine USB/SDIO TX path error handling Eason Lai
@ 2026-08-19 8:21 ` Eason Lai
2026-08-19 8:21 ` [PATCH v3 2/2] wifi: mt76: fix memory leak in USB TX path Eason Lai
` (2 subsequent siblings)
3 siblings, 0 replies; 7+ messages in thread
From: Eason Lai @ 2026-08-19 8:21 UTC (permalink / raw)
To: nbd, lorenzo
Cc: linux-wireless, linux-mediatek, kun.wu, deren.wu, sean.wang,
quan.zhou, ryder.lee, leon.yen, litien.chang, jb.tsai, eason.lai,
stable, Devin Wittmayer
Using __skb_pad() instead of skb_pad() in mt76_skb_adjust_pad()
to prevent double-free, as the caller handles cleanup.
Fixes: 808f2767d421 ("wifi: mt76: mt792x: Fix memory leak in SDIO TX path")
Co-developed-by: Devin Wittmayer <lucid_duck@justthetip.ca>
Signed-off-by: Devin Wittmayer <lucid_duck@justthetip.ca>
Signed-off-by: Eason Lai <eason.lai@mediatek.com>
---
v2: no v2 change
v3: add Signed-off-by: Devin Wittmayer and send as series
---
drivers/net/wireless/mediatek/mt76/tx.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c
index 3707ee19e4ae..ec503521ae63 100644
--- a/drivers/net/wireless/mediatek/mt76/tx.c
+++ b/drivers/net/wireless/mediatek/mt76/tx.c
@@ -879,7 +879,7 @@ int mt76_skb_adjust_pad(struct sk_buff *skb, int pad)
}
}
- if (skb_pad(last, pad))
+ if (__skb_pad(last, pad, false))
return -ENOMEM;
__skb_put(last, pad);
--
2.45.2
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH v3 2/2] wifi: mt76: fix memory leak in USB TX path
2026-08-19 8:21 [PATCH v3 0/2] wifi: mt76: refine USB/SDIO TX path error handling Eason Lai
2026-08-19 8:21 ` [PATCH v3 1/2] wifi: mt76: mt792x: fix UAF in SDIO TX path when out of memory Eason Lai
@ 2026-08-19 8:21 ` Eason Lai
2026-08-24 15:29 ` [PATCH v3 0/2] wifi: mt76: refine USB/SDIO TX path error handling Devin Wittmayer
2026-08-27 8:35 ` [PATCH v4 " Eason Lai
3 siblings, 0 replies; 7+ messages in thread
From: Eason Lai @ 2026-08-19 8:21 UTC (permalink / raw)
To: nbd, lorenzo
Cc: linux-wireless, linux-mediatek, kun.wu, deren.wu, sean.wang,
quan.zhou, ryder.lee, leon.yen, litien.chang, jb.tsai, eason.lai,
stable, Devin Wittmayer
When errors occur in mt76u_tx_queue_skb(), the skb is not properly
freed, leading to memory leaks. This happens when:
- The queue is full
- tx_prepare_skb() drops zero-length frames (such as WMM NULL frames)
to prevent hardware TX hangs
- Buffer setup fails
Fix by properly releasing the skb with ieee80211_tx_status_ext() when
the queue is full or tx_prepare_skb() fails, and using
mt76_tx_complete_skb() when mt76u_tx_setup_buffers() fails (since
tx_prepare_skb() has already succeeded and may have allocated resources
that need cleanup)
Fixes: b40b15e1521f ("mt76: add usb support to mt76 layer")
Cc: stable@vger.kernel.org
Tested-by: Devin Wittmayer <lucid_duck@justthetip.ca>
Signed-off-by: Eason Lai <eason.lai@mediatek.com>
---
v2:
- add error handling for queue full and tx_prepare_skb()
- correct error handling for mt76u_tx_setup_buffers()
v3: add Tested-by: Devin Wittmayer and cc stable
---
drivers/net/wireless/mediatek/mt76/usb.c | 31 ++++++++++++++++++++----
1 file changed, 26 insertions(+), 5 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c
index a9af3aa6b80a..dfc12f6944a7 100644
--- a/drivers/net/wireless/mediatek/mt76/usb.c
+++ b/drivers/net/wireless/mediatek/mt76/usb.c
@@ -893,6 +893,9 @@ mt76u_tx_queue_skb(struct mt76_phy *phy, struct mt76_queue *q,
enum mt76_txq_id qid, struct sk_buff *skb,
struct mt76_wcid *wcid, struct ieee80211_sta *sta)
{
+ struct ieee80211_tx_status status = {
+ .sta = sta,
+ };
struct mt76_tx_info tx_info = {
.skb = skb,
};
@@ -900,17 +903,27 @@ mt76u_tx_queue_skb(struct mt76_phy *phy, struct mt76_queue *q,
u16 idx = q->head;
int err;
- if (q->queued == q->ndesc)
- return -ENOSPC;
+ if (q->queued == q->ndesc) {
+ err = -ENOSPC;
+ goto err_free_skb;
+ }
skb->prev = skb->next = NULL;
err = dev->drv->tx_prepare_skb(dev, NULL, qid, wcid, sta, &tx_info);
if (err < 0)
- return err;
+ goto err_free_skb;
err = mt76u_tx_setup_buffers(dev, tx_info.skb, q->entry[idx].urb);
- if (err < 0)
- return err;
+ if (err < 0) {
+ /*
+ * mt76_tx_status_skb_get() walks the idr and dereferences
+ * a freed skb. This SKB is not counted in non-AQL counter
+ * due to error return, so using 0xffff as wcid to keep
+ * balanced.
+ */
+ mt76_tx_complete_skb(dev, 0xffff, tx_info.skb);
+ goto err_ret;
+ }
mt76u_fill_bulk_urb(dev, USB_DIR_OUT, q->ep, q->entry[idx].urb,
mt76u_complete_tx, &q->entry[idx]);
@@ -921,6 +934,14 @@ mt76u_tx_queue_skb(struct mt76_phy *phy, struct mt76_queue *q,
q->queued++;
return idx;
+
+err_free_skb:
+ status.skb = tx_info.skb;
+ spin_lock_bh(&dev->rx_lock);
+ ieee80211_tx_status_ext(dev->hw, &status);
+ spin_unlock_bh(&dev->rx_lock);
+err_ret:
+ return err;
}
static void mt76u_tx_kick(struct mt76_dev *dev, struct mt76_queue *q)
--
2.45.2
^ permalink raw reply related [flat|nested] 7+ messages in thread* Re: [PATCH v3 0/2] wifi: mt76: refine USB/SDIO TX path error handling
2026-08-19 8:21 [PATCH v3 0/2] wifi: mt76: refine USB/SDIO TX path error handling Eason Lai
2026-08-19 8:21 ` [PATCH v3 1/2] wifi: mt76: mt792x: fix UAF in SDIO TX path when out of memory Eason Lai
2026-08-19 8:21 ` [PATCH v3 2/2] wifi: mt76: fix memory leak in USB TX path Eason Lai
@ 2026-08-24 15:29 ` Devin Wittmayer
2026-08-27 8:35 ` [PATCH v4 " Eason Lai
3 siblings, 0 replies; 7+ messages in thread
From: Devin Wittmayer @ 2026-08-24 15:29 UTC (permalink / raw)
To: Eason Lai
Cc: nbd, lorenzo, linux-wireless, linux-mediatek, kun.wu, deren.wu,
sean.wang, quan.zhou, ryder.lee, leon.yen, litien.chang, jb.tsai,
stable
On Wed, 2026-08-19 at 16:21 +0800, Eason Lai wrote:
> This series fixes a UAF in the SDIO TX path when out of memory and
> a memory leak in the USB TX path.
Thanks for turning that around so fast, and for taking all of it. The
code reads right to me now.
One thing to sort out before it lands. 2/2 is marked for stable and 1/2
is not, but the two only work together. The padding helper frees the skb
itself when it fails, which is fine today because the caller returns
without touching it. 2/2 changes that, and starts reporting the prepare
failure with a skb that is already gone. 1/2 is what stops the helper
freeing. So a stable tree that takes 2/2 on its own gets a use after
free where there is no bug today.
It will not get caught on the way through, either. 2/2 applies and
passes without 1/2, because the frame returns before the padding runs.
Marking 1/2 for stable is all it takes. The stable rules say you do not
have to list a prerequisite that is already in the same series, but only
if that patch is itself marked for stable.
The Closes line did not make it onto either patch:
https://github.com/morrownr/mt76/issues/83
Devin
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v4 0/2] wifi: mt76: refine USB/SDIO TX path error handling
2026-08-19 8:21 [PATCH v3 0/2] wifi: mt76: refine USB/SDIO TX path error handling Eason Lai
` (2 preceding siblings ...)
2026-08-24 15:29 ` [PATCH v3 0/2] wifi: mt76: refine USB/SDIO TX path error handling Devin Wittmayer
@ 2026-08-27 8:35 ` Eason Lai
2026-08-27 8:35 ` [PATCH v4 1/2] wifi: mt76: mt792x: fix UAF in SDIO TX path when out of memory Eason Lai
2026-08-27 8:35 ` [PATCH v4 2/2] wifi: mt76: fix memory leak in USB TX path Eason Lai
3 siblings, 2 replies; 7+ messages in thread
From: Eason Lai @ 2026-08-27 8:35 UTC (permalink / raw)
To: nbd, lorenzo
Cc: linux-wireless, linux-mediatek, kun.wu, deren.wu, sean.wang,
quan.zhou, ryder.lee, leon.yen, litien.chang, jb.tsai, lucid_duck,
eason.lai, stable
This series fixes a UAF in the SDIO TX path when out of memory and
a memory leak in the USB TX path.
Eason Lai (2):
wifi: mt76: mt792x: fix UAF in SDIO TX path when out of memory
wifi: mt76: fix memory leak in USB TX path
drivers/net/wireless/mediatek/mt76/tx.c | 2 +-
drivers/net/wireless/mediatek/mt76/usb.c | 31 ++++++++++++++++++++----
2 files changed, 27 insertions(+), 6 deletions(-)
--
2.45.2
^ permalink raw reply [flat|nested] 7+ messages in thread* [PATCH v4 1/2] wifi: mt76: mt792x: fix UAF in SDIO TX path when out of memory
2026-08-27 8:35 ` [PATCH v4 " Eason Lai
@ 2026-08-27 8:35 ` Eason Lai
2026-08-27 8:35 ` [PATCH v4 2/2] wifi: mt76: fix memory leak in USB TX path Eason Lai
1 sibling, 0 replies; 7+ messages in thread
From: Eason Lai @ 2026-08-27 8:35 UTC (permalink / raw)
To: nbd, lorenzo
Cc: linux-wireless, linux-mediatek, kun.wu, deren.wu, sean.wang,
quan.zhou, ryder.lee, leon.yen, litien.chang, jb.tsai, lucid_duck,
eason.lai, stable
Using __skb_pad() instead of skb_pad() in mt76_skb_adjust_pad()
to prevent double-free, as the caller handles cleanup.
Fixes: 808f2767d421 ("wifi: mt76: mt792x: Fix memory leak in SDIO TX path")
Cc: stable@vger.kernel.org
Closes: https://github.com/morrownr/mt76/issues/83
Co-developed-by: Devin Wittmayer <lucid_duck@justthetip.ca>
Signed-off-by: Devin Wittmayer <lucid_duck@justthetip.ca>
Signed-off-by: Eason Lai <eason.lai@mediatek.com>
---
v2: no v2 change
v3: add Signed-off-by: Devin Wittmayer and send as series
v4: add CC stable
---
drivers/net/wireless/mediatek/mt76/tx.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c
index 3707ee19e4ae..ec503521ae63 100644
--- a/drivers/net/wireless/mediatek/mt76/tx.c
+++ b/drivers/net/wireless/mediatek/mt76/tx.c
@@ -879,7 +879,7 @@ int mt76_skb_adjust_pad(struct sk_buff *skb, int pad)
}
}
- if (skb_pad(last, pad))
+ if (__skb_pad(last, pad, false))
return -ENOMEM;
__skb_put(last, pad);
--
2.45.2
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH v4 2/2] wifi: mt76: fix memory leak in USB TX path
2026-08-27 8:35 ` [PATCH v4 " Eason Lai
2026-08-27 8:35 ` [PATCH v4 1/2] wifi: mt76: mt792x: fix UAF in SDIO TX path when out of memory Eason Lai
@ 2026-08-27 8:35 ` Eason Lai
1 sibling, 0 replies; 7+ messages in thread
From: Eason Lai @ 2026-08-27 8:35 UTC (permalink / raw)
To: nbd, lorenzo
Cc: linux-wireless, linux-mediatek, kun.wu, deren.wu, sean.wang,
quan.zhou, ryder.lee, leon.yen, litien.chang, jb.tsai, lucid_duck,
eason.lai, stable
When errors occur in mt76u_tx_queue_skb(), the skb is not properly
freed, leading to memory leaks. This happens when:
- The queue is full
- tx_prepare_skb() drops zero-length frames (such as WMM NULL frames)
to prevent hardware TX hangs
- Buffer setup fails
Fix by properly releasing the skb with ieee80211_tx_status_ext() when
the queue is full or tx_prepare_skb() fails, and using
mt76_tx_complete_skb() when mt76u_tx_setup_buffers() fails (since
tx_prepare_skb() has already succeeded and may have allocated resources
that need cleanup)
Fixes: b40b15e1521f ("mt76: add usb support to mt76 layer")
Cc: stable@vger.kernel.org
Tested-by: Devin Wittmayer <lucid_duck@justthetip.ca>
Closes: https://github.com/morrownr/mt76/issues/83
Signed-off-by: Eason Lai <eason.lai@mediatek.com>
---
v2:
- add error handling for queue full and tx_prepare_skb()
- correct error handling for mt76u_tx_setup_buffers()
v3: add Tested-by: Devin Wittmayer and cc stable
v4: add Closes line
---
drivers/net/wireless/mediatek/mt76/usb.c | 31 ++++++++++++++++++++----
1 file changed, 26 insertions(+), 5 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c
index a9af3aa6b80a..dfc12f6944a7 100644
--- a/drivers/net/wireless/mediatek/mt76/usb.c
+++ b/drivers/net/wireless/mediatek/mt76/usb.c
@@ -893,6 +893,9 @@ mt76u_tx_queue_skb(struct mt76_phy *phy, struct mt76_queue *q,
enum mt76_txq_id qid, struct sk_buff *skb,
struct mt76_wcid *wcid, struct ieee80211_sta *sta)
{
+ struct ieee80211_tx_status status = {
+ .sta = sta,
+ };
struct mt76_tx_info tx_info = {
.skb = skb,
};
@@ -900,17 +903,27 @@ mt76u_tx_queue_skb(struct mt76_phy *phy, struct mt76_queue *q,
u16 idx = q->head;
int err;
- if (q->queued == q->ndesc)
- return -ENOSPC;
+ if (q->queued == q->ndesc) {
+ err = -ENOSPC;
+ goto err_free_skb;
+ }
skb->prev = skb->next = NULL;
err = dev->drv->tx_prepare_skb(dev, NULL, qid, wcid, sta, &tx_info);
if (err < 0)
- return err;
+ goto err_free_skb;
err = mt76u_tx_setup_buffers(dev, tx_info.skb, q->entry[idx].urb);
- if (err < 0)
- return err;
+ if (err < 0) {
+ /*
+ * mt76_tx_status_skb_get() walks the idr and dereferences
+ * a freed skb. This SKB is not counted in non-AQL counter
+ * due to error return, so using 0xffff as wcid to keep
+ * balanced.
+ */
+ mt76_tx_complete_skb(dev, 0xffff, tx_info.skb);
+ goto err_ret;
+ }
mt76u_fill_bulk_urb(dev, USB_DIR_OUT, q->ep, q->entry[idx].urb,
mt76u_complete_tx, &q->entry[idx]);
@@ -921,6 +934,14 @@ mt76u_tx_queue_skb(struct mt76_phy *phy, struct mt76_queue *q,
q->queued++;
return idx;
+
+err_free_skb:
+ status.skb = tx_info.skb;
+ spin_lock_bh(&dev->rx_lock);
+ ieee80211_tx_status_ext(dev->hw, &status);
+ spin_unlock_bh(&dev->rx_lock);
+err_ret:
+ return err;
}
static void mt76u_tx_kick(struct mt76_dev *dev, struct mt76_queue *q)
--
2.45.2
^ permalink raw reply related [flat|nested] 7+ messages in thread