3.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mathias Payer mathias.payer@nebelwelt.net
commit 704620afc70cf47abb9d6a1a57f3825d2bca49cf upstream.
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 | 3 ++- drivers/usb/core/usb.c | 6 +++--- drivers/usb/host/hwa-hc.c | 2 +- include/linux/usb.h | 4 ++-- 4 files changed, 8 insertions(+), 7 deletions(-)
--- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -2236,7 +2236,8 @@ static int usb_enumerate_device_otg(stru /* descriptor may appear anywhere in config */ if (__usb_get_extra_descriptor (udev->rawdescriptors[0], le16_to_cpu(udev->config[0].desc.wTotalLength), - USB_DT_OTG, (void **) &desc) == 0) { + USB_DT_OTG, (void **) &desc, + sizeof(*desc)) == 0) { if (desc->bmAttributes & USB_OTG_HNP) { unsigned port1 = udev->portnum;
--- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -664,14 +664,14 @@ EXPORT_SYMBOL_GPL(usb_get_current_frame_ */
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, @@ -680,7 +680,7 @@ int __usb_get_extra_descriptor(char *buf return -1; }
- if (header->bDescriptorType == type) { + if (header->bDescriptorType == type && header->bLength >= minsize) { *ptr = header; return 0; } --- a/drivers/usb/host/hwa-hc.c +++ b/drivers/usb/host/hwa-hc.c @@ -654,7 +654,7 @@ static int hwahc_security_create(struct 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; --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -329,11 +329,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)))
/* ----------------------------------------------------------------------- */