| From 7a68d9fb851012829c29e770621905529bd9490b Mon Sep 17 00:00:00 2001 |
| From: Oliver Neukum <oneukum@suse.com> |
| Date: Wed, 5 Sep 2018 12:07:02 +0200 |
| Subject: USB: usbdevfs: sanitize flags more |
| |
| From: Oliver Neukum <oneukum@suse.com> |
| |
| commit 7a68d9fb851012829c29e770621905529bd9490b upstream. |
| |
| Requesting a ZERO_PACKET or not is sensible only for output. |
| In the input direction the device decides. |
| Likewise accepting short packets makes sense only for input. |
| |
| This allows operation with panic_on_warn without opening up |
| a local DOS. |
| |
| Signed-off-by: Oliver Neukum <oneukum@suse.com> |
| Reported-by: syzbot+843efa30c8821bd69f53@syzkaller.appspotmail.com |
| Fixes: 0cb54a3e47cb ("USB: debugging code shouldn't alter control flow") |
| Cc: stable <stable@vger.kernel.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/usb/core/devio.c | 19 ++++++++++++++++--- |
| 1 file changed, 16 insertions(+), 3 deletions(-) |
| |
| --- a/drivers/usb/core/devio.c |
| +++ b/drivers/usb/core/devio.c |
| @@ -1450,10 +1450,13 @@ static int proc_do_submiturb(struct usb_ |
| struct async *as = NULL; |
| struct usb_ctrlrequest *dr = NULL; |
| unsigned int u, totlen, isofrmlen; |
| - int i, ret, is_in, num_sgs = 0, ifnum = -1; |
| + int i, ret, num_sgs = 0, ifnum = -1; |
| int number_of_packets = 0; |
| unsigned int stream_id = 0; |
| void *buf; |
| + bool is_in; |
| + bool allow_short = false; |
| + bool allow_zero = false; |
| unsigned long mask = USBDEVFS_URB_SHORT_NOT_OK | |
| USBDEVFS_URB_BULK_CONTINUATION | |
| USBDEVFS_URB_NO_FSBR | |
| @@ -1487,6 +1490,8 @@ static int proc_do_submiturb(struct usb_ |
| u = 0; |
| switch (uurb->type) { |
| case USBDEVFS_URB_TYPE_CONTROL: |
| + if (is_in) |
| + allow_short = true; |
| if (!usb_endpoint_xfer_control(&ep->desc)) |
| return -EINVAL; |
| /* min 8 byte setup packet */ |
| @@ -1527,6 +1532,10 @@ static int proc_do_submiturb(struct usb_ |
| break; |
| |
| case USBDEVFS_URB_TYPE_BULK: |
| + if (!is_in) |
| + allow_zero = true; |
| + else |
| + allow_short = true; |
| switch (usb_endpoint_type(&ep->desc)) { |
| case USB_ENDPOINT_XFER_CONTROL: |
| case USB_ENDPOINT_XFER_ISOC: |
| @@ -1547,6 +1556,10 @@ static int proc_do_submiturb(struct usb_ |
| if (!usb_endpoint_xfer_int(&ep->desc)) |
| return -EINVAL; |
| interrupt_urb: |
| + if (!is_in) |
| + allow_zero = true; |
| + else |
| + allow_short = true; |
| break; |
| |
| case USBDEVFS_URB_TYPE_ISO: |
| @@ -1691,11 +1704,11 @@ static int proc_do_submiturb(struct usb_ |
| u = (is_in ? URB_DIR_IN : URB_DIR_OUT); |
| if (uurb->flags & USBDEVFS_URB_ISO_ASAP) |
| u |= URB_ISO_ASAP; |
| - if (uurb->flags & USBDEVFS_URB_SHORT_NOT_OK && is_in) |
| + if (allow_short && uurb->flags & USBDEVFS_URB_SHORT_NOT_OK) |
| u |= URB_SHORT_NOT_OK; |
| if (uurb->flags & USBDEVFS_URB_NO_FSBR) |
| u |= URB_NO_FSBR; |
| - if (uurb->flags & USBDEVFS_URB_ZERO_PACKET) |
| + if (allow_zero && uurb->flags & USBDEVFS_URB_ZERO_PACKET) |
| u |= URB_ZERO_PACKET; |
| if (uurb->flags & USBDEVFS_URB_NO_INTERRUPT) |
| u |= URB_NO_INTERRUPT; |