[PATCH net-next v2 2/2] net/stmmac: Fix free-after-use panic when interface goes down
From: Jakub Raczynski
Date: Mon Jun 01 2026 - 12:47:16 EST
When stmmac interface releases, kernel might panic with wrong memory access or
show SLUB "poison overwritten" errors due to a race condition between
NAPI polling and resource freeing.
Observed error is one of following:
- Poison overwriten
[ 1889.547746] eth1: Link is Down
[ 1889.549940] =============================================================================
[ 1889.549954] BUG kmalloc-4k (Tainted: G B ): Poison overwritten
[ 1889.549959] -----------------------------------------------------------------------------
[ 1889.549963] 0xffffff882dcc4d80-0xffffff882dcc4da7 @offset=19840. First byte 0x0 instead of 0x6b
[ 1889.549969] Allocated in __alloc_dma_tx_desc_resources+0x60/0x10c [stmmac] age=169 cpu=7 pid=27759
[ 1889.550020] __kmem_cache_alloc_node+0x100/0x2e8
[ 1889.550032] __kmalloc+0x58/0x1a0
[ 1889.550039] __alloc_dma_tx_desc_resources+0x60/0x10c [stmmac]
[ 1889.550052] alloc_dma_desc_resources+0xec/0x164 [stmmac]
[ 1889.550064] stmmac_setup_dma_desc+0xec/0x1e4 [stmmac]
[ 1889.550076] stmmac_open+0x28/0x94 [stmmac]
[...]
- Wrong memory address
[ 1901.546692] Unable to handle kernel paging request at virtual address dead000000000122
[...]
[ 1902.964068] Call trace:
[ 1902.967193] free_to_partial_list+0x560/0x600
[ 1902.972227] __slab_free+0x1a8/0x420
[ 1902.976480] __kmem_cache_free+0x204/0x218
[ 1902.981254] kfree+0x6c/0x128
[ 1902.984900] kvfree+0x3c/0x4c
[ 1902.988545] page_pool_release+0x234/0x27c
[ 1902.993320] page_pool_destroy+0xcc/0x190
[ 1902.998006] __free_dma_rx_desc_resources+0x100/0x360 [stmmac]
[ 1903.004516] free_dma_desc_resources+0x8c/0xac [stmmac]
[ 1903.010419] stmmac_release+0x1c0/0x2b4 [stmmac]
[...]
Root cause is stmmac_release() stops DMA and frees TX/RX ring buffers and
page pools while NAPI/XDP could still be accessing these resources in the
background.
Fix is by applying napi_synchronize() instead of synchronize_rcu() to
every RX or RXTX queue, instead of only for XDP. Also synchronize_rcu() is
not correct nor sufficient function to assure NAPI has finished processing.
There might be need for potential clearing again after IRQ disable,
but this is very hard to reproduce. If this happens, we need to recheck
after IRQ disable.
Co-developed-by: Chang-Sub Lee <cs0617.lee@xxxxxxxxxxx>
Signed-off-by: Chang-Sub Lee <cs0617.lee@xxxxxxxxxxx>
Signed-off-by: Jakub Raczynski <j.raczynski@xxxxxxxxxxx>
---
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 3a66f2842527..2c6abd5efd55 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -292,16 +292,18 @@ static void __stmmac_disable_all_queues(struct stmmac_priv *priv)
static void stmmac_disable_all_queues(struct stmmac_priv *priv)
{
u8 rx_queues_cnt = priv->plat->rx_queues_to_use;
- struct stmmac_rx_queue *rx_q;
u8 queue;
- /* synchronize_rcu() needed for pending XDP buffers to drain */
for (queue = 0; queue < rx_queues_cnt; queue++) {
- rx_q = &priv->dma_conf.rx_queue[queue];
- if (rx_q->xsk_pool) {
- synchronize_rcu();
- break;
+ struct stmmac_channel *ch = &priv->channel[queue];
+
+ if (stmmac_xdp_is_enabled(priv) &&
+ test_bit(queue, priv->af_xdp_zc_qps)) {
+ napi_synchronize(&ch->rxtx_napi);
+ } else {
+ napi_synchronize(&ch->rx_napi);
}
+
}
__stmmac_disable_all_queues(priv);
--
2.34.1