[RFC PATCH] driver core: Stop driver bind on NOTIFY_BAD

From: Alex Williamson
Date: Mon Jun 26 2017 - 15:36:08 EST


Allow participants in the BUS_NOTIFY_BIND_DRIVER to prevent driver
binding with a NOTIFY_BAD. An example case where this might be useful
is when we're dealing with IOMMU groups and userspace drivers. We've
defined that devices within the same IOMMU group are not necessarily
DMA isolated from one another and therefore allowing those devices to
be split between host and user drivers may compromise the kernel. The
vfio driver currently handles this with a BUG_ON when such a condition
occurs. A better solution is to prevent the case from occurring,
which this change enables.

Signed-off-by: Alex Williamson <alex.williamson@xxxxxxxxxx>
Suggested-by: Russell King <linux@xxxxxxxxxxxxxxx>
---
drivers/base/dd.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)

For due diligence, none of the current notifier blocks registered with
bus_register_notifier() return anything other than { 0, NOTIFY_OK,
NOTIFY_DONE } except for the case of BUS_NOTIFY_ADD_DEVICE, where
NOTIFY_BAD is possible for NULL data in keystone_platform_notifier()
and an errno return is possible from tce_iommu_bus_notifier() and
i2cdev_notifier_call(). device_add() also ignores the call chain
return value, so these three cases are all ineffective at preventing
anything.

If this is acceptable, I'll re-spin https://lkml.org/lkml/2017/6/20/681
dropping the last 3 patches, instead using the patch below, plumbing
the IOMMU group notifier to percolate notifier block returns, and
simply return NOTIFY_BAD from vfio rather than mucking with
driver_override. Thanks

Alex

diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index 4882f06d12df..32c1d841e8d9 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -265,9 +265,11 @@ static int driver_sysfs_add(struct device *dev)
{
int ret;

- if (dev->bus)
- blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
- BUS_NOTIFY_BIND_DRIVER, dev);
+ if (dev->bus) {
+ if (blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
+ BUS_NOTIFY_BIND_DRIVER, dev) == NOTIFY_BAD)
+ return -EINVAL;
+ }

ret = sysfs_create_link(&dev->driver->p->kobj, &dev->kobj,
kobject_name(&dev->kobj));