]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
net: ibm: emac: Fix use-after-free during device removal
authorRosen Penev <rosenp@gmail.com>
Wed, 3 Jun 2026 22:12:17 +0000 (15:12 -0700)
committerJakub Kicinski <kuba@kernel.org>
Tue, 9 Jun 2026 00:24:58 +0000 (17:24 -0700)
The driver was using devm_register_netdev() which causes unregister_netdev()
to be deferred until the devres cleanup phase, which runs after emac_remove()
returns. This creates a use-after-free window where:

1. emac_remove() is called, which tears down hardware (cancels work, detaches
   modules, unregisters from MAL)
2. emac_remove() returns
3. devres cleanup runs and finally calls unregister_netdev()

During step 3, the network stack might still process packets, triggering
emac_irq(), emac_poll(), or other handlers that access now-freed hardware
resources (dev->emacp, dev->mal, etc.).

Fix this by replacing devm_register_netdev() with manual register_netdev()
and calling unregister_netdev() at the beginning of emac_remove(), before
any hardware teardown. This ensures the network device is fully stopped and
unregistered before hardware resources are released.

The change is safe because:
- dev->ndev is assigned very early in probe (before any error paths that
  could bypass emac_remove)
- platform_set_drvdata() is only called after successful registration, so
  emac_remove() only runs for fully registered devices
- unregister_netdev() is idempotent and safe to call on any registered device

Fixes: a4dd8535a527 ("net: ibm: emac: use devm for register_netdev")
Signed-off-by: Rosen Penev <rosenp@gmail.com>
Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/ibm/emac/core.c

index 417dfa18daae3a40fc1838b9d70720bf9140092f..4e503b3d0d2d345ae49bdd7faebbbc658ccf98cc 100644 (file)
@@ -3144,7 +3144,7 @@ static int emac_probe(struct platform_device *ofdev)
 
        netif_carrier_off(ndev);
 
-       err = devm_register_netdev(&ofdev->dev, ndev);
+       err = register_netdev(ndev);
        if (err) {
                printk(KERN_ERR "%pOF: failed to register net device (%d)!\n",
                       np, err);
@@ -3197,6 +3197,13 @@ static void emac_remove(struct platform_device *ofdev)
 
        DBG(dev, "remove" NL);
 
+       /* Unregister network device before tearing down hardware
+        * to prevent use-after-free during deferred cleanup. This ensures
+        * the network stack stops all operations before hardware resources
+        * are released.
+        */
+       unregister_netdev(dev->ndev);
+
        cancel_work_sync(&dev->reset_work);
 
        if (emac_has_feature(dev, EMAC_FTR_HAS_TAH))