ChangeSet 1.1315.8.24, 2003/09/17 17:59:40-07:00, stern@rowland.harvard.edu [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. drivers/usb/core/config.c | 76 ++++++++++++++++++++++------------------------ 1 files changed, 37 insertions(+), 39 deletions(-) diff -Nru a/drivers/usb/core/config.c b/drivers/usb/core/config.c --- a/drivers/usb/core/config.c Fri Sep 19 17:09:44 2003 +++ b/drivers/usb/core/config.c Fri Sep 19 17:09:44 2003 @@ -37,23 +37,15 @@ buffer += header->bLength; size -= header->bLength; - /* Skip over the rest of the Class Specific or Vendor Specific */ - /* descriptors */ + /* Skip over any Class Specific or Vendor Specific descriptors */ begin = buffer; numskipped = 0; while (size >= sizeof(struct usb_descriptor_header)) { 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 ((header->bDescriptorType == USB_DT_ENDPOINT) || - (header->bDescriptorType == USB_DT_INTERFACE) || - (header->bDescriptorType == USB_DT_CONFIG) || - (header->bDescriptorType == USB_DT_DEVICE)) + (header->bDescriptorType == USB_DT_INTERFACE)) break; dbg("skipping descriptor 0x%X", header->bDescriptorType); @@ -155,27 +147,18 @@ memcpy(&ifp->desc, buffer, USB_DT_INTERFACE_SIZE); - /* Skip over the interface */ buffer += ifp->desc.bLength; size -= ifp->desc.bLength; + /* Skip over any Class Specific or Vendor Specific descriptors */ begin = buffer; numskipped = 0; - - /* Skip over any interface, class or vendor descriptors */ while (size >= sizeof(struct usb_descriptor_header)) { 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 ((header->bDescriptorType == USB_DT_INTERFACE) || - (header->bDescriptorType == USB_DT_ENDPOINT) || - (header->bDescriptorType == USB_DT_CONFIG) || - (header->bDescriptorType == USB_DT_DEVICE)) + (header->bDescriptorType == USB_DT_ENDPOINT)) break; dbg("skipping descriptor 0x%X", header->bDescriptorType); @@ -184,7 +167,6 @@ buffer += header->bLength; size -= header->bLength; } - if (numskipped) { dbg("skipped %d class/vendor specific interface descriptors", numskipped); @@ -201,13 +183,6 @@ 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) { warn("too many endpoints"); return -EINVAL; @@ -249,11 +224,13 @@ int usb_parse_configuration(struct usb_host_config *config, char *buffer) { int nintf; - int i, size; + int i, j, size; struct usb_interface *interface; + char *buffer2; + int size2; + struct usb_descriptor_header *header; int numskipped, len; char *begin; - struct usb_descriptor_header *header; int retval; memcpy(&config->desc, buffer, USB_DT_CONFIG_SIZE); @@ -283,6 +260,34 @@ 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; size -= config->desc.bLength; @@ -292,16 +297,9 @@ while (size >= sizeof(struct usb_descriptor_header)) { 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 ((header->bDescriptorType == USB_DT_ENDPOINT) || - (header->bDescriptorType == USB_DT_INTERFACE) || - (header->bDescriptorType == USB_DT_CONFIG) || - (header->bDescriptorType == USB_DT_DEVICE)) + (header->bDescriptorType == USB_DT_INTERFACE)) break; dbg("skipping descriptor 0x%X", header->bDescriptorType);