Re: [PATCH 07/12] rpmsg: use generic driver_override infrastructure

Mathieu Poirier
2026-03-25T15:49:44Z

On Mon, 23 Mar 2026 at 19:00, Danilo Krummrich <dakr@kernel.org> wrote:
>
> 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 <hanguidong02@gmail.com>
> Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220789
> Fixes: e95060478244 ("rpmsg: Introduce a driver override mechanism")
> Signed-off-by: Danilo Krummrich <dakr@kernel.org>
> ---
> drivers/rpmsg/qcom_glink_native.c | 2 --

For the below files:

Reviewed-by: Mathieu Poirier <mathieu.poirier@linaro.org>

> drivers/rpmsg/rpmsg_core.c | 43 +++++--------------------------
> drivers/rpmsg/virtio_rpmsg_bus.c | 1 -
> include/linux/rpmsg.h | 4 ---
> 4 files changed, 7 insertions(+), 43 deletions(-)
>
> diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c
> index 9ef17c2e45b0..e9d1b2082477 100644
> --- a/drivers/rpmsg/qcom_glink_native.c
> +++ b/drivers/rpmsg/qcom_glink_native.c
> @@ -1623,7 +1623,6 @@ static void qcom_glink_rpdev_release(struct device *dev)
> {
> struct rpmsg_device *rpdev = to_rpmsg_device(dev);
>
> - kfree(rpdev->driver_override);
> kfree(rpdev);
> }
>
> @@ -1859,7 +1858,6 @@ static void qcom_glink_device_release(struct device *dev)
>
> /* Release qcom_glink_alloc_channel() reference */
> kref_put(&channel->refcount, qcom_glink_channel_release);
> - kfree(rpdev->driver_override);
> kfree(rpdev);
> }
>
> diff --git a/drivers/rpmsg/rpmsg_core.c b/drivers/rpmsg/rpmsg_core.c
> index 96964745065b..2b9f6d5a9a4f 100644
> --- a/drivers/rpmsg/rpmsg_core.c
> +++ b/drivers/rpmsg/rpmsg_core.c
> @@ -358,33 +358,6 @@ rpmsg_show_attr(src, src, "0x%x\n");
> rpmsg_show_attr(dst, dst, "0x%x\n");
> rpmsg_show_attr(announce, announce ? "true" : "false", "%s\n");
>
> -static ssize_t driver_override_store(struct device *dev,
> - struct device_attribute *attr,
> - const char *buf, size_t count)
> -{
> - struct rpmsg_device *rpdev = to_rpmsg_device(dev);
> - int ret;
> -
> - ret = driver_set_override(dev, &rpdev->driver_override, buf, count);
> - if (ret)
> - return ret;
> -
> - return count;
> -}
> -
> -static ssize_t driver_override_show(struct device *dev,
> - struct device_attribute *attr, char *buf)
> -{
> - struct rpmsg_device *rpdev = to_rpmsg_device(dev);
> - ssize_t len;
> -
> - device_lock(dev);
> - len = sysfs_emit(buf, "%s\n", rpdev->driver_override);
> - device_unlock(dev);
> - return len;
> -}
> -static DEVICE_ATTR_RW(driver_override);
> -
> static ssize_t modalias_show(struct device *dev,
> struct device_attribute *attr, char *buf)
> {
> @@ -405,7 +378,6 @@ static struct attribute *rpmsg_dev_attrs[] = {
> &dev_attr_dst.attr,
> &dev_attr_src.attr,
> &dev_attr_announce.attr,
> - &dev_attr_driver_override.attr,
> NULL,
> };
> ATTRIBUTE_GROUPS(rpmsg_dev);
> @@ -424,9 +396,11 @@ static int rpmsg_dev_match(struct device *dev, const struct device_driver *drv)
> const struct rpmsg_driver *rpdrv = to_rpmsg_driver(drv);
> const struct rpmsg_device_id *ids = rpdrv->id_table;
> unsigned int i;
> + int ret;
>
> - if (rpdev->driver_override)
> - return !strcmp(rpdev->driver_override, drv->name);
> + ret = device_match_driver_override(dev, drv);
> + if (ret >= 0)
> + return ret;
>
> if (ids)
> for (i = 0; ids[i].name[0]; i++)
> @@ -535,6 +509,7 @@ static const struct bus_type rpmsg_bus = {
> .name = "rpmsg",
> .match = rpmsg_dev_match,
> .dev_groups = rpmsg_dev_groups,
> + .driver_override = true,
> .uevent = rpmsg_uevent,
> .probe = rpmsg_dev_probe,
> .remove = rpmsg_dev_remove,
> @@ -560,11 +535,9 @@ int rpmsg_register_device_override(struct rpmsg_device *rpdev,
>
> device_initialize(dev);
> if (driver_override) {
> - ret = driver_set_override(dev, &rpdev->driver_override,
> - driver_override,
> - strlen(driver_override));
> + ret = device_set_driver_override(dev, driver_override);
> if (ret) {
> - dev_err(dev, "device_set_override failed: %d\n", ret);
> + dev_err(dev, "device_set_driver_override() failed: %d\n", ret);
> put_device(dev);
> return ret;
> }
> @@ -573,8 +546,6 @@ int rpmsg_register_device_override(struct rpmsg_device *rpdev,
> ret = device_add(dev);
> if (ret) {
> dev_err(dev, "device_add failed: %d\n", ret);
> - kfree(rpdev->driver_override);
> - rpdev->driver_override = NULL;
> put_device(dev);
> }
>
> diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c
> index 8d9e2b4dc7c1..e0dacb736ef9 100644
> --- a/drivers/rpmsg/virtio_rpmsg_bus.c
> +++ b/drivers/rpmsg/virtio_rpmsg_bus.c
> @@ -373,7 +373,6 @@ static void virtio_rpmsg_release_device(struct device *dev)
> struct rpmsg_device *rpdev = to_rpmsg_device(dev);
> struct virtio_rpmsg_channel *vch = to_virtio_rpmsg_channel(rpdev);
>
> - kfree(rpdev->driver_override);
> kfree(vch);
> }
>
> diff --git a/include/linux/rpmsg.h b/include/linux/rpmsg.h
> index fb7ab9165645..c2e3ef8480d5 100644
> --- a/include/linux/rpmsg.h
> +++ b/include/linux/rpmsg.h
> @@ -41,9 +41,6 @@ struct rpmsg_channel_info {
> * rpmsg_device - device that belong to the rpmsg bus
> * @dev: the device struct
> * @id: device id (used to match between rpmsg drivers and devices)
> - * @driver_override: driver name to force a match; do not set directly,
> - * because core frees it; use driver_set_override() to
> - * set or clear it.
> * @src: local address
> * @dst: destination address
> * @ept: the rpmsg endpoint of this channel
> @@ -53,7 +50,6 @@ struct rpmsg_channel_info {
> struct rpmsg_device {
> struct device dev;
> struct rpmsg_device_id id;
> - const char *driver_override;
> u32 src;
> u32 dst;
> struct rpmsg_endpoint *ept;
> --
> 2.53.0
>