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
