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.

platform/wmi: 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: 12046f8c77e0 ("platform/x86: wmi: Add driver_override support")
Reviewed-by: Armin Wolf <W_Armin@gmx.de>
Acked-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Link: https://patch.msgid.link/20260324005919.2408620-7-dakr@kernel.org
Signed-off-by: Danilo Krummrich <dakr@kernel.org>

+5 -35
+5 -31
drivers/platform/wmi/core.c
··· 842 842 } 843 843 static DEVICE_ATTR_RO(expensive); 844 844 845 - static ssize_t driver_override_show(struct device *dev, struct device_attribute *attr, 846 - char *buf) 847 - { 848 - struct wmi_device *wdev = to_wmi_device(dev); 849 - ssize_t ret; 850 - 851 - device_lock(dev); 852 - ret = sysfs_emit(buf, "%s\n", wdev->driver_override); 853 - device_unlock(dev); 854 - 855 - return ret; 856 - } 857 - 858 - static ssize_t driver_override_store(struct device *dev, struct device_attribute *attr, 859 - const char *buf, size_t count) 860 - { 861 - struct wmi_device *wdev = to_wmi_device(dev); 862 - int ret; 863 - 864 - ret = driver_set_override(dev, &wdev->driver_override, buf, count); 865 - if (ret < 0) 866 - return ret; 867 - 868 - return count; 869 - } 870 - static DEVICE_ATTR_RW(driver_override); 871 - 872 845 static struct attribute *wmi_attrs[] = { 873 846 &dev_attr_modalias.attr, 874 847 &dev_attr_guid.attr, 875 848 &dev_attr_instance_count.attr, 876 849 &dev_attr_expensive.attr, 877 - &dev_attr_driver_override.attr, 878 850 NULL 879 851 }; 880 852 ATTRIBUTE_GROUPS(wmi); ··· 915 943 { 916 944 struct wmi_block *wblock = dev_to_wblock(dev); 917 945 918 - kfree(wblock->dev.driver_override); 919 946 kfree(wblock); 920 947 } 921 948 ··· 923 952 const struct wmi_driver *wmi_driver = to_wmi_driver(driver); 924 953 struct wmi_block *wblock = dev_to_wblock(dev); 925 954 const struct wmi_device_id *id = wmi_driver->id_table; 955 + int ret; 926 956 927 957 /* When driver_override is set, only bind to the matching driver */ 928 - if (wblock->dev.driver_override) 929 - return !strcmp(wblock->dev.driver_override, driver->name); 958 + ret = device_match_driver_override(dev, driver); 959 + if (ret >= 0) 960 + return ret; 930 961 931 962 if (id == NULL) 932 963 return 0; ··· 1049 1076 static const struct bus_type wmi_bus_type = { 1050 1077 .name = "wmi", 1051 1078 .dev_groups = wmi_groups, 1079 + .driver_override = true, 1052 1080 .match = wmi_dev_match, 1053 1081 .uevent = wmi_dev_uevent, 1054 1082 .probe = wmi_dev_probe,
-4
include/linux/wmi.h
··· 18 18 * struct wmi_device - WMI device structure 19 19 * @dev: Device associated with this WMI device 20 20 * @setable: True for devices implementing the Set Control Method 21 - * @driver_override: Driver name to force a match; do not set directly, 22 - * because core frees it; use driver_set_override() to 23 - * set or clear it. 24 21 * 25 22 * This represents WMI devices discovered by the WMI driver core. 26 23 */ 27 24 struct wmi_device { 28 25 struct device dev; 29 26 bool setable; 30 - const char *driver_override; 31 27 }; 32 28 33 29 /**