* RE: [PATCH net] net: usb: usbnet: fix use-after-free in race on workqueue
[not found] <CGME20250627061156epcas1p1dfe3323378b314d98b660de33f50e0c2@epcas1p1.samsung.com>
@ 2025-06-27 6:11 ` Peter GJ. Park
2025-06-27 7:40 ` Andrew Lunn
0 siblings, 1 reply; 3+ messages in thread
From: Peter GJ. Park @ 2025-06-27 6:11 UTC (permalink / raw)
To: 'Paolo Abeni', 'Oliver Neukum',
'Andrew Lunn', 'David S. Miller',
'Eric Dumazet', 'Jakub Kicinski'
Cc: netdev, linux-usb, linux-kernel
>On 6/25/25 11:33 AM, Peter GJ. Park wrote:
>> When usbnet_disconnect() queued while usbnet_probe() processing, it
>> results to free_netdev before kevent gets to run on workqueue, thus
>> workqueue does assign_work() with referencing freeed memory address.
>>
>> For graceful disconnect and to prevent use-after-free of netdev
>> pointer, the fix adds canceling work and timer those are placed by
>> usbnet_probe()
>>
>> Signed-off-by: Peter GJ. Park <gyujoon.park@samsung.com>
>
>You should include a suitable fixes tag, and you should have specified the target tree ('net' in this case) in the prefix subjext
Prefix net added to subject, but for fixes tag, by looking git blame, the last line of usbnet_disconnect()are based on initial commit,
thus I couldn't put the fixes tag for it. Please let me know how can I handle this.
>
>> ---
>> drivers/net/usb/usbnet.c | 3 +++
>> 1 file changed, 3 insertions(+)
>>
>> diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index
>> c04e715a4c2ade3bc5587b0df71643a25cf88c55..3c5d9ba7fa6660273137c8010674
>> 6103f84f5a37 100644
>> --- a/drivers/net/usb/usbnet.c
>> +++ b/drivers/net/usb/usbnet.c
>> @@ -1660,6 +1660,9 @@ void usbnet_disconnect (struct usb_interface *intf)
>> usb_free_urb(dev->interrupt);
>> kfree(dev->padding_pkt);
>>
>> + timer_delete_sync(&dev->delay);
>> + tasklet_kill(&dev->bh);
>> + cancel_work_sync(&dev->kevent);
>> free_netdev(net);
>
>This happens after unregister_netdev(), which calls usbnet_stop() that already performs the above cleanup. How the race is supposed to take place?
>
This uaf detected while my syzkaller project for usb kernel driver.
First hub_event work:usb_new_device arrived and processing in wq,
While second new hub_event work:usb_disconnect put into wq.
Then third usbnet:kevent work put by first hub_event work.
Dev pointer free-ed by second work without preceding usbnet_stop(), so the usbnetkevent still queued in wq,
Finally it detected by kasan as use-after-free when wq try to access that poiter.
Here is log snippet.
[ 3041.949116] [5: kworker/5:1: 130] BUG: KASAN: slab-use-after-free in assign_work+0xe8/0x280
[ 3041.949128] [5: kworker/5:1: 130] Read of size 8 at addr ffffff88ef60ece8 by task kworker/5:1/130
...
[ 3041.949155] [5: kworker/5:1: 130] Workqueue: 0x0 (usb_hub_wq)
[ 3041.949167] [5: kworker/5:1: 130] Call trace:
[ 3041.949170] [5: kworker/5:1: 130] dump_backtrace+0x120/0x170
[ 3041.949178] [5: kworker/5:1: 130] show_stack+0x2c/0x40
[ 3041.949184] [5: kworker/5:1: 130] dump_stack_lvl+0x68/0x84
[ 3041.949193] [5: kworker/5:1: 130] print_report+0x13c/0x6f8
[ 3041.949203] [5: kworker/5:1: 130] kasan_report+0xdc/0x13c
[ 3041.949211] [5: kworker/5:1: 130] __asan_load8+0x98/0xa0
[ 3041.949216] [5: kworker/5:1: 130] assign_work+0xe8/0x280
[ 3041.949224] [5: kworker/5:1: 130] worker_thread+0x458/0x670
[ 3041.949231] [5: kworker/5:1: 130] kthread+0x1d8/0x298
[ 3041.949238] [5: kworker/5:1: 130] ret_from_fork+0x10/0x20
[ 3041.949248] [5: kworker/5:1: 130] Allocated by task 130:
...
[ 3041.949275] [5: kworker/5:1: 130] __kmalloc_node+0x74/0x194
[ 3041.949282] [5: kworker/5:1: 130] kvmalloc_node+0x160/0x394
[ 3041.949289] [5: kworker/5:1: 130] alloc_netdev_mqs+0x6c/0x718
[ 3041.949298] [5: kworker/5:1: 130] alloc_etherdev_mqs+0x48/0x60
[ 3041.949305] [5: kworker/5:1: 130] usbnet_probe+0xd8/0xf10 [usbnet]
[ 3041.949348] [5: kworker/5:1: 130] usb_probe_interface+0x338/0x4fc
...
[ 3041.949516] [5: kworker/5:1: 130] usb_new_device+0x7c8/0xbdc
[ 3041.949523] [5: kworker/5:1: 130] hub_event+0x1808/0x2564
[ 3041.949530] [5: kworker/5:1: 130] process_scheduled_works+0x3cc/0x92c
[ 3041.949538] [5: kworker/5:1: 130] worker_thread+0x468/0x670
[ 3041.949546] [5: kworker/5:1: 130] kthread+0x1d8/0x298
[ 3041.949552] [5: kworker/5:1: 130] ret_from_fork+0x10/0x20
[ 3041.949561] [5: kworker/5:1: 130] Freed by task 130:
...
[ 3041.949604] [5: kworker/5:1: 130] __kmem_cache_free+0xa0/0x260
[ 3041.949610] [5: kworker/5:1: 130] kfree+0x60/0x124
[ 3041.949617] [5: kworker/5:1: 130] kvfree+0x40/0x54
[ 3041.949622] [5: kworker/5:1: 130] netdev_freemem+0x2c/0x40
[ 3041.949630] [5: kworker/5:1: 130] netdev_release+0x50/0x6c
[ 3041.949638] [5: kworker/5:1: 130] device_release+0x74/0x13c
[ 3041.949645] [5: kworker/5:1: 130] kobject_put+0xfc/0x1a8
[ 3041.949654] [5: kworker/5:1: 130] put_device+0x28/0x40
[ 3041.949660] [5: kworker/5:1: 130] free_netdev+0x234/0x284
[ 3041.949667] [5: kworker/5:1: 130] usbnet_disconnect+0x18c/0x250 [usbnet]
[ 3041.949706] [5: kworker/5:1: 130] usb_unbind_interface+0x130/0x414
[ 3041.949713] [5: kworker/5:1: 130] device_release_driver_internal+0x2e8/0x494
[ 3041.949721] [5: kworker/5:1: 130] device_release_driver+0x28/0x3c
[ 3041.949730] [5: kworker/5:1: 130] bus_remove_device+0x250/0x268
[ 3041.949737] [5: kworker/5:1: 130] device_del+0x304/0x530
[ 3041.949744] [5: kworker/5:1: 130] usb_disable_device+0x1d8/0x340
[ 3041.949750] [5: kworker/5:1: 130] usb_disconnect+0x1c4/0x4f0
[ 3041.949757] [5: kworker/5:1: 130] hub_event+0x1200/0x2564
[ 3041.949764] [5: kworker/5:1: 130] process_scheduled_works+0x3cc/0x92c
[ 3041.949772] [5: kworker/5:1: 130] worker_thread+0x468/0x670
[ 3041.949780] [5: kworker/5:1: 130] kthread+0x1d8/0x298
[ 3041.949786] [5: kworker/5:1: 130] ret_from_fork+0x10/0x20
[ 3041.949796] [5: kworker/5:1: 130] Last potentially related work creation:
...
[ 3041.949820] [5: kworker/5:1: 130] __queue_work+0x5d0/0xaf4
[ 3041.949827] [5: kworker/5:1: 130] queue_work_on+0x64/0xb0
[ 3041.949833] [5: kworker/5:1: 130] usbnet_link_change+0xdc/0x13c [usbnet]
[ 3041.949873] [5: kworker/5:1: 130] usbnet_probe+0xe5c/0xf10 [usbnet]
...
[ 3041.950078] [5: kworker/5:1: 130] usb_new_device+0x7c8/0xbdc
[ 3041.950085] [5: kworker/5:1: 130] hub_event+0x1808/0x2564
[ 3041.950092] [5: kworker/5:1: 130] process_scheduled_works+0x3cc/0x92c
[ 3041.950100] [5: kworker/5:1: 130] worker_thread+0x468/0x670
[ 3041.950107] [5: kworker/5:1: 130] kthread+0x1d8/0x298
[ 3041.950113] [5: kworker/5:1: 130] ret_from_fork+0x10/0x20
[ 3041.950120] [5: kworker/5:1: 130]
>/P
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH net] net: usb: usbnet: fix use-after-free in race on workqueue
2025-06-27 6:11 ` [PATCH net] net: usb: usbnet: fix use-after-free in race on workqueue Peter GJ. Park
@ 2025-06-27 7:40 ` Andrew Lunn
0 siblings, 0 replies; 3+ messages in thread
From: Andrew Lunn @ 2025-06-27 7:40 UTC (permalink / raw)
To: Peter GJ. Park
Cc: 'Paolo Abeni', 'Oliver Neukum',
'Andrew Lunn', 'David S. Miller',
'Eric Dumazet', 'Jakub Kicinski', netdev,
linux-usb, linux-kernel
On Fri, Jun 27, 2025 at 03:11:55PM +0900, Peter GJ. Park wrote:
> >On 6/25/25 11:33 AM, Peter GJ. Park wrote:
> >> When usbnet_disconnect() queued while usbnet_probe() processing, it
> >> results to free_netdev before kevent gets to run on workqueue, thus
> >> workqueue does assign_work() with referencing freeed memory address.
> >>
> >> For graceful disconnect and to prevent use-after-free of netdev
> >> pointer, the fix adds canceling work and timer those are placed by
> >> usbnet_probe()
> >>
> >> Signed-off-by: Peter GJ. Park <gyujoon.park@samsung.com>
> >
> >You should include a suitable fixes tag, and you should have specified the target tree ('net' in this case) in the prefix subjext
> Prefix net added to subject, but for fixes tag, by looking git blame, the last line of usbnet_disconnect()are based on initial commit,
> thus I couldn't put the fixes tag for it. Please let me know how can I handle this.
By initial commit, do you mean:
commit 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (tag: v2.6.12-rc2)
Author: Linus Torvalds <torvalds@ppc970.osdl.org>
Date: Sat Apr 16 15:20:36 2005 -0700
Linux-2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Then use that as the Fixes: tag. The Fixes: tag is a guide to
developers who do the backport. Nobody is going to backport this to
2.6.12, but it does make it clear that LTS 5.4.294 could get this
patch.
Andrew
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH net] net: usb: usbnet: fix use-after-free in race on workqueue
2025-06-26 9:21 ` Paolo Abeni
@ 2025-07-01 4:19 ` Peter GJ. Park
0 siblings, 0 replies; 3+ messages in thread
From: Peter GJ. Park @ 2025-07-01 4:19 UTC (permalink / raw)
To: Paolo Abeni
Cc: Oliver Neukum, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, netdev, linux-usb, linux-kernel
[-- Attachment #1: Type: text/plain, Size: 6262 bytes --]
On Thu, Jun 26, 2025 at 11:21:39AM +0200, Paolo Abeni wrote:
> On 6/25/25 11:33 AM, Peter GJ. Park wrote:
> > When usbnet_disconnect() queued while usbnet_probe() processing,
> > it results to free_netdev before kevent gets to run on workqueue,
> > thus workqueue does assign_work() with referencing freeed memory address.
> >
> > For graceful disconnect and to prevent use-after-free of netdev pointer,
> > the fix adds canceling work and timer those are placed by usbnet_probe()
> >
> > Signed-off-by: Peter GJ. Park <gyujoon.park@samsung.com>
>
> You should include a suitable fixes tag, and you should have specified
> the target tree ('net' in this case) in the prefix subjext
>
It has been applied with v2 patch. Thank you for this.
> > ---
> > drivers/net/usb/usbnet.c | 3 +++
> > 1 file changed, 3 insertions(+)
> >
> > diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
> > index c04e715a4c2ade3bc5587b0df71643a25cf88c55..3c5d9ba7fa6660273137c80106746103f84f5a37 100644
> > --- a/drivers/net/usb/usbnet.c
> > +++ b/drivers/net/usb/usbnet.c
> > @@ -1660,6 +1660,9 @@ void usbnet_disconnect (struct usb_interface *intf)
> > usb_free_urb(dev->interrupt);
> > kfree(dev->padding_pkt);
> >
> > + timer_delete_sync(&dev->delay);
> > + tasklet_kill(&dev->bh);
> > + cancel_work_sync(&dev->kevent);
> > free_netdev(net);
>
> This happens after unregister_netdev(), which calls usbnet_stop() that
> already performs the above cleanup. How the race is supposed to take place?
>
> /P
>
This uaf detected while my syzkaller project for usb kernel driver.
First hub_event work:usb_new_device arrived and processing in wq,
While second new hub_event work:usb_disconnect put into wq.
Then third usbnet:kevent work put by first hub_event work.
Dev pointer free-ed by second work without preceding usbnet_stop(), so the usbnetkevent still queued in wq,
Finally it detected by kasan as use-after-free when wq try to access that poiter.
Here is log snippet.
[ 3041.949116] [5: kworker/5:1: 130] BUG: KASAN: slab-use-after-free in assign_work+0xe8/0x280
[ 3041.949128] [5: kworker/5:1: 130] Read of size 8 at addr ffffff88ef60ece8 by task kworker/5:1/130
...
[ 3041.949155] [5: kworker/5:1: 130] Workqueue: 0x0 (usb_hub_wq)
[ 3041.949167] [5: kworker/5:1: 130] Call trace:
[ 3041.949170] [5: kworker/5:1: 130] dump_backtrace+0x120/0x170
[ 3041.949178] [5: kworker/5:1: 130] show_stack+0x2c/0x40
[ 3041.949184] [5: kworker/5:1: 130] dump_stack_lvl+0x68/0x84
[ 3041.949193] [5: kworker/5:1: 130] print_report+0x13c/0x6f8
[ 3041.949203] [5: kworker/5:1: 130] kasan_report+0xdc/0x13c
[ 3041.949211] [5: kworker/5:1: 130] __asan_load8+0x98/0xa0
[ 3041.949216] [5: kworker/5:1: 130] assign_work+0xe8/0x280
[ 3041.949224] [5: kworker/5:1: 130] worker_thread+0x458/0x670
[ 3041.949231] [5: kworker/5:1: 130] kthread+0x1d8/0x298
[ 3041.949238] [5: kworker/5:1: 130] ret_from_fork+0x10/0x20
[ 3041.949248] [5: kworker/5:1: 130] Allocated by task 130:
...
[ 3041.949275] [5: kworker/5:1: 130] __kmalloc_node+0x74/0x194
[ 3041.949282] [5: kworker/5:1: 130] kvmalloc_node+0x160/0x394
[ 3041.949289] [5: kworker/5:1: 130] alloc_netdev_mqs+0x6c/0x718
[ 3041.949298] [5: kworker/5:1: 130] alloc_etherdev_mqs+0x48/0x60
[ 3041.949305] [5: kworker/5:1: 130] usbnet_probe+0xd8/0xf10 [usbnet]
[ 3041.949348] [5: kworker/5:1: 130] usb_probe_interface+0x338/0x4fc
...
[ 3041.949516] [5: kworker/5:1: 130] usb_new_device+0x7c8/0xbdc
[ 3041.949523] [5: kworker/5:1: 130] hub_event+0x1808/0x2564
[ 3041.949530] [5: kworker/5:1: 130] process_scheduled_works+0x3cc/0x92c
[ 3041.949538] [5: kworker/5:1: 130] worker_thread+0x468/0x670
[ 3041.949546] [5: kworker/5:1: 130] kthread+0x1d8/0x298
[ 3041.949552] [5: kworker/5:1: 130] ret_from_fork+0x10/0x20
[ 3041.949561] [5: kworker/5:1: 130] Freed by task 130:
...
[ 3041.949604] [5: kworker/5:1: 130] __kmem_cache_free+0xa0/0x260
[ 3041.949610] [5: kworker/5:1: 130] kfree+0x60/0x124
[ 3041.949617] [5: kworker/5:1: 130] kvfree+0x40/0x54
[ 3041.949622] [5: kworker/5:1: 130] netdev_freemem+0x2c/0x40
[ 3041.949630] [5: kworker/5:1: 130] netdev_release+0x50/0x6c
[ 3041.949638] [5: kworker/5:1: 130] device_release+0x74/0x13c
[ 3041.949645] [5: kworker/5:1: 130] kobject_put+0xfc/0x1a8
[ 3041.949654] [5: kworker/5:1: 130] put_device+0x28/0x40
[ 3041.949660] [5: kworker/5:1: 130] free_netdev+0x234/0x284
[ 3041.949667] [5: kworker/5:1: 130] usbnet_disconnect+0x18c/0x250 [usbnet]
[ 3041.949706] [5: kworker/5:1: 130] usb_unbind_interface+0x130/0x414
[ 3041.949713] [5: kworker/5:1: 130] device_release_driver_internal+0x2e8/0x494
[ 3041.949721] [5: kworker/5:1: 130] device_release_driver+0x28/0x3c
[ 3041.949730] [5: kworker/5:1: 130] bus_remove_device+0x250/0x268
[ 3041.949737] [5: kworker/5:1: 130] device_del+0x304/0x530
[ 3041.949744] [5: kworker/5:1: 130] usb_disable_device+0x1d8/0x340
[ 3041.949750] [5: kworker/5:1: 130] usb_disconnect+0x1c4/0x4f0
[ 3041.949757] [5: kworker/5:1: 130] hub_event+0x1200/0x2564
[ 3041.949764] [5: kworker/5:1: 130] process_scheduled_works+0x3cc/0x92c
[ 3041.949772] [5: kworker/5:1: 130] worker_thread+0x468/0x670
[ 3041.949780] [5: kworker/5:1: 130] kthread+0x1d8/0x298
[ 3041.949786] [5: kworker/5:1: 130] ret_from_fork+0x10/0x20
[ 3041.949796] [5: kworker/5:1: 130] Last potentially related work creation:
...
[ 3041.949820] [5: kworker/5:1: 130] __queue_work+0x5d0/0xaf4
[ 3041.949827] [5: kworker/5:1: 130] queue_work_on+0x64/0xb0
[ 3041.949833] [5: kworker/5:1: 130] usbnet_link_change+0xdc/0x13c [usbnet]
[ 3041.949873] [5: kworker/5:1: 130] usbnet_probe+0xe5c/0xf10 [usbnet]
...
[ 3041.950078] [5: kworker/5:1: 130] usb_new_device+0x7c8/0xbdc
[ 3041.950085] [5: kworker/5:1: 130] hub_event+0x1808/0x2564
[ 3041.950092] [5: kworker/5:1: 130] process_scheduled_works+0x3cc/0x92c
[ 3041.950100] [5: kworker/5:1: 130] worker_thread+0x468/0x670
[ 3041.950107] [5: kworker/5:1: 130] kthread+0x1d8/0x298
[ 3041.950113] [5: kworker/5:1: 130] ret_from_fork+0x10/0x20
Best Regards,
GJ
[-- Attachment #2: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2025-07-01 4:19 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <CGME20250627061156epcas1p1dfe3323378b314d98b660de33f50e0c2@epcas1p1.samsung.com>
2025-06-27 6:11 ` [PATCH net] net: usb: usbnet: fix use-after-free in race on workqueue Peter GJ. Park
2025-06-27 7:40 ` Andrew Lunn
[not found] <CGME20250625093354epcas1p1c9817df6e1d1599e8b4eb16c5715a6fd@epcas1p1.samsung.com>
2025-06-25 9:33 ` [PATCH] " Peter GJ. Park
2025-06-26 9:21 ` Paolo Abeni
2025-07-01 4:19 ` [PATCH net] " Peter GJ. Park
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.