[PATCHv2 net] net: emac: mal: replace devm_request_irq with request_irq to fix probe error race
From: Rosen Penev <hidden>
Date: 2026-07-04 03:32:31
Also in:
lkml
Subsystem:
networking drivers, the rest · Maintainers:
Andrew Lunn, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds
devm_request_irq() is a managed resource: the IRQ is not freed until
devres_release_all() runs after the probe function returns. In the
probe error path, free_netdev(mal->dummy_dev) and dcr_unmap() execute
while the IRQ is still live. If the shared IRQ fires during cleanup,
the handler accesses unmapped DCR registers (crash) or the already-
freed dummy_dev (use-after-free).
Switch to plain request_irq() with per-IRQ error labels that tear down
only the IRQs that were successfully registered, and add the matching
free_irq() calls in mal_remove().
Tested on Cisco Meraki MX60
Fixes: 14f59154ff0b ("net: ibm: emac: mal: use devm for request_irq")
Assisted-by: opencode:big-pickle
Signed-off-by: Rosen Penev <redacted>
---
v2: rebase and add tested comment
drivers/net/ethernet/ibm/emac/mal.c | 43 +++++++++++++++++++----------
1 file changed, 29 insertions(+), 14 deletions(-)
diff --git a/drivers/net/ethernet/ibm/emac/mal.c b/drivers/net/ethernet/ibm/emac/mal.c
index e88e4a1ddcd4..b42ba53671fd 100644
--- a/drivers/net/ethernet/ibm/emac/mal.c
+++ b/drivers/net/ethernet/ibm/emac/mal.c@@ -656,26 +656,26 @@ static int mal_probe(struct platform_device *ofdev) hdlr_rxde = mal_rxde; } - err = devm_request_irq(&ofdev->dev, mal->serr_irq, hdlr_serr, irqflags, - "MAL SERR", mal); + err = request_irq(mal->serr_irq, hdlr_serr, irqflags, + "MAL SERR", mal); if (err) goto fail2; - err = devm_request_irq(&ofdev->dev, mal->txde_irq, hdlr_txde, irqflags, - "MAL TX DE", mal); + err = request_irq(mal->txde_irq, hdlr_txde, irqflags, + "MAL TX DE", mal); if (err) - goto fail2; - err = devm_request_irq(&ofdev->dev, mal->txeob_irq, mal_txeob, 0, - "MAL TX EOB", mal); + goto fail_serr_irq; + err = request_irq(mal->txeob_irq, mal_txeob, 0, + "MAL TX EOB", mal); if (err) - goto fail2; - err = devm_request_irq(&ofdev->dev, mal->rxde_irq, hdlr_rxde, irqflags, - "MAL RX DE", mal); + goto fail_txde_irq; + err = request_irq(mal->rxde_irq, hdlr_rxde, irqflags, + "MAL RX DE", mal); if (err) - goto fail2; - err = devm_request_irq(&ofdev->dev, mal->rxeob_irq, mal_rxeob, 0, - "MAL RX EOB", mal); + goto fail_txeob_irq; + err = request_irq(mal->rxeob_irq, mal_rxeob, 0, + "MAL RX EOB", mal); if (err) - goto fail2; + goto fail_rxde_irq; /* Enable all MAL SERR interrupt sources */ set_mal_dcrn(mal, MAL_IER, MAL_IER_EVENTS);
@@ -694,6 +694,14 @@ static int mal_probe(struct platform_device *ofdev) return 0; + fail_rxde_irq: + free_irq(mal->rxde_irq, mal); + fail_txeob_irq: + free_irq(mal->txeob_irq, mal); + fail_txde_irq: + free_irq(mal->txde_irq, mal); + fail_serr_irq: + free_irq(mal->serr_irq, mal); fail2: dma_free_coherent(&ofdev->dev, bd_size, mal->bd_virt, mal->bd_dma); fail_dummy:
@@ -720,6 +728,13 @@ static void mal_remove(struct platform_device *ofdev) mal_reset(mal); + /* Free IRQs before freeing resources they access */ + free_irq(mal->serr_irq, mal); + free_irq(mal->txde_irq, mal); + free_irq(mal->txeob_irq, mal); + free_irq(mal->rxde_irq, mal); + free_irq(mal->rxeob_irq, mal); + free_netdev(mal->dummy_dev); dcr_unmap(mal->dcr_host, 0x100);
--
2.55.0