From: Gui-Dong Han <hanguidong02@gmail.com>
To: gregkh@linuxfoundation.org, rafael@kernel.org, dakr@kernel.org
Cc: linux-kernel@vger.kernel.org, baijiaju1990@gmail.com,
Gui-Dong Han <hanguidong02@gmail.com>,
Qiu-ji Chen <chenqiuji666@gmail.com>
Subject: [PATCH] driver core: fix use-after-free of driver_override via driver_match_device()
Date: Wed, 26 Nov 2025 19:30:06 +0800 [thread overview]
Message-ID: <20251126113006.9925-1-hanguidong02@gmail.com> (raw)
driver_set_override() modifies and frees dev->driver_override while
holding device_lock(dev). However, driver_match_device() reads
dev->driver_override when calling bus match functions.
Currently, driver_match_device() is called from three sites. One site
(__device_attach_driver) holds device_lock(dev), but the other two
(bind_store and __driver_attach) do not. This allows a concurrent
driver_set_override() to free the string while driver_match_device() is
using it, leading to a use-after-free (UAF).
This issue affects at least 11 bus types (including PCI, AMBA, Platform)
that rely on driver_override for matching.
Fix this by holding device_lock(dev) around the driver_match_device() calls
in bind_store() and __driver_attach(). This ensures all access to
dev->driver_override via driver_match_device() is protected by the device
lock.
Tested with the PoCs from Bugzilla that trigger this UAF. Stress testing
the two newly locked paths for 24 hours with CONFIG_PROVE_LOCKING and
CONFIG_LOCKDEP enabled showed no UAF recurrence and no lockdep
warnings.
Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220789
Suggested-by: Qiu-ji Chen <chenqiuji666@gmail.com>
Signed-off-by: Gui-Dong Han <hanguidong02@gmail.com>
---
The Bugzilla entry contains full KASAN reports and two PoCs that reliably
reproduce the UAF on both unlocked paths using a standard QEMU setup
(default e1000 device at 0000:00:03.0).
I chose to fix this in the driver core for the following reasons:
1. Both racing functions are part of the driver core.
2. Fixing this per-driver/per-bus is tedious and would require careful
ad-hoc locking that does not align with the existing device_lock(dev).
3. We cannot simply add device_lock(dev) inside bus match functions because
one call path (__device_attach_driver) already holds this lock. Adding the
lock inside the match callback would cause a deadlock on that path.
---
drivers/base/bus.c | 17 ++++++++++++-----
drivers/base/dd.c | 3 +++
2 files changed, 15 insertions(+), 5 deletions(-)
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index 5e75e1bce551..9e62d6009058 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -261,13 +261,20 @@ static ssize_t bind_store(struct device_driver *drv, const char *buf,
const struct bus_type *bus = bus_get(drv->bus);
struct device *dev;
int err = -ENODEV;
+ int ret;
dev = bus_find_device_by_name(bus, NULL, buf);
- if (dev && driver_match_device(drv, dev)) {
- err = device_driver_attach(drv, dev);
- if (!err) {
- /* success */
- err = count;
+ if (dev) {
+ /* Protects against driver_set_override() races */
+ device_lock(dev);
+ ret = driver_match_device(drv, dev);
+ device_unlock(dev);
+ if (ret) {
+ err = device_driver_attach(drv, dev);
+ if (!err) {
+ /* success */
+ err = count;
+ }
}
}
put_device(dev);
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index 13ab98e033ea..db60b4500136 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -1170,7 +1170,10 @@ static int __driver_attach(struct device *dev, void *data)
* is an error.
*/
+ /* Protects against driver_set_override() races */
+ device_lock(dev);
ret = driver_match_device(drv, dev);
+ device_unlock(dev);
if (ret == 0) {
/* no match */
return 0;
--
2.43.0
next reply other threads:[~2025-11-26 11:30 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-11-26 11:30 Gui-Dong Han [this message]
2025-11-26 11:39 ` [PATCH] driver core: fix use-after-free of driver_override via driver_match_device() Greg KH
2025-11-26 11:55 ` Gui-Dong Han
2025-11-26 12:28 ` Greg KH
2025-11-26 16:06 ` Gui-Dong Han
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20251126113006.9925-1-hanguidong02@gmail.com \
--to=hanguidong02@gmail.com \
--cc=baijiaju1990@gmail.com \
--cc=chenqiuji666@gmail.com \
--cc=dakr@kernel.org \
--cc=gregkh@linuxfoundation.org \
--cc=linux-kernel@vger.kernel.org \
--cc=rafael@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.