Skip to content

Commit

Permalink
USB: core: Add type-specific length check of BOS descriptors
Browse files Browse the repository at this point in the history
commit 81cf4a4 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>
  • Loading branch information
Masakazu Mokuno authored and Greg Kroah-Hartman committed Dec 9, 2017
1 parent 34ba2f0 commit 05ffc7e
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 4 deletions.
28 changes: 24 additions & 4 deletions drivers/usb/core/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -900,14 +900,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 */
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);
Expand Down Expand Up @@ -960,15 +971,21 @@ int usb_get_bos_descriptor(struct usb_device *dev)
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) {
dev_warn(ddev, "descriptor type invalid, skip\n");
continue;
}

switch (cap->bDevCapabilityType) {
switch (cap_type) {
case USB_CAP_TYPE_WIRELESS_USB:
/* Wireless USB cap descriptor is handled by wusb */
break;
Expand All @@ -981,8 +998,11 @@ int usb_get_bos_descriptor(struct usb_device *dev)
(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 =
Expand Down
3 changes: 3 additions & 0 deletions include/uapi/linux/usb/ch9.h
Original file line number Diff line number Diff line change
Expand Up @@ -854,6 +854,8 @@ struct usb_wireless_cap_descriptor { /* Ultra Wide Band */
__u8 bReserved;
} __attribute__((packed));

#define USB_DT_USB_WIRELESS_CAP_SIZE 11

/* USB 2.0 Extension descriptor */
#define USB_CAP_TYPE_EXT 2

Expand Down Expand Up @@ -1046,6 +1048,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].
Expand Down

0 comments on commit 05ffc7e

Please sign in to comment.