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

USB: fix bugs in usb_(de)authorize_device

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: default avatarAlan Stern <stern@rowland.harvard.edu>
CC: Inaky Perez-Gonzalez <inaky@linux.intel.com>
Acked-by: default avatarDavid Vrabel <david.vrabel@csr.com>
Cc: stable <stable@kernel.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 8d8558d1
...@@ -1849,21 +1849,23 @@ int usb_new_device(struct usb_device *udev) ...@@ -1849,21 +1849,23 @@ int usb_new_device(struct usb_device *udev)
*/ */
int usb_deauthorize_device(struct usb_device *usb_dev) int usb_deauthorize_device(struct usb_device *usb_dev)
{ {
unsigned cnt;
usb_lock_device(usb_dev); usb_lock_device(usb_dev);
if (usb_dev->authorized == 0) if (usb_dev->authorized == 0)
goto out_unauthorized; goto out_unauthorized;
usb_dev->authorized = 0; usb_dev->authorized = 0;
usb_set_configuration(usb_dev, -1); usb_set_configuration(usb_dev, -1);
kfree(usb_dev->product);
usb_dev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL); usb_dev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL);
kfree(usb_dev->manufacturer);
usb_dev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL); usb_dev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL);
kfree(usb_dev->serial);
usb_dev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL); usb_dev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL);
kfree(usb_dev->config);
usb_dev->config = NULL; usb_destroy_configuration(usb_dev);
for (cnt = 0; cnt < usb_dev->descriptor.bNumConfigurations; cnt++)
kfree(usb_dev->rawdescriptors[cnt]);
usb_dev->descriptor.bNumConfigurations = 0; usb_dev->descriptor.bNumConfigurations = 0;
kfree(usb_dev->rawdescriptors);
out_unauthorized: out_unauthorized:
usb_unlock_device(usb_dev); usb_unlock_device(usb_dev);
return 0; return 0;
...@@ -1873,15 +1875,11 @@ int usb_deauthorize_device(struct usb_device *usb_dev) ...@@ -1873,15 +1875,11 @@ int usb_deauthorize_device(struct usb_device *usb_dev)
int usb_authorize_device(struct usb_device *usb_dev) int usb_authorize_device(struct usb_device *usb_dev)
{ {
int result = 0, c; int result = 0, c;
usb_lock_device(usb_dev); usb_lock_device(usb_dev);
if (usb_dev->authorized == 1) if (usb_dev->authorized == 1)
goto out_authorized; 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); result = usb_autoresume_device(usb_dev);
if (result < 0) { if (result < 0) {
dev_err(&usb_dev->dev, dev_err(&usb_dev->dev,
...@@ -1894,6 +1892,14 @@ int usb_authorize_device(struct usb_device *usb_dev) ...@@ -1894,6 +1892,14 @@ int usb_authorize_device(struct usb_device *usb_dev)
"authorization: %d\n", result); "authorization: %d\n", result);
goto error_device_descriptor; 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; usb_dev->authorized = 1;
result = usb_enumerate_device(usb_dev); result = usb_enumerate_device(usb_dev);
if (result < 0) if (result < 0)
...@@ -1912,8 +1918,10 @@ int usb_authorize_device(struct usb_device *usb_dev) ...@@ -1912,8 +1918,10 @@ int usb_authorize_device(struct usb_device *usb_dev)
} }
} }
dev_info(&usb_dev->dev, "authorized to connect\n"); dev_info(&usb_dev->dev, "authorized to connect\n");
error_enumerate: error_enumerate:
error_device_descriptor: error_device_descriptor:
usb_autosuspend_device(usb_dev);
error_autoresume: error_autoresume:
out_authorized: out_authorized:
usb_unlock_device(usb_dev); // complements locktree usb_unlock_device(usb_dev); // complements locktree
......
...@@ -82,9 +82,13 @@ static ssize_t show_##name(struct device *dev, \ ...@@ -82,9 +82,13 @@ static ssize_t show_##name(struct device *dev, \
struct device_attribute *attr, char *buf) \ struct device_attribute *attr, char *buf) \
{ \ { \
struct usb_device *udev; \ struct usb_device *udev; \
int retval; \
\ \
udev = to_usb_device(dev); \ 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); static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL);
......
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