| From 81cf4a45360f70528f1f64ba018d61cb5767249a Mon Sep 17 00:00:00 2001 |
| From: Masakazu Mokuno <masakazu.mokuno@gmail.com> |
| Date: Fri, 10 Nov 2017 01:25:50 +0900 |
| Subject: USB: core: Add type-specific length check of BOS descriptors |
| |
| From: Masakazu Mokuno <masakazu.mokuno@gmail.com> |
| |
| 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@gmail.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/usb/core/config.c | 28 ++++++++++++++++++++++++---- |
| include/uapi/linux/usb/ch9.h | 3 +++ |
| 2 files changed, 27 insertions(+), 4 deletions(-) |
| |
| --- a/drivers/usb/core/config.c |
| +++ b/drivers/usb/core/config.c |
| @@ -905,14 +905,25 @@ 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, |
| + [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 */ |
| int usb_get_bos_descriptor(struct usb_device *dev) |
| { |
| struct device *ddev = &dev->dev; |
| struct usb_bos_descriptor *bos; |
| struct usb_dev_cap_header *cap; |
| + struct usb_ssp_cap_descriptor *ssp_cap; |
| unsigned char *buffer; |
| - int length, total_len, num, i; |
| + int length, total_len, num, i, ssac; |
| + __u8 cap_type; |
| int ret; |
| |
| bos = kzalloc(sizeof(struct usb_bos_descriptor), GFP_KERNEL); |
| @@ -965,7 +976,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) { |
| @@ -973,7 +990,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; |
| @@ -986,8 +1003,11 @@ int usb_get_bos_descriptor(struct usb_de |
| (struct usb_ss_cap_descriptor *)buffer; |
| break; |
| case USB_SSP_CAP_TYPE: |
| - dev->bos->ssp_cap = |
| - (struct usb_ssp_cap_descriptor *)buffer; |
| + ssp_cap = (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; |
| case CONTAINER_ID_TYPE: |
| dev->bos->ss_id = |
| --- a/include/uapi/linux/usb/ch9.h |
| +++ b/include/uapi/linux/usb/ch9.h |
| @@ -876,6 +876,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 |
| |
| @@ -1068,6 +1070,7 @@ struct usb_ptm_cap_descriptor { |
| __u8 bDevCapabilityType; |
| } __attribute__((packed)); |
| |
| +#define USB_DT_USB_PTM_ID_SIZE 3 |
| /* |
| * The size of the descriptor for the Sublink Speed Attribute Count |
| * (SSAC) specified in bmAttributes[4:0]. |