Patch "net: usb: lan78xx: reorder cleanup operations to avoid UAF bugs" has been added to the 6.4-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    net: usb: lan78xx: reorder cleanup operations to avoid UAF bugs

to the 6.4-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     net-usb-lan78xx-reorder-cleanup-operations-to-avoid-.patch
and it can be found in the queue-6.4 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit 8e93dc2d5190b8a686c47711df216004dafab779
Author: Duoming Zhou <duoming@xxxxxxxxxx>
Date:   Wed Jul 26 16:14:07 2023 +0800

    net: usb: lan78xx: reorder cleanup operations to avoid UAF bugs
    
    [ Upstream commit 1e7417c188d0a83fb385ba2dbe35fd2563f2b6f3 ]
    
    The timer dev->stat_monitor can schedule the delayed work dev->wq and
    the delayed work dev->wq can also arm the dev->stat_monitor timer.
    
    When the device is detaching, the net_device will be deallocated. but
    the net_device private data could still be dereferenced in delayed work
    or timer handler. As a result, the UAF bugs will happen.
    
    One racy situation is shown below:
    
          (Thread 1)                 |      (Thread 2)
    lan78xx_stat_monitor()           |
     ...                             |  lan78xx_disconnect()
     lan78xx_defer_kevent()          |    ...
      ...                            |    cancel_delayed_work_sync(&dev->wq);
      schedule_delayed_work()        |    ...
      (wait some time)               |    free_netdev(net); //free net_device
      lan78xx_delayedwork()          |
      //use net_device private data  |
      dev-> //use                    |
    
    Although we use cancel_delayed_work_sync() to cancel the delayed work
    in lan78xx_disconnect(), it could still be scheduled in timer handler
    lan78xx_stat_monitor().
    
    Another racy situation is shown below:
    
          (Thread 1)                |      (Thread 2)
    lan78xx_delayedwork             |
     mod_timer()                    |  lan78xx_disconnect()
                                    |   cancel_delayed_work_sync()
     (wait some time)               |   if (timer_pending(&dev->stat_monitor))
                                    |       del_timer_sync(&dev->stat_monitor);
     lan78xx_stat_monitor()         |   ...
      lan78xx_defer_kevent()        |   free_netdev(net); //free
       //use net_device private data|
       dev-> //use                  |
    
    Although we use del_timer_sync() to delete the timer, the function
    timer_pending() returns 0 when the timer is activated. As a result,
    the del_timer_sync() will not be executed and the timer could be
    re-armed.
    
    In order to mitigate this bug, We use timer_shutdown_sync() to shutdown
    the timer and then use cancel_delayed_work_sync() to cancel the delayed
    work. As a result, the net_device could be deallocated safely.
    
    What's more, the dev->flags is set to EVENT_DEV_DISCONNECT in
    lan78xx_disconnect(). But it could still be set to EVENT_STAT_UPDATE
    in lan78xx_stat_monitor(). So this patch put the set_bit() behind
    timer_shutdown_sync().
    
    Fixes: 77dfff5bb7e2 ("lan78xx: Fix race condition in disconnect handling")
    Signed-off-by: Duoming Zhou <duoming@xxxxxxxxxx>
    Signed-off-by: David S. Miller <davem@xxxxxxxxxxxxx>
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c
index c458c030fadf6..59cde06aa7f60 100644
--- a/drivers/net/usb/lan78xx.c
+++ b/drivers/net/usb/lan78xx.c
@@ -4224,8 +4224,6 @@ static void lan78xx_disconnect(struct usb_interface *intf)
 	if (!dev)
 		return;
 
-	set_bit(EVENT_DEV_DISCONNECT, &dev->flags);
-
 	netif_napi_del(&dev->napi);
 
 	udev = interface_to_usbdev(intf);
@@ -4233,6 +4231,8 @@ static void lan78xx_disconnect(struct usb_interface *intf)
 
 	unregister_netdev(net);
 
+	timer_shutdown_sync(&dev->stat_monitor);
+	set_bit(EVENT_DEV_DISCONNECT, &dev->flags);
 	cancel_delayed_work_sync(&dev->wq);
 
 	phydev = net->phydev;
@@ -4247,9 +4247,6 @@ static void lan78xx_disconnect(struct usb_interface *intf)
 
 	usb_scuttle_anchored_urbs(&dev->deferred);
 
-	if (timer_pending(&dev->stat_monitor))
-		del_timer_sync(&dev->stat_monitor);
-
 	lan78xx_unbind(dev, intf);
 
 	lan78xx_free_tx_resources(dev);



[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux