Commit 5446ab92 authored by Alan Stern's avatar Alan Stern Committed by Greg Kroah-Hartman

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

This patch centralizes the error checking for invalid descriptor lengths
and unexpected descriptor types.  Instead of doing it in three different
places -- while parsing configuration, interface, and endpoint descriptors
-- the new code does it all at once.  Not surprisingly, this yields a net
savings in code size.
parent 43345b84
...@@ -37,23 +37,15 @@ static int usb_parse_endpoint(struct usb_host_endpoint *endpoint, unsigned char ...@@ -37,23 +37,15 @@ static int usb_parse_endpoint(struct usb_host_endpoint *endpoint, unsigned char
buffer += header->bLength; buffer += header->bLength;
size -= header->bLength; size -= header->bLength;
/* Skip over the rest of the Class Specific or Vendor Specific */ /* Skip over any Class Specific or Vendor Specific descriptors */
/* descriptors */
begin = buffer; begin = buffer;
numskipped = 0; numskipped = 0;
while (size >= sizeof(struct usb_descriptor_header)) { while (size >= sizeof(struct usb_descriptor_header)) {
header = (struct usb_descriptor_header *)buffer; header = (struct usb_descriptor_header *)buffer;
if (header->bLength < 2) {
err("invalid descriptor length of %d", header->bLength);
return -EINVAL;
}
/* If we find another "proper" descriptor then we're done */ /* If we find another "proper" descriptor then we're done */
if ((header->bDescriptorType == USB_DT_ENDPOINT) || if ((header->bDescriptorType == USB_DT_ENDPOINT) ||
(header->bDescriptorType == USB_DT_INTERFACE) || (header->bDescriptorType == USB_DT_INTERFACE))
(header->bDescriptorType == USB_DT_CONFIG) ||
(header->bDescriptorType == USB_DT_DEVICE))
break; break;
dbg("skipping descriptor 0x%X", header->bDescriptorType); dbg("skipping descriptor 0x%X", header->bDescriptorType);
...@@ -155,27 +147,18 @@ static int usb_parse_interface(struct usb_interface *interface, unsigned char *b ...@@ -155,27 +147,18 @@ static int usb_parse_interface(struct usb_interface *interface, unsigned char *b
memcpy(&ifp->desc, buffer, USB_DT_INTERFACE_SIZE); memcpy(&ifp->desc, buffer, USB_DT_INTERFACE_SIZE);
/* Skip over the interface */
buffer += ifp->desc.bLength; buffer += ifp->desc.bLength;
size -= ifp->desc.bLength; size -= ifp->desc.bLength;
/* Skip over any Class Specific or Vendor Specific descriptors */
begin = buffer; begin = buffer;
numskipped = 0; numskipped = 0;
/* Skip over any interface, class or vendor descriptors */
while (size >= sizeof(struct usb_descriptor_header)) { while (size >= sizeof(struct usb_descriptor_header)) {
header = (struct usb_descriptor_header *)buffer; header = (struct usb_descriptor_header *)buffer;
if (header->bLength < 2) {
err("invalid descriptor length of %d", header->bLength);
return -EINVAL;
}
/* If we find another "proper" descriptor then we're done */ /* If we find another "proper" descriptor then we're done */
if ((header->bDescriptorType == USB_DT_INTERFACE) || if ((header->bDescriptorType == USB_DT_INTERFACE) ||
(header->bDescriptorType == USB_DT_ENDPOINT) || (header->bDescriptorType == USB_DT_ENDPOINT))
(header->bDescriptorType == USB_DT_CONFIG) ||
(header->bDescriptorType == USB_DT_DEVICE))
break; break;
dbg("skipping descriptor 0x%X", header->bDescriptorType); dbg("skipping descriptor 0x%X", header->bDescriptorType);
...@@ -184,7 +167,6 @@ static int usb_parse_interface(struct usb_interface *interface, unsigned char *b ...@@ -184,7 +167,6 @@ static int usb_parse_interface(struct usb_interface *interface, unsigned char *b
buffer += header->bLength; buffer += header->bLength;
size -= header->bLength; size -= header->bLength;
} }
if (numskipped) { if (numskipped) {
dbg("skipped %d class/vendor specific interface descriptors", numskipped); dbg("skipped %d class/vendor specific interface descriptors", numskipped);
...@@ -201,13 +183,6 @@ static int usb_parse_interface(struct usb_interface *interface, unsigned char *b ...@@ -201,13 +183,6 @@ static int usb_parse_interface(struct usb_interface *interface, unsigned char *b
ifp->extralen = len; ifp->extralen = len;
} }
/* Did we hit an unexpected descriptor? */
header = (struct usb_descriptor_header *)buffer;
if ((size >= sizeof(struct usb_descriptor_header)) &&
((header->bDescriptorType == USB_DT_CONFIG) ||
(header->bDescriptorType == USB_DT_DEVICE)))
break;
if (ifp->desc.bNumEndpoints > USB_MAXENDPOINTS) { if (ifp->desc.bNumEndpoints > USB_MAXENDPOINTS) {
warn("too many endpoints"); warn("too many endpoints");
return -EINVAL; return -EINVAL;
...@@ -249,11 +224,13 @@ static int usb_parse_interface(struct usb_interface *interface, unsigned char *b ...@@ -249,11 +224,13 @@ static int usb_parse_interface(struct usb_interface *interface, unsigned char *b
int usb_parse_configuration(struct usb_host_config *config, char *buffer) int usb_parse_configuration(struct usb_host_config *config, char *buffer)
{ {
int nintf; int nintf;
int i, size; int i, j, size;
struct usb_interface *interface; struct usb_interface *interface;
char *buffer2;
int size2;
struct usb_descriptor_header *header;
int numskipped, len; int numskipped, len;
char *begin; char *begin;
struct usb_descriptor_header *header;
int retval; int retval;
memcpy(&config->desc, buffer, USB_DT_CONFIG_SIZE); memcpy(&config->desc, buffer, USB_DT_CONFIG_SIZE);
...@@ -283,6 +260,34 @@ int usb_parse_configuration(struct usb_host_config *config, char *buffer) ...@@ -283,6 +260,34 @@ int usb_parse_configuration(struct usb_host_config *config, char *buffer)
get_device(&interface->dev); get_device(&interface->dev);
} }
/* Go through the descriptors, checking their length */
buffer2 = buffer;
size2 = size;
j = 0;
while (size2 >= sizeof(struct usb_descriptor_header)) {
header = (struct usb_descriptor_header *) buffer2;
if ((header->bLength > size2) || (header->bLength < 2)) {
err("invalid descriptor of length %d", header->bLength);
return -EINVAL;
}
if (header->bDescriptorType == USB_DT_INTERFACE) {
if (header->bLength < USB_DT_INTERFACE_SIZE) {
warn("invalid interface descriptor");
return -EINVAL;
}
} else if ((header->bDescriptorType == USB_DT_DEVICE ||
header->bDescriptorType == USB_DT_CONFIG) && j) {
warn("unexpected descriptor type 0x%X", header->bDescriptorType);
return -EINVAL;
}
j = 1;
buffer2 += header->bLength;
size2 -= header->bLength;
}
buffer += config->desc.bLength; buffer += config->desc.bLength;
size -= config->desc.bLength; size -= config->desc.bLength;
...@@ -292,16 +297,9 @@ int usb_parse_configuration(struct usb_host_config *config, char *buffer) ...@@ -292,16 +297,9 @@ int usb_parse_configuration(struct usb_host_config *config, char *buffer)
while (size >= sizeof(struct usb_descriptor_header)) { while (size >= sizeof(struct usb_descriptor_header)) {
header = (struct usb_descriptor_header *)buffer; header = (struct usb_descriptor_header *)buffer;
if ((header->bLength > size) || (header->bLength < 2)) {
err("invalid descriptor length of %d", header->bLength);
return -EINVAL;
}
/* If we find another "proper" descriptor then we're done */ /* If we find another "proper" descriptor then we're done */
if ((header->bDescriptorType == USB_DT_ENDPOINT) || if ((header->bDescriptorType == USB_DT_ENDPOINT) ||
(header->bDescriptorType == USB_DT_INTERFACE) || (header->bDescriptorType == USB_DT_INTERFACE))
(header->bDescriptorType == USB_DT_CONFIG) ||
(header->bDescriptorType == USB_DT_DEVICE))
break; break;
dbg("skipping descriptor 0x%X", header->bDescriptorType); dbg("skipping descriptor 0x%X", header->bDescriptorType);
......
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