]> git.itanic.dy.fi Git - linux-stable/commitdiff
usbnet: Run unregister_netdev() before unbind() again
authorLukas Wunner <lukas@wunner.de>
Thu, 12 May 2022 08:42:01 +0000 (10:42 +0200)
committerDavid S. Miller <davem@davemloft.net>
Fri, 13 May 2022 10:35:46 +0000 (11:35 +0100)
Commit 2c9d6c2b871d ("usbnet: run unbind() before unregister_netdev()")
sought to fix a use-after-free on disconnect of USB Ethernet adapters.

It turns out that a different fix is necessary to address the issue:
https://lore.kernel.org/netdev/18b3541e5372bc9b9fc733d422f4e698c089077c.1650177997.git.lukas@wunner.de/

So the commit was not necessary.

The commit made binding and unbinding of USB Ethernet asymmetrical:
Before, usbnet_probe() first invoked the ->bind() callback and then
register_netdev().  usbnet_disconnect() mirrored that by first invoking
unregister_netdev() and then ->unbind().

Since the commit, the order in usbnet_disconnect() is reversed and no
longer mirrors usbnet_probe().

One consequence is that a PHY disconnected (and stopped) in ->unbind()
is afterwards stopped once more by unregister_netdev() as it closes the
netdev before unregistering.  That necessitates a contortion in ->stop()
because the PHY may only be stopped if it hasn't already been
disconnected.

Reverting the commit allows making the call to phy_stop() unconditional
in ->stop().

Tested-by: Oleksij Rempel <o.rempel@pengutronix.de> # LAN9514/9512/9500
Tested-by: Ferry Toth <fntoth@gmail.com> # LAN9514
Signed-off-by: Lukas Wunner <lukas@wunner.de>
Acked-by: Oliver Neukum <oneukum@suse.com>
Cc: Martyn Welch <martyn.welch@collabora.com>
Cc: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/usb/asix_devices.c
drivers/net/usb/smsc95xx.c
drivers/net/usb/usbnet.c

index 38e47a93fb833749093fb96b700a8e941632af99..5b5eb630c4b7918371a48b098a15dcdb6c070a68 100644 (file)
@@ -795,11 +795,7 @@ static int ax88772_stop(struct usbnet *dev)
 {
        struct asix_common_private *priv = dev->driver_priv;
 
-       /* On unplugged USB, we will get MDIO communication errors and the
-        * PHY will be set in to PHY_HALTED state.
-        */
-       if (priv->phydev->state != PHY_HALTED)
-               phy_stop(priv->phydev);
+       phy_stop(priv->phydev);
 
        return 0;
 }
index 4ef61f6b85df543e60c05aebad9bccb9b16e16fc..edf0492ad489afc8eda9c6edebffe3233391ba20 100644 (file)
@@ -1243,8 +1243,7 @@ static int smsc95xx_start_phy(struct usbnet *dev)
 
 static int smsc95xx_stop(struct usbnet *dev)
 {
-       if (dev->net->phydev)
-               phy_stop(dev->net->phydev);
+       phy_stop(dev->net->phydev);
 
        return 0;
 }
index 9a6450f796dcb34abf15ea096d9ff68ef4c11b1a..36b24ec1165043def00bfd151eb1b60929995deb 100644 (file)
@@ -1616,9 +1616,6 @@ void usbnet_disconnect (struct usb_interface *intf)
                   xdev->bus->bus_name, xdev->devpath,
                   dev->driver_info->description);
 
-       if (dev->driver_info->unbind)
-               dev->driver_info->unbind(dev, intf);
-
        net = dev->net;
        unregister_netdev (net);
 
@@ -1626,6 +1623,9 @@ void usbnet_disconnect (struct usb_interface *intf)
 
        usb_scuttle_anchored_urbs(&dev->deferred);
 
+       if (dev->driver_info->unbind)
+               dev->driver_info->unbind(dev, intf);
+
        usb_kill_urb(dev->interrupt);
        usb_free_urb(dev->interrupt);
        kfree(dev->padding_pkt);