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

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>

authored by

Jean Delvare and committed by
Jesse Barnes
b41d6cf3 edbc25ca

+20 -10
+4
Documentation/PCI/pci.txt
··· 163 163 o class and classmask fields default to 0 164 164 o driver_data defaults to 0UL. 165 165 166 + Note that driver_data must match the value used by any of the pci_device_id 167 + entries defined in the driver. This makes the driver_data field mandatory 168 + if all the pci_device_id entries have a non-zero driver_data value. 169 + 166 170 Once added, the driver probe routine will be invoked for any unclaimed 167 171 PCI devices listed in its (newly updated) pci_ids list. 168 172
-4
drivers/i2c/busses/i2c-amd756.c
··· 332 332 int error; 333 333 u8 temp; 334 334 335 - /* driver_data might come from user-space, so check it */ 336 - if (id->driver_data >= ARRAY_SIZE(chipname)) 337 - return -EINVAL; 338 - 339 335 if (amd756_ioport) { 340 336 dev_err(&pdev->dev, "Only one device supported " 341 337 "(you have a strange motherboard, btw)\n");
-4
drivers/i2c/busses/i2c-viapro.c
··· 332 332 unsigned char temp; 333 333 int error = -ENODEV; 334 334 335 - /* driver_data might come from user-space, so check it */ 336 - if (id->driver_data & 1 || id->driver_data > 0xff) 337 - return -EINVAL; 338 - 339 335 /* Determine the address of the SMBus areas */ 340 336 if (force_addr) { 341 337 vt596_smba = force_addr & 0xfff0;
+16 -2
drivers/pci/pci-driver.c
··· 43 43 { 44 44 struct pci_dynid *dynid; 45 45 struct pci_driver *pdrv = to_pci_driver(driver); 46 + const struct pci_device_id *ids = pdrv->id_table; 46 47 __u32 vendor, device, subvendor=PCI_ANY_ID, 47 48 subdevice=PCI_ANY_ID, class=0, class_mask=0; 48 49 unsigned long driver_data=0; 49 50 int fields=0; 50 - int retval = 0; 51 + int retval; 51 52 52 - fields = sscanf(buf, "%x %x %x %x %x %x %lux", 53 + fields = sscanf(buf, "%x %x %x %x %x %x %lx", 53 54 &vendor, &device, &subvendor, &subdevice, 54 55 &class, &class_mask, &driver_data); 55 56 if (fields < 2) 56 57 return -EINVAL; 58 + 59 + /* Only accept driver_data values that match an existing id_table 60 + entry */ 61 + retval = -EINVAL; 62 + while (ids->vendor || ids->subvendor || ids->class_mask) { 63 + if (driver_data == ids->driver_data) { 64 + retval = 0; 65 + break; 66 + } 67 + ids++; 68 + } 69 + if (retval) /* No match */ 70 + return retval; 57 71 58 72 dynid = kzalloc(sizeof(*dynid), GFP_KERNEL); 59 73 if (!dynid)