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.

Merge tag 'driver-core-7.0-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/driver-core/driver-core

Pull driver core fixes from Danilo Krummrich:

- Generalize driver_override in the driver core, providing a common
sysfs implementation and concurrency-safe accessors for bus
implementations

- Do not use driver_override as IRQ name in the hwmon axi-fan driver

- Remove an unnecessary driver_override check in sh platform_early

- Migrate the platform bus to use the generic driver_override
infrastructure, fixing a UAF condition caused by accessing the
driver_override field without proper locking in the platform_match()
callback

* tag 'driver-core-7.0-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/driver-core/driver-core:
driver core: platform: use generic driver_override infrastructure
sh: platform_early: remove pdev->driver_override check
hwmon: axi-fan: don't use driver_override as IRQ name
docs: driver-model: document driver_override
driver core: generalize driver_override in struct device

+224 -54
+48
Documentation/driver-api/driver-model/binding.rst
··· 99 99 When a driver is removed, the list of devices that it supports is 100 100 iterated over, and the driver's remove callback is called for each 101 101 one. The device is removed from that list and the symlinks removed. 102 + 103 + 104 + Driver Override 105 + ~~~~~~~~~~~~~~~ 106 + 107 + Userspace may override the standard matching by writing a driver name to 108 + a device's ``driver_override`` sysfs attribute. When set, only a driver 109 + whose name matches the override will be considered during binding. This 110 + bypasses all bus-specific matching (OF, ACPI, ID tables, etc.). 111 + 112 + The override may be cleared by writing an empty string, which returns 113 + the device to standard matching rules. Writing to ``driver_override`` 114 + does not automatically unbind the device from its current driver or 115 + make any attempt to load the specified driver. 116 + 117 + Buses opt into this mechanism by setting the ``driver_override`` flag in 118 + their ``struct bus_type``:: 119 + 120 + const struct bus_type example_bus_type = { 121 + ... 122 + .driver_override = true, 123 + }; 124 + 125 + When the flag is set, the driver core automatically creates the 126 + ``driver_override`` sysfs attribute for every device on that bus. 127 + 128 + The bus's ``match()`` callback should check the override before performing 129 + its own matching, using ``device_match_driver_override()``:: 130 + 131 + static int example_match(struct device *dev, const struct device_driver *drv) 132 + { 133 + int ret; 134 + 135 + ret = device_match_driver_override(dev, drv); 136 + if (ret >= 0) 137 + return ret; 138 + 139 + /* Fall through to bus-specific matching... */ 140 + } 141 + 142 + ``device_match_driver_override()`` returns > 0 if the override matches 143 + the given driver, 0 if the override is set but does not match, or < 0 if 144 + no override is set at all. 145 + 146 + Additional helpers are available: 147 + 148 + - ``device_set_driver_override()`` - set or clear the override from kernel code. 149 + - ``device_has_driver_override()`` - check whether an override is set.
-4
arch/sh/drivers/platform_early.c
··· 26 26 struct platform_device *pdev = to_platform_device(dev); 27 27 struct platform_driver *pdrv = to_platform_driver(drv); 28 28 29 - /* When driver_override is set, only bind to the matching driver */ 30 - if (pdev->driver_override) 31 - return !strcmp(pdev->driver_override, drv->name); 32 - 33 29 /* Then try to match against the id table */ 34 30 if (pdrv->id_table) 35 31 return platform_match_id(pdrv->id_table, pdev) != NULL;
+42 -1
drivers/base/bus.c
··· 504 504 } 505 505 EXPORT_SYMBOL_GPL(bus_for_each_drv); 506 506 507 + static ssize_t driver_override_store(struct device *dev, 508 + struct device_attribute *attr, 509 + const char *buf, size_t count) 510 + { 511 + int ret; 512 + 513 + ret = __device_set_driver_override(dev, buf, count); 514 + if (ret) 515 + return ret; 516 + 517 + return count; 518 + } 519 + 520 + static ssize_t driver_override_show(struct device *dev, 521 + struct device_attribute *attr, char *buf) 522 + { 523 + guard(spinlock)(&dev->driver_override.lock); 524 + return sysfs_emit(buf, "%s\n", dev->driver_override.name); 525 + } 526 + static DEVICE_ATTR_RW(driver_override); 527 + 528 + static struct attribute *driver_override_dev_attrs[] = { 529 + &dev_attr_driver_override.attr, 530 + NULL, 531 + }; 532 + 533 + static const struct attribute_group driver_override_dev_group = { 534 + .attrs = driver_override_dev_attrs, 535 + }; 536 + 507 537 /** 508 538 * bus_add_device - add device to bus 509 539 * @dev: device being added ··· 567 537 if (error) 568 538 goto out_put; 569 539 540 + if (dev->bus->driver_override) { 541 + error = device_add_group(dev, &driver_override_dev_group); 542 + if (error) 543 + goto out_groups; 544 + } 545 + 570 546 error = sysfs_create_link(&sp->devices_kset->kobj, &dev->kobj, dev_name(dev)); 571 547 if (error) 572 - goto out_groups; 548 + goto out_override; 573 549 574 550 error = sysfs_create_link(&dev->kobj, &sp->subsys.kobj, "subsystem"); 575 551 if (error) ··· 586 550 587 551 out_subsys: 588 552 sysfs_remove_link(&sp->devices_kset->kobj, dev_name(dev)); 553 + out_override: 554 + if (dev->bus->driver_override) 555 + device_remove_group(dev, &driver_override_dev_group); 589 556 out_groups: 590 557 device_remove_groups(dev, sp->bus->dev_groups); 591 558 out_put: ··· 646 607 647 608 sysfs_remove_link(&dev->kobj, "subsystem"); 648 609 sysfs_remove_link(&sp->devices_kset->kobj, dev_name(dev)); 610 + if (dev->bus->driver_override) 611 + device_remove_group(dev, &driver_override_dev_group); 649 612 device_remove_groups(dev, dev->bus->dev_groups); 650 613 if (klist_node_attached(&dev->p->knode_bus)) 651 614 klist_del(&dev->p->knode_bus);
+2
drivers/base/core.c
··· 2556 2556 devres_release_all(dev); 2557 2557 2558 2558 kfree(dev->dma_range_map); 2559 + kfree(dev->driver_override.name); 2559 2560 2560 2561 if (dev->release) 2561 2562 dev->release(dev); ··· 3160 3159 kobject_init(&dev->kobj, &device_ktype); 3161 3160 INIT_LIST_HEAD(&dev->dma_pools); 3162 3161 mutex_init(&dev->mutex); 3162 + spin_lock_init(&dev->driver_override.lock); 3163 3163 lockdep_set_novalidate_class(&dev->mutex); 3164 3164 spin_lock_init(&dev->devres_lock); 3165 3165 INIT_LIST_HEAD(&dev->devres_head);
+60
drivers/base/dd.c
··· 381 381 } 382 382 __exitcall(deferred_probe_exit); 383 383 384 + int __device_set_driver_override(struct device *dev, const char *s, size_t len) 385 + { 386 + const char *new, *old; 387 + char *cp; 388 + 389 + if (!s) 390 + return -EINVAL; 391 + 392 + /* 393 + * The stored value will be used in sysfs show callback (sysfs_emit()), 394 + * which has a length limit of PAGE_SIZE and adds a trailing newline. 395 + * Thus we can store one character less to avoid truncation during sysfs 396 + * show. 397 + */ 398 + if (len >= (PAGE_SIZE - 1)) 399 + return -EINVAL; 400 + 401 + /* 402 + * Compute the real length of the string in case userspace sends us a 403 + * bunch of \0 characters like python likes to do. 404 + */ 405 + len = strlen(s); 406 + 407 + if (!len) { 408 + /* Empty string passed - clear override */ 409 + spin_lock(&dev->driver_override.lock); 410 + old = dev->driver_override.name; 411 + dev->driver_override.name = NULL; 412 + spin_unlock(&dev->driver_override.lock); 413 + kfree(old); 414 + 415 + return 0; 416 + } 417 + 418 + cp = strnchr(s, len, '\n'); 419 + if (cp) 420 + len = cp - s; 421 + 422 + new = kstrndup(s, len, GFP_KERNEL); 423 + if (!new) 424 + return -ENOMEM; 425 + 426 + spin_lock(&dev->driver_override.lock); 427 + old = dev->driver_override.name; 428 + if (cp != s) { 429 + dev->driver_override.name = new; 430 + spin_unlock(&dev->driver_override.lock); 431 + } else { 432 + /* "\n" passed - clear override */ 433 + dev->driver_override.name = NULL; 434 + spin_unlock(&dev->driver_override.lock); 435 + 436 + kfree(new); 437 + } 438 + kfree(old); 439 + 440 + return 0; 441 + } 442 + EXPORT_SYMBOL_GPL(__device_set_driver_override); 443 + 384 444 /** 385 445 * device_is_bound() - Check if device is bound to a driver 386 446 * @dev: device to check
+5 -32
drivers/base/platform.c
··· 603 603 kfree(pa->pdev.dev.platform_data); 604 604 kfree(pa->pdev.mfd_cell); 605 605 kfree(pa->pdev.resource); 606 - kfree(pa->pdev.driver_override); 607 606 kfree(pa); 608 607 } 609 608 ··· 1305 1306 } 1306 1307 static DEVICE_ATTR_RO(numa_node); 1307 1308 1308 - static ssize_t driver_override_show(struct device *dev, 1309 - struct device_attribute *attr, char *buf) 1310 - { 1311 - struct platform_device *pdev = to_platform_device(dev); 1312 - ssize_t len; 1313 - 1314 - device_lock(dev); 1315 - len = sysfs_emit(buf, "%s\n", pdev->driver_override); 1316 - device_unlock(dev); 1317 - 1318 - return len; 1319 - } 1320 - 1321 - static ssize_t driver_override_store(struct device *dev, 1322 - struct device_attribute *attr, 1323 - const char *buf, size_t count) 1324 - { 1325 - struct platform_device *pdev = to_platform_device(dev); 1326 - int ret; 1327 - 1328 - ret = driver_set_override(dev, &pdev->driver_override, buf, count); 1329 - if (ret) 1330 - return ret; 1331 - 1332 - return count; 1333 - } 1334 - static DEVICE_ATTR_RW(driver_override); 1335 - 1336 1309 static struct attribute *platform_dev_attrs[] = { 1337 1310 &dev_attr_modalias.attr, 1338 1311 &dev_attr_numa_node.attr, 1339 - &dev_attr_driver_override.attr, 1340 1312 NULL, 1341 1313 }; 1342 1314 ··· 1347 1377 { 1348 1378 struct platform_device *pdev = to_platform_device(dev); 1349 1379 struct platform_driver *pdrv = to_platform_driver(drv); 1380 + int ret; 1350 1381 1351 1382 /* When driver_override is set, only bind to the matching driver */ 1352 - if (pdev->driver_override) 1353 - return !strcmp(pdev->driver_override, drv->name); 1383 + ret = device_match_driver_override(dev, drv); 1384 + if (ret >= 0) 1385 + return ret; 1354 1386 1355 1387 /* Attempt an OF style match first */ 1356 1388 if (of_driver_match_device(dev, drv)) ··· 1488 1516 const struct bus_type platform_bus_type = { 1489 1517 .name = "platform", 1490 1518 .dev_groups = platform_dev_groups, 1519 + .driver_override = true, 1491 1520 .match = platform_match, 1492 1521 .uevent = platform_uevent, 1493 1522 .probe = platform_probe,
+2 -2
drivers/bus/simple-pm-bus.c
··· 36 36 * that's not listed in simple_pm_bus_of_match. We don't want to do any 37 37 * of the simple-pm-bus tasks for these devices, so return early. 38 38 */ 39 - if (pdev->driver_override) 39 + if (device_has_driver_override(&pdev->dev)) 40 40 return 0; 41 41 42 42 match = of_match_device(dev->driver->of_match_table, dev); ··· 78 78 { 79 79 const void *data = of_device_get_match_data(&pdev->dev); 80 80 81 - if (pdev->driver_override || data) 81 + if (device_has_driver_override(&pdev->dev) || data) 82 82 return; 83 83 84 84 dev_dbg(&pdev->dev, "%s\n", __func__);
+1 -2
drivers/clk/imx/clk-scu.c
··· 706 706 if (ret) 707 707 goto put_device; 708 708 709 - ret = driver_set_override(&pdev->dev, &pdev->driver_override, 710 - "imx-scu-clk", strlen("imx-scu-clk")); 709 + ret = device_set_driver_override(&pdev->dev, "imx-scu-clk"); 711 710 if (ret) 712 711 goto put_device; 713 712
+1 -1
drivers/hwmon/axi-fan-control.c
··· 507 507 ret = devm_request_threaded_irq(&pdev->dev, ctl->irq, NULL, 508 508 axi_fan_control_irq_handler, 509 509 IRQF_ONESHOT | IRQF_TRIGGER_HIGH, 510 - pdev->driver_override, ctl); 510 + NULL, ctl); 511 511 if (ret) 512 512 return dev_err_probe(&pdev->dev, ret, 513 513 "failed to request an irq\n");
+2 -4
drivers/slimbus/qcom-ngd-ctrl.c
··· 1535 1535 ngd->id = id; 1536 1536 ngd->pdev->dev.parent = parent; 1537 1537 1538 - ret = driver_set_override(&ngd->pdev->dev, 1539 - &ngd->pdev->driver_override, 1540 - QCOM_SLIM_NGD_DRV_NAME, 1541 - strlen(QCOM_SLIM_NGD_DRV_NAME)); 1538 + ret = device_set_driver_override(&ngd->pdev->dev, 1539 + QCOM_SLIM_NGD_DRV_NAME); 1542 1540 if (ret) { 1543 1541 platform_device_put(ngd->pdev); 1544 1542 kfree(ngd);
+54
include/linux/device.h
··· 483 483 * on. This shrinks the "Board Support Packages" (BSPs) and 484 484 * minimizes board-specific #ifdefs in drivers. 485 485 * @driver_data: Private pointer for driver specific info. 486 + * @driver_override: Driver name to force a match. Do not touch directly; use 487 + * device_set_driver_override() instead. 486 488 * @links: Links to suppliers and consumers of this device. 487 489 * @power: For device power management. 488 490 * See Documentation/driver-api/pm/devices.rst for details. ··· 578 576 core doesn't touch it */ 579 577 void *driver_data; /* Driver data, set and get with 580 578 dev_set_drvdata/dev_get_drvdata */ 579 + struct { 580 + const char *name; 581 + spinlock_t lock; 582 + } driver_override; 581 583 struct mutex mutex; /* mutex to synchronize calls to 582 584 * its driver. 583 585 */ ··· 706 700 }; 707 701 708 702 #define kobj_to_dev(__kobj) container_of_const(__kobj, struct device, kobj) 703 + 704 + int __device_set_driver_override(struct device *dev, const char *s, size_t len); 705 + 706 + /** 707 + * device_set_driver_override() - Helper to set or clear driver override. 708 + * @dev: Device to change 709 + * @s: NUL-terminated string, new driver name to force a match, pass empty 710 + * string to clear it ("" or "\n", where the latter is only for sysfs 711 + * interface). 712 + * 713 + * Helper to set or clear driver override of a device. 714 + * 715 + * Returns: 0 on success or a negative error code on failure. 716 + */ 717 + static inline int device_set_driver_override(struct device *dev, const char *s) 718 + { 719 + return __device_set_driver_override(dev, s, s ? strlen(s) : 0); 720 + } 721 + 722 + /** 723 + * device_has_driver_override() - Check if a driver override has been set. 724 + * @dev: device to check 725 + * 726 + * Returns true if a driver override has been set for this device. 727 + */ 728 + static inline bool device_has_driver_override(struct device *dev) 729 + { 730 + guard(spinlock)(&dev->driver_override.lock); 731 + return !!dev->driver_override.name; 732 + } 733 + 734 + /** 735 + * device_match_driver_override() - Match a driver against the device's driver_override. 736 + * @dev: device to check 737 + * @drv: driver to match against 738 + * 739 + * Returns > 0 if a driver override is set and matches the given driver, 0 if a 740 + * driver override is set but does not match, or < 0 if a driver override is not 741 + * set at all. 742 + */ 743 + static inline int device_match_driver_override(struct device *dev, 744 + const struct device_driver *drv) 745 + { 746 + guard(spinlock)(&dev->driver_override.lock); 747 + if (dev->driver_override.name) 748 + return !strcmp(dev->driver_override.name, drv->name); 749 + return -1; 750 + } 709 751 710 752 /** 711 753 * device_iommu_mapped - Returns true when the device DMA is translated
+4
include/linux/device/bus.h
··· 65 65 * this bus. 66 66 * @pm: Power management operations of this bus, callback the specific 67 67 * device driver's pm-ops. 68 + * @driver_override: Set to true if this bus supports the driver_override 69 + * mechanism, which allows userspace to force a specific 70 + * driver to bind to a device via a sysfs attribute. 68 71 * @need_parent_lock: When probing or removing a device on this bus, the 69 72 * device core should lock the device's parent. 70 73 * ··· 109 106 110 107 const struct dev_pm_ops *pm; 111 108 109 + bool driver_override; 112 110 bool need_parent_lock; 113 111 }; 114 112
-5
include/linux/platform_device.h
··· 31 31 struct resource *resource; 32 32 33 33 const struct platform_device_id *id_entry; 34 - /* 35 - * Driver name to force a match. Do not set directly, because core 36 - * frees it. Use driver_set_override() to set or clear it. 37 - */ 38 - const char *driver_override; 39 34 40 35 /* MFD cell pointer */ 41 36 struct mfd_cell *mfd_cell;
+3 -3
sound/soc/samsung/i2s.c
··· 1360 1360 if (!pdev_sec) 1361 1361 return -ENOMEM; 1362 1362 1363 - pdev_sec->driver_override = kstrdup("samsung-i2s", GFP_KERNEL); 1364 - if (!pdev_sec->driver_override) { 1363 + ret = device_set_driver_override(&pdev_sec->dev, "samsung-i2s"); 1364 + if (ret) { 1365 1365 platform_device_put(pdev_sec); 1366 - return -ENOMEM; 1366 + return ret; 1367 1367 } 1368 1368 1369 1369 ret = platform_device_add(pdev_sec);