| From 16b1941eac2bd499f065a6739a40ce0011a3d740 Mon Sep 17 00:00:00 2001 |
| From: Alan Stern <stern@rowland.harvard.edu> |
| Date: Sat, 5 Mar 2022 21:47:22 -0500 |
| Subject: usb: gadget: Fix use-after-free bug by not setting udc->dev.driver |
| |
| From: Alan Stern <stern@rowland.harvard.edu> |
| |
| commit 16b1941eac2bd499f065a6739a40ce0011a3d740 upstream. |
| |
| The syzbot fuzzer found a use-after-free bug: |
| |
| BUG: KASAN: use-after-free in dev_uevent+0x712/0x780 drivers/base/core.c:2320 |
| Read of size 8 at addr ffff88802b934098 by task udevd/3689 |
| |
| CPU: 2 PID: 3689 Comm: udevd Not tainted 5.17.0-rc4-syzkaller-00229-g4f12b742eb2b #0 |
| Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.14.0-2 04/01/2014 |
| Call Trace: |
| <TASK> |
| __dump_stack lib/dump_stack.c:88 [inline] |
| dump_stack_lvl+0xcd/0x134 lib/dump_stack.c:106 |
| print_address_description.constprop.0.cold+0x8d/0x303 mm/kasan/report.c:255 |
| __kasan_report mm/kasan/report.c:442 [inline] |
| kasan_report.cold+0x83/0xdf mm/kasan/report.c:459 |
| dev_uevent+0x712/0x780 drivers/base/core.c:2320 |
| uevent_show+0x1b8/0x380 drivers/base/core.c:2391 |
| dev_attr_show+0x4b/0x90 drivers/base/core.c:2094 |
| |
| Although the bug manifested in the driver core, the real cause was a |
| race with the gadget core. dev_uevent() does: |
| |
| if (dev->driver) |
| add_uevent_var(env, "DRIVER=%s", dev->driver->name); |
| |
| and between the test and the dereference of dev->driver, the gadget |
| core sets dev->driver to NULL. |
| |
| The race wouldn't occur if the gadget core registered its devices on |
| a real bus, using the standard synchronization techniques of the |
| driver core. However, it's not necessary to make such a large change |
| in order to fix this bug; all we need to do is make sure that |
| udc->dev.driver is always NULL. |
| |
| In fact, there is no reason for udc->dev.driver ever to be set to |
| anything, let alone to the value it currently gets: the address of the |
| gadget's driver. After all, a gadget driver only knows how to manage |
| a gadget, not how to manage a UDC. |
| |
| This patch simply removes the statements in the gadget core that touch |
| udc->dev.driver. |
| |
| Fixes: 2ccea03a8f7e ("usb: gadget: introduce UDC Class") |
| CC: <stable@vger.kernel.org> |
| Reported-and-tested-by: syzbot+348b571beb5eeb70a582@syzkaller.appspotmail.com |
| Signed-off-by: Alan Stern <stern@rowland.harvard.edu> |
| Link: https://lore.kernel.org/r/YiQgukfFFbBnwJ/9@rowland.harvard.edu |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/usb/gadget/udc/core.c | 3 --- |
| 1 file changed, 3 deletions(-) |
| |
| --- a/drivers/usb/gadget/udc/core.c |
| +++ b/drivers/usb/gadget/udc/core.c |
| @@ -1297,7 +1297,6 @@ static void usb_gadget_remove_driver(str |
| usb_gadget_udc_stop(udc); |
| |
| udc->driver = NULL; |
| - udc->dev.driver = NULL; |
| udc->gadget->dev.driver = NULL; |
| } |
| |
| @@ -1346,7 +1345,6 @@ static int udc_bind_to_driver(struct usb |
| driver->function); |
| |
| udc->driver = driver; |
| - udc->dev.driver = &driver->driver; |
| udc->gadget->dev.driver = &driver->driver; |
| |
| usb_gadget_udc_set_speed(udc, driver->max_speed); |
| @@ -1368,7 +1366,6 @@ err1: |
| dev_err(&udc->dev, "failed to start %s: %d\n", |
| udc->driver->function, ret); |
| udc->driver = NULL; |
| - udc->dev.driver = NULL; |
| udc->gadget->dev.driver = NULL; |
| return ret; |
| } |