Module Name:    src
Committed By:   riastradh
Date:           Sun Mar 13 11:28:42 UTC 2022

Modified Files:
        src/sys/dev/usb: usb_subr.c usbdi.c usbdivar.h

Log Message:
usbdi(9): Assert no concurrent aborts on a single pipe.

It is a driver bug to try to abort a pipe at the same time in two
different threads.

HCI drivers may release the bus lock to sleep in upm_abort while
waiting for the hardware to acknowledge an abort, so it won't try to,
e.g., scribble over a DMA buffer in the xfer that we've recycled
after usbd_abort_pipe returns.

If this happens, a concurrent usbd_abort_pipe might try to apply
upm_abort to the same xfer, which HCI drivers are not prepared for
and may wreak havoc.

To avoid this, allow only one usbd_abort_pipe in flight at any given
time.


To generate a diff of this commit:
cvs rdiff -u -r1.270 -r1.271 src/sys/dev/usb/usb_subr.c
cvs rdiff -u -r1.234 -r1.235 src/sys/dev/usb/usbdi.c
cvs rdiff -u -r1.135 -r1.136 src/sys/dev/usb/usbdivar.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/usb/usb_subr.c
diff -u src/sys/dev/usb/usb_subr.c:1.270 src/sys/dev/usb/usb_subr.c:1.271
--- src/sys/dev/usb/usb_subr.c:1.270	Thu Mar  3 06:13:35 2022
+++ src/sys/dev/usb/usb_subr.c	Sun Mar 13 11:28:42 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: usb_subr.c,v 1.270 2022/03/03 06:13:35 riastradh Exp $	*/
+/*	$NetBSD: usb_subr.c,v 1.271 2022/03/13 11:28:42 riastradh Exp $	*/
 /*	$FreeBSD: src/sys/dev/usb/usb_subr.c,v 1.18 1999/11/17 22:33:47 n_hibma Exp $	*/
 
 /*
@@ -32,7 +32,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: usb_subr.c,v 1.270 2022/03/03 06:13:35 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: usb_subr.c,v 1.271 2022/03/13 11:28:42 riastradh Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_compat_netbsd.h"
@@ -948,6 +948,7 @@ usbd_setup_pipe_flags(struct usbd_device
 	SIMPLEQ_INIT(&p->up_queue);
 	p->up_callingxfer = NULL;
 	cv_init(&p->up_callingcv, "usbpipecb");
+	p->up_abortlwp = NULL;
 
 	err = dev->ud_bus->ub_methods->ubm_open(p);
 	if (err) {
@@ -967,6 +968,8 @@ usbd_setup_pipe_flags(struct usbd_device
 	err = USBD_NORMAL_COMPLETION;
 
 out:	if (p) {
+		KASSERT(p->up_abortlwp == NULL);
+		KASSERT(p->up_callingxfer == NULL);
 		cv_destroy(&p->up_callingcv);
 		kmem_free(p, dev->ud_bus->ub_pipesize);
 	}

Index: src/sys/dev/usb/usbdi.c
diff -u src/sys/dev/usb/usbdi.c:1.234 src/sys/dev/usb/usbdi.c:1.235
--- src/sys/dev/usb/usbdi.c:1.234	Sun Mar 13 11:28:33 2022
+++ src/sys/dev/usb/usbdi.c	Sun Mar 13 11:28:42 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: usbdi.c,v 1.234 2022/03/13 11:28:33 riastradh Exp $	*/
+/*	$NetBSD: usbdi.c,v 1.235 2022/03/13 11:28:42 riastradh Exp $	*/
 
 /*
  * Copyright (c) 1998, 2012, 2015 The NetBSD Foundation, Inc.
@@ -32,7 +32,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: usbdi.c,v 1.234 2022/03/13 11:28:33 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: usbdi.c,v 1.235 2022/03/13 11:28:42 riastradh Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_usb.h"
@@ -1020,6 +1020,16 @@ usbd_ar_pipe(struct usbd_pipe *pipe)
 	ASSERT_SLEEPABLE();
 	KASSERT(mutex_owned(pipe->up_dev->ud_bus->ub_lock));
 
+	/*
+	 * Allow only one thread at a time to abort the pipe, so we
+	 * don't get confused if upm_abort drops the lock in the middle
+	 * of the abort to wait for hardware completion softints to
+	 * stop using the xfer before returning.
+	 */
+	KASSERTMSG(pipe->up_abortlwp == NULL, "pipe->up_abortlwp=%p",
+	    pipe->up_abortlwp);
+	pipe->up_abortlwp = curlwp;
+
 #ifdef USB_DEBUG
 	if (usbdebug > 5)
 		usbd_dump_queue(pipe);
@@ -1051,6 +1061,12 @@ usbd_ar_pipe(struct usbd_pipe *pipe)
 			/* XXX only for non-0 usbd_clear_endpoint_stall(pipe); */
 		}
 	}
+
+	KASSERT(mutex_owned(pipe->up_dev->ud_bus->ub_lock));
+	KASSERTMSG(pipe->up_abortlwp == NULL, "pipe->up_abortlwp=%p",
+	    pipe->up_abortlwp);
+	pipe->up_abortlwp = NULL;
+
 	SDT_PROBE1(usb, device, pipe, abort__done,  pipe);
 }
 

Index: src/sys/dev/usb/usbdivar.h
diff -u src/sys/dev/usb/usbdivar.h:1.135 src/sys/dev/usb/usbdivar.h:1.136
--- src/sys/dev/usb/usbdivar.h:1.135	Wed Mar  9 22:17:41 2022
+++ src/sys/dev/usb/usbdivar.h	Sun Mar 13 11:28:42 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: usbdivar.h,v 1.135 2022/03/09 22:17:41 riastradh Exp $	*/
+/*	$NetBSD: usbdivar.h,v 1.136 2022/03/13 11:28:42 riastradh Exp $	*/
 
 /*
  * Copyright (c) 1998, 2012 The NetBSD Foundation, Inc.
@@ -257,6 +257,8 @@ struct usbd_pipe {
 	struct usbd_xfer       *up_callingxfer; /* currently in callback */
 	kcondvar_t		up_callingcv;
 
+	struct lwp	       *up_abortlwp;	/* lwp currently aborting */
+
 	/* Filled by HC driver. */
 	const struct usbd_pipe_methods
 			       *up_methods;

Reply via email to