[PATCH] net: ethernet: arc: fix use-after-free in probe error path
Fan Wu
fanwu01 at zju.edu.cn
Tue Mar 3 18:53:03 PST 2026
The arc_emac_probe() function calls devm_request_irq() with the
net_device as the dev_id. However, in the error path of
emac_rockchip_probe(), free_netdev(ndev) is called before the devm
cleanup happens. This creates a race window where an interrupt can
fire and the ISR (arc_emac_intr) will access the already freed
net_device structure.
Race window:
CPU 0 (probe error path) CPU 1 (interrupt)
------------------------ ------------------
emac_rockchip_probe()
arc_emac_probe()
devm_request_irq(..., ndev)
[probe fails]
goto out_netdev;
free_netdev(ndev) // freed!
<Interrupt fires>
arc_emac_intr()
ndev = dev_instance
priv = netdev_priv(ndev)
// UAF! Accessing freed mem
return err;
devres_release_all() // Driver core cleanup
devm_irq_release() // IRQ disabled too late!
Fix this by using devm_alloc_etherdev() instead of alloc_etherdev().
With fully managed allocation, the devres mechanism ensures proper
LIFO cleanup order: IRQ is released before net_device memory, thus
eliminating the race window entirely.
Remove the now-unnecessary free_netdev() calls from both the probe
error path and the remove function, as the memory is automatically
freed by devres when the device is detached.
Fixes: 6eacf31139bf ("ethernet: arc: Add support for Rockchip SoC layer device tree bindings")
Signed-off-by: Fan Wu <fanwu01 at zju.edu.cn>
---
drivers/net/ethernet/arc/emac_rockchip.c | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/arc/emac_rockchip.c b/drivers/net/ethernet/arc/emac_rockchip.c
index 780e70ea1c22..a695ea6547c8 100644
--- a/drivers/net/ethernet/arc/emac_rockchip.c
+++ b/drivers/net/ethernet/arc/emac_rockchip.c
@@ -103,7 +103,7 @@ static int emac_rockchip_probe(struct platform_device *pdev)
if (!pdev->dev.of_node)
return -ENODEV;
- ndev = alloc_etherdev(sizeof(struct rockchip_priv_data));
+ ndev = devm_alloc_etherdev(dev, sizeof(struct rockchip_priv_data));
if (!ndev)
return -ENOMEM;
platform_set_drvdata(pdev, ndev);
@@ -240,7 +240,6 @@ static int emac_rockchip_probe(struct platform_device *pdev)
out_clk_disable:
clk_disable_unprepare(priv->refclk);
out_netdev:
- free_netdev(ndev);
return err;
}
@@ -258,8 +257,6 @@ static void emac_rockchip_remove(struct platform_device *pdev)
if (priv->soc_data->need_div_macclk)
clk_disable_unprepare(priv->macclk);
-
- free_netdev(ndev);
}
static struct platform_driver emac_rockchip_driver = {
--
2.34.1
More information about the Linux-rockchip
mailing list