| From 9561475db680f7144d2223a409dd3d7e322aca03 Mon Sep 17 00:00:00 2001 |
| From: Nicolai Stange <nstange@suse.de> |
| Date: Mon, 11 Sep 2017 09:45:40 +0200 |
| Subject: PCI: Fix race condition with driver_override |
| |
| From: Nicolai Stange <nstange@suse.de> |
| |
| commit 9561475db680f7144d2223a409dd3d7e322aca03 upstream. |
| |
| The driver_override implementation is susceptible to a race condition when |
| different threads are reading vs. storing a different driver override. Add |
| locking to avoid the race condition. |
| |
| This is in close analogy to commit 6265539776a0 ("driver core: platform: |
| fix race condition with driver_override") from Adrian Salido. |
| |
| Fixes: 782a985d7af2 ("PCI: Introduce new device binding path using pci_dev.driver_override") |
| Signed-off-by: Nicolai Stange <nstange@suse.de> |
| Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/pci/pci-sysfs.c | 11 +++++++++-- |
| 1 file changed, 9 insertions(+), 2 deletions(-) |
| |
| --- a/drivers/pci/pci-sysfs.c |
| +++ b/drivers/pci/pci-sysfs.c |
| @@ -527,7 +527,7 @@ static ssize_t driver_override_store(str |
| const char *buf, size_t count) |
| { |
| struct pci_dev *pdev = to_pci_dev(dev); |
| - char *driver_override, *old = pdev->driver_override, *cp; |
| + char *driver_override, *old, *cp; |
| |
| /* We need to keep extra room for a newline */ |
| if (count >= (PAGE_SIZE - 1)) |
| @@ -541,12 +541,15 @@ static ssize_t driver_override_store(str |
| if (cp) |
| *cp = '\0'; |
| |
| + device_lock(dev); |
| + old = pdev->driver_override; |
| if (strlen(driver_override)) { |
| pdev->driver_override = driver_override; |
| } else { |
| kfree(driver_override); |
| pdev->driver_override = NULL; |
| } |
| + device_unlock(dev); |
| |
| kfree(old); |
| |
| @@ -557,8 +560,12 @@ static ssize_t driver_override_show(stru |
| struct device_attribute *attr, char *buf) |
| { |
| struct pci_dev *pdev = to_pci_dev(dev); |
| + ssize_t len; |
| |
| - return snprintf(buf, PAGE_SIZE, "%s\n", pdev->driver_override); |
| + device_lock(dev); |
| + len = snprintf(buf, PAGE_SIZE, "%s\n", pdev->driver_override); |
| + device_unlock(dev); |
| + return len; |
| } |
| static DEVICE_ATTR_RW(driver_override); |
| |