Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

vdpa: use generic driver_override infrastructure

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: 539fec78edb4 ("vdpa: add driver_override support")
Acked-by: Eugenio Pérez <eperezma@redhat.com>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
Link: https://patch.msgid.link/20260324005919.2408620-9-dakr@kernel.org
Signed-off-by: Danilo Krummrich <dakr@kernel.org>

+5 -47
+5 -43
drivers/vdpa/vdpa.c
··· 67 67 68 68 static int vdpa_dev_match(struct device *dev, const struct device_driver *drv) 69 69 { 70 - struct vdpa_device *vdev = dev_to_vdpa(dev); 70 + int ret; 71 71 72 72 /* Check override first, and if set, only use the named driver */ 73 - if (vdev->driver_override) 74 - return strcmp(vdev->driver_override, drv->name) == 0; 73 + ret = device_match_driver_override(dev, drv); 74 + if (ret >= 0) 75 + return ret; 75 76 76 77 /* Currently devices must be supported by all vDPA bus drivers */ 77 78 return 1; 78 79 } 79 80 80 - static ssize_t driver_override_store(struct device *dev, 81 - struct device_attribute *attr, 82 - const char *buf, size_t count) 83 - { 84 - struct vdpa_device *vdev = dev_to_vdpa(dev); 85 - int ret; 86 - 87 - ret = driver_set_override(dev, &vdev->driver_override, buf, count); 88 - if (ret) 89 - return ret; 90 - 91 - return count; 92 - } 93 - 94 - static ssize_t driver_override_show(struct device *dev, 95 - struct device_attribute *attr, char *buf) 96 - { 97 - struct vdpa_device *vdev = dev_to_vdpa(dev); 98 - ssize_t len; 99 - 100 - device_lock(dev); 101 - len = sysfs_emit(buf, "%s\n", vdev->driver_override); 102 - device_unlock(dev); 103 - 104 - return len; 105 - } 106 - static DEVICE_ATTR_RW(driver_override); 107 - 108 - static struct attribute *vdpa_dev_attrs[] = { 109 - &dev_attr_driver_override.attr, 110 - NULL, 111 - }; 112 - 113 - static const struct attribute_group vdpa_dev_group = { 114 - .attrs = vdpa_dev_attrs, 115 - }; 116 - __ATTRIBUTE_GROUPS(vdpa_dev); 117 - 118 81 static const struct bus_type vdpa_bus = { 119 82 .name = "vdpa", 120 - .dev_groups = vdpa_dev_groups, 83 + .driver_override = true, 121 84 .match = vdpa_dev_match, 122 85 .probe = vdpa_dev_probe, 123 86 .remove = vdpa_dev_remove, ··· 95 132 ops->free(vdev); 96 133 97 134 ida_free(&vdpa_index_ida, vdev->index); 98 - kfree(vdev->driver_override); 99 135 kfree(vdev); 100 136 } 101 137
-4
include/linux/vdpa.h
··· 72 72 * struct vdpa_device - representation of a vDPA device 73 73 * @dev: underlying device 74 74 * @vmap: the metadata passed to upper layer to be used for mapping 75 - * @driver_override: driver name to force a match; do not set directly, 76 - * because core frees it; use driver_set_override() to 77 - * set or clear it. 78 75 * @config: the configuration ops for this device. 79 76 * @map: the map ops for this device 80 77 * @cf_lock: Protects get and set access to configuration layout. ··· 87 90 struct vdpa_device { 88 91 struct device dev; 89 92 union virtio_map vmap; 90 - const char *driver_override; 91 93 const struct vdpa_config_ops *config; 92 94 const struct virtio_map_ops *map; 93 95 struct rw_semaphore cf_lock; /* Protects get/set config */