Everybody:
Here follows a set of changes for the descriptor parsing routines in
core/config.c, broken up into a set of 9 patches. The code isn't very
complex but it does require study, and I would appreciate people reading
through my changes to make sure there aren't any mistakes. Though perhaps
it would be best just to read the final version and not try to follow so
closely the individual changes in each patch. (Especially since some of
the intermediate versions contain slightly questionable code that gets
fixed up in later patches.)
The existing code works okay for devices that have no errors in their
descriptors and list them in the expected order. But it is fragile; it
does not always fail gracefully when encountering a device that doesn't
fit its assumptions. It can leak memory, call put_device() for
uninitialized struct devices, and try to free uninitialized pointers. It
doesn't check interface and altsetting values; if the device lists them
out of order they will be stored in the wrong locations. (Note: Although
the USB 2.0 spec mentions in what order a device having 2 interfaces (one
of which has 2 altsettings) _should_ list the descriptors, nowhere does it
say that devices _must_ use this ordering. And some real devices don't.)
Also, the Linux USB stack includes some arbitrary implementation limits on
the maximum number of configurations and interfaces per device; if a
device has too many of either it is rejected completely.
This set of changes fixes these problems. It adds extra error checking,
to make sure the data structures it constructs are consistent. And if a
device has more configurations or interfaces than we are prepared to
handle, the new code simply stores as many as it can and ignores the rest
(along with logging a warning message).
There is still room for improvement. For example, the size of the
initialized data area could be reduced by consolidating all the various
"out of memory" type error messages -- most of which don't convey much
useful information anyhow. But that's not as important as the changes
made in this series of patches.
This first patch makes only trivial changes. Excess whitespace at the end
of lines is removed and return codes are altered from -1 to symbolic error
values. The only significant difference is that in one spot a valid
return is changed to an error return, when a descriptor does not have the
correct type.
Alan Stern
# This is a BitKeeper generated patch for the following project:
# Project Name: greg k-h's linux 2.5 USB kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
# ChangeSet 1.1669 -> 1.1670
# drivers/usb/core/config.c 1.16 -> 1.17
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 03/09/15 [EMAIL PROTECTED] 1.1670
# Remove excess whitespace at the ends of lines.
# Change return codes to symbolic values.
# Return an error when an invalid endpoint descriptor is found.
# --------------------------------------------
#
diff -Nru a/drivers/usb/core/config.c b/drivers/usb/core/config.c
--- a/drivers/usb/core/config.c Mon Sep 15 10:50:21 2003
+++ b/drivers/usb/core/config.c Mon Sep 15 10:50:21 2003
@@ -25,20 +25,20 @@
/* check JIC */
if (header->bLength > size) {
err("ran out of descriptors parsing");
- return -1;
+ return -EINVAL;
}
-
+
if (header->bDescriptorType != USB_DT_ENDPOINT) {
warn("unexpected descriptor 0x%X, expecting endpoint, 0x%X",
header->bDescriptorType, USB_DT_ENDPOINT);
- return parsed;
+ return -EINVAL;
}
if (header->bLength == USB_DT_ENDPOINT_AUDIO_SIZE)
memcpy(&endpoint->desc, buffer, USB_DT_ENDPOINT_AUDIO_SIZE);
else
memcpy(&endpoint->desc, buffer, USB_DT_ENDPOINT_SIZE);
-
+
le16_to_cpus(&endpoint->desc.wMaxPacketSize);
buffer += header->bLength;
@@ -54,7 +54,7 @@
if (header->bLength < 2) {
err("invalid descriptor length of %d", header->bLength);
- return -1;
+ return -EINVAL;
}
/* If we find another "proper" descriptor then we're done */
@@ -139,18 +139,18 @@
/* put happens in usb_destroy_configuration */
get_device(&interface->dev);
-
+
interface->altsetting = kmalloc(sizeof(*interface->altsetting) *
interface->max_altsetting,
GFP_KERNEL);
-
+
if (!interface->altsetting) {
err("couldn't kmalloc interface->altsetting");
- return -1;
+ return -ENOMEM;
}
while (size > 0) {
struct usb_interface_descriptor *d;
-
+
if (interface->num_altsetting >= interface->max_altsetting) {
struct usb_host_interface *ptr;
int oldmas;
@@ -160,13 +160,13 @@
if (interface->max_altsetting > USB_MAXALTSETTING) {
warn("too many alternate settings (incr %d max %d)\n",
USB_ALTSETTINGALLOC, USB_MAXALTSETTING);
- return -1;
+ return -EINVAL;
}
ptr = kmalloc(sizeof(*ptr) * interface->max_altsetting,
GFP_KERNEL);
if (ptr == NULL) {
err("couldn't kmalloc interface->altsetting");
- return -1;
+ return -ENOMEM;
}
memcpy(ptr, interface->altsetting,
sizeof(*interface->altsetting) * oldmas);
kfree(interface->altsetting);
@@ -195,7 +195,7 @@
if (header->bLength < 2) {
err("invalid descriptor length of %d",
header->bLength);
- return -1;
+ return -EINVAL;
}
/* If we find another "proper" descriptor then we're done */
@@ -224,7 +224,7 @@
if (!ifp->extra) {
err("couldn't allocate memory for interface extra
descriptors");
ifp->extralen = 0;
- return -1;
+ return -ENOMEM;
}
memcpy(ifp->extra, begin, len);
ifp->extralen = len;
@@ -239,7 +239,7 @@
if (ifp->desc.bNumEndpoints > USB_MAXENDPOINTS) {
warn("too many endpoints");
- return -1;
+ return -EINVAL;
}
ifp->endpoint = (struct usb_host_endpoint *)
@@ -247,20 +247,20 @@
sizeof(struct usb_host_endpoint), GFP_KERNEL);
if (!ifp->endpoint) {
err("out of memory");
- return -1;
+ return -ENOMEM;
}
memset(ifp->endpoint, 0, ifp->desc.bNumEndpoints *
sizeof(struct usb_host_endpoint));
-
+
for (i = 0; i < ifp->desc.bNumEndpoints; i++) {
header = (struct usb_descriptor_header *)buffer;
if (header->bLength > size) {
err("ran out of descriptors parsing");
- return -1;
+ return -EINVAL;
}
-
+
retval = usb_parse_endpoint(ifp->endpoint + i, buffer, size);
if (retval < 0)
return retval;
@@ -312,7 +312,7 @@
buffer += config->desc.bLength;
size -= config->desc.bLength;
-
+
config->extra = NULL;
config->extralen = 0;
@@ -329,7 +329,7 @@
if ((header->bLength > size) || (header->bLength < 2)) {
err("invalid descriptor length of %d",
header->bLength);
- return -1;
+ return -EINVAL;
}
/* If we find another "proper" descriptor then we're done */
@@ -359,7 +359,7 @@
if (!config->extra) {
err("couldn't allocate memory for config extra
descriptors");
config->extralen = 0;
- return -1;
+ return -ENOMEM;
}
memcpy(config->extra, begin, len);
@@ -387,7 +387,7 @@
void usb_destroy_configuration(struct usb_device *dev)
{
int c, i;
-
+
if (!dev->config)
return;
@@ -438,7 +438,7 @@
sizeof(struct usb_host_config), GFP_KERNEL);
if (!dev->config) {
err("out of memory");
- return -ENOMEM;
+ return -ENOMEM;
}
memset(dev->config, 0, dev->descriptor.bNumConfigurations *
sizeof(struct usb_host_config));
@@ -487,8 +487,8 @@
err("couldn't get all of config descriptors");
kfree(bigbuffer);
goto err;
- }
-
+ }
+
if (result < length) {
err("config descriptor too short (expected %i, got %i)",
length, result);
result = -EINVAL;
-------------------------------------------------------
This sf.net email is sponsored by:ThinkGeek
Welcome to geek heaven.
http://thinkgeek.com/sf
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel