Commit 9e9f9f31 authored by Alan Stern's avatar Alan Stern Committed by Greg Kroah-Hartman

USB: validate wMaxPacketValue entries in endpoint descriptors

commit aed9d65a upstream.

Erroneous or malicious endpoint descriptors may have non-zero bits in
reserved positions, or out-of-bounds values.  This patch helps prevent
these from causing problems by bounds-checking the wMaxPacketValue
entries in endpoint descriptors and capping the values at the maximum
allowed.

This issue was first discovered and tests were conducted by Jake Lamberson
<jake.lamberson1@gmail.com>, an intern working for Rosie Hall.
Signed-off-by: default avatarAlan Stern <stern@rowland.harvard.edu>
Reported-by: default avatarroswest <roswest@cisco.com>
Tested-by: default avatarroswest <roswest@cisco.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 857acd14
...@@ -171,6 +171,31 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno, ...@@ -171,6 +171,31 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
ep, buffer, size); ep, buffer, size);
} }
static const unsigned short low_speed_maxpacket_maxes[4] = {
[USB_ENDPOINT_XFER_CONTROL] = 8,
[USB_ENDPOINT_XFER_ISOC] = 0,
[USB_ENDPOINT_XFER_BULK] = 0,
[USB_ENDPOINT_XFER_INT] = 8,
};
static const unsigned short full_speed_maxpacket_maxes[4] = {
[USB_ENDPOINT_XFER_CONTROL] = 64,
[USB_ENDPOINT_XFER_ISOC] = 1023,
[USB_ENDPOINT_XFER_BULK] = 64,
[USB_ENDPOINT_XFER_INT] = 64,
};
static const unsigned short high_speed_maxpacket_maxes[4] = {
[USB_ENDPOINT_XFER_CONTROL] = 64,
[USB_ENDPOINT_XFER_ISOC] = 1024,
[USB_ENDPOINT_XFER_BULK] = 512,
[USB_ENDPOINT_XFER_INT] = 1023,
};
static const unsigned short super_speed_maxpacket_maxes[4] = {
[USB_ENDPOINT_XFER_CONTROL] = 512,
[USB_ENDPOINT_XFER_ISOC] = 1024,
[USB_ENDPOINT_XFER_BULK] = 1024,
[USB_ENDPOINT_XFER_INT] = 1024,
};
static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
int asnum, struct usb_host_interface *ifp, int num_ep, int asnum, struct usb_host_interface *ifp, int num_ep,
unsigned char *buffer, int size) unsigned char *buffer, int size)
...@@ -179,6 +204,8 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, ...@@ -179,6 +204,8 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
struct usb_endpoint_descriptor *d; struct usb_endpoint_descriptor *d;
struct usb_host_endpoint *endpoint; struct usb_host_endpoint *endpoint;
int n, i, j, retval; int n, i, j, retval;
unsigned int maxp;
const unsigned short *maxpacket_maxes;
d = (struct usb_endpoint_descriptor *) buffer; d = (struct usb_endpoint_descriptor *) buffer;
buffer += d->bLength; buffer += d->bLength;
...@@ -286,6 +313,42 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, ...@@ -286,6 +313,42 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
endpoint->desc.wMaxPacketSize = cpu_to_le16(8); endpoint->desc.wMaxPacketSize = cpu_to_le16(8);
} }
/* Validate the wMaxPacketSize field */
maxp = usb_endpoint_maxp(&endpoint->desc);
/* Find the highest legal maxpacket size for this endpoint */
i = 0; /* additional transactions per microframe */
switch (to_usb_device(ddev)->speed) {
case USB_SPEED_LOW:
maxpacket_maxes = low_speed_maxpacket_maxes;
break;
case USB_SPEED_FULL:
maxpacket_maxes = full_speed_maxpacket_maxes;
break;
case USB_SPEED_HIGH:
/* Bits 12..11 are allowed only for HS periodic endpoints */
if (usb_endpoint_xfer_int(d) || usb_endpoint_xfer_isoc(d)) {
i = maxp & (BIT(12) | BIT(11));
maxp &= ~i;
}
/* fallthrough */
default:
maxpacket_maxes = high_speed_maxpacket_maxes;
break;
case USB_SPEED_SUPER:
case USB_SPEED_SUPER_PLUS:
maxpacket_maxes = super_speed_maxpacket_maxes;
break;
}
j = maxpacket_maxes[usb_endpoint_type(&endpoint->desc)];
if (maxp > j) {
dev_warn(ddev, "config %d interface %d altsetting %d endpoint 0x%X has invalid maxpacket %d, setting to %d\n",
cfgno, inum, asnum, d->bEndpointAddress, maxp, j);
maxp = j;
endpoint->desc.wMaxPacketSize = cpu_to_le16(i | maxp);
}
/* /*
* Some buggy high speed devices have bulk endpoints using * Some buggy high speed devices have bulk endpoints using
* maxpacket sizes other than 512. High speed HCDs may not * maxpacket sizes other than 512. High speed HCDs may not
...@@ -293,9 +356,6 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, ...@@ -293,9 +356,6 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
*/ */
if (to_usb_device(ddev)->speed == USB_SPEED_HIGH if (to_usb_device(ddev)->speed == USB_SPEED_HIGH
&& usb_endpoint_xfer_bulk(d)) { && usb_endpoint_xfer_bulk(d)) {
unsigned maxp;
maxp = usb_endpoint_maxp(&endpoint->desc) & 0x07ff;
if (maxp != 512) if (maxp != 512)
dev_warn(ddev, "config %d interface %d altsetting %d " dev_warn(ddev, "config %d interface %d altsetting %d "
"bulk endpoint 0x%X has invalid maxpacket %d\n", "bulk endpoint 0x%X has invalid maxpacket %d\n",
......
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