ehrhardt@ reported to me a use-after-free in USB polling mode, turns out
it's a design problem.  That means there's a lot of them.  That's scary.

Diff below is a small piece of a huge fix.  It concerns root hub codes. 

To keep it short, it is not safe to dereference ``xfer'' after having
called usb_transfer_complete().  Internally usb_transfer_complete()
calls a callback that in some situations free the ``xfer''.

So in this case we should not return USBD_IN_PROGRESS, because doing
so will make usb_transfer() do the following check:

341:            s = splusb();
342:            while (!xfer->done) {
                        ...

...and that's a user-after-free.

Instead return USBD_NORMAL_COMPLETION or the corresponding error code.

Index: ehci.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/ehci.c,v
retrieving revision 1.195
diff -u -p -r1.195 ehci.c
--- ehci.c      8 Nov 2016 10:31:30 -0000       1.195
+++ ehci.c      7 Mar 2017 14:58:12 -0000
@@ -2170,7 +2170,7 @@ ehci_root_ctrl_start(struct usbd_xfer *x
        s = splusb();
        usb_transfer_complete(xfer);
        splx(s);
-       return (USBD_IN_PROGRESS);
+       return (err);
 }
 
 void
Index: ohci.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/ohci.c,v
retrieving revision 1.147
diff -u -p -r1.147 ohci.c
--- ohci.c      15 Sep 2016 02:00:17 -0000      1.147
+++ ohci.c      7 Mar 2017 14:58:33 -0000
@@ -2587,7 +2587,7 @@ ohci_root_ctrl_start(struct usbd_xfer *x
        s = splusb();
        usb_transfer_complete(xfer);
        splx(s);
-       return (USBD_IN_PROGRESS);
+       return (err);
 }
 
 /* Abort a root control request. */
Index: uhci.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/uhci.c,v
retrieving revision 1.140
diff -u -p -r1.140 uhci.c
--- uhci.c      2 Feb 2017 22:31:05 -0000       1.140
+++ uhci.c      7 Mar 2017 14:59:26 -0000
@@ -3231,7 +3231,7 @@ uhci_root_ctrl_start(struct usbd_xfer *x
        s = splusb();
        usb_transfer_complete(xfer);
        splx(s);
-       return (USBD_IN_PROGRESS);
+       return (err);
 }
 
 /* Abort a root control request. */
Index: usbdi.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/usbdi.c,v
retrieving revision 1.87
diff -u -p -r1.87 usbdi.c
--- usbdi.c     6 Mar 2017 12:13:58 -0000       1.87
+++ usbdi.c     7 Mar 2017 14:59:25 -0000
@@ -322,7 +322,7 @@ usbd_transfer(struct usbd_xfer *xfer)
 
        err = pipe->methods->transfer(xfer);
 
-       if (err != USBD_IN_PROGRESS && err) {
+       if (err != USBD_IN_PROGRESS && err != USBD_NORMAL_COMPLETION) {
                /* The transfer has not been queued, so free buffer. */
                if (xfer->rqflags & URQ_AUTO_DMABUF) {
                        struct usbd_bus *bus = pipe->device->bus;
Index: xhci.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/xhci.c,v
retrieving revision 1.70
diff -u -p -r1.70 xhci.c
--- xhci.c      8 Nov 2016 10:31:30 -0000       1.70
+++ xhci.c      7 Mar 2017 14:58:23 -0000
@@ -2366,7 +2366,7 @@ ret:
        s = splusb();
        usb_transfer_complete(xfer);
        splx(s);
-       return (USBD_IN_PROGRESS);
+       return (err);
 }
 
 
Index: dwc2/dwc2.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/dwc2/dwc2.c,v
retrieving revision 1.41
diff -u -p -r1.41 dwc2.c
--- dwc2/dwc2.c 16 Feb 2017 14:09:00 -0000      1.41
+++ dwc2/dwc2.c 7 Mar 2017 14:59:26 -0000
@@ -874,7 +874,7 @@ fail:
        usb_transfer_complete(xfer);
        splx(s);
 
-       return USBD_IN_PROGRESS;
+       return err;
 }
 
 STATIC void

Reply via email to