All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/1] UBUNTU: SAUCE: khubd -- switch USB product/manufacturer/serial handling to RCU
@ 2010-06-14 11:14 Andy Whitcroft
  2010-06-14 11:17 ` Andy Whitcroft
  0 siblings, 1 reply; 2+ messages in thread
From: Andy Whitcroft @ 2010-06-14 11:14 UTC (permalink / raw)
  To: Greg Kroah-Hartman, linux-usb
  Cc: Inaky Perez-Gonzalez, Andy Whitcroft, linux-kernel

With the introduction of wireless USB hubs the product, manufacturer,
and serial number are now mutable.  This necessitates new locking in the
consumers of these values including the sysfs read routines in order to
prevent use-after-free acces to these values.  These extra locks create
significant lock contention leading to increased boot times (0.3s for an
example Atom based system).  Move update of these values to RCU based
locking.

BugLink: http://bugs.launchpad.net/bugs/510937
Signed-off-by: Andy Whitcroft <apw@canonical.com>
---
 drivers/usb/core/hub.c   |   34 ++++++++++++++++++++++++++++------
 drivers/usb/core/sysfs.c |    6 +++---
 2 files changed, 31 insertions(+), 9 deletions(-)

diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 83e7bbb..6967421 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -24,6 +24,7 @@
 #include <linux/mutex.h>
 #include <linux/freezer.h>
 #include <linux/pm_runtime.h>
+#include <linux/rcupdate.h>
 
 #include <asm/uaccess.h>
 #include <asm/byteorder.h>
@@ -1849,6 +1850,10 @@ fail:
  */
 int usb_deauthorize_device(struct usb_device *usb_dev)
 {
+	char *product = NULL;
+	char *manufacturer = NULL;
+	char *serial = NULL;
+
 	usb_lock_device(usb_dev);
 	if (usb_dev->authorized == 0)
 		goto out_unauthorized;
@@ -1856,11 +1861,12 @@ int usb_deauthorize_device(struct usb_device *usb_dev)
 	usb_dev->authorized = 0;
 	usb_set_configuration(usb_dev, -1);
 
-	kfree(usb_dev->product);
+	product = usb_dev->product;
+	manufacturer = usb_dev->manufacturer;
+	serial = usb_dev->serial;
+
 	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);
 
 	usb_destroy_configuration(usb_dev);
@@ -1868,6 +1874,12 @@ int usb_deauthorize_device(struct usb_device *usb_dev)
 
 out_unauthorized:
 	usb_unlock_device(usb_dev);
+	if (product || manufacturer || serial) {
+		synchronize_rcu();
+		kfree(product);
+		kfree(manufacturer);
+		kfree(serial);
+	}
 	return 0;
 }
 
@@ -1875,6 +1887,9 @@ out_unauthorized:
 int usb_authorize_device(struct usb_device *usb_dev)
 {
 	int result = 0, c;
+	char *product = NULL;
+	char *manufacturer = NULL;
+	char *serial = NULL;
 
 	usb_lock_device(usb_dev);
 	if (usb_dev->authorized == 1)
@@ -1893,11 +1908,12 @@ int usb_authorize_device(struct usb_device *usb_dev)
 		goto error_device_descriptor;
 	}
 
-	kfree(usb_dev->product);
+	product = usb_dev->product;
+	manufacturer = usb_dev->manufacturer;
+	serial = usb_dev->serial;
+
 	usb_dev->product = NULL;
-	kfree(usb_dev->manufacturer);
 	usb_dev->manufacturer = NULL;
-	kfree(usb_dev->serial);
 	usb_dev->serial = NULL;
 
 	usb_dev->authorized = 1;
@@ -1925,6 +1941,12 @@ error_device_descriptor:
 error_autoresume:
 out_authorized:
 	usb_unlock_device(usb_dev);	// complements locktree
+	if (product || manufacturer || serial) {
+		synchronize_rcu();
+		kfree(product);
+		kfree(manufacturer);
+		kfree(serial);
+	}
 	return result;
 }
 
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index 448f5b4..98856d8 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -85,9 +85,9 @@ static ssize_t  show_##name(struct device *dev,				\
 	int retval;							\
 									\
 	udev = to_usb_device(dev);					\
-	usb_lock_device(udev);						\
-	retval = sprintf(buf, "%s\n", udev->name);			\
-	usb_unlock_device(udev);					\
+	rcu_read_lock();						\
+	retval = sprintf(buf, "%s\n", rcu_dereference(udev->name));	\
+	rcu_read_unlock();						\
 	return retval;							\
 }									\
 static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL);
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH 1/1] UBUNTU: SAUCE: khubd -- switch USB product/manufacturer/serial handling to RCU
  2010-06-14 11:14 [PATCH 1/1] UBUNTU: SAUCE: khubd -- switch USB product/manufacturer/serial handling to RCU Andy Whitcroft
@ 2010-06-14 11:17 ` Andy Whitcroft
  0 siblings, 0 replies; 2+ messages in thread
From: Andy Whitcroft @ 2010-06-14 11:17 UTC (permalink / raw)
  To: Greg Kroah-Hartman, linux-usb; +Cc: Inaky Perez-Gonzalez, linux-kernel

On Mon, Jun 14, 2010 at 12:14:28PM +0100, Andy Whitcroft wrote:
> With the introduction of wireless USB hubs the product, manufacturer,
> and serial number are now mutable.  This necessitates new locking in the
> consumers of these values including the sysfs read routines in order to
> prevent use-after-free acces to these values.  These extra locks create
> significant lock contention leading to increased boot times (0.3s for an
> example Atom based system).  Move update of these values to RCU based
> locking.

Bah, some Ubuntu-ism leaked out in the summary test, I've resent it with
those removed.

-apw

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2010-06-14 11:17 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-06-14 11:14 [PATCH 1/1] UBUNTU: SAUCE: khubd -- switch USB product/manufacturer/serial handling to RCU Andy Whitcroft
2010-06-14 11:17 ` Andy Whitcroft

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.