From: Greg KH <gregkh@linuxfoundation.org>
To: Gui-Dong Han <hanguidong02@gmail.com>
Cc: rafael@kernel.org, dakr@kernel.org, linux-kernel@vger.kernel.org,
baijiaju1990@gmail.com, Qiu-ji Chen <chenqiuji666@gmail.com>
Subject: Re: [PATCH v2] driver core: fix use-after-free of driver_override via driver_match_device()
Date: Thu, 27 Nov 2025 10:16:01 +0100 [thread overview]
Message-ID: <2025112726-directly-underfeed-fb07@gregkh> (raw)
In-Reply-To: <20251126160011.11649-1-hanguidong02@gmail.com>
On Thu, Nov 27, 2025 at 12:00:11AM +0800, Gui-Dong Han wrote:
> 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. Also add a lock assertion to driver_match_device() to prevent future
> locking regressions.
>
> 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>
> ---
> v2:
> * Add device_lock_assert() in driver_match_device() to enforce locking
> requirement, as suggested by Greg KH.
> v1:
> * 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/base.h | 2 ++
> drivers/base/bus.c | 17 ++++++++++++-----
> drivers/base/dd.c | 3 +++
> 3 files changed, 17 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/base/base.h b/drivers/base/base.h
> index 86fa7fbb3548..011e910a53f8 100644
> --- a/drivers/base/base.h
> +++ b/drivers/base/base.h
> @@ -166,6 +166,8 @@ 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)
> {
> + /* Protects against driver_set_override() races */
> + device_lock_assert(dev);
> return drv->bus->match ? drv->bus->match(dev, drv) : 1;
A new line after the assert?
And thanks for adding the comment, but:
> }
>
> 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 */
This comment isn't needed anymore.
> + 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 */
Nor is this one.
Also, I looked again, and why are you not grabbing the lock in the
bind_store() sysfs call? driver_match_device() is only called in 3
places, 2 now have the lock held, and one does not. This feels wrong.
thanks,
greg k-h
next prev parent reply other threads:[~2025-11-27 9:16 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-11-26 16:00 [PATCH v2] driver core: fix use-after-free of driver_override via driver_match_device() Gui-Dong Han
2025-11-27 9:16 ` Greg KH [this message]
2025-11-27 15:00 ` Gui-Dong Han
2025-11-27 15:21 ` Greg KH
2026-01-13 2:27 ` Gui-Dong Han
2026-01-13 9:58 ` Danilo Krummrich
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=2025112726-directly-underfeed-fb07@gregkh \
--to=gregkh@linuxfoundation.org \
--cc=baijiaju1990@gmail.com \
--cc=chenqiuji666@gmail.com \
--cc=dakr@kernel.org \
--cc=hanguidong02@gmail.com \
--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.