Skip to content

Commit 1e7417c

Browse files
stonezdmdavem330
authored andcommitted
net: usb: lan78xx: reorder cleanup operations to avoid UAF bugs
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: 77dfff5 ("lan78xx: Fix race condition in disconnect handling") Signed-off-by: Duoming Zhou <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 8469c7f commit 1e7417c

File tree

1 file changed

+2
-5
lines changed

1 file changed

+2
-5
lines changed

drivers/net/usb/lan78xx.c

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4224,15 +4224,15 @@ static void lan78xx_disconnect(struct usb_interface *intf)
42244224
if (!dev)
42254225
return;
42264226

4227-
set_bit(EVENT_DEV_DISCONNECT, &dev->flags);
4228-
42294227
netif_napi_del(&dev->napi);
42304228

42314229
udev = interface_to_usbdev(intf);
42324230
net = dev->net;
42334231

42344232
unregister_netdev(net);
42354233

4234+
timer_shutdown_sync(&dev->stat_monitor);
4235+
set_bit(EVENT_DEV_DISCONNECT, &dev->flags);
42364236
cancel_delayed_work_sync(&dev->wq);
42374237

42384238
phydev = net->phydev;
@@ -4247,9 +4247,6 @@ static void lan78xx_disconnect(struct usb_interface *intf)
42474247

42484248
usb_scuttle_anchored_urbs(&dev->deferred);
42494249

4250-
if (timer_pending(&dev->stat_monitor))
4251-
del_timer_sync(&dev->stat_monitor);
4252-
42534250
lan78xx_unbind(dev, intf);
42544251

42554252
lan78xx_free_tx_resources(dev);

0 commit comments

Comments
 (0)