USB: core: Add type-specific length check of BOS descriptors
authorMasakazu Mokuno <masakazu.mokuno@gmail.com>
Thu, 9 Nov 2017 16:25:50 +0000 (01:25 +0900)
committerBen Hutchings <ben@decadent.org.uk>
Sat, 3 Mar 2018 15:50:40 +0000 (15:50 +0000)
commit 81cf4a45360f70528f1f64ba018d61cb5767249a upstream.

As most of BOS descriptors are longer in length than their header
'struct usb_dev_cap_header', comparing solely with it is not sufficient
to avoid out-of-bounds access to BOS descriptors.

This patch adds descriptor type specific length check in
usb_get_bos_descriptor() to fix the issue.

Signed-off-by: Masakazu Mokuno <masakazu.mokuno@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
[bwh: Backported to 3.2:
 - Drop handling of USB_PTM_CAP_TYPE and USB_SSP_CAP_TYPE
 - Adjust filename]
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
drivers/usb/core/config.c
include/linux/usb/ch9.h

index 0a80b59..4c09812 100644 (file)
@@ -878,6 +878,13 @@ void usb_release_bos_descriptor(struct usb_device *dev)
        }
 }
 
+static const __u8 bos_desc_len[256] = {
+       [USB_CAP_TYPE_WIRELESS_USB] = USB_DT_USB_WIRELESS_CAP_SIZE,
+       [USB_CAP_TYPE_EXT]          = USB_DT_USB_EXT_CAP_SIZE,
+       [USB_SS_CAP_TYPE]           = USB_DT_USB_SS_CAP_SIZE,
+       [CONTAINER_ID_TYPE]         = USB_DT_USB_SS_CONTN_ID_SIZE,
+};
+
 /* Get BOS descriptor set */
 int usb_get_bos_descriptor(struct usb_device *dev)
 {
@@ -886,6 +893,7 @@ int usb_get_bos_descriptor(struct usb_device *dev)
        struct usb_dev_cap_header *cap;
        unsigned char *buffer;
        int length, total_len, num, i;
+       __u8 cap_type;
        int ret;
 
        bos = kzalloc(sizeof(struct usb_bos_descriptor), GFP_KERNEL);
@@ -938,7 +946,13 @@ int usb_get_bos_descriptor(struct usb_device *dev)
                        dev->bos->desc->bNumDeviceCaps = i;
                        break;
                }
+               cap_type = cap->bDevCapabilityType;
                length = cap->bLength;
+               if (bos_desc_len[cap_type] && length < bos_desc_len[cap_type]) {
+                       dev->bos->desc->bNumDeviceCaps = i;
+                       break;
+               }
+
                total_len -= length;
 
                if (cap->bDescriptorType != USB_DT_DEVICE_CAPABILITY) {
@@ -946,7 +960,7 @@ int usb_get_bos_descriptor(struct usb_device *dev)
                        continue;
                }
 
-               switch (cap->bDevCapabilityType) {
+               switch (cap_type) {
                case USB_CAP_TYPE_WIRELESS_USB:
                        /* Wireless USB cap descriptor is handled by wusb */
                        break;
index 68a3b10..e89e286 100644 (file)
@@ -800,6 +800,8 @@ struct usb_wireless_cap_descriptor {        /* Ultra Wide Band */
        __u8  bReserved;
 } __attribute__((packed));
 
+#define USB_DT_USB_WIRELESS_CAP_SIZE   11
+
 /* USB 2.0 Extension descriptor */
 #define        USB_CAP_TYPE_EXT                2