lan966x_fdma_reload() replaces the RX ring when the MTU or the XDP program changes. It copies rx->page[] and the RX FDMA state, allocates the new ring, and on success returns the old pages to the old page pool. If the allocation fails, it restores the old state instead. Before this patch, the copies are taken before the NAPI is disabled. A poll still running at that point refills the ring and advances the DCB index and the last DCB pointer after the copy. The success path then returns a page that the stack still owns to the old pool and never returns the page that replaced it, and the restore path puts back a stale DCB index and last DCB pointer. Disable the NAPI and stop the queues before taking the copies. The copy of rx->page[] is still allocated first, so a failed allocation returns before anything has to be undone. Found by an AI code review agent. The race was not reproduced, as its window is narrow. The reworked reload was tested on a lan9668 board with repeated MTU and XDP program changes under RX traffic, with no page pool or UAF splat. Fixes: 59c3d55a946c ("net: lan966x: fix use-after-free and leak in lan966x_fdma_reload()") Signed-off-by: Daniel Machon --- drivers/net/ethernet/microchip/lan966x/lan966x_fdma.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_fdma.c b/drivers/net/ethernet/microchip/lan966x/lan966x_fdma.c index 21668bbcc9063..2dbc25c098fec 100644 --- a/drivers/net/ethernet/microchip/lan966x/lan966x_fdma.c +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_fdma.c @@ -819,21 +819,21 @@ static int lan966x_fdma_reload(struct lan966x *lan966x, int new_mtu) int page_order, max_mtu; int err, i, j; - old_pages = kmemdup(lan966x->rx.page, sizeof(lan966x->rx.page), - GFP_KERNEL); + old_pages = kmalloc_objs(*lan966x->rx.page, FDMA_DCB_MAX); if (!old_pages) return -ENOMEM; + napi_synchronize(&lan966x->napi); + napi_disable(&lan966x->napi); + lan966x_fdma_stop_netdev(lan966x); + /* Store these for later to free them */ + memcpy(old_pages, lan966x->rx.page, sizeof(lan966x->rx.page)); memcpy(&fdma_rx_old, &lan966x->rx.fdma, sizeof(struct fdma)); page_pool = lan966x->rx.page_pool; page_order = lan966x->rx.page_order; max_mtu = lan966x->rx.max_mtu; - napi_synchronize(&lan966x->napi); - napi_disable(&lan966x->napi); - lan966x_fdma_stop_netdev(lan966x); - lan966x_fdma_rx_disable(&lan966x->rx); lan966x->rx.page_order = round_up(new_mtu, PAGE_SIZE) / PAGE_SIZE - 1; lan966x->rx.max_mtu = new_mtu; --- base-commit: 829a09df899dcce860dcf5f70e09c1b2d7d425ab change-id: 20261028-lan966x-fdma-reload-quiesce-8fb5c277e284 Best regards, -- Daniel Machon