Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

USB: check usb_get_extra_descriptor for proper size

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>

authored by

Mathias Payer and committed by
Greg Kroah-Hartman
704620af 2f2dde6b

+7 -7
+1 -1
drivers/usb/core/hub.c
··· 2251 2251 /* descriptor may appear anywhere in config */ 2252 2252 err = __usb_get_extra_descriptor(udev->rawdescriptors[0], 2253 2253 le16_to_cpu(udev->config[0].desc.wTotalLength), 2254 - USB_DT_OTG, (void **) &desc); 2254 + USB_DT_OTG, (void **) &desc, sizeof(*desc)); 2255 2255 if (err || !(desc->bmAttributes & USB_OTG_HNP)) 2256 2256 return 0; 2257 2257
+3 -3
drivers/usb/core/usb.c
··· 832 832 */ 833 833 834 834 int __usb_get_extra_descriptor(char *buffer, unsigned size, 835 - unsigned char type, void **ptr) 835 + unsigned char type, void **ptr, size_t minsize) 836 836 { 837 837 struct usb_descriptor_header *header; 838 838 839 839 while (size >= sizeof(struct usb_descriptor_header)) { 840 840 header = (struct usb_descriptor_header *)buffer; 841 841 842 - if (header->bLength < 2) { 842 + if (header->bLength < 2 || header->bLength > size) { 843 843 printk(KERN_ERR 844 844 "%s: bogus descriptor, type %d length %d\n", 845 845 usbcore_name, ··· 848 848 return -1; 849 849 } 850 850 851 - if (header->bDescriptorType == type) { 851 + if (header->bDescriptorType == type && header->bLength >= minsize) { 852 852 *ptr = header; 853 853 return 0; 854 854 }
+1 -1
drivers/usb/host/hwa-hc.c
··· 640 640 top = itr + itr_size; 641 641 result = __usb_get_extra_descriptor(usb_dev->rawdescriptors[index], 642 642 le16_to_cpu(usb_dev->actconfig->desc.wTotalLength), 643 - USB_DT_SECURITY, (void **) &secd); 643 + USB_DT_SECURITY, (void **) &secd, sizeof(*secd)); 644 644 if (result == -1) { 645 645 dev_warn(dev, "BUG? WUSB host has no security descriptors\n"); 646 646 return 0;
+2 -2
include/linux/usb.h
··· 407 407 }; 408 408 409 409 int __usb_get_extra_descriptor(char *buffer, unsigned size, 410 - unsigned char type, void **ptr); 410 + unsigned char type, void **ptr, size_t min); 411 411 #define usb_get_extra_descriptor(ifpoint, type, ptr) \ 412 412 __usb_get_extra_descriptor((ifpoint)->extra, \ 413 413 (ifpoint)->extralen, \ 414 - type, (void **)ptr) 414 + type, (void **)ptr, sizeof(**(ptr))) 415 415 416 416 /* ----------------------------------------------------------------------- */ 417 417