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

PCI: Fix race condition with driver_override

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>
Cc: stable@vger.kernel.org # v3.16+

authored by

Nicolai Stange and committed by
Bjorn Helgaas
9561475d fe594932

+9 -2
+9 -2
drivers/pci/pci-sysfs.c
··· 686 686 const char *buf, size_t count) 687 687 { 688 688 struct pci_dev *pdev = to_pci_dev(dev); 689 - char *driver_override, *old = pdev->driver_override, *cp; 689 + char *driver_override, *old, *cp; 690 690 691 691 /* We need to keep extra room for a newline */ 692 692 if (count >= (PAGE_SIZE - 1)) ··· 700 700 if (cp) 701 701 *cp = '\0'; 702 702 703 + device_lock(dev); 704 + old = pdev->driver_override; 703 705 if (strlen(driver_override)) { 704 706 pdev->driver_override = driver_override; 705 707 } else { 706 708 kfree(driver_override); 707 709 pdev->driver_override = NULL; 708 710 } 711 + device_unlock(dev); 709 712 710 713 kfree(old); 711 714 ··· 719 716 struct device_attribute *attr, char *buf) 720 717 { 721 718 struct pci_dev *pdev = to_pci_dev(dev); 719 + ssize_t len; 722 720 723 - return snprintf(buf, PAGE_SIZE, "%s\n", pdev->driver_override); 721 + device_lock(dev); 722 + len = snprintf(buf, PAGE_SIZE, "%s\n", pdev->driver_override); 723 + device_unlock(dev); 724 + return len; 724 725 } 725 726 static DEVICE_ATTR_RW(driver_override); 726 727