Commit b41d6cf3 authored by Jean Delvare's avatar Jean Delvare Committed by Jesse Barnes

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: default avatarGreg Kroah-Hartman <gregkh@suse.de>
Signed-off-by: default avatarJean Delvare <khali@linux-fr.org>
Signed-off-by: default avatarJesse Barnes <jbarnes@virtuousgeek.org>
parent edbc25ca
...@@ -163,6 +163,10 @@ need pass only as many optional fields as necessary: ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment