On Mon, 23 Mar 2026 at 19:00, Danilo Krummrich <[email protected]> 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/[email protected]/ [1] > Reported-by: Gui-Dong Han <[email protected]> > Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220789 > Fixes: e95060478244 ("rpmsg: Introduce a driver override mechanism") > Signed-off-by: Danilo Krummrich <[email protected]> > --- > drivers/rpmsg/qcom_glink_native.c | 2 --
For the below files: Reviewed-by: Mathieu Poirier <[email protected]> > 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 >

