瀏覽代碼

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>
Jean Delvare 16 年之前
父節點
當前提交
b41d6cf38e
共有 4 個文件被更改,包括 20 次插入10 次删除
  1. 4 0
      Documentation/PCI/pci.txt
  2. 0 4
      drivers/i2c/busses/i2c-amd756.c
  3. 0 4
      drivers/i2c/busses/i2c-viapro.c
  4. 16 2
      drivers/pci/pci-driver.c

+ 4 - 0
Documentation/PCI/pci.txt

@@ -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.
 
 

+ 0 - 4
drivers/i2c/busses/i2c-amd756.c

@@ -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");

+ 0 - 4
drivers/i2c/busses/i2c-viapro.c

@@ -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;

+ 16 - 2
drivers/pci/pci-driver.c

@@ -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;