mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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 commit6265539776("driver core: platform: fix race condition with driver_override") from Adrian Salido. Fixes:782a985d7a("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+
This commit is contained in:
		
							parent
							
								
									fe59493240
								
							
						
					
					
						commit
						9561475db6
					
				
					 1 changed files with 9 additions and 2 deletions
				
			
		| 
						 | 
					@ -686,7 +686,7 @@ static ssize_t driver_override_store(struct device *dev,
 | 
				
			||||||
				     const char *buf, size_t count)
 | 
									     const char *buf, size_t count)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct pci_dev *pdev = to_pci_dev(dev);
 | 
						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 */
 | 
						/* We need to keep extra room for a newline */
 | 
				
			||||||
	if (count >= (PAGE_SIZE - 1))
 | 
						if (count >= (PAGE_SIZE - 1))
 | 
				
			||||||
| 
						 | 
					@ -700,12 +700,15 @@ static ssize_t driver_override_store(struct device *dev,
 | 
				
			||||||
	if (cp)
 | 
						if (cp)
 | 
				
			||||||
		*cp = '\0';
 | 
							*cp = '\0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						device_lock(dev);
 | 
				
			||||||
 | 
						old = pdev->driver_override;
 | 
				
			||||||
	if (strlen(driver_override)) {
 | 
						if (strlen(driver_override)) {
 | 
				
			||||||
		pdev->driver_override = driver_override;
 | 
							pdev->driver_override = driver_override;
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		kfree(driver_override);
 | 
							kfree(driver_override);
 | 
				
			||||||
		pdev->driver_override = NULL;
 | 
							pdev->driver_override = NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						device_unlock(dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	kfree(old);
 | 
						kfree(old);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -716,8 +719,12 @@ static ssize_t driver_override_show(struct device *dev,
 | 
				
			||||||
				    struct device_attribute *attr, char *buf)
 | 
									    struct device_attribute *attr, char *buf)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct pci_dev *pdev = to_pci_dev(dev);
 | 
						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);
 | 
					static DEVICE_ATTR_RW(driver_override);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue