PCI: Check dynids driver_data value for validity
Only accept dynids whose driver_data value matches one of the driver's pci_driver_id entries. This prevents the user from accidentally passing values the drivers do not expect. Cc: Milton Miller <miltonm@bga.com> Acked-by: Greg Kroah-Hartman <gregkh@suse.de> Signed-off-by: Jean Delvare <khali@linux-fr.org> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
This commit is contained in:
		
							parent
							
								
									edbc25caaa
								
							
						
					
					
						commit
						b41d6cf38e
					
				| @ -163,6 +163,10 @@ need pass only as many optional fields as necessary: | |||||||
| 	o class and classmask fields default to 0 | 	o class and classmask fields default to 0 | ||||||
| 	o driver_data defaults to 0UL. | 	o driver_data defaults to 0UL. | ||||||
| 
 | 
 | ||||||
|  | Note that driver_data must match the value used by any of the pci_device_id | ||||||
|  | entries defined in the driver. This makes the driver_data field mandatory | ||||||
|  | if all the pci_device_id entries have a non-zero driver_data value. | ||||||
|  | 
 | ||||||
| Once added, the driver probe routine will be invoked for any unclaimed | Once added, the driver probe routine will be invoked for any unclaimed | ||||||
| PCI devices listed in its (newly updated) pci_ids list. | PCI devices listed in its (newly updated) pci_ids list. | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -332,10 +332,6 @@ static int __devinit amd756_probe(struct pci_dev *pdev, | |||||||
| 	int error; | 	int error; | ||||||
| 	u8 temp; | 	u8 temp; | ||||||
| 	 | 	 | ||||||
| 	/* driver_data might come from user-space, so check it */ |  | ||||||
| 	if (id->driver_data >= ARRAY_SIZE(chipname)) |  | ||||||
| 		return -EINVAL; |  | ||||||
| 
 |  | ||||||
| 	if (amd756_ioport) { | 	if (amd756_ioport) { | ||||||
| 		dev_err(&pdev->dev, "Only one device supported " | 		dev_err(&pdev->dev, "Only one device supported " | ||||||
| 		       "(you have a strange motherboard, btw)\n"); | 		       "(you have a strange motherboard, btw)\n"); | ||||||
|  | |||||||
| @ -332,10 +332,6 @@ static int __devinit vt596_probe(struct pci_dev *pdev, | |||||||
| 	unsigned char temp; | 	unsigned char temp; | ||||||
| 	int error = -ENODEV; | 	int error = -ENODEV; | ||||||
| 
 | 
 | ||||||
| 	/* driver_data might come from user-space, so check it */ |  | ||||||
| 	if (id->driver_data & 1 || id->driver_data > 0xff) |  | ||||||
| 		return -EINVAL; |  | ||||||
| 
 |  | ||||||
| 	/* Determine the address of the SMBus areas */ | 	/* Determine the address of the SMBus areas */ | ||||||
| 	if (force_addr) { | 	if (force_addr) { | ||||||
| 		vt596_smba = force_addr & 0xfff0; | 		vt596_smba = force_addr & 0xfff0; | ||||||
|  | |||||||
| @ -43,18 +43,32 @@ store_new_id(struct device_driver *driver, const char *buf, size_t count) | |||||||
| { | { | ||||||
| 	struct pci_dynid *dynid; | 	struct pci_dynid *dynid; | ||||||
| 	struct pci_driver *pdrv = to_pci_driver(driver); | 	struct pci_driver *pdrv = to_pci_driver(driver); | ||||||
|  | 	const struct pci_device_id *ids = pdrv->id_table; | ||||||
| 	__u32 vendor, device, subvendor=PCI_ANY_ID, | 	__u32 vendor, device, subvendor=PCI_ANY_ID, | ||||||
| 		subdevice=PCI_ANY_ID, class=0, class_mask=0; | 		subdevice=PCI_ANY_ID, class=0, class_mask=0; | ||||||
| 	unsigned long driver_data=0; | 	unsigned long driver_data=0; | ||||||
| 	int fields=0; | 	int fields=0; | ||||||
| 	int retval = 0; | 	int retval; | ||||||
| 
 | 
 | ||||||
| 	fields = sscanf(buf, "%x %x %x %x %x %x %lux", | 	fields = sscanf(buf, "%x %x %x %x %x %x %lx", | ||||||
| 			&vendor, &device, &subvendor, &subdevice, | 			&vendor, &device, &subvendor, &subdevice, | ||||||
| 			&class, &class_mask, &driver_data); | 			&class, &class_mask, &driver_data); | ||||||
| 	if (fields < 2) | 	if (fields < 2) | ||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
| 
 | 
 | ||||||
|  | 	/* Only accept driver_data values that match an existing id_table
 | ||||||
|  | 	   entry */ | ||||||
|  | 	retval = -EINVAL; | ||||||
|  | 	while (ids->vendor || ids->subvendor || ids->class_mask) { | ||||||
|  | 		if (driver_data == ids->driver_data) { | ||||||
|  | 			retval = 0; | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 		ids++; | ||||||
|  | 	} | ||||||
|  | 	if (retval)	/* No match */ | ||||||
|  | 		return retval; | ||||||
|  | 
 | ||||||
| 	dynid = kzalloc(sizeof(*dynid), GFP_KERNEL); | 	dynid = kzalloc(sizeof(*dynid), GFP_KERNEL); | ||||||
| 	if (!dynid) | 	if (!dynid) | ||||||
| 		return -ENOMEM; | 		return -ENOMEM; | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user