Takashi Iwai 960b00
From 26fbe9772b8c459687930511444ce443011f86bf Mon Sep 17 00:00:00 2001
Takashi Iwai 960b00
From: Alan Stern <stern@rowland.harvard.edu>
Takashi Iwai 960b00
Date: Mon, 24 Jan 2022 15:23:45 -0500
Takashi Iwai 960b00
Subject: [PATCH] USB: core: Fix hang in usb_kill_urb by adding memory barriers
Takashi Iwai 960b00
Git-commit: 26fbe9772b8c459687930511444ce443011f86bf
Takashi Iwai 960b00
Patch-mainline: v5.17-rc2
Takashi Iwai 960b00
References: git-fixes
Takashi Iwai 960b00
Takashi Iwai 960b00
The syzbot fuzzer has identified a bug in which processes hang waiting
Takashi Iwai 960b00
for usb_kill_urb() to return.  It turns out the issue is not unlinking
Takashi Iwai 960b00
the URB; that works just fine.  Rather, the problem arises when the
Takashi Iwai 960b00
wakeup notification that the URB has completed is not received.
Takashi Iwai 960b00
Takashi Iwai 960b00
The reason is memory-access ordering on SMP systems.  In outline form,
Takashi Iwai 960b00
usb_kill_urb() and __usb_hcd_giveback_urb() operating concurrently on
Takashi Iwai 960b00
different CPUs perform the following actions:
Takashi Iwai 960b00
Takashi Iwai 960b00
CPU 0					CPU 1
Takashi Iwai 960b00
Takashi Iwai 960b00
Acked-by: Takashi Iwai <tiwai@suse.de>
Takashi Iwai 960b00
Takashi Iwai 960b00
----------------------------		---------------------------------
Takashi Iwai 960b00
usb_kill_urb():				__usb_hcd_giveback_urb():
Takashi Iwai 960b00
  ...					  ...
Takashi Iwai 960b00
  atomic_inc(&urb->reject);		  atomic_dec(&urb->use_count);
Takashi Iwai 960b00
  ...					  ...
Takashi Iwai 960b00
  wait_event(usb_kill_urb_queue,
Takashi Iwai 960b00
	atomic_read(&urb->use_count) == 0);
Takashi Iwai 960b00
					  if (atomic_read(&urb->reject))
Takashi Iwai 960b00
						wake_up(&usb_kill_urb_queue);
Takashi Iwai 960b00
Takashi Iwai 960b00
Confining your attention to urb->reject and urb->use_count, you can
Takashi Iwai 960b00
see that the overall pattern of accesses on CPU 0 is:
Takashi Iwai 960b00
Takashi Iwai 960b00
	write urb->reject, then read urb->use_count;
Takashi Iwai 960b00
Takashi Iwai 960b00
whereas the overall pattern of accesses on CPU 1 is:
Takashi Iwai 960b00
Takashi Iwai 960b00
	write urb->use_count, then read urb->reject.
Takashi Iwai 960b00
Takashi Iwai 960b00
This pattern is referred to in memory-model circles as SB (for "Store
Takashi Iwai 960b00
Buffering"), and it is well known that without suitable enforcement of
Takashi Iwai 960b00
the desired order of accesses -- in the form of memory barriers -- it
Takashi Iwai 960b00
is entirely possible for one or both CPUs to execute their reads ahead
Takashi Iwai 960b00
of their writes.  The end result will be that sometimes CPU 0 sees the
Takashi Iwai 960b00
old un-decremented value of urb->use_count while CPU 1 sees the old
Takashi Iwai 960b00
un-incremented value of urb->reject.  Consequently CPU 0 ends up on
Takashi Iwai 960b00
the wait queue and never gets woken up, leading to the observed hang
Takashi Iwai 960b00
in usb_kill_urb().
Takashi Iwai 960b00
Takashi Iwai 960b00
The same pattern of accesses occurs in usb_poison_urb() and the
Takashi Iwai 960b00
failure pathway of usb_hcd_submit_urb().
Takashi Iwai 960b00
Takashi Iwai 960b00
The problem is fixed by adding suitable memory barriers.  To provide
Takashi Iwai 960b00
proper memory-access ordering in the SB pattern, a full barrier is
Takashi Iwai 960b00
required on both CPUs.  The atomic_inc() and atomic_dec() accesses
Takashi Iwai 960b00
themselves don't provide any memory ordering, but since they are
Takashi Iwai 960b00
present, we can use the optimized smp_mb__after_atomic() memory
Takashi Iwai 960b00
barrier in the various routines to obtain the desired effect.
Takashi Iwai 960b00
Takashi Iwai 960b00
This patch adds the necessary memory barriers.
Takashi Iwai 960b00
Takashi Iwai 960b00
CC: <stable@vger.kernel.org>
Takashi Iwai 960b00
Reported-and-tested-by: syzbot+76629376e06e2c2ad626@syzkaller.appspotmail.com
Takashi Iwai 960b00
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Takashi Iwai 960b00
Link: https://lore.kernel.org/r/Ye8K0QYee0Q0Nna2@rowland.harvard.edu
Takashi Iwai 960b00
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Takashi Iwai 960b00
---
Takashi Iwai 960b00
 drivers/usb/core/hcd.c | 14 ++++++++++++++
Takashi Iwai 960b00
 drivers/usb/core/urb.c | 12 ++++++++++++
Takashi Iwai 960b00
 2 files changed, 26 insertions(+)
Takashi Iwai 960b00
Takashi Iwai 960b00
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
Takashi Iwai 960b00
index 3e01dd6e509b..d9712c2602af 100644
Takashi Iwai 960b00
--- a/drivers/usb/core/hcd.c
Takashi Iwai 960b00
+++ b/drivers/usb/core/hcd.c
Takashi Iwai 960b00
@@ -1563,6 +1563,13 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
Takashi Iwai 960b00
 		urb->hcpriv = NULL;
Takashi Iwai 960b00
 		INIT_LIST_HEAD(&urb->urb_list);
Takashi Iwai 960b00
 		atomic_dec(&urb->use_count);
Takashi Iwai 960b00
+		/*
Takashi Iwai 960b00
+		 * Order the write of urb->use_count above before the read
Takashi Iwai 960b00
+		 * of urb->reject below.  Pairs with the memory barriers in
Takashi Iwai 960b00
+		 * usb_kill_urb() and usb_poison_urb().
Takashi Iwai 960b00
+		 */
Takashi Iwai 960b00
+		smp_mb__after_atomic();
Takashi Iwai 960b00
+
Takashi Iwai 960b00
 		atomic_dec(&urb->dev->urbnum);
Takashi Iwai 960b00
 		if (atomic_read(&urb->reject))
Takashi Iwai 960b00
 			wake_up(&usb_kill_urb_queue);
Takashi Iwai 960b00
@@ -1665,6 +1672,13 @@ static void __usb_hcd_giveback_urb(struct urb *urb)
Takashi Iwai 960b00
 
Takashi Iwai 960b00
 	usb_anchor_resume_wakeups(anchor);
Takashi Iwai 960b00
 	atomic_dec(&urb->use_count);
Takashi Iwai 960b00
+	/*
Takashi Iwai 960b00
+	 * Order the write of urb->use_count above before the read
Takashi Iwai 960b00
+	 * of urb->reject below.  Pairs with the memory barriers in
Takashi Iwai 960b00
+	 * usb_kill_urb() and usb_poison_urb().
Takashi Iwai 960b00
+	 */
Takashi Iwai 960b00
+	smp_mb__after_atomic();
Takashi Iwai 960b00
+
Takashi Iwai 960b00
 	if (unlikely(atomic_read(&urb->reject)))
Takashi Iwai 960b00
 		wake_up(&usb_kill_urb_queue);
Takashi Iwai 960b00
 	usb_put_urb(urb);
Takashi Iwai 960b00
diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
Takashi Iwai 960b00
index 30727729a44c..33d62d7e3929 100644
Takashi Iwai 960b00
--- a/drivers/usb/core/urb.c
Takashi Iwai 960b00
+++ b/drivers/usb/core/urb.c
Takashi Iwai 960b00
@@ -715,6 +715,12 @@ void usb_kill_urb(struct urb *urb)
Takashi Iwai 960b00
 	if (!(urb && urb->dev && urb->ep))
Takashi Iwai 960b00
 		return;
Takashi Iwai 960b00
 	atomic_inc(&urb->reject);
Takashi Iwai 960b00
+	/*
Takashi Iwai 960b00
+	 * Order the write of urb->reject above before the read
Takashi Iwai 960b00
+	 * of urb->use_count below.  Pairs with the barriers in
Takashi Iwai 960b00
+	 * __usb_hcd_giveback_urb() and usb_hcd_submit_urb().
Takashi Iwai 960b00
+	 */
Takashi Iwai 960b00
+	smp_mb__after_atomic();
Takashi Iwai 960b00
 
Takashi Iwai 960b00
 	usb_hcd_unlink_urb(urb, -ENOENT);
Takashi Iwai 960b00
 	wait_event(usb_kill_urb_queue, atomic_read(&urb->use_count) == 0);
Takashi Iwai 960b00
@@ -756,6 +762,12 @@ void usb_poison_urb(struct urb *urb)
Takashi Iwai 960b00
 	if (!urb)
Takashi Iwai 960b00
 		return;
Takashi Iwai 960b00
 	atomic_inc(&urb->reject);
Takashi Iwai 960b00
+	/*
Takashi Iwai 960b00
+	 * Order the write of urb->reject above before the read
Takashi Iwai 960b00
+	 * of urb->use_count below.  Pairs with the barriers in
Takashi Iwai 960b00
+	 * __usb_hcd_giveback_urb() and usb_hcd_submit_urb().
Takashi Iwai 960b00
+	 */
Takashi Iwai 960b00
+	smp_mb__after_atomic();
Takashi Iwai 960b00
 
Takashi Iwai 960b00
 	if (!urb->dev || !urb->ep)
Takashi Iwai 960b00
 		return;
Takashi Iwai 960b00
-- 
Takashi Iwai 960b00
2.31.1
Takashi Iwai 960b00