Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+4 −0
Original line number Original line Diff line number Diff line
@@ -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
Original line number Original line Diff line number Diff line
@@ -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
Original line number Original line Diff line number Diff line
@@ -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
Original line number Original line Diff line number Diff line
@@ -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;