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, 23 Dec 2009 19:34:10 +0000 (11:34 -0800)
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>
Cc: stable <stable@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/usb/core/hub.c
drivers/usb/core/sysfs.c

index 28738fa17afb697a4e037f9ff40a074ad95394d9..0cec6caf6e9b26ca385927c6e6b19b67fabbfae2 100644 (file)
@@ -1849,21 +1849,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;
@@ -1873,15 +1875,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,
@@ -1894,6 +1892,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)
@@ -1912,8 +1918,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 15477008b63179fdd3f28443c508653be74a744e..485edf937f257ae846b921eae465f2655841f1b7 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);