Re: [PATCH] USB: gadget: Fix use-after-free Read in usb_udc_uevent()

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

 



Hi Alan,

On 21.07.2022 17:07, Alan Stern wrote:
> The syzbot fuzzer found a race between uevent callbacks and gadget
> driver unregistration that can cause a use-after-free bug:
>
> ---------------------------------------------------------------
> BUG: KASAN: use-after-free in usb_udc_uevent+0x11f/0x130
> drivers/usb/gadget/udc/core.c:1732
> Read of size 8 at addr ffff888078ce2050 by task udevd/2968
>
> CPU: 1 PID: 2968 Comm: udevd Not tainted 5.19.0-rc4-next-20220628-syzkaller #0
> Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google
> 06/29/2022
> Call Trace:
>   <TASK>
>   __dump_stack lib/dump_stack.c:88 [inline]
>   dump_stack_lvl+0xcd/0x134 lib/dump_stack.c:106
>   print_address_description mm/kasan/report.c:317 [inline]
>   print_report.cold+0x2ba/0x719 mm/kasan/report.c:433
>   kasan_report+0xbe/0x1f0 mm/kasan/report.c:495
>   usb_udc_uevent+0x11f/0x130 drivers/usb/gadget/udc/core.c:1732
>   dev_uevent+0x290/0x770 drivers/base/core.c:2424
> ---------------------------------------------------------------
>
> The bug occurs because usb_udc_uevent() dereferences udc->driver but
> does so without acquiring the udc_lock mutex, which protects this
> field.  If the gadget driver is unbound from the udc concurrently with
> uevent processing, the driver structure may be accessed after it has
> been deallocated.
>
> To prevent the race, we make sure that the routine holds the mutex
> around the racing accesses.
>
> Signed-off-by: Alan Stern <stern@xxxxxxxxxxxxxxxxxxx>
> Reported-and-tested-by: syzbot+b0de012ceb1e2a97891b@xxxxxxxxxxxxxxxxxxxxxxxxx
> CC: stable@xxxxxxxxxxxxxxx
> Link: <https://lore.kernel.org/all/0000000000004de90405a719c951@xxxxxxxxxx>

This patch landed recently in linux-next as commit 2191c00855b0 ("USB: 
gadget: Fix use-after-free Read in usb_udc_uevent()"). Unfortunately it 
fixes the issue by introducing another one. It doesn't look very 
probable, but it would be nice to fix it to make the lock dependency 
checker happy.

======================================================
WARNING: possible circular locking dependency detected
5.19.0-rc7+ #12510 Not tainted
------------------------------------------------------
udevadm/312 is trying to acquire lock:
ffff80000aae1058 (udc_lock){+.+.}-{3:3}, at: usb_udc_uevent+0x54/0xe0

but task is already holding lock:
ffff000002277548 (kn->active#4){++++}-{0:0}, at: kernfs_seq_start+0x34/0xe0

which lock already depends on the new lock.


the existing dependency chain (in reverse order) is:

-> #3 (kn->active#4){++++}-{0:0}:
        lock_acquire+0x68/0x84
        __kernfs_remove+0x268/0x380
        kernfs_remove_by_name_ns+0x58/0xac
        sysfs_remove_file_ns+0x18/0x24
        device_del+0x15c/0x440
        device_link_drop_managed+0xa8/0xe0
        device_links_driver_bound+0x1b8/0x230
        driver_bound+0x68/0xc0
        really_probe.part.0+0x1f8/0x2ac
        __driver_probe_device+0x98/0x144
        driver_probe_device+0xac/0x14c
        __driver_attach+0x104/0x1b0
        bus_for_each_dev+0x70/0xd0
        driver_attach+0x24/0x30
        bus_add_driver+0x154/0x204
        driver_register+0x78/0x130
        __platform_driver_register+0x28/0x34
        simple_pm_bus_driver_init+0x1c/0x28
        do_one_initcall+0x74/0x400
        kernel_init_freeable+0x2f4/0x37c
        kernel_init+0x28/0x130
        ret_from_fork+0x10/0x20

-> #2 (device_links_lock){+.+.}-{3:3}:
        lock_acquire+0x68/0x84
        __mutex_lock+0x9c/0x430
        mutex_lock_nested+0x38/0x64
        device_link_remove+0x3c/0xa0
        _regulator_put.part.0+0x168/0x190
        regulator_put+0x3c/0x54
        devm_regulator_release+0x14/0x20
        release_nodes+0x5c/0x90
        devres_release_all+0x8c/0xe0
        device_unbind_cleanup+0x18/0x70
        really_probe.part.0+0x174/0x2ac
        __driver_probe_device+0x98/0x144
        driver_probe_device+0xac/0x14c
        __device_attach_driver+0xb8/0x120
        bus_for_each_drv+0x78/0xd0
        __device_attach_async_helper+0xb0/0xd4
        async_run_entry_fn+0x34/0xd0
        process_one_work+0x288/0x6bc
        worker_thread+0x74/0x450
        kthread+0x118/0x11c
        ret_from_fork+0x10/0x20

-> #1 (regulator_list_mutex){+.+.}-{3:3}:
        lock_acquire+0x68/0x84
        __mutex_lock+0x9c/0x430
        mutex_lock_nested+0x38/0x64
        regulator_lock_dependent+0x54/0x284
        regulator_enable+0x34/0x80
        phy_power_on+0x24/0x130
        __dwc2_lowlevel_hw_enable+0x100/0x130
        dwc2_lowlevel_hw_enable+0x18/0x40
        dwc2_hsotg_udc_start+0x6c/0x2f0
        gadget_bind_driver+0x124/0x1f4
        really_probe.part.0+0x9c/0x2ac
        __driver_probe_device+0x98/0x144
        driver_probe_device+0xac/0x14c
        __device_attach_driver+0xb8/0x120
        bus_for_each_drv+0x78/0xd0
        __device_attach+0xa8/0x1c0
        device_initial_probe+0x14/0x20
        bus_probe_device+0x9c/0xa4
        device_add+0x3a0/0x890
        usb_add_gadget+0x170/0x200
        usb_add_gadget_udc+0x94/0xd4
        dwc2_driver_probe+0x580/0x78c
        platform_probe+0x68/0xe0
        really_probe.part.0+0x9c/0x2ac
        __driver_probe_device+0x98/0x144
        driver_probe_device+0xac/0x14c
        __device_attach_driver+0xb8/0x120
        bus_for_each_drv+0x78/0xd0
        __device_attach+0xa8/0x1c0
        device_initial_probe+0x14/0x20
        bus_probe_device+0x9c/0xa4
        device_add+0x3a0/0x890
        of_device_add+0x48/0x6c
        of_platform_device_create_pdata+0x98/0x100
        of_platform_bus_create+0x17c/0x37c
        of_platform_populate+0x58/0xec
        dwc3_meson_g12a_probe+0x314/0x5d0
        platform_probe+0x68/0xe0
        really_probe.part.0+0x9c/0x2ac
        __driver_probe_device+0x98/0x144
        driver_probe_device+0xac/0x14c
        __device_attach_driver+0xb8/0x120
        bus_for_each_drv+0x78/0xd0
        __device_attach+0xa8/0x1c0
        device_initial_probe+0x14/0x20
        bus_probe_device+0x9c/0xa4
        deferred_probe_work_func+0x88/0xc4
        process_one_work+0x288/0x6bc
        worker_thread+0x74/0x450
        kthread+0x118/0x11c
        ret_from_fork+0x10/0x20

-> #0 (udc_lock){+.+.}-{3:3}:
        __lock_acquire+0x1298/0x20cc
        lock_acquire.part.0+0xe0/0x230
        lock_acquire+0x68/0x84
        __mutex_lock+0x9c/0x430
        mutex_lock_nested+0x38/0x64
        usb_udc_uevent+0x54/0xe0
        dev_uevent+0xb8/0x1ec
        uevent_show+0x8c/0x114
        dev_attr_show+0x20/0x60
        sysfs_kf_seq_show+0xa8/0x120
        kernfs_seq_show+0x2c/0x40
        seq_read_iter+0x1bc/0x4b0
        kernfs_fop_read_iter+0x140/0x1d0
        new_sync_read+0xd4/0x150
        vfs_read+0x190/0x1dc
        ksys_read+0x68/0xfc
        __arm64_sys_read+0x20/0x30
        invoke_syscall+0x48/0x114
        el0_svc_common.constprop.0+0x60/0x11c
        do_el0_svc_compat+0x1c/0x50
        el0_svc_compat+0x58/0x100
        el0t_32_sync_handler+0x90/0x140
        el0t_32_sync+0x190/0x194

other info that might help us debug this:

Chain exists of:
   udc_lock --> device_links_lock --> kn->active#4

  Possible unsafe locking scenario:

        CPU0                    CPU1
        ----                    ----
   lock(kn->active#4);
                                lock(device_links_lock);
                                lock(kn->active#4);
   lock(udc_lock);

  *** DEADLOCK ***

3 locks held by udevadm/312:
  #0: ffff000001ab80a0 (&p->lock){+.+.}-{3:3}, at: seq_read_iter+0x60/0x4b0
  #1: ffff00003cdf7e88 (&of->mutex){+.+.}-{3:3}, at: 
kernfs_seq_start+0x2c/0xe0
  #2: ffff000002277548 (kn->active#4){++++}-{0:0}, at: 
kernfs_seq_start+0x34/0xe0

stack backtrace:
CPU: 2 PID: 312 Comm: udevadm Not tainted 5.19.0-rc7+ #12510
Hardware name: Khadas VIM3 (DT)
Call trace:
  dump_backtrace.part.0+0xd0/0xe0
  show_stack+0x18/0x6c
  dump_stack_lvl+0x8c/0xb8
  dump_stack+0x18/0x34
  print_circular_bug+0x1f8/0x200
  check_noncircular+0x130/0x144
  __lock_acquire+0x1298/0x20cc
  lock_acquire.part.0+0xe0/0x230
  lock_acquire+0x68/0x84
  __mutex_lock+0x9c/0x430
  mutex_lock_nested+0x38/0x64
  usb_udc_uevent+0x54/0xe0
  dev_uevent+0xb8/0x1ec
  uevent_show+0x8c/0x114
  dev_attr_show+0x20/0x60
  sysfs_kf_seq_show+0xa8/0x120
  kernfs_seq_show+0x2c/0x40
  seq_read_iter+0x1bc/0x4b0
  kernfs_fop_read_iter+0x140/0x1d0
  new_sync_read+0xd4/0x150
  vfs_read+0x190/0x1dc
  ksys_read+0x68/0xfc
  __arm64_sys_read+0x20/0x30
  invoke_syscall+0x48/0x114
  el0_svc_common.constprop.0+0x60/0x11c
  do_el0_svc_compat+0x1c/0x50
  el0_svc_compat+0x58/0x100
  el0t_32_sync_handler+0x90/0x140
  el0t_32_sync+0x190/0x194



> ---
>
> As far as I can tell, this bug has always been present.  However, the
> udc_lock mutex used by the patch was added in commit fc274c1e9973
> ("USB: gadget: Add a new bus for gadgets"), so this patch won't apply
> to trees which don't include that commit or a backport of it.  I don't
> know what tag, if any, can express this requirement.
>
>
> [as1983]
>
>
>   drivers/usb/gadget/udc/core.c |   11 ++++++-----
>   1 file changed, 6 insertions(+), 5 deletions(-)
>
> Index: usb-devel/drivers/usb/gadget/udc/core.c
> ===================================================================
> --- usb-devel.orig/drivers/usb/gadget/udc/core.c
> +++ usb-devel/drivers/usb/gadget/udc/core.c
> @@ -1728,13 +1728,14 @@ static int usb_udc_uevent(struct device
>   		return ret;
>   	}
>   
> -	if (udc->driver) {
> +	mutex_lock(&udc_lock);
> +	if (udc->driver)
>   		ret = add_uevent_var(env, "USB_UDC_DRIVER=%s",
>   				udc->driver->function);
> -		if (ret) {
> -			dev_err(dev, "failed to add uevent USB_UDC_DRIVER\n");
> -			return ret;
> -		}
> +	mutex_unlock(&udc_lock);
> +	if (ret) {
> +		dev_err(dev, "failed to add uevent USB_UDC_DRIVER\n");
> +		return ret;
>   	}
>   
>   	return 0;
>
Best regards
-- 
Marek Szyprowski, PhD
Samsung R&D Institute Poland




[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux