[PATCH 3.2 016/140] USB: core: Add type-specific length check of BOS descriptors

From: Ben Hutchings
Date: Wed Feb 28 2018 - 12:46:19 EST


3.2.100-rc1 review patch. If anyone has any objections, please let me know.

------------------

From: Masakazu Mokuno <masakazu.mokuno@xxxxxxxxx>

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@xxxxxxxxx>
Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>
[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@xxxxxxxxxxxxxxx>
---
--- a/drivers/usb/core/config.c
+++ b/drivers/usb/core/config.c
@@ -878,6 +878,13 @@ void usb_release_bos_descriptor(struct u
}
}

+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_de
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_de
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_de
continue;
}

- switch (cap->bDevCapabilityType) {
+ switch (cap_type) {
case USB_CAP_TYPE_WIRELESS_USB:
/* Wireless USB cap descriptor is handled by wusb */
break;
--- a/include/linux/usb/ch9.h
+++ b/include/linux/usb/ch9.h
@@ -800,6 +800,8 @@ struct usb_wireless_cap_descriptor { /*
__u8 bReserved;
} __attribute__((packed));

+#define USB_DT_USB_WIRELESS_CAP_SIZE 11
+
/* USB 2.0 Extension descriptor */
#define USB_CAP_TYPE_EXT 2