Blob Blame History Raw
From a5bbd694fa41d1117c6fec90a72e4baa67572d58 Mon Sep 17 00:00:00 2001
From: Oliver Neukum <oneukum@suse.com>
Date: Tue, 18 Dec 2018 14:52:56 +0100
Subject: [PATCH] USB: check usb_get_extra_descriptor for proper size (For
 SUSE)
Patch-mainline: Never (the upstream version breaks kABI)
References: bsc#1119714 CVE-2018-20169

This is an adaptation of the upstream fix:

commit 704620afc70cf47abb9d6a1a57f3825d2bca49cf
Author: Mathias Payer <mathias.payer@nebelwelt.net>
Date:   Wed Dec 5 21:19:59 2018 +0100

    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.

As it relies on changing a macro we cannot use it as such. Old code
must keep running and compiling, albeit at the unavoidable drawback
of keeping the system vulnerable.
Hence the old buggy version is kept and a clean _suse_ version is
introduced.

Signed-off-by: Oliver Neukum <oneukum@suse.com>
---
 drivers/usb/core/hub.c    |    4 ++--
 drivers/usb/core/usb.c    |   32 +++++++++++++++++++++++++++++++-
 drivers/usb/host/hwa-hc.c |    4 ++--
 include/linux/usb.h       |    6 ++++--
 4 files changed, 39 insertions(+), 7 deletions(-)

--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -2225,9 +2225,9 @@ static int usb_enumerate_device_otg(stru
 		unsigned			port1 = udev->portnum;
 
 		/* descriptor may appear anywhere in config */
-		err = __usb_get_extra_descriptor(udev->rawdescriptors[0],
+		err = __usb_suse_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;
 
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -837,10 +837,11 @@ int __usb_get_extra_descriptor(char *buf
 {
 	struct usb_descriptor_header *header;
 
+	WARN_ONCE(1, KERN_CRIT"An external module is leaving this system open to CVE-2018-20169\n ");
 	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,
@@ -1274,6 +1275,35 @@ static void __exit usb_exit(void)
 	idr_destroy(&usb_bus_idr);
 }
 
+int __usb_suse_get_extra_descriptor(char *buffer, unsigned size,
+                               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 || header->bLength > size) {
+                        printk(KERN_ERR
+                                "%s: bogus descriptor, type %d length %d\n",
+                                usbcore_name,
+                                header->bDescriptorType,
+                                header->bLength);
+                        return -1;
+                }
+
+                if (header->bDescriptorType == type && header->bLength >= minsize) {
+                        *ptr = header;
+                        return 0;
+                }
+
+                buffer += header->bLength;
+                size -= header->bLength;
+        }
+        return -1;
+}
+EXPORT_SYMBOL_GPL(__usb_suse_get_extra_descriptor);
+
 subsys_initcall(usb_init);
 module_exit(usb_exit);
 MODULE_LICENSE("GPL");
--- a/drivers/usb/host/hwa-hc.c
+++ b/drivers/usb/host/hwa-hc.c
@@ -652,9 +652,9 @@ static int hwahc_security_create(struct
 	itr = usb_dev->rawdescriptors[index];
 	itr_size = le16_to_cpu(usb_dev->actconfig->desc.wTotalLength);
 	top = itr + itr_size;
-	result = __usb_get_extra_descriptor(usb_dev->rawdescriptors[index],
+	result = __usb_suse_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
@@ -407,10 +407,12 @@ struct usb_host_bos {
 
 int __usb_get_extra_descriptor(char *buffer, unsigned size,
 	unsigned char type, void **ptr);
+int __usb_suse_get_extra_descriptor(char *buffer, unsigned size,
+	unsigned char type, void **ptr, size_t min);
 #define usb_get_extra_descriptor(ifpoint, type, ptr) \
-				__usb_get_extra_descriptor((ifpoint)->extra, \
+				__usb_suse_get_extra_descriptor((ifpoint)->extra, \
 				(ifpoint)->extralen, \
-				type, (void **)ptr)
+				type, (void **)ptr, sizeof(**(ptr)))
 
 /* ----------------------------------------------------------------------- */