Skip to content

Commit 59c3d55

Browse files
devnexenPaolo Abeni
authored andcommitted
net: lan966x: fix use-after-free and leak in lan966x_fdma_reload()
When lan966x_fdma_reload() fails to allocate new RX buffers, the restore path restarts DMA using old descriptors whose pages were already freed via lan966x_fdma_rx_free_pages(). Since page_pool_put_full_page() can release pages back to the buddy allocator, the hardware may DMA into memory now owned by other kernel subsystems. Additionally, on the restore path, the newly created page pool (if allocation partially succeeded) is overwritten without being destroyed, leaking it. Fix both issues by deferring the release of old pages until after the new allocation succeeds. Save the old page array before the allocation so old pages can be freed on the success path. On the failure path, the old descriptors, pages and page pool are all still valid, making the restore safe. Also ensure the restore path re-enables NAPI and wakes the netdev, matching the success path. Fixes: 89ba464 ("net: lan966x: refactor buffer reload function") Cc: stable@vger.kernel.org Signed-off-by: David Carlier <devnexen@gmail.com> Link: https://patch.msgid.link/20260405055241.35767-4-devnexen@gmail.com Signed-off-by: Paolo Abeni <pabeni@redhat.com>
1 parent 076344a commit 59c3d55

1 file changed

Lines changed: 18 additions & 3 deletions

File tree

drivers/net/ethernet/microchip/lan966x/lan966x_fdma.c

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -812,9 +812,15 @@ static int lan966x_qsys_sw_status(struct lan966x *lan966x)
812812

813813
static int lan966x_fdma_reload(struct lan966x *lan966x, int new_mtu)
814814
{
815+
struct page *(*old_pages)[FDMA_RX_DCB_MAX_DBS];
815816
struct page_pool *page_pool;
816817
struct fdma fdma_rx_old;
817-
int err;
818+
int err, i, j;
819+
820+
old_pages = kmemdup(lan966x->rx.page, sizeof(lan966x->rx.page),
821+
GFP_KERNEL);
822+
if (!old_pages)
823+
return -ENOMEM;
818824

819825
/* Store these for later to free them */
820826
memcpy(&fdma_rx_old, &lan966x->rx.fdma, sizeof(struct fdma));
@@ -825,27 +831,36 @@ static int lan966x_fdma_reload(struct lan966x *lan966x, int new_mtu)
825831
lan966x_fdma_stop_netdev(lan966x);
826832

827833
lan966x_fdma_rx_disable(&lan966x->rx);
828-
lan966x_fdma_rx_free_pages(&lan966x->rx);
829834
lan966x->rx.page_order = round_up(new_mtu, PAGE_SIZE) / PAGE_SIZE - 1;
830835
lan966x->rx.max_mtu = new_mtu;
831836
err = lan966x_fdma_rx_alloc(&lan966x->rx);
832837
if (err)
833838
goto restore;
834839
lan966x_fdma_rx_start(&lan966x->rx);
835840

841+
for (i = 0; i < fdma_rx_old.n_dcbs; ++i)
842+
for (j = 0; j < fdma_rx_old.n_dbs; ++j)
843+
page_pool_put_full_page(page_pool,
844+
old_pages[i][j], false);
845+
836846
fdma_free_coherent(lan966x->dev, &fdma_rx_old);
837847

838848
page_pool_destroy(page_pool);
839849

840850
lan966x_fdma_wakeup_netdev(lan966x);
841851
napi_enable(&lan966x->napi);
842852

843-
return err;
853+
kfree(old_pages);
854+
return 0;
844855
restore:
845856
lan966x->rx.page_pool = page_pool;
846857
memcpy(&lan966x->rx.fdma, &fdma_rx_old, sizeof(struct fdma));
847858
lan966x_fdma_rx_start(&lan966x->rx);
848859

860+
lan966x_fdma_wakeup_netdev(lan966x);
861+
napi_enable(&lan966x->napi);
862+
863+
kfree(old_pages);
849864
return err;
850865
}
851866

0 commit comments

Comments
 (0)