From nobody Thu Apr 9 16:32:34 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4090033F8D4; Tue, 3 Mar 2026 11:57:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772539055; cv=none; b=EooF72/Uuyss3auUMF6Af8lWpYEr1p/mtPpXC71kV3+VlvvEl9WJKBkeZHMr0xBkCX/KfLGkYM7zaWYBLjtgQLlN4dsbdAA69jgOEax2viV+j/xgNwNRreGPxELMZSAgFfvKhV8rh2TuJpbe7n4jmx84xvlCf+AvRGcSq+APT8Q= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772539055; c=relaxed/simple; bh=bM/WxmTLJTdChrUodxAPjrbTJrXuDhe2tNOzUWPxoao=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=hw5J3pmWIS09LZJBoUTWUCsNlaYZgbr0mWjvu/WLvm/NZOY9FogfDZYVyzfVGS6AX1QRLgM7+BL0VZ8HFAi1WrJrY/v+SMslGTcRJxg2uhyN46sdyhLADhQGOPZSHwPuw+wbV1hnTp9vYKe8DwLg30got4/frV9BrIC0BBWrVwk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=BFlN4PJR; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="BFlN4PJR" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 49008C2BC9E; Tue, 3 Mar 2026 11:57:31 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1772539054; bh=bM/WxmTLJTdChrUodxAPjrbTJrXuDhe2tNOzUWPxoao=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=BFlN4PJRqNZQEpDNMgLegxcUHkAxH2m8F82gK75vDU4k0pXlgYSTG6aDN7Tz1MaTb 9YfaJ2F2y6bEnfAH0k9MmnBByPtLti4uiNtiepfhKmbSjDW8/b8B+vuspV8BVsESqp vJACe5q0SN5BnYEmUMmJ13OkTcyTmuPKdJ5wvQIaw8z1mXXw5xXwZrL2uwSzO5GWDL idDXCCX5yKzam+zhl/S3P2NQ8q7+AkI+Oq7BPTePiwjbglAuOfH92Iw2YMlnH5YGBO r9isp5ry2HoXuJ3yQ3gbBxYUuNippkG2w73D578cu1bHE434aFOfU7QlVUvsMAo/nX AUp1N0iRixsmQ== From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, hanguidong02@gmail.com, ysato@users.sourceforge.jp, dalias@libc.org, glaubitz@physik.fu-berlin.de, abelvesa@kernel.org, srini@kernel.org, s.nawrocki@samsung.com, nuno.sa@analog.com Cc: driver-core@lists.linux.dev, linux-kernel@vger.kernel.org, imx@lists.linux.dev, linux-hwmon@vger.kernel.org, linux-arm-msm@vger.kernel.org, linux-sound@vger.kernel.org, linux-sh@vger.kernel.org, Danilo Krummrich Subject: [PATCH v2 1/4] driver core: generalize driver_override in struct device Date: Tue, 3 Mar 2026 12:53:18 +0100 Message-ID: <20260303115720.48783-2-dakr@kernel.org> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260303115720.48783-1-dakr@kernel.org> References: <20260303115720.48783-1-dakr@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Currently, there are 12 busses (including platform and PCI) that duplicate the driver_override logic for their individual devices. All of them seem to be prone to the bug described in [1]. While this could be solved for every bus individually using a separate lock, solving this in the driver-core generically results in less (and cleaner) changes overall. Thus, move driver_override to struct device, provide corresponding accessors for busses and handle locking with a separate lock internally. In particular, add device_set_driver_override(), device_has_driver_override(), device_match_driver_override() and a helper, DEVICE_ATTR_DRIVER_OVERRIDE(), to declare the corresponding sysfs store() and show() callbacks. Until all busses have migrated, keep driver_set_override() in place. Note that we can't use the device lock for the reasons described in [2]. Link: https://bugzilla.kernel.org/show_bug.cgi?id=3D220789 [1] Link: https://lore.kernel.org/driver-core/DGRGTIRHA62X.3RY09D9SOK77P@kernel= .org/ [2] Co-developed-by: Gui-Dong Han Signed-off-by: Gui-Dong Han Signed-off-by: Danilo Krummrich Reviewed-by: Greg Kroah-Hartman --- drivers/base/bus.c | 43 ++++++++++++++++++++++++++- drivers/base/core.c | 2 ++ drivers/base/dd.c | 60 ++++++++++++++++++++++++++++++++++++++ include/linux/device.h | 54 ++++++++++++++++++++++++++++++++++ include/linux/device/bus.h | 4 +++ 5 files changed, 162 insertions(+), 1 deletion(-) diff --git a/drivers/base/bus.c b/drivers/base/bus.c index bb61d8adbab1..c734e7162b74 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -504,6 +504,36 @@ int bus_for_each_drv(const struct bus_type *bus, struc= t device_driver *start, } EXPORT_SYMBOL_GPL(bus_for_each_drv); =20 +static ssize_t driver_override_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int ret; + + ret =3D __device_set_driver_override(dev, buf, count); + if (ret) + return ret; + + return count; +} + +static ssize_t driver_override_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + guard(spinlock)(&dev->driver_override.lock); + return sysfs_emit(buf, "%s\n", dev->driver_override.name); +} +static DEVICE_ATTR_RW(driver_override); + +static struct attribute *driver_override_dev_attrs[] =3D { + &dev_attr_driver_override.attr, + NULL, +}; + +static const struct attribute_group driver_override_dev_group =3D { + .attrs =3D driver_override_dev_attrs, +}; + /** * bus_add_device - add device to bus * @dev: device being added @@ -537,9 +567,15 @@ int bus_add_device(struct device *dev) if (error) goto out_put; =20 + if (sp->bus->driver_override) { + error =3D device_add_group(dev, &driver_override_dev_group); + if (error) + goto out_groups; + } + error =3D sysfs_create_link(&sp->devices_kset->kobj, &dev->kobj, dev_name= (dev)); if (error) - goto out_groups; + goto out_override; =20 error =3D sysfs_create_link(&dev->kobj, &sp->subsys.kobj, "subsystem"); if (error) @@ -550,6 +586,9 @@ int bus_add_device(struct device *dev) =20 out_subsys: sysfs_remove_link(&sp->devices_kset->kobj, dev_name(dev)); +out_override: + if (dev->bus->driver_override) + device_remove_group(dev, &driver_override_dev_group); out_groups: device_remove_groups(dev, sp->bus->dev_groups); out_put: @@ -607,6 +646,8 @@ void bus_remove_device(struct device *dev) =20 sysfs_remove_link(&dev->kobj, "subsystem"); sysfs_remove_link(&sp->devices_kset->kobj, dev_name(dev)); + if (dev->bus->driver_override) + device_remove_group(dev, &driver_override_dev_group); device_remove_groups(dev, dev->bus->dev_groups); if (klist_node_attached(&dev->p->knode_bus)) klist_del(&dev->p->knode_bus); diff --git a/drivers/base/core.c b/drivers/base/core.c index 791f9e444df8..09b98f02f559 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -2556,6 +2556,7 @@ static void device_release(struct kobject *kobj) devres_release_all(dev); =20 kfree(dev->dma_range_map); + kfree(dev->driver_override.name); =20 if (dev->release) dev->release(dev); @@ -3159,6 +3160,7 @@ void device_initialize(struct device *dev) kobject_init(&dev->kobj, &device_ktype); INIT_LIST_HEAD(&dev->dma_pools); mutex_init(&dev->mutex); + spin_lock_init(&dev->driver_override.lock); lockdep_set_novalidate_class(&dev->mutex); spin_lock_init(&dev->devres_lock); INIT_LIST_HEAD(&dev->devres_head); diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 0354f209529c..697e36e63cab 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -381,6 +381,66 @@ static void __exit deferred_probe_exit(void) } __exitcall(deferred_probe_exit); =20 +int __device_set_driver_override(struct device *dev, const char *s, size_t= len) +{ + const char *new, *old; + char *cp; + + if (!s) + return -EINVAL; + + /* + * The stored value will be used in sysfs show callback (sysfs_emit()), + * which has a length limit of PAGE_SIZE and adds a trailing newline. + * Thus we can store one character less to avoid truncation during sysfs + * show. + */ + if (len >=3D (PAGE_SIZE - 1)) + return -EINVAL; + + /* + * Compute the real length of the string in case userspace sends us a + * bunch of \0 characters like python likes to do. + */ + len =3D strlen(s); + + if (!len) { + /* Empty string passed - clear override */ + spin_lock(&dev->driver_override.lock); + old =3D dev->driver_override.name; + dev->driver_override.name =3D NULL; + spin_unlock(&dev->driver_override.lock); + kfree(old); + + return 0; + } + + cp =3D strnchr(s, len, '\n'); + if (cp) + len =3D cp - s; + + new =3D kstrndup(s, len, GFP_KERNEL); + if (!new) + return -ENOMEM; + + spin_lock(&dev->driver_override.lock); + old =3D dev->driver_override.name; + if (cp !=3D s) { + dev->driver_override.name =3D new; + spin_unlock(&dev->driver_override.lock); + } else { + /* "\n" passed - clear override */ + dev->driver_override.name =3D NULL; + spin_unlock(&dev->driver_override.lock); + + kfree(new); + } + kfree(old); + + return 0; +} +EXPORT_SYMBOL_GPL(__device_set_driver_override); + /** * device_is_bound() - Check if device is bound to a driver * @dev: device to check diff --git a/include/linux/device.h b/include/linux/device.h index 0be95294b6e6..e65d564f01cd 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -483,6 +483,8 @@ struct device_physical_location { * on. This shrinks the "Board Support Packages" (BSPs) and * minimizes board-specific #ifdefs in drivers. * @driver_data: Private pointer for driver specific info. + * @driver_override: Driver name to force a match. Do not touch directly;= use + * device_set_driver_override() instead. * @links: Links to suppliers and consumers of this device. * @power: For device power management. * See Documentation/driver-api/pm/devices.rst for details. @@ -576,6 +578,10 @@ struct device { core doesn't touch it */ void *driver_data; /* Driver data, set and get with dev_set_drvdata/dev_get_drvdata */ + struct { + const char *name; + spinlock_t lock; + } driver_override; struct mutex mutex; /* mutex to synchronize calls to * its driver. */ @@ -701,6 +707,54 @@ struct device_link { =20 #define kobj_to_dev(__kobj) container_of_const(__kobj, struct device, kobj) =20 +int __device_set_driver_override(struct device *dev, const char *s, size_t= len); + +/** + * device_set_driver_override() - Helper to set or clear driver override. + * @dev: Device to change + * @s: NUL-terminated string, new driver name to force a match, pass empty + * string to clear it ("" or "\n", where the latter is only for sysfs + * interface). + * + * Helper to set or clear driver override of a device. + * + * Returns: 0 on success or a negative error code on failure. + */ +static inline int device_set_driver_override(struct device *dev, const cha= r *s) +{ + return __device_set_driver_override(dev, s, s ? strlen(s) : 0); +} + +/** + * device_has_driver_override() - Check if a driver override has been set. + * @dev: device to check + * + * Returns true if a driver override has been set for this device. + */ +static inline bool device_has_driver_override(struct device *dev) +{ + guard(spinlock)(&dev->driver_override.lock); + return !!dev->driver_override.name; +} + +/** + * device_match_driver_override() - Match a driver against the device's dr= iver_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) + return !strcmp(dev->driver_override.name, drv->name); + return -1; +} + /** * device_iommu_mapped - Returns true when the device DMA is translated * by an IOMMU diff --git a/include/linux/device/bus.h b/include/linux/device/bus.h index 99c3c83ea520..cda597812324 100644 --- a/include/linux/device/bus.h +++ b/include/linux/device/bus.h @@ -63,6 +63,9 @@ struct fwnode_handle; * this bus. * @pm: Power management operations of this bus, callback the specific * device driver's pm-ops. + * @driver_override: Set to true if this bus supports the driver_override + * mechanism, which allows userspace to force a specific + * driver to bind to a device via a sysfs attribute. * @need_parent_lock: When probing or removing a device on this bus, the * device core should lock the device's parent. * @@ -104,6 +107,7 @@ struct bus_type { =20 const struct dev_pm_ops *pm; =20 + bool driver_override; bool need_parent_lock; }; =20 --=20 2.53.0 From nobody Thu Apr 9 16:32:34 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 26D0833F595; Tue, 3 Mar 2026 11:57:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772539059; cv=none; b=cqG0yj1Bc0utmUCd2slwumminfAaWdCNVpt9AXlU+DUFY/azwAm50sXgiY3RxFqRX11wn5lbQ8tvwzHPARsFhzUTiMB7Ir9IdKCfjONHioGiJwFV6sgqu0jBBmmskiN2KIdxwQS0bp1OUSBVGWqSOlRPfObdOLmsBsNxdGdqixw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772539059; c=relaxed/simple; bh=CFaaL8gRJL7PBLsD3XJRYlsmDMT6/BIrxbJWYBiGnpo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=sogdDAhIMi8I/c3HbwHFNrEh0mAly0/fTehHbrw7nsD81zLxZc80xIFw52FTwWmHiEpSQQdXeDTTKLZ3WJSm8iyNYFGMn4rKIUrmoyCnzr5QopoM/Sfzjg9ONAYEgIQS7qnawCGEG8B5x3+Fy8Wj+aa2QwqWVdiGBl6ovOCfcy4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=sdJJ1hcZ; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="sdJJ1hcZ" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 5FFD1C116C6; Tue, 3 Mar 2026 11:57:35 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1772539059; bh=CFaaL8gRJL7PBLsD3XJRYlsmDMT6/BIrxbJWYBiGnpo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=sdJJ1hcZxUomU+fjclbkwf+MtC81BxuFQXpXOLl7wgh4UmEO69KicOlh226CGAIsN qpIGsgcPmwJS2C2oqYGJFNLRT5FCX75MgPo6xpzh6Irth0J1xiFTynpv+8UXcQ6+Ek ixSlNz9wsim1YM6CXfe6I4UkNPm0qaD3Hjz5fW7plA9i1mNnvQNMEZn1VQiReA7jCs szH7vWdH0dVxqm0/pjYEvlUEgcZQrpPWlE9dwmvc9a2mn4OJ3G3GUWIi7GeaVOXNAC CMp0KiC7XRKcQOPh1buUDAGy8O6ucjDY45bP9jomy4g7l/+gJOIGf+3GC2ncQBFuEX nVZ9tckMeJN/w== From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, hanguidong02@gmail.com, ysato@users.sourceforge.jp, dalias@libc.org, glaubitz@physik.fu-berlin.de, abelvesa@kernel.org, srini@kernel.org, s.nawrocki@samsung.com, nuno.sa@analog.com Cc: driver-core@lists.linux.dev, linux-kernel@vger.kernel.org, imx@lists.linux.dev, linux-hwmon@vger.kernel.org, linux-arm-msm@vger.kernel.org, linux-sound@vger.kernel.org, linux-sh@vger.kernel.org, Danilo Krummrich Subject: [PATCH v2 2/4] docs: driver-model: document driver_override Date: Tue, 3 Mar 2026 12:53:19 +0100 Message-ID: <20260303115720.48783-3-dakr@kernel.org> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260303115720.48783-1-dakr@kernel.org> References: <20260303115720.48783-1-dakr@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Now that we support driver_override as a driver-core feature through struct device and struct bus_type, add some documentation in the context of how a device / driver binding is established. Signed-off-by: Danilo Krummrich Reviewed-by: Greg Kroah-Hartman --- .../driver-api/driver-model/binding.rst | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/Documentation/driver-api/driver-model/binding.rst b/Documentat= ion/driver-api/driver-model/binding.rst index d1d311a4011f..fa0888c2b3b9 100644 --- a/Documentation/driver-api/driver-model/binding.rst +++ b/Documentation/driver-api/driver-model/binding.rst @@ -99,3 +99,51 @@ of the driver is decremented. All symlinks between the t= wo are removed. When a driver is removed, the list of devices that it supports is iterated over, and the driver's remove callback is called for each one. The device is removed from that list and the symlinks removed. + + +Driver Override +~~~~~~~~~~~~~~~ + +Userspace may override the standard matching by writing a driver name to +a device's ``driver_override`` sysfs attribute. When set, only a driver +whose name matches the override will be considered during binding. This +bypasses all bus-specific matching (OF, ACPI, ID tables, etc.). + +The override may be cleared by writing an empty string, which returns +the device to standard matching rules. Writing to ``driver_override`` +does not automatically unbind the device from its current driver or +make any attempt to load the specified driver. + +Buses opt into this mechanism by setting the ``driver_override`` flag in +their ``struct bus_type``:: + + const struct bus_type example_bus_type =3D { + ... + .driver_override =3D true, + }; + +When the flag is set, the driver core automatically creates the +``driver_override`` sysfs attribute for every device on that bus. + +The bus's ``match()`` callback should check the override before performing +its own matching, using ``device_match_driver_override()``:: + + static int example_match(struct device *dev, const struct device_driver = *drv) + { + int ret; + + ret =3D device_match_driver_override(dev, drv); + if (ret >=3D 0) + return ret; + + /* Fall through to bus-specific matching... */ + } + +``device_match_driver_override()`` returns > 0 if the override matches +the given driver, 0 if the override is set but does not match, or < 0 if +no override is set at all. + +Additional helpers are available: + +- ``device_set_driver_override()`` - set or clear the override from kernel= code. +- ``device_has_driver_override()`` - check whether an override is set. --=20 2.53.0 From nobody Thu Apr 9 16:32:34 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3DA3330C359; Tue, 3 Mar 2026 11:57:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772539063; cv=none; b=tgua4IEWVKCRWd1DUyX13XTkSyDy89+O6TqvDRlxCTwmi4YTyLfpoSsDA+5Sse1Kt8iC/dMeWGobp515W+OSV3F9HXK0ABQNEiPP5kKhK/CYmJIdKdbuPyLZZyxij6zA3H8Fcvg4v/3hGeBSyOqyLWkhAeZRt/0SzbwWZibxhCE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772539063; c=relaxed/simple; bh=+QuUzVAtygxEq4K2NyuuefSYb1+7X2pqddTzd+Vv4rs=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=sdfE3WDzuenvC7M2GZBfPqSsSVfzz25ELZyzi8aLuJOaxJi8i/x/3zN4G7uzydTvpSKAGlLBXTdYvhDu2SkQ7TvzzUorLpWX34qpNwHRJuB7DDftjbSI4ED38AzA+VRcVZyxBpLH7g6XUK82tNhkT2e2HXZWJbMO48gINukAI1E= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=LIy+Ev0i; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="LIy+Ev0i" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 77286C19422; Tue, 3 Mar 2026 11:57:39 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1772539063; bh=+QuUzVAtygxEq4K2NyuuefSYb1+7X2pqddTzd+Vv4rs=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=LIy+Ev0iUQHIhrpTlxpUBb7h12iXOaWHgwNdHcKB2DcWYrmwV2DI/zWY1L3QwEj7d VRWLDxy3yula8EdWtuiHDss8XooOXLU/aV+C9tdAZ0c+6QDW/7urEgt2+bqV5ZhdV5 Eo11pAUCfpaXFK3L0ixJTYY7ukglmK2RtUVBj61VAZyyVJZzK8nKyIYcKfWBvjJmBx 0G1UMQDY8Od3IpBRZFMH2xaGsz8Sta+9LDDda9McC+O2jBe3HUPo4DlXXK+sHdCmec P4+234ZWTS4Nk0xr0e0YqC2DOnAJNnkaZjGKQWh6Q1joiMZeljdkhTvU85guKHk7eM /IlAhPe+3kM7g== From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, hanguidong02@gmail.com, ysato@users.sourceforge.jp, dalias@libc.org, glaubitz@physik.fu-berlin.de, abelvesa@kernel.org, srini@kernel.org, s.nawrocki@samsung.com, nuno.sa@analog.com Cc: driver-core@lists.linux.dev, linux-kernel@vger.kernel.org, imx@lists.linux.dev, linux-hwmon@vger.kernel.org, linux-arm-msm@vger.kernel.org, linux-sound@vger.kernel.org, linux-sh@vger.kernel.org, Danilo Krummrich Subject: [PATCH v2 3/4] hwmon: axi-fan: don't use driver_override as IRQ name Date: Tue, 3 Mar 2026 12:53:20 +0100 Message-ID: <20260303115720.48783-4-dakr@kernel.org> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260303115720.48783-1-dakr@kernel.org> References: <20260303115720.48783-1-dakr@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Do not use driver_override as IRQ name, as it is not guaranteed to point to a valid string; use NULL instead (which makes the devm IRQ helpers use dev_name()). Fixes: 8412b410fa5e ("hwmon: Support ADI Fan Control IP") Signed-off-by: Danilo Krummrich Acked-by: Guenter Roeck Reviewed-by: Greg Kroah-Hartman Reviewed-by: Nuno S=C3=A1 --- drivers/hwmon/axi-fan-control.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hwmon/axi-fan-control.c b/drivers/hwmon/axi-fan-contro= l.c index b7bb325c3ad9..01590dfa55e6 100644 --- a/drivers/hwmon/axi-fan-control.c +++ b/drivers/hwmon/axi-fan-control.c @@ -507,7 +507,7 @@ static int axi_fan_control_probe(struct platform_device= *pdev) ret =3D devm_request_threaded_irq(&pdev->dev, ctl->irq, NULL, axi_fan_control_irq_handler, IRQF_ONESHOT | IRQF_TRIGGER_HIGH, - pdev->driver_override, ctl); + NULL, ctl); if (ret) return dev_err_probe(&pdev->dev, ret, "failed to request an irq\n"); --=20 2.53.0 From nobody Thu Apr 9 16:32:34 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B890C33DEE0; Tue, 3 Mar 2026 11:57:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772539067; cv=none; b=I+jyviOZ3utaZ+XsRyS1AHHG4ibl09HvRt6hxjXo0eowxl91qW3gmuRtk8WxBfeVG+2RlAhWnB+kA1juAOg6bbtoQFv7N1EDjKLfjyCKtEkDMe9Lovw2VaXy/vh/Cymn4P8hZBttNe0Pe1+YDv894qvrfSfH0chk12iAAMcp47I= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772539067; c=relaxed/simple; bh=gMiU4B7aXqUIwr1QMMO3H+NRPoBJrVaacNBNpA/ZYTw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ag6cXEMPaSWcK8/+LIeszzCqybIt83y/SWhHn25XbTq8Nlfil8wLx8qKl2CKueKiRksQLO9IOZt7yln8WpAkFVi+FsE044tN3E0rkhdmYy80Ulu6icsAJ9c656+5xXVQIQMkWqXNxbr5V8QgJYRA6zOnIQJ93ol8Uewd1lkayoQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=ZYdEyHSk; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="ZYdEyHSk" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 8F1C5C116C6; Tue, 3 Mar 2026 11:57:43 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1772539067; bh=gMiU4B7aXqUIwr1QMMO3H+NRPoBJrVaacNBNpA/ZYTw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ZYdEyHSkPk0Q+jTdZU0EFxuXND5MW1lXOobmRpuVKvoecoW1h8SuvPEp13UvRI1e+ 42muQQmPujqgFsZEI+JjIZcieTQKhCPIBKqn7y/qeY/U3XUcIo8y33sb4I448Z31HE KCmFRgwUWOpCxKJNX8z8SO0BlrQRYWA0kSj/EclyQkm/VcXF5GnZw337xCA1khtx0O HB0R/1D16n0DZSsxIpFXqQzxYE4M0n/XDQvj0F+g3YxDO09O5aBi/bZVo4DMVctiE9 7cOkRdaxC7ABOF0Qf+pjiwypPWnF1kjhoGin3HansScyRnRh4ueaQGcWM6Z/l41IZw ZLOYBQEyIBaHg== From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, hanguidong02@gmail.com, ysato@users.sourceforge.jp, dalias@libc.org, glaubitz@physik.fu-berlin.de, abelvesa@kernel.org, srini@kernel.org, s.nawrocki@samsung.com, nuno.sa@analog.com Cc: driver-core@lists.linux.dev, linux-kernel@vger.kernel.org, imx@lists.linux.dev, linux-hwmon@vger.kernel.org, linux-arm-msm@vger.kernel.org, linux-sound@vger.kernel.org, linux-sh@vger.kernel.org, Danilo Krummrich Subject: [PATCH v2 4/4] driver core: platform: use generic driver_override infrastructure Date: Tue, 3 Mar 2026 12:53:21 +0100 Message-ID: <20260303115720.48783-5-dakr@kernel.org> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260303115720.48783-1-dakr@kernel.org> References: <20260303115720.48783-1-dakr@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" When a driver is probed through __driver_attach(), the bus' match() callback is called without the device lock held, thus accessing the driver_override field without a lock, which can cause a UAF. Fix this by using the driver-core driver_override infrastructure taking care of proper locking internally. Note that calling match() from __driver_attach() without the device lock held is intentional. [1] Link: https://lore.kernel.org/driver-core/DGRGTIRHA62X.3RY09D9SOK77P@kernel= .org/ [1] Reported-by: Gui-Dong Han Closes: https://bugzilla.kernel.org/show_bug.cgi?id=3D220789 Fixes: 3d713e0e382e ("driver core: platform: add device binding path 'drive= r_override'") Signed-off-by: Danilo Krummrich Reviewed-by: Geert Uytterhoeven Reviewed-by: Greg Kroah-Hartman --- arch/sh/drivers/platform_early.c | 6 ++++-- drivers/base/platform.c | 37 +++++--------------------------- drivers/bus/simple-pm-bus.c | 4 ++-- drivers/clk/imx/clk-scu.c | 3 +-- drivers/slimbus/qcom-ngd-ctrl.c | 6 ++---- include/linux/platform_device.h | 5 ----- sound/soc/samsung/i2s.c | 6 +++--- 7 files changed, 17 insertions(+), 50 deletions(-) diff --git a/arch/sh/drivers/platform_early.c b/arch/sh/drivers/platform_ea= rly.c index 143747c45206..3cd17bb0be67 100644 --- a/arch/sh/drivers/platform_early.c +++ b/arch/sh/drivers/platform_early.c @@ -25,10 +25,12 @@ static int platform_match(struct device *dev, struct de= vice_driver *drv) { struct platform_device *pdev =3D to_platform_device(dev); struct platform_driver *pdrv =3D to_platform_driver(drv); + int ret; =20 /* When driver_override is set, only bind to the matching driver */ - if (pdev->driver_override) - return !strcmp(pdev->driver_override, drv->name); + ret =3D device_match_driver_override(dev, drv); + if (ret >=3D 0) + return ret; =20 /* Then try to match against the id table */ if (pdrv->id_table) diff --git a/drivers/base/platform.c b/drivers/base/platform.c index b45d41b018ca..d44591d52e36 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -603,7 +603,6 @@ static void platform_device_release(struct device *dev) kfree(pa->pdev.dev.platform_data); kfree(pa->pdev.mfd_cell); kfree(pa->pdev.resource); - kfree(pa->pdev.driver_override); kfree(pa); } =20 @@ -1306,38 +1305,9 @@ static ssize_t numa_node_show(struct device *dev, } static DEVICE_ATTR_RO(numa_node); =20 -static ssize_t driver_override_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct platform_device *pdev =3D to_platform_device(dev); - ssize_t len; - - device_lock(dev); - len =3D sysfs_emit(buf, "%s\n", pdev->driver_override); - device_unlock(dev); - - return len; -} - -static ssize_t driver_override_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct platform_device *pdev =3D to_platform_device(dev); - int ret; - - ret =3D driver_set_override(dev, &pdev->driver_override, buf, count); - if (ret) - return ret; - - return count; -} -static DEVICE_ATTR_RW(driver_override); - static struct attribute *platform_dev_attrs[] =3D { &dev_attr_modalias.attr, &dev_attr_numa_node.attr, - &dev_attr_driver_override.attr, NULL, }; =20 @@ -1377,10 +1347,12 @@ static int platform_match(struct device *dev, const= struct device_driver *drv) { struct platform_device *pdev =3D to_platform_device(dev); struct platform_driver *pdrv =3D to_platform_driver(drv); + int ret; =20 /* When driver_override is set, only bind to the matching driver */ - if (pdev->driver_override) - return !strcmp(pdev->driver_override, drv->name); + ret =3D device_match_driver_override(dev, drv); + if (ret >=3D 0) + return ret; =20 /* Attempt an OF style match first */ if (of_driver_match_device(dev, drv)) @@ -1516,6 +1488,7 @@ static const struct dev_pm_ops platform_dev_pm_ops = =3D { const struct bus_type platform_bus_type =3D { .name =3D "platform", .dev_groups =3D platform_dev_groups, + .driver_override =3D true, .match =3D platform_match, .uevent =3D platform_uevent, .probe =3D platform_probe, diff --git a/drivers/bus/simple-pm-bus.c b/drivers/bus/simple-pm-bus.c index 3f00d953fb9a..c920bd6fbaaf 100644 --- a/drivers/bus/simple-pm-bus.c +++ b/drivers/bus/simple-pm-bus.c @@ -36,7 +36,7 @@ static int simple_pm_bus_probe(struct platform_device *pd= ev) * that's not listed in simple_pm_bus_of_match. We don't want to do any * of the simple-pm-bus tasks for these devices, so return early. */ - if (pdev->driver_override) + if (device_has_driver_override(&pdev->dev)) return 0; =20 match =3D of_match_device(dev->driver->of_match_table, dev); @@ -78,7 +78,7 @@ static void simple_pm_bus_remove(struct platform_device *= pdev) { const void *data =3D of_device_get_match_data(&pdev->dev); =20 - if (pdev->driver_override || data) + if (device_has_driver_override(&pdev->dev) || data) return; =20 dev_dbg(&pdev->dev, "%s\n", __func__); diff --git a/drivers/clk/imx/clk-scu.c b/drivers/clk/imx/clk-scu.c index a85ec48a798b..9b33df9967ec 100644 --- a/drivers/clk/imx/clk-scu.c +++ b/drivers/clk/imx/clk-scu.c @@ -706,8 +706,7 @@ struct clk_hw *imx_clk_scu_alloc_dev(const char *name, if (ret) goto put_device; =20 - ret =3D driver_set_override(&pdev->dev, &pdev->driver_override, - "imx-scu-clk", strlen("imx-scu-clk")); + ret =3D device_set_driver_override(&pdev->dev, "imx-scu-clk"); if (ret) goto put_device; =20 diff --git a/drivers/slimbus/qcom-ngd-ctrl.c b/drivers/slimbus/qcom-ngd-ctr= l.c index 9aa7218b4e8d..1ed6be6e85d2 100644 --- a/drivers/slimbus/qcom-ngd-ctrl.c +++ b/drivers/slimbus/qcom-ngd-ctrl.c @@ -1535,10 +1535,8 @@ static int of_qcom_slim_ngd_register(struct device *= parent, ngd->id =3D id; ngd->pdev->dev.parent =3D parent; =20 - ret =3D driver_set_override(&ngd->pdev->dev, - &ngd->pdev->driver_override, - QCOM_SLIM_NGD_DRV_NAME, - strlen(QCOM_SLIM_NGD_DRV_NAME)); + ret =3D device_set_driver_override(&ngd->pdev->dev, + QCOM_SLIM_NGD_DRV_NAME); if (ret) { platform_device_put(ngd->pdev); kfree(ngd); diff --git a/include/linux/platform_device.h b/include/linux/platform_devic= e.h index 813da101b5bf..ed1d50d1c3c1 100644 --- a/include/linux/platform_device.h +++ b/include/linux/platform_device.h @@ -31,11 +31,6 @@ struct platform_device { struct resource *resource; =20 const struct platform_device_id *id_entry; - /* - * Driver name to force a match. Do not set directly, because core - * frees it. Use driver_set_override() to set or clear it. - */ - const char *driver_override; =20 /* MFD cell pointer */ struct mfd_cell *mfd_cell; diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index e9964f0e010a..140907a41a70 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -1360,10 +1360,10 @@ static int i2s_create_secondary_device(struct samsu= ng_i2s_priv *priv) if (!pdev_sec) return -ENOMEM; =20 - pdev_sec->driver_override =3D kstrdup("samsung-i2s", GFP_KERNEL); - if (!pdev_sec->driver_override) { + ret =3D device_set_driver_override(&pdev_sec->dev, "samsung-i2s"); + if (ret) { platform_device_put(pdev_sec); - return -ENOMEM; + return ret; } =20 ret =3D platform_device_add(pdev_sec); --=20 2.53.0