Driver overriding is useful only in a very limited set of situations
and then only with very few drivers that are designed to support that.

Disallow matching via driver_override unless the driver explicitly
allows it or the safe guard is disabled using the
"allow_driver_override" kernel parameter.

Implementation detail: device_match_driver_override() isn't a static
inline any more. It grew a certain complexity (e.g. a pr_info()) and so
was made a regular exported function.

Signed-off-by: Uwe Kleine-König <[email protected]>
---
 drivers/base/bus.c            | 43 +++++++++++++++++++++++++++++++++++
 include/linux/device.h        | 26 ++-------------------
 include/linux/device/driver.h |  2 ++
 3 files changed, 47 insertions(+), 24 deletions(-)

diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index c51ad96d4de4..d294c198ab0c 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -606,6 +606,49 @@ int bus_add_device(struct device *dev)
        return error;
 }
 
+static int __read_mostly allow_driver_override;
+
+static int __init allow_driver_override_setup(char *str)
+{
+       allow_driver_override = 1;
+
+       return 1;
+}
+__setup("allow_driver_override", allow_driver_override_setup);
+
+/**
+ * device_match_driver_override() - Match a driver against the device's 
driver_override.
+ * @dev: device to check
+ * @drv: driver to match against
+ *
+ * Returns > 0 if a driver override is set and matches the given driver, 0 if a
+ * driver override is set but does not match, or < 0 if a driver override is 
not
+ * set at all.
+ */
+int device_match_driver_override(struct device *dev,
+                                const struct device_driver *drv)
+{
+       guard(spinlock)(&dev->driver_override.lock);
+       if (dev->driver_override.name) {
+               int ret = !strcmp(dev->driver_override.name, drv->name);
+
+               if (ret > 0) {
+                       if (!allow_driver_override && 
!drv->support_driver_override) {
+                               pr_info("Suppress driver override binding. 
Allow %ps to do overriding or boot with allow_driver_override on cmdline\n",
+                                       drv);
+                               return -1;
+                       }
+
+                       add_taint_module(drv->owner,
+                                        TAINT_DRIVER_OVERRIDE, 
LOCKDEP_STILL_OK);
+               }
+
+               return ret;
+       }
+       return -1;
+}
+EXPORT_SYMBOL_GPL(device_match_driver_override);
+
 /**
  * bus_probe_device - probe drivers for a new device
  * @dev: device to probe
diff --git a/include/linux/device.h b/include/linux/device.h
index 4dac5e09b74c..a142bf384f1e 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -892,30 +892,8 @@ static inline bool device_has_driver_override(struct 
device *dev)
        return !!dev->driver_override.name;
 }
 
-/**
- * device_match_driver_override() - Match a driver against the device's 
driver_override.
- * @dev: device to check
- * @drv: driver to match against
- *
- * Returns > 0 if a driver override is set and matches the given driver, 0 if a
- * driver override is set but does not match, or < 0 if a driver override is 
not
- * set at all.
- */
-static inline int device_match_driver_override(struct device *dev,
-                                              const struct device_driver *drv)
-{
-       guard(spinlock)(&dev->driver_override.lock);
-       if (dev->driver_override.name) {
-               int ret = !strcmp(dev->driver_override.name, drv->name);
-
-               if (ret > 0)
-                       add_taint_module(drv->owner,
-                                        TAINT_DRIVER_OVERRIDE, 
LOCKDEP_STILL_OK);
-
-               return ret;
-       }
-       return -1;
-}
+int device_match_driver_override(struct device *dev,
+                                const struct device_driver *drv);
 
 /**
  * device_iommu_mapped - Returns true when the device DMA is translated
diff --git a/include/linux/device/driver.h b/include/linux/device/driver.h
index 29fbc01ef06f..0153cfcbe1b9 100644
--- a/include/linux/device/driver.h
+++ b/include/linux/device/driver.h
@@ -56,6 +56,7 @@ enum probe_type {
  * @bus:       The bus which the device of this driver belongs to.
  * @owner:     The module owner.
  * @mod_name:  Used for built-in modules.
+ * @support_driver_override: driver_override only works if this is true.
  * @suppress_bind_attrs: Disables bind/unbind via sysfs.
  * @probe_type:        Type of the probe (synchronous or asynchronous) to use.
  * @of_match_table: The open firmware table.
@@ -104,6 +105,7 @@ struct device_driver {
        struct module           *owner;
        const char              *mod_name;      /* used for built-in modules */
 
+       bool support_driver_override;
        bool suppress_bind_attrs;       /* disables bind/unbind via sysfs */
        enum probe_type probe_type;
 
-- 
2.47.3


Reply via email to