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

Commit 8895d3bc authored by Bandan Das's avatar Bandan Das Committed by Bjorn Helgaas
Browse files

PCI: Fail new_id for vendor/device values already built into driver



While using the sysfs new_id interface, the user can unintentionally feed
incorrect values if the driver static table has a matching entry.  This is
possible since only the device and vendor fields are mandatory and the rest
are optional.  As a result, store_new_id() will fill in default values that
are then passed on to the driver and can have unintended consequences.

As an example, consider the ixgbe driver and the 82599EB network card:

  echo "8086 10fb" > /sys/bus/pci/drivers/ixgbe/new_id

This will pass a pci_device_id with driver_data = 0 to ixgbe_probe(), which
uses that zero to index a table of card operations.  The zeroth entry of
the table does *not* correspond to the 82599 operations.

This change returns an error if the user attempts to add a dynid for a
vendor/device combination for which a static entry already exists.
However, if the user intentionally wants a different set of values, she
must provide all the 7 fields and that will be accepted.

[bhelgaas: drop KVM text since the problem isn't KVM-specific]
Signed-off-by: default avatarBandan Das <bsd@redhat.com>
Signed-off-by: default avatarBjorn Helgaas <bhelgaas@google.com>
Reviewed-by: default avatarAlex Williamson <alex.williamson@redhat.com>
parent 7c82126a
Loading
Loading
Loading
Loading
+21 −1
Original line number Diff line number Diff line
@@ -107,7 +107,7 @@ store_new_id(struct device_driver *driver, const char *buf, size_t count)
		subdevice=PCI_ANY_ID, class=0, class_mask=0;
	unsigned long driver_data=0;
	int fields=0;
	int retval;
	int retval = 0;

	fields = sscanf(buf, "%x %x %x %x %x %x %lx",
			&vendor, &device, &subvendor, &subdevice,
@@ -115,6 +115,26 @@ store_new_id(struct device_driver *driver, const char *buf, size_t count)
	if (fields < 2)
		return -EINVAL;

	if (fields != 7) {
		struct pci_dev *pdev = kzalloc(sizeof(*pdev), GFP_KERNEL);
		if (!pdev)
			return -ENOMEM;

		pdev->vendor = vendor;
		pdev->device = device;
		pdev->subsystem_vendor = subvendor;
		pdev->subsystem_device = subdevice;
		pdev->class = class;

		if (pci_match_id(pdrv->id_table, pdev))
			retval = -EEXIST;

		kfree(pdev);

		if (retval)
			return retval;
	}

	/* Only accept driver_data values that match an existing id_table
	   entry */
	if (ids) {