WSL2-Linux-Kernel/drivers/usb/core
Alan Stern 9340226388 USB: core: Fix hang in usb_kill_urb by adding memory barriers
commit 26fbe9772b upstream.

The syzbot fuzzer has identified a bug in which processes hang waiting
for usb_kill_urb() to return.  It turns out the issue is not unlinking
the URB; that works just fine.  Rather, the problem arises when the
wakeup notification that the URB has completed is not received.

The reason is memory-access ordering on SMP systems.  In outline form,
usb_kill_urb() and __usb_hcd_giveback_urb() operating concurrently on
different CPUs perform the following actions:

CPU 0					CPU 1
----------------------------		---------------------------------
usb_kill_urb():				__usb_hcd_giveback_urb():
  ...					  ...
  atomic_inc(&urb->reject);		  atomic_dec(&urb->use_count);
  ...					  ...
  wait_event(usb_kill_urb_queue,
	atomic_read(&urb->use_count) == 0);
					  if (atomic_read(&urb->reject))
						wake_up(&usb_kill_urb_queue);

Confining your attention to urb->reject and urb->use_count, you can
see that the overall pattern of accesses on CPU 0 is:

	write urb->reject, then read urb->use_count;

whereas the overall pattern of accesses on CPU 1 is:

	write urb->use_count, then read urb->reject.

This pattern is referred to in memory-model circles as SB (for "Store
Buffering"), and it is well known that without suitable enforcement of
the desired order of accesses -- in the form of memory barriers -- it
is entirely possible for one or both CPUs to execute their reads ahead
of their writes.  The end result will be that sometimes CPU 0 sees the
old un-decremented value of urb->use_count while CPU 1 sees the old
un-incremented value of urb->reject.  Consequently CPU 0 ends up on
the wait queue and never gets woken up, leading to the observed hang
in usb_kill_urb().

The same pattern of accesses occurs in usb_poison_urb() and the
failure pathway of usb_hcd_submit_urb().

The problem is fixed by adding suitable memory barriers.  To provide
proper memory-access ordering in the SB pattern, a full barrier is
required on both CPUs.  The atomic_inc() and atomic_dec() accesses
themselves don't provide any memory ordering, but since they are
present, we can use the optimized smp_mb__after_atomic() memory
barrier in the various routines to obtain the desired effect.

This patch adds the necessary memory barriers.

CC: <stable@vger.kernel.org>
Reported-and-tested-by: syzbot+76629376e06e2c2ad626@syzkaller.appspotmail.com
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Link: https://lore.kernel.org/r/Ye8K0QYee0Q0Nna2@rowland.harvard.edu
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2022-02-01 17:27:04 +01:00
..
Kconfig USB: hub: Add Kconfig option to reduce number of port initialization retries 2020-10-02 11:29:02 +02:00
Makefile
buffer.c usb: core: Replace in_interrupt() in comments 2020-10-28 12:32:59 +01:00
config.c usb: core: config: using bit mask instead of individual bits 2021-12-14 10:57:20 +01:00
devices.c usb: common: add function to get interval expressed in us unit 2021-03-10 09:37:17 +01:00
devio.c USB: core: Make do_proc_control() and do_proc_bulk() killable 2021-12-22 09:32:50 +01:00
driver.c USB: core: rename usb_driver_claim_interface() data parameter 2021-03-23 12:39:39 +01:00
endpoint.c usb: common: add function to get interval expressed in us unit 2021-03-10 09:37:17 +01:00
file.c
generic.c usbcore: Check both id_table and match() when both available 2020-10-28 13:24:58 +01:00
hcd-pci.c usb: core: Replace in_interrupt() in comments 2020-10-28 12:32:59 +01:00
hcd.c USB: core: Fix hang in usb_kill_urb by adding memory barriers 2022-02-01 17:27:04 +01:00
hub.c usb: hub: Add delay for SuperSpeed hub resume to let links transit to U0 2022-01-27 11:04:44 +01:00
hub.h usb: core: reduce power-on-good delay time of root hub 2021-04-10 10:45:48 +02:00
ledtrig-usbport.c usb: core: ledtrig-usbport: Demote obvious misuse of kerneldoc to standard comment blocks 2020-07-09 16:46:57 +02:00
message.c USB: core: Avoid WARNings for 0-length descriptor requests 2021-06-09 11:11:39 +02:00
notify.c
of.c drivers: usb: Fix trivial spelling 2020-06-18 10:13:16 +02:00
otg_productlist.h USB: OTG: rename product list of devices 2020-06-19 08:58:55 +02:00
phy.c
phy.h
port.c Revert "usb: Link the ports to the connectors they are attached to" 2021-04-12 14:36:02 +02:00
quirks.c USB: NO_LPM quirk Lenovo USB-C to Ethernet Adapher(RTL8153-04) 2021-12-22 09:32:46 +01:00
sysfs.c driver core: Move the "removable" attribute from USB to core 2021-05-27 09:36:31 +02:00
urb.c USB: core: Fix hang in usb_kill_urb by adding memory barriers 2022-02-01 17:27:04 +01:00
usb-acpi.c
usb.c usb: Iterator for ports 2021-04-09 16:00:00 +02:00
usb.h usbcore: Check both id_table and match() when both available 2020-10-28 13:24:58 +01:00