mirror of
https://github.com/torvalds/linux.git
synced 2024-12-04 01:51:34 +00:00
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: Bandan Das <bsd@redhat.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Reviewed-by: Alex Williamson <alex.williamson@redhat.com>
This commit is contained in:
parent
7c82126a94
commit
8895d3bcb8
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user