Commit 69d7ab7d authored by Alan Stern's avatar Alan Stern Committed by Greg Kroah-Hartman

[PATCH] USB: Changes to core/config.c (8 of 9)

This patch adds some extra error checking.  The patch-comments list most
it.  Particularly worth noting is the check on the endpoint addresses.
Since these addresses are used as indexes for the epmaxpacketin and
epmaxpacketout arrays, illegal values could result in overwriting
unrelated areas of memory.

Other noteworthy checks involve interface and alsetting numbers.  Since
the old code ignored those values, of course it didn't bother to check
them.  Here we make sure that the numbers lie in the proper ranges and
that there are no "missing" entries.

 Add error checking and improved error messages:
   Check for invalid endpoint descriptors and invalid endpoint addresses.
   Check for duplicate interface/altsetting descriptors.
   Check for invalid configuration descriptors.
   Check for missing interface/altsetting descriptors.
parent 104cc087
...@@ -26,10 +26,20 @@ static int usb_parse_endpoint(struct usb_host_endpoint *endpoint, unsigned char ...@@ -26,10 +26,20 @@ static int usb_parse_endpoint(struct usb_host_endpoint *endpoint, unsigned char
return -EINVAL; return -EINVAL;
} }
if (header->bLength == USB_DT_ENDPOINT_AUDIO_SIZE) if (header->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE)
memcpy(&endpoint->desc, buffer, USB_DT_ENDPOINT_AUDIO_SIZE); memcpy(&endpoint->desc, buffer, USB_DT_ENDPOINT_AUDIO_SIZE);
else else if (header->bLength >= USB_DT_ENDPOINT_SIZE)
memcpy(&endpoint->desc, buffer, USB_DT_ENDPOINT_SIZE); memcpy(&endpoint->desc, buffer, USB_DT_ENDPOINT_SIZE);
else {
warn("invalid endpoint descriptor");
return -EINVAL;
}
if ((endpoint->desc.bEndpointAddress & ~USB_ENDPOINT_DIR_MASK) >= 16) {
warn("invalid endpoint address 0x%X",
endpoint->desc.bEndpointAddress);
return -EINVAL;
}
le16_to_cpus(&endpoint->desc.wMaxPacketSize); le16_to_cpus(&endpoint->desc.wMaxPacketSize);
...@@ -144,6 +154,11 @@ static int usb_parse_interface(struct usb_host_config *config, unsigned char *bu ...@@ -144,6 +154,11 @@ static int usb_parse_interface(struct usb_host_config *config, unsigned char *bu
} }
ifp = &interface->altsetting[asnum]; ifp = &interface->altsetting[asnum];
if (ifp->desc.bLength) {
warn("duplicate descriptor for interface %d altsetting %d",
inum, asnum);
return -EINVAL;
}
memcpy(&ifp->desc, buffer, USB_DT_INTERFACE_SIZE); memcpy(&ifp->desc, buffer, USB_DT_INTERFACE_SIZE);
buffer += d->bLength; buffer += d->bLength;
...@@ -183,7 +198,8 @@ static int usb_parse_interface(struct usb_host_config *config, unsigned char *bu ...@@ -183,7 +198,8 @@ static int usb_parse_interface(struct usb_host_config *config, unsigned char *bu
} }
if (ifp->desc.bNumEndpoints > USB_MAXENDPOINTS) { if (ifp->desc.bNumEndpoints > USB_MAXENDPOINTS) {
warn("too many endpoints"); warn("too many endpoints for interface %d altsetting %d",
inum, asnum);
return -EINVAL; return -EINVAL;
} }
...@@ -197,7 +213,7 @@ static int usb_parse_interface(struct usb_host_config *config, unsigned char *bu ...@@ -197,7 +213,7 @@ static int usb_parse_interface(struct usb_host_config *config, unsigned char *bu
for (i = 0; i < ifp->desc.bNumEndpoints; i++) { for (i = 0; i < ifp->desc.bNumEndpoints; i++) {
if (size < USB_DT_ENDPOINT_SIZE) { if (size < USB_DT_ENDPOINT_SIZE) {
err("ran out of descriptors parsing"); warn("ran out of descriptors while parsing endpoints");
return -EINVAL; return -EINVAL;
} }
...@@ -212,10 +228,10 @@ static int usb_parse_interface(struct usb_host_config *config, unsigned char *bu ...@@ -212,10 +228,10 @@ static int usb_parse_interface(struct usb_host_config *config, unsigned char *bu
return buffer - buffer0; return buffer - buffer0;
} }
int usb_parse_configuration(struct usb_host_config *config, char *buffer) int usb_parse_configuration(struct usb_host_config *config, char *buffer, int size)
{ {
int nintf, nintf_orig; int nintf, nintf_orig;
int i, j, size; int i, j;
struct usb_interface *interface; struct usb_interface *interface;
char *buffer2; char *buffer2;
int size2; int size2;
...@@ -225,8 +241,12 @@ int usb_parse_configuration(struct usb_host_config *config, char *buffer) ...@@ -225,8 +241,12 @@ int usb_parse_configuration(struct usb_host_config *config, char *buffer)
int retval; int retval;
memcpy(&config->desc, buffer, USB_DT_CONFIG_SIZE); memcpy(&config->desc, buffer, USB_DT_CONFIG_SIZE);
le16_to_cpus(&config->desc.wTotalLength); if (config->desc.bDescriptorType != USB_DT_CONFIG ||
size = config->desc.wTotalLength; config->desc.bLength < USB_DT_CONFIG_SIZE) {
warn("invalid configuration descriptor");
return -EINVAL;
}
config->desc.wTotalLength = size;
nintf = nintf_orig = config->desc.bNumInterfaces; nintf = nintf_orig = config->desc.bNumInterfaces;
if (nintf > USB_MAXINTERFACES) { if (nintf > USB_MAXINTERFACES) {
...@@ -259,7 +279,7 @@ int usb_parse_configuration(struct usb_host_config *config, char *buffer) ...@@ -259,7 +279,7 @@ int usb_parse_configuration(struct usb_host_config *config, char *buffer)
while (size2 >= sizeof(struct usb_descriptor_header)) { while (size2 >= sizeof(struct usb_descriptor_header)) {
header = (struct usb_descriptor_header *) buffer2; header = (struct usb_descriptor_header *) buffer2;
if ((header->bLength > size2) || (header->bLength < 2)) { if ((header->bLength > size2) || (header->bLength < 2)) {
err("invalid descriptor of length %d", header->bLength); warn("invalid descriptor of length %d", header->bLength);
return -EINVAL; return -EINVAL;
} }
...@@ -359,6 +379,17 @@ int usb_parse_configuration(struct usb_host_config *config, char *buffer) ...@@ -359,6 +379,17 @@ int usb_parse_configuration(struct usb_host_config *config, char *buffer)
size -= retval; size -= retval;
} }
/* Check for missing altsettings */
for (i = 0; i < nintf; ++i) {
interface = config->interface[i];
for (j = 0; j < interface->num_altsetting; ++j) {
if (!interface->altsetting[j].desc.bLength) {
warn("missing altsetting %d for interface %d", j, i);
return -EINVAL;
}
}
}
return size; return size;
} }
...@@ -446,14 +477,14 @@ int usb_get_configuration(struct usb_device *dev) ...@@ -446,14 +477,14 @@ int usb_get_configuration(struct usb_device *dev)
if (result < 0) if (result < 0)
err("unable to get descriptor"); err("unable to get descriptor");
else { else {
err("config descriptor too short (expected %i, got %i)", 8, result); warn("config descriptor too short (expected %i, got %i)", 8, result);
result = -EINVAL; result = -EINVAL;
} }
goto err; goto err;
} }
/* Get the full buffer */ /* Get the full buffer */
length = le16_to_cpu(desc->wTotalLength); length = max((int) le16_to_cpu(desc->wTotalLength), USB_DT_CONFIG_SIZE);
bigbuffer = kmalloc(length, GFP_KERNEL); bigbuffer = kmalloc(length, GFP_KERNEL);
if (!bigbuffer) { if (!bigbuffer) {
...@@ -479,7 +510,7 @@ int usb_get_configuration(struct usb_device *dev) ...@@ -479,7 +510,7 @@ int usb_get_configuration(struct usb_device *dev)
dev->rawdescriptors[cfgno] = bigbuffer; dev->rawdescriptors[cfgno] = bigbuffer;
result = usb_parse_configuration(&dev->config[cfgno], bigbuffer); result = usb_parse_configuration(&dev->config[cfgno], bigbuffer, length);
if (result > 0) if (result > 0)
dbg("descriptor data left"); dbg("descriptor data left");
else if (result < 0) { else if (result < 0) {
......
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