lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Date:	Mon, 29 Nov 2010 20:43:28 +0100 (CET)
From:	Guennadi Liakhovetski <g.liakhovetski@....de>
To:	linux-kernel@...r.kernel.org
cc:	Greg KH <greg@...ah.com>
Subject: [PATCH/RFC] core: add a function to safely try to get device driver
 owner

When two drivers interoperate without an explicit dependency, it is often
required to prevent one of them from being unloaded safely by dereferencing
dev->driver->owner. This patch provides a generic function to do this in a
race-free way.

Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@....de>
---

Not run-time tested in this form, but this is just a generalisation of the 
code in drivers/media/video/sh_mobile_ceu_camera.c::sh_mobile_ceu_probe(). 
If the idea is accepted in principle, I will replace that specific 
implementation with a call to this function, test... But I am not sure, if 
I'd be able to test it for races. If such testing is required on SMP, I'd 
have to write some test-case for it. Thoughts?

 drivers/base/dd.c      |   63 ++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/device.h |    1 +
 2 files changed, 64 insertions(+), 0 deletions(-)

diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index da57ee9..44c6672 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -17,10 +17,12 @@
  * This file is released under the GPLv2
  */
 
+#include <linux/completion.h>
 #include <linux/device.h>
 #include <linux/delay.h>
 #include <linux/module.h>
 #include <linux/kthread.h>
+#include <linux/notifier.h>
 #include <linux/wait.h>
 #include <linux/async.h>
 #include <linux/pm_runtime.h>
@@ -422,3 +424,64 @@ void dev_set_drvdata(struct device *dev, void *data)
 	dev->p->driver_data = data;
 }
 EXPORT_SYMBOL(dev_set_drvdata);
+
+struct bus_wait {
+	struct notifier_block	notifier;
+	struct completion	completion;
+	struct device		*dev;
+};
+
+static int bus_notify(struct notifier_block *nb,
+		      unsigned long action, void *data)
+{
+	struct device *dev = data;
+	struct bus_wait *wait = container_of(nb, struct bus_wait, notifier);
+
+	if (wait->dev != dev)
+		return NOTIFY_DONE;
+
+	switch (action) {
+	case BUS_NOTIFY_UNBOUND_DRIVER:
+		/* Protect from module unloading */
+		wait_for_completion(&wait->completion);
+		return NOTIFY_OK;
+	}
+	return NOTIFY_DONE;
+}
+
+int device_try_get_driver(struct device *dev)
+{
+	struct bus_wait wait = {
+		.completion = COMPLETION_INITIALIZER_ONSTACK(wait.completion),
+		.dev = dev,
+		.notifier.notifier_call = bus_notify,
+	};
+	struct bus_type	*bus;
+	int ret;
+
+	if (!dev || !dev->bus)
+		return 0;
+
+	bus = dev->bus;
+
+	if (bus_register_notifier(bus, &wait.notifier) < 0)
+		return 0;
+
+	/*
+	 * From this point the driver module will not unload, until we complete
+	 * the completion. In the worst case it is hanging in device release on
+	 * our completion. So, _now_ dereferencing the "owner" is safe.
+	 */
+	if (dev->driver && dev->driver->owner)
+		ret = try_module_get(dev->driver->owner);
+	else
+		/* Either no driver, or too late, or probing failed */
+		ret = 0;
+
+	/* Let notifier complete, if it has been blocked */
+	complete(&wait.completion);
+	bus_unregister_notifier(bus, &wait.notifier);
+
+	return ret;
+}
+EXPORT_SYMBOL(device_try_get_driver);
diff --git a/include/linux/device.h b/include/linux/device.h
index dd48953..5932169 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -559,6 +559,7 @@ extern const char *device_get_devnode(struct device *dev,
 				      mode_t *mode, const char **tmp);
 extern void *dev_get_drvdata(const struct device *dev);
 extern void dev_set_drvdata(struct device *dev, void *data);
+int device_try_get_driver(struct device *dev);
 
 /*
  * Root device objects for grouping under /sys/devices
-- 
1.7.2.3

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ