All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] driver core: enforce device_lock for driver_match_device()
@ 2026-06-02 16:08 Runyu Xiao
  2026-06-02 16:39 ` Greg KH
                   ` (2 more replies)
  0 siblings, 3 replies; 13+ messages in thread
From: Runyu Xiao @ 2026-06-02 16:08 UTC (permalink / raw)
  To: gregkh
  Cc: rafael, dakr, cornelia.huck, tom.leiming, linux-kernel, stable,
	jianhao.xu, runyu.xiao

Currently driver_match_device() is called from three sites. The
__device_attach_driver() path already runs under device_lock(dev), but
bind_store() and __driver_attach() can still enter bus match()
callbacks without that lock held.

That inconsistency leaves bus-private driver_override readers exposed.
Several buses still read private driver_override strings from their
match callbacks while the write side relies on driver_set_override()
under device_lock(dev). If bind_store() or __driver_attach() reaches
such a match callback without that lock, it can race with
driver_override replacement and old-string free.

This issue was first flagged by our static analysis tool while auditing
driver_override match paths, then manually confirmed on Linux v6.18.21.
We reproduced the race with no-device KCSAN/MSV harnesses across AMBA,
WMI, RPMSG, VMBUS, VDPA, CDX, CSS, FSL-MC, and PCI. Those reports all
reduce to the same core-side gap in driver_match_device().

Fix this by introducing driver_match_device_locked(), which guarantees
holding device_lock(dev) with a scoped guard before entering the bus
match callback. Convert the two unlocked call sites to this helper, and
add a device_lock_assert() to driver_match_device() so the contract is
explicit.

This matches the locking requirement already assumed by
driver_set_override()-based driver_override implementations and avoids
trying to paper over the problem in each individual bus match()
callback, where taking device_lock(dev) locally would conflict with
already-locked callers.

Build-tested with:
  make olddefconfig
  make -j"$(nproc)" drivers/base/bus.o drivers/base/dd.o

Fixes: 49b420a13ff9 ("driver core: check bus->match without holding device lock")
Cc: stable@vger.kernel.org
Signed-off-by: Runyu Xiao <runyu.xiao@seu.edu.cn>
---
 drivers/base/base.h | 10 ++++++++++
 drivers/base/bus.c  |  2 +-
 drivers/base/dd.c   |  2 +-
 3 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/drivers/base/base.h b/drivers/base/base.h
index 86fa7fbb3548..4ec487e34d1a 100644
--- a/drivers/base/base.h
+++ b/drivers/base/base.h
@@ -166,9 +166,19 @@ void device_set_deferred_probe_reason(const struct device *dev, struct va_format
 static inline int driver_match_device(const struct device_driver *drv,
 				      struct device *dev)
 {
+	device_lock_assert(dev);
+
 	return drv->bus->match ? drv->bus->match(dev, drv) : 1;
 }
 
+static inline int driver_match_device_locked(const struct device_driver *drv,
+					     struct device *dev)
+{
+	guard(device)(dev);
+
+	return driver_match_device(drv, dev);
+}
+
 static inline void dev_sync_state(struct device *dev)
 {
 	if (dev->bus->sync_state)
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index 2653670f962f..2b039aa2da74 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -263,7 +263,7 @@ static ssize_t bind_store(struct device_driver *drv, const char *buf,
 	int err = -ENODEV;
 
 	dev = bus_find_device_by_name(bus, NULL, buf);
-	if (dev && driver_match_device(drv, dev)) {
+	if (dev && driver_match_device_locked(drv, dev)) {
 		err = device_driver_attach(drv, dev);
 		if (!err) {
 			/* success */
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index 2996f4c667c4..30c3e55ff5ff 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -1230,7 +1230,7 @@ static int __driver_attach(struct device *dev, void *data)
 	 * is an error.
 	 */
 
-	ret = driver_match_device(drv, dev);
+	ret = driver_match_device_locked(drv, dev);
 	if (ret == 0) {
 		/* no match */
 		return 0;
-- 
2.34.1

^ permalink raw reply related	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2026-06-08 18:09 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-02 16:08 [PATCH] driver core: enforce device_lock for driver_match_device() Runyu Xiao
2026-06-02 16:39 ` Greg KH
2026-06-02 16:44 ` Danilo Krummrich
2026-06-03  3:36   ` Runyu Xiao
2026-06-04  3:52 ` [PATCH v2 0/4] Convert remaining buses to generic driver_override handling Runyu Xiao
2026-06-04  3:52   ` [PATCH v2 1/4] amba: use generic driver_override infrastructure Runyu Xiao
2026-06-04  3:52   ` [PATCH v2 2/4] rpmsg: core: " Runyu Xiao
2026-06-08 17:47     ` Mathieu Poirier
2026-06-04  3:52   ` [PATCH v2 3/4] vmbus: " Runyu Xiao
2026-06-04  4:13     ` sashiko-bot
2026-06-04  3:52   ` [PATCH v2 4/4] cdx: " Runyu Xiao
2026-06-04  4:08     ` sashiko-bot
2026-06-08 18:09   ` [PATCH v2 0/4] Convert remaining buses to generic driver_override handling Danilo Krummrich

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.