Commit 9d812f7b authored by Masakazu Mokuno's avatar Masakazu Mokuno Committed by Greg Kroah-Hartman

USB: core: Add type-specific length check of BOS descriptors

commit 81cf4a45 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: default avatarMasakazu Mokuno <masakazu.mokuno@gmail.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent f044af8c
...@@ -871,14 +871,25 @@ void usb_release_bos_descriptor(struct usb_device *dev) ...@@ -871,14 +871,25 @@ void usb_release_bos_descriptor(struct usb_device *dev)
} }
} }
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,
[USB_SSP_CAP_TYPE] = USB_DT_USB_SSP_CAP_SIZE(1),
[CONTAINER_ID_TYPE] = USB_DT_USB_SS_CONTN_ID_SIZE,
[USB_PTM_CAP_TYPE] = USB_DT_USB_PTM_ID_SIZE,
};
/* Get BOS descriptor set */ /* Get BOS descriptor set */
int usb_get_bos_descriptor(struct usb_device *dev) int usb_get_bos_descriptor(struct usb_device *dev)
{ {
struct device *ddev = &dev->dev; struct device *ddev = &dev->dev;
struct usb_bos_descriptor *bos; struct usb_bos_descriptor *bos;
struct usb_dev_cap_header *cap; struct usb_dev_cap_header *cap;
struct usb_ssp_cap_descriptor *ssp_cap;
unsigned char *buffer; unsigned char *buffer;
int length, total_len, num, i; int length, total_len, num, i, ssac;
__u8 cap_type;
int ret; int ret;
bos = kzalloc(sizeof(struct usb_bos_descriptor), GFP_KERNEL); bos = kzalloc(sizeof(struct usb_bos_descriptor), GFP_KERNEL);
...@@ -931,7 +942,13 @@ int usb_get_bos_descriptor(struct usb_device *dev) ...@@ -931,7 +942,13 @@ int usb_get_bos_descriptor(struct usb_device *dev)
dev->bos->desc->bNumDeviceCaps = i; dev->bos->desc->bNumDeviceCaps = i;
break; break;
} }
cap_type = cap->bDevCapabilityType;
length = cap->bLength; length = cap->bLength;
if (bos_desc_len[cap_type] && length < bos_desc_len[cap_type]) {
dev->bos->desc->bNumDeviceCaps = i;
break;
}
total_len -= length; total_len -= length;
if (cap->bDescriptorType != USB_DT_DEVICE_CAPABILITY) { if (cap->bDescriptorType != USB_DT_DEVICE_CAPABILITY) {
...@@ -939,7 +956,7 @@ int usb_get_bos_descriptor(struct usb_device *dev) ...@@ -939,7 +956,7 @@ int usb_get_bos_descriptor(struct usb_device *dev)
continue; continue;
} }
switch (cap->bDevCapabilityType) { switch (cap_type) {
case USB_CAP_TYPE_WIRELESS_USB: case USB_CAP_TYPE_WIRELESS_USB:
/* Wireless USB cap descriptor is handled by wusb */ /* Wireless USB cap descriptor is handled by wusb */
break; break;
...@@ -952,8 +969,11 @@ int usb_get_bos_descriptor(struct usb_device *dev) ...@@ -952,8 +969,11 @@ int usb_get_bos_descriptor(struct usb_device *dev)
(struct usb_ss_cap_descriptor *)buffer; (struct usb_ss_cap_descriptor *)buffer;
break; break;
case USB_SSP_CAP_TYPE: case USB_SSP_CAP_TYPE:
dev->bos->ssp_cap = ssp_cap = (struct usb_ssp_cap_descriptor *)buffer;
(struct usb_ssp_cap_descriptor *)buffer; ssac = (le32_to_cpu(ssp_cap->bmAttributes) &
USB_SSP_SUBLINK_SPEED_ATTRIBS) + 1;
if (length >= USB_DT_USB_SSP_CAP_SIZE(ssac))
dev->bos->ssp_cap = ssp_cap;
break; break;
case CONTAINER_ID_TYPE: case CONTAINER_ID_TYPE:
dev->bos->ss_id = dev->bos->ss_id =
......
...@@ -812,6 +812,8 @@ struct usb_wireless_cap_descriptor { /* Ultra Wide Band */ ...@@ -812,6 +812,8 @@ struct usb_wireless_cap_descriptor { /* Ultra Wide Band */
__u8 bReserved; __u8 bReserved;
} __attribute__((packed)); } __attribute__((packed));
#define USB_DT_USB_WIRELESS_CAP_SIZE 11
/* USB 2.0 Extension descriptor */ /* USB 2.0 Extension descriptor */
#define USB_CAP_TYPE_EXT 2 #define USB_CAP_TYPE_EXT 2
...@@ -1007,6 +1009,7 @@ enum usb3_link_state { ...@@ -1007,6 +1009,7 @@ enum usb3_link_state {
USB3_LPM_U3 USB3_LPM_U3
}; };
#define USB_DT_USB_PTM_ID_SIZE 3
/* /*
* A U1 timeout of 0x0 means the parent hub will reject any transitions to U1. * A U1 timeout of 0x0 means the parent hub will reject any transitions to U1.
* 0xff means the parent hub will accept transitions to U1, but will not * 0xff means the parent hub will accept transitions to U1, but will not
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment