]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
driver core: platform: use generic driver_override infrastructure
authorDanilo Krummrich <dakr@kernel.org>
Tue, 3 Mar 2026 11:53:21 +0000 (12:53 +0100)
committerDanilo Krummrich <dakr@kernel.org>
Tue, 17 Mar 2026 19:30:57 +0000 (20:30 +0100)
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/
Reported-by: Gui-Dong Han <hanguidong02@gmail.com>
Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220789
Fixes: 3d713e0e382e ("driver core: platform: add device binding path 'driver_override'")
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Link: https://patch.msgid.link/20260303115720.48783-5-dakr@kernel.org
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
drivers/base/platform.c
drivers/bus/simple-pm-bus.c
drivers/clk/imx/clk-scu.c
drivers/slimbus/qcom-ngd-ctrl.c
include/linux/platform_device.h
sound/soc/samsung/i2s.c

index b45d41b018ca6dc2677af7709b27a3735a4bc780..d44591d52e3633decefb0ea2cdf5d18d17d0ccdc 100644 (file)
@@ -603,7 +603,6 @@ static void platform_device_release(struct device *dev)
        kfree(pa->pdev.dev.platform_data);
        kfree(pa->pdev.mfd_cell);
        kfree(pa->pdev.resource);
-       kfree(pa->pdev.driver_override);
        kfree(pa);
 }
 
@@ -1306,38 +1305,9 @@ static ssize_t numa_node_show(struct device *dev,
 }
 static DEVICE_ATTR_RO(numa_node);
 
-static ssize_t driver_override_show(struct device *dev,
-                                   struct device_attribute *attr, char *buf)
-{
-       struct platform_device *pdev = to_platform_device(dev);
-       ssize_t len;
-
-       device_lock(dev);
-       len = sysfs_emit(buf, "%s\n", pdev->driver_override);
-       device_unlock(dev);
-
-       return len;
-}
-
-static ssize_t driver_override_store(struct device *dev,
-                                    struct device_attribute *attr,
-                                    const char *buf, size_t count)
-{
-       struct platform_device *pdev = to_platform_device(dev);
-       int ret;
-
-       ret = driver_set_override(dev, &pdev->driver_override, buf, count);
-       if (ret)
-               return ret;
-
-       return count;
-}
-static DEVICE_ATTR_RW(driver_override);
-
 static struct attribute *platform_dev_attrs[] = {
        &dev_attr_modalias.attr,
        &dev_attr_numa_node.attr,
-       &dev_attr_driver_override.attr,
        NULL,
 };
 
@@ -1377,10 +1347,12 @@ static int platform_match(struct device *dev, const struct device_driver *drv)
 {
        struct platform_device *pdev = to_platform_device(dev);
        struct platform_driver *pdrv = to_platform_driver(drv);
+       int ret;
 
        /* When driver_override is set, only bind to the matching driver */
-       if (pdev->driver_override)
-               return !strcmp(pdev->driver_override, drv->name);
+       ret = device_match_driver_override(dev, drv);
+       if (ret >= 0)
+               return ret;
 
        /* Attempt an OF style match first */
        if (of_driver_match_device(dev, drv))
@@ -1516,6 +1488,7 @@ static const struct dev_pm_ops platform_dev_pm_ops = {
 const struct bus_type platform_bus_type = {
        .name           = "platform",
        .dev_groups     = platform_dev_groups,
+       .driver_override = true,
        .match          = platform_match,
        .uevent         = platform_uevent,
        .probe          = platform_probe,
index 3f00d953fb9a0eb3f3225ffa913ab4f12336913f..c920bd6fbaafd42a5ec6c4af9bd66d683a5deef5 100644 (file)
@@ -36,7 +36,7 @@ static int simple_pm_bus_probe(struct platform_device *pdev)
         * that's not listed in simple_pm_bus_of_match. We don't want to do any
         * of the simple-pm-bus tasks for these devices, so return early.
         */
-       if (pdev->driver_override)
+       if (device_has_driver_override(&pdev->dev))
                return 0;
 
        match = of_match_device(dev->driver->of_match_table, dev);
@@ -78,7 +78,7 @@ static void simple_pm_bus_remove(struct platform_device *pdev)
 {
        const void *data = of_device_get_match_data(&pdev->dev);
 
-       if (pdev->driver_override || data)
+       if (device_has_driver_override(&pdev->dev) || data)
                return;
 
        dev_dbg(&pdev->dev, "%s\n", __func__);
index a85ec48a798b58a12f893587c85709bbd8476310..9b33df9967ece452f0b1b6452ec6010013d8d830 100644 (file)
@@ -706,8 +706,7 @@ struct clk_hw *imx_clk_scu_alloc_dev(const char *name,
        if (ret)
                goto put_device;
 
-       ret = driver_set_override(&pdev->dev, &pdev->driver_override,
-                                 "imx-scu-clk", strlen("imx-scu-clk"));
+       ret = device_set_driver_override(&pdev->dev, "imx-scu-clk");
        if (ret)
                goto put_device;
 
index 9aa7218b4e8d2b350835626839371ed6e19860e2..1ed6be6e85d2cfc0a2b65a5ae24f666de922c89d 100644 (file)
@@ -1535,10 +1535,8 @@ static int of_qcom_slim_ngd_register(struct device *parent,
                ngd->id = id;
                ngd->pdev->dev.parent = parent;
 
-               ret = driver_set_override(&ngd->pdev->dev,
-                                         &ngd->pdev->driver_override,
-                                         QCOM_SLIM_NGD_DRV_NAME,
-                                         strlen(QCOM_SLIM_NGD_DRV_NAME));
+               ret = device_set_driver_override(&ngd->pdev->dev,
+                                                QCOM_SLIM_NGD_DRV_NAME);
                if (ret) {
                        platform_device_put(ngd->pdev);
                        kfree(ngd);
index 813da101b5bf8e32b49948a47f59a6072514ef4e..ed1d50d1c3c15c8bf8ca41fb9a0c89e09391699f 100644 (file)
@@ -31,11 +31,6 @@ struct platform_device {
        struct resource *resource;
 
        const struct platform_device_id *id_entry;
-       /*
-        * Driver name to force a match.  Do not set directly, because core
-        * frees it.  Use driver_set_override() to set or clear it.
-        */
-       const char *driver_override;
 
        /* MFD cell pointer */
        struct mfd_cell *mfd_cell;
index e9964f0e010aee549cced75d8fe2023e8271d443..140907a41a70dfabb7735b4b38c0af7c254b85e2 100644 (file)
@@ -1360,10 +1360,10 @@ static int i2s_create_secondary_device(struct samsung_i2s_priv *priv)
        if (!pdev_sec)
                return -ENOMEM;
 
-       pdev_sec->driver_override = kstrdup("samsung-i2s", GFP_KERNEL);
-       if (!pdev_sec->driver_override) {
+       ret = device_set_driver_override(&pdev_sec->dev, "samsung-i2s");
+       if (ret) {
                platform_device_put(pdev_sec);
-               return -ENOMEM;
+               return ret;
        }
 
        ret = platform_device_add(pdev_sec);