]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
USB: fix bugs in usb_(de)authorize_device
authorAlan Stern <stern@rowland.harvard.edu>
Tue, 8 Dec 2009 20:54:44 +0000 (15:54 -0500)
committerGreg Kroah-Hartman <gregkh@suse.de>
Wed, 6 Jan 2010 23:03:46 +0000 (15:03 -0800)
commit da307123c621b01cce147a4be313d8a754674f63 upstream.

This patch (as1315) fixes some bugs in the USB core authorization
code:

usb_deauthorize_device() should deallocate the device strings
instead of leaking them, and it should invoke
usb_destroy_configuration() (which does proper reference
counting) instead of freeing the config information directly.

usb_authorize_device() shouldn't change the device strings
until it knows that the authorization will succeed, and it should
autosuspend the device at the end (having autoresumed the
device at the start).

Because the device strings can be changed, the sysfs routines
to display the strings must protect the string pointers by
locking the device.

Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
CC: Inaky Perez-Gonzalez <inaky@linux.intel.com>
Acked-by: David Vrabel <david.vrabel@csr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/usb/core/hub.c
drivers/usb/core/sysfs.c

index 276fc688f98d3190218782dc335e01348e146093..8b0c2350d95159aeb1ed6a540d0bb43b75e74a7a 100644 (file)
@@ -1803,21 +1803,23 @@ fail:
  */
 int usb_deauthorize_device(struct usb_device *usb_dev)
 {
-       unsigned cnt;
        usb_lock_device(usb_dev);
        if (usb_dev->authorized == 0)
                goto out_unauthorized;
+
        usb_dev->authorized = 0;
        usb_set_configuration(usb_dev, -1);
+
+       kfree(usb_dev->product);
        usb_dev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+       kfree(usb_dev->manufacturer);
        usb_dev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+       kfree(usb_dev->serial);
        usb_dev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL);
-       kfree(usb_dev->config);
-       usb_dev->config = NULL;
-       for (cnt = 0; cnt < usb_dev->descriptor.bNumConfigurations; cnt++)
-               kfree(usb_dev->rawdescriptors[cnt]);
+
+       usb_destroy_configuration(usb_dev);
        usb_dev->descriptor.bNumConfigurations = 0;
-       kfree(usb_dev->rawdescriptors);
+
 out_unauthorized:
        usb_unlock_device(usb_dev);
        return 0;
@@ -1827,15 +1829,11 @@ out_unauthorized:
 int usb_authorize_device(struct usb_device *usb_dev)
 {
        int result = 0, c;
+
        usb_lock_device(usb_dev);
        if (usb_dev->authorized == 1)
                goto out_authorized;
-       kfree(usb_dev->product);
-       usb_dev->product = NULL;
-       kfree(usb_dev->manufacturer);
-       usb_dev->manufacturer = NULL;
-       kfree(usb_dev->serial);
-       usb_dev->serial = NULL;
+
        result = usb_autoresume_device(usb_dev);
        if (result < 0) {
                dev_err(&usb_dev->dev,
@@ -1848,6 +1846,14 @@ int usb_authorize_device(struct usb_device *usb_dev)
                        "authorization: %d\n", result);
                goto error_device_descriptor;
        }
+
+       kfree(usb_dev->product);
+       usb_dev->product = NULL;
+       kfree(usb_dev->manufacturer);
+       usb_dev->manufacturer = NULL;
+       kfree(usb_dev->serial);
+       usb_dev->serial = NULL;
+
        usb_dev->authorized = 1;
        result = usb_enumerate_device(usb_dev);
        if (result < 0)
@@ -1866,8 +1872,10 @@ int usb_authorize_device(struct usb_device *usb_dev)
                }
        }
        dev_info(&usb_dev->dev, "authorized to connect\n");
+
 error_enumerate:
 error_device_descriptor:
+       usb_autosuspend_device(usb_dev);
 error_autoresume:
 out_authorized:
        usb_unlock_device(usb_dev);     // complements locktree
index 7ec3041ae79ec7c2789193d44cdab5c83e904b0f..8752e5532369a00d68890ad7e98e3551c652f1bf 100644 (file)
@@ -82,9 +82,13 @@ static ssize_t  show_##name(struct device *dev,                              \
                struct device_attribute *attr, char *buf)               \
 {                                                                      \
        struct usb_device *udev;                                        \
+       int retval;                                                     \
                                                                        \
        udev = to_usb_device(dev);                                      \
-       return sprintf(buf, "%s\n", udev->name);                        \
+       usb_lock_device(udev);                                          \
+       retval = sprintf(buf, "%s\n", udev->name);                      \
+       usb_unlock_device(udev);                                        \
+       return retval;                                                  \
 }                                                                      \
 static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL);