ChangeSet 1.1315.8.21, 2003/09/17 17:08:46-07:00, stern@rowland.harvard.edu [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. drivers/usb/core/config.c | 41 +++++++++++++++++++---------------------- 1 files changed, 19 insertions(+), 22 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:10:34 2003 +++ b/drivers/usb/core/config.c Fri Sep 19 17:10:34 2003 @@ -134,12 +134,6 @@ interface->act_altsetting = 0; interface->num_altsetting = 0; 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, GFP_KERNEL); @@ -284,6 +278,7 @@ int usb_parse_configuration(struct usb_host_config *config, char *buffer) { int i, size; + struct usb_interface *interface; int retval = -EINVAL; struct usb_descriptor_header *header; @@ -296,18 +291,23 @@ if (config->desc.bNumInterfaces > USB_MAXINTERFACES) { warn("too many interfaces"); - goto error; + return -EINVAL; } for (i = 0; i < config->desc.bNumInterfaces; ++i) { - config->interface[i] = kmalloc(sizeof(struct usb_interface), GFP_KERNEL); - dbg("kmalloc IF %p, numif %i", config->interface[i], i); - if (!config->interface[i]) { + interface = config->interface[i] = + kmalloc(sizeof(struct usb_interface), GFP_KERNEL); + dbg("kmalloc IF %p, numif %i", interface, i); + if (!interface) { err("out of memory"); - retval = -ENOMEM; - goto error; + return -ENOMEM; } - 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; @@ -376,10 +376,6 @@ } 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. @@ -401,13 +397,13 @@ for (c = 0; c < dev->descriptor.bNumConfigurations; c++) { struct usb_host_config *cf = &dev->config[c]; - if (!cf->interface) - break; - for (i = 0; i < cf->desc.bNumInterfaces; i++) { struct usb_interface *ifp = cf->interface[i]; - put_device(&ifp->dev); + + if (ifp) + put_device(&ifp->dev); } + kfree(cf->extra); } kfree(dev->config); } @@ -449,6 +445,7 @@ err("out of memory"); return -ENOMEM; } + memset(dev->rawdescriptors, 0, sizeof(char *) * dev->descriptor.bNumConfigurations); buffer = kmalloc(8, GFP_KERNEL); if (!buffer) { @@ -502,7 +499,7 @@ if (result > 0) dbg("descriptor data left"); else if (result < 0) { - result = -EINVAL; + ++cfgno; goto err; } }