USB: check usb_get_extra_descriptor for proper size
authorMathias Payer <mathias.payer@nebelwelt.net>
Wed, 5 Dec 2018 20:19:59 +0000 (21:19 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 5 Dec 2018 20:20:14 +0000 (21:20 +0100)
When reading an extra descriptor, we need to properly check the minimum
and maximum size allowed, to prevent from invalid data being sent by a
device.

Reported-by: Hui Peng <benquike@gmail.com>
Reported-by: Mathias Payer <mathias.payer@nebelwelt.net>
Co-developed-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Hui Peng <benquike@gmail.com>
Signed-off-by: Mathias Payer <mathias.payer@nebelwelt.net>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Cc: stable <stable@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/core/hub.c
drivers/usb/core/usb.c
drivers/usb/host/hwa-hc.c
include/linux/usb.h

index 528664059a1266dd181c8b2600935925079d4516..f76b2e0aba9d5f11d994cd06ebe217f283bada16 100644 (file)
@@ -2251,7 +2251,7 @@ static int usb_enumerate_device_otg(struct usb_device *udev)
                /* descriptor may appear anywhere in config */
                err = __usb_get_extra_descriptor(udev->rawdescriptors[0],
                                le16_to_cpu(udev->config[0].desc.wTotalLength),
-                               USB_DT_OTG, (void **) &desc);
+                               USB_DT_OTG, (void **) &desc, sizeof(*desc));
                if (err || !(desc->bmAttributes & USB_OTG_HNP))
                        return 0;
 
index 79d8bd7a612e65b5c765f16e0c5567a440cdc1da..4ebfbd737905169d1b96904952576defbd01e8f1 100644 (file)
@@ -832,14 +832,14 @@ EXPORT_SYMBOL_GPL(usb_get_current_frame_number);
  */
 
 int __usb_get_extra_descriptor(char *buffer, unsigned size,
-                              unsigned char type, void **ptr)
+                              unsigned char type, void **ptr, size_t minsize)
 {
        struct usb_descriptor_header *header;
 
        while (size >= sizeof(struct usb_descriptor_header)) {
                header = (struct usb_descriptor_header *)buffer;
 
-               if (header->bLength < 2) {
+               if (header->bLength < 2 || header->bLength > size) {
                        printk(KERN_ERR
                                "%s: bogus descriptor, type %d length %d\n",
                                usbcore_name,
@@ -848,7 +848,7 @@ int __usb_get_extra_descriptor(char *buffer, unsigned size,
                        return -1;
                }
 
-               if (header->bDescriptorType == type) {
+               if (header->bDescriptorType == type && header->bLength >= minsize) {
                        *ptr = header;
                        return 0;
                }
index 684d6f074c3a490a291109ff9603ec4b44f84e58..09a8ebd955888d6d375d7cee3d0fc53fd1cf0d9c 100644 (file)
@@ -640,7 +640,7 @@ static int hwahc_security_create(struct hwahc *hwahc)
        top = itr + itr_size;
        result = __usb_get_extra_descriptor(usb_dev->rawdescriptors[index],
                        le16_to_cpu(usb_dev->actconfig->desc.wTotalLength),
-                       USB_DT_SECURITY, (void **) &secd);
+                       USB_DT_SECURITY, (void **) &secd, sizeof(*secd));
        if (result == -1) {
                dev_warn(dev, "BUG? WUSB host has no security descriptors\n");
                return 0;
index 4cdd515a4385f1a99d95a7bb7b5b29b09a5c1c1a..5e49e82c43684854c379e18a1d698d79ac4ef347 100644 (file)
@@ -407,11 +407,11 @@ struct usb_host_bos {
 };
 
 int __usb_get_extra_descriptor(char *buffer, unsigned size,
-       unsigned char type, void **ptr);
+       unsigned char type, void **ptr, size_t min);
 #define usb_get_extra_descriptor(ifpoint, type, ptr) \
                                __usb_get_extra_descriptor((ifpoint)->extra, \
                                (ifpoint)->extralen, \
-                               type, (void **)ptr)
+                               type, (void **)ptr, sizeof(**(ptr)))
 
 /* ----------------------------------------------------------------------- */