Module Name:    src
Committed By:   skrll
Date:           Thu Jan  2 15:54:10 UTC 2014

Modified Files:
        src/sys/external/bsd/dwc2: dwc2.c
        src/sys/external/bsd/dwc2/dist: dwc2_hcd.c dwc2_hcdqueue.c

Log Message:
Protect access of urb->hcpriv by adapting the following change from the
Raspberry PI dwc_otg driver.

https://github.com/raspberrypi/linux/commit/38753ce72d4f10d5d0f1ed27fa691a2ba8910941

dwc_otg: prevent OOPSes during device disconnects

The dwc_otg_urb_enqueue function is thread-unsafe. In particular the
access of urb->hcpriv, usb_hcd_link_urb_to_ep, dwc_otg_urb->qtd and
friends does not occur within a critical section and so if a device
was unplugged during activity there was a high chance that the
usbcore hub_thread would try to disable the endpoint with partially-
formed entries in the URB queue. This would result in BUG() or null
pointer dereferences.

Fix so that access of urb->hcpriv, enqueuing to the hardware and
adding to usbcore endpoint URB lists is contained within a single
critical section.


To generate a diff of this commit:
cvs rdiff -u -r1.22 -r1.23 src/sys/external/bsd/dwc2/dwc2.c
cvs rdiff -u -r1.9 -r1.10 src/sys/external/bsd/dwc2/dist/dwc2_hcd.c
cvs rdiff -u -r1.6 -r1.7 src/sys/external/bsd/dwc2/dist/dwc2_hcdqueue.c

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

Modified files:

Index: src/sys/external/bsd/dwc2/dwc2.c
diff -u src/sys/external/bsd/dwc2/dwc2.c:1.22 src/sys/external/bsd/dwc2/dwc2.c:1.23
--- src/sys/external/bsd/dwc2/dwc2.c:1.22	Tue Dec 31 09:10:43 2013
+++ src/sys/external/bsd/dwc2/dwc2.c	Thu Jan  2 15:54:10 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: dwc2.c,v 1.22 2013/12/31 09:10:43 skrll Exp $	*/
+/*	$NetBSD: dwc2.c,v 1.23 2014/01/02 15:54:10 skrll Exp $	*/
 
 /*-
  * Copyright (c) 2013 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: dwc2.c,v 1.22 2013/12/31 09:10:43 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: dwc2.c,v 1.23 2014/01/02 15:54:10 skrll Exp $");
 
 #include "opt_usb.h"
 
@@ -1298,7 +1298,6 @@ dwc2_device_start(usbd_xfer_handle xfer)
 	memset(dwc2_urb, 0, sizeof(*dwc2_urb) +
 	    sizeof(dwc2_urb->iso_descs[0]) * DWC2_MAXISOCPACKETS);
 
-	dwc2_urb->priv = xfer;
 	dwc2_hcd_urb_set_pipeinfo(hsotg, dwc2_urb, addr, epnum, xfertype, dir,
 				  mps);
 
@@ -1379,6 +1378,9 @@ dwc2_device_start(usbd_xfer_handle xfer)
 	}
 
 	/* might need to check cpu_intr_p */
+	mutex_spin_enter(&hsotg->lock);
+
+	dwc2_urb->priv = xfer;
 	retval = dwc2_hcd_urb_enqueue(hsotg, dwc2_urb, &dpipe->priv, 0);
 	if (retval)
 		goto fail;
@@ -1389,14 +1391,14 @@ dwc2_device_start(usbd_xfer_handle xfer)
 	}
 
 	if (alloc_bandwidth) {
-		mutex_spin_enter(&hsotg->lock);
 		dwc2_allocate_bus_bandwidth(hsotg,
 				dwc2_hcd_get_ep_bandwidth(hsotg, dpipe),
 				xfer);
-		mutex_spin_exit(&hsotg->lock);
 	}
 
 fail:
+	mutex_spin_exit(&hsotg->lock);
+
 // 	mutex_exit(&sc->sc_lock);
 
 	switch (retval) {

Index: src/sys/external/bsd/dwc2/dist/dwc2_hcd.c
diff -u src/sys/external/bsd/dwc2/dist/dwc2_hcd.c:1.9 src/sys/external/bsd/dwc2/dist/dwc2_hcd.c:1.10
--- src/sys/external/bsd/dwc2/dist/dwc2_hcd.c:1.9	Sun Nov 24 12:25:19 2013
+++ src/sys/external/bsd/dwc2/dist/dwc2_hcd.c	Thu Jan  2 15:54:10 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: dwc2_hcd.c,v 1.9 2013/11/24 12:25:19 skrll Exp $	*/
+/*	$NetBSD: dwc2_hcd.c,v 1.10 2014/01/02 15:54:10 skrll Exp $	*/
 
 /*
  * hcd.c - DesignWare HS OTG Controller host-mode routines
@@ -42,7 +42,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: dwc2_hcd.c,v 1.9 2013/11/24 12:25:19 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: dwc2_hcd.c,v 1.10 2014/01/02 15:54:10 skrll Exp $");
 
 #include <sys/types.h>
 #include <sys/kmem.h>
@@ -367,7 +367,6 @@ dwc2_hcd_urb_enqueue(struct dwc2_hsotg *
 {
 	struct dwc2_softc *sc = hsotg->hsotg_sc;
 	struct dwc2_qtd *qtd;
-	unsigned long flags;
 	u32 intr_mask;
 	int retval;
 	int dev_speed;
@@ -421,11 +420,9 @@ dwc2_hcd_urb_enqueue(struct dwc2_hsotg *
 			 */
 			return 0;
 
-		spin_lock_irqsave(&hsotg->lock, flags);
 		tr_type = dwc2_hcd_select_transactions(hsotg);
 		if (tr_type != DWC2_TRANSACTION_NONE)
 			dwc2_hcd_queue_transactions(hsotg, tr_type);
-		spin_unlock_irqrestore(&hsotg->lock, flags);
 	}
 
 	return retval;

Index: src/sys/external/bsd/dwc2/dist/dwc2_hcdqueue.c
diff -u src/sys/external/bsd/dwc2/dist/dwc2_hcdqueue.c:1.6 src/sys/external/bsd/dwc2/dist/dwc2_hcdqueue.c:1.7
--- src/sys/external/bsd/dwc2/dist/dwc2_hcdqueue.c:1.6	Sun Nov 24 12:25:19 2013
+++ src/sys/external/bsd/dwc2/dist/dwc2_hcdqueue.c	Thu Jan  2 15:54:10 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: dwc2_hcdqueue.c,v 1.6 2013/11/24 12:25:19 skrll Exp $	*/
+/*	$NetBSD: dwc2_hcdqueue.c,v 1.7 2014/01/02 15:54:10 skrll Exp $	*/
 
 /*
  * hcd_queue.c - DesignWare HS OTG Controller host queuing routines
@@ -42,7 +42,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: dwc2_hcdqueue.c,v 1.6 2013/11/24 12:25:19 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: dwc2_hcdqueue.c,v 1.7 2014/01/02 15:54:10 skrll Exp $");
 
 #include <sys/types.h>
 #include <sys/kmem.h>
@@ -787,12 +787,13 @@ void dwc2_hcd_qtd_init(struct dwc2_qtd *
  * Finds the correct QH to place the QTD into. If it does not find a QH, it
  * will create a new QH. If the QH to which the QTD is added is not currently
  * scheduled, it is placed into the proper schedule based on its EP type.
+ *
+ * HCD lock must be held and interrupts must be disabled on entry
  */
 int dwc2_hcd_qtd_add(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd,
 		     struct dwc2_qh **qh, gfp_t mem_flags)
 {
 	struct dwc2_hcd_urb *urb = qtd->urb;
-	unsigned long flags;
 	int allocated = 0;
 	int retval;
 
@@ -807,15 +808,12 @@ int dwc2_hcd_qtd_add(struct dwc2_hsotg *
 		allocated = 1;
 	}
 
-	spin_lock_irqsave(&hsotg->lock, flags);
-
 	retval = dwc2_hcd_qh_add(hsotg, *qh);
 	if (retval)
 		goto fail;
 
 	qtd->qh = *qh;
 	list_add_tail(&qtd->qtd_list_entry, &(*qh)->qtd_list);
-	spin_unlock_irqrestore(&hsotg->lock, flags);
 
 	return 0;
 
@@ -832,10 +830,7 @@ fail:
 					 qtd_list_entry)
 			dwc2_hcd_qtd_unlink_and_free(hsotg, qtd2, qh_tmp);
 
-		spin_unlock_irqrestore(&hsotg->lock, flags);
 		dwc2_hcd_qh_free(hsotg, qh_tmp);
-	} else {
-		spin_unlock_irqrestore(&hsotg->lock, flags);
 	}
 
 	return retval;

Reply via email to