Commit 8fc9363d authored by Alan Stern's avatar Alan Stern Committed by Greg Kroah-Hartman

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

This patch fixes the most blatant problems that can happen when an error
is encountered during descriptor parsing.

	The struct device embedded within a struct usb_interface is
initialized as soon as the structure is allocated, so that when
put_device() is called it will contain valid data.

	put_device() is not called for unallocated interfaces.

	The pointers in config->extra are freed when the struct
usb_host_config is freed.

	rawdescriptor pointers are initialized to 0 so that they can be
freed without error.

	Partially parsed configurations are remembered so that they will
be deallocated when the entire struct usb_device is freed.
parent 94e549ea
...@@ -134,12 +134,6 @@ static int usb_parse_interface(struct usb_interface *interface, unsigned char *b ...@@ -134,12 +134,6 @@ static int usb_parse_interface(struct usb_interface *interface, unsigned char *b
interface->act_altsetting = 0; interface->act_altsetting = 0;
interface->num_altsetting = 0; interface->num_altsetting = 0;
interface->max_altsetting = USB_ALTSETTINGALLOC; interface->max_altsetting = USB_ALTSETTINGALLOC;
device_initialize(&interface->dev);
interface->dev.release = usb_release_intf;
/* put happens in usb_destroy_configuration */
get_device(&interface->dev);
interface->altsetting = kmalloc(sizeof(*interface->altsetting) * interface->max_altsetting, interface->altsetting = kmalloc(sizeof(*interface->altsetting) * interface->max_altsetting,
GFP_KERNEL); GFP_KERNEL);
...@@ -284,6 +278,7 @@ static int usb_parse_interface(struct usb_interface *interface, unsigned char *b ...@@ -284,6 +278,7 @@ 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 i, size; int i, size;
struct usb_interface *interface;
int retval = -EINVAL; int retval = -EINVAL;
struct usb_descriptor_header *header; struct usb_descriptor_header *header;
...@@ -296,18 +291,23 @@ int usb_parse_configuration(struct usb_host_config *config, char *buffer) ...@@ -296,18 +291,23 @@ int usb_parse_configuration(struct usb_host_config *config, char *buffer)
if (config->desc.bNumInterfaces > USB_MAXINTERFACES) { if (config->desc.bNumInterfaces > USB_MAXINTERFACES) {
warn("too many interfaces"); warn("too many interfaces");
goto error; return -EINVAL;
} }
for (i = 0; i < config->desc.bNumInterfaces; ++i) { for (i = 0; i < config->desc.bNumInterfaces; ++i) {
config->interface[i] = kmalloc(sizeof(struct usb_interface), GFP_KERNEL); interface = config->interface[i] =
dbg("kmalloc IF %p, numif %i", config->interface[i], i); kmalloc(sizeof(struct usb_interface), GFP_KERNEL);
if (!config->interface[i]) { dbg("kmalloc IF %p, numif %i", interface, i);
if (!interface) {
err("out of memory"); err("out of memory");
retval = -ENOMEM; return -ENOMEM;
goto error;
} }
memset(config->interface[i], 0x00, sizeof(struct usb_interface)); memset(interface, 0, sizeof(struct usb_interface));
interface->dev.release = usb_release_intf;
device_initialize(&interface->dev);
/* put happens in usb_destroy_configuration */
get_device(&interface->dev);
} }
buffer += config->desc.bLength; buffer += config->desc.bLength;
...@@ -376,10 +376,6 @@ int usb_parse_configuration(struct usb_host_config *config, char *buffer) ...@@ -376,10 +376,6 @@ int usb_parse_configuration(struct usb_host_config *config, char *buffer)
} }
return size; return size;
error:
for (i = 0; i < USB_MAXINTERFACES; ++i)
kfree(config->interface[i]);
return retval;
} }
// hub-only!! ... and only exported for reset/reinit path. // hub-only!! ... and only exported for reset/reinit path.
...@@ -401,13 +397,13 @@ void usb_destroy_configuration(struct usb_device *dev) ...@@ -401,13 +397,13 @@ void usb_destroy_configuration(struct usb_device *dev)
for (c = 0; c < dev->descriptor.bNumConfigurations; c++) { for (c = 0; c < dev->descriptor.bNumConfigurations; c++) {
struct usb_host_config *cf = &dev->config[c]; struct usb_host_config *cf = &dev->config[c];
if (!cf->interface)
break;
for (i = 0; i < cf->desc.bNumInterfaces; i++) { for (i = 0; i < cf->desc.bNumInterfaces; i++) {
struct usb_interface *ifp = cf->interface[i]; struct usb_interface *ifp = cf->interface[i];
put_device(&ifp->dev);
if (ifp)
put_device(&ifp->dev);
} }
kfree(cf->extra);
} }
kfree(dev->config); kfree(dev->config);
} }
...@@ -449,6 +445,7 @@ int usb_get_configuration(struct usb_device *dev) ...@@ -449,6 +445,7 @@ int usb_get_configuration(struct usb_device *dev)
err("out of memory"); err("out of memory");
return -ENOMEM; return -ENOMEM;
} }
memset(dev->rawdescriptors, 0, sizeof(char *) * dev->descriptor.bNumConfigurations);
buffer = kmalloc(8, GFP_KERNEL); buffer = kmalloc(8, GFP_KERNEL);
if (!buffer) { if (!buffer) {
...@@ -502,7 +499,7 @@ int usb_get_configuration(struct usb_device *dev) ...@@ -502,7 +499,7 @@ int usb_get_configuration(struct usb_device *dev)
if (result > 0) if (result > 0)
dbg("descriptor data left"); dbg("descriptor data left");
else if (result < 0) { else if (result < 0) {
result = -EINVAL; ++cfgno;
goto err; goto err;
} }
} }
......
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