pciback: improve input validation Reject - where this is not already being done elsewhere - out of range values originating from user mode. This goes as far as reasonably possible considering the non-conformance of the in-kernel sscanf(). At the same time, relax quirk parsing so that 0x prefixes get tolerated without unnecessarily limiting the range of values (in some cases using the prefix would make parsing outright fail no matter what value was intended to be specified) for the (future) case where the in-kernel sscanf() properly honors field width specifications even for integer conversions. Plus, to match parsing of standalone PCI device specifications, allow a second form of input not having a domain specified (implying domain 0). Signed-off-by: Jan Beulich --- a/drivers/xen/pciback/pci_stub.c +++ b/drivers/xen/pciback/pci_stub.c @@ -121,7 +121,8 @@ static struct pcistub_device *pcistub_de if (psdev->dev != NULL && domain == pci_domain_nr(psdev->dev->bus) && bus == psdev->dev->bus->number - && PCI_DEVFN(slot, func) == psdev->dev->devfn) { + && slot == PCI_SLOT(psdev->dev->devfn) + && func == PCI_FUNC(psdev->dev->devfn)) { pcistub_device_get(psdev); goto out; } @@ -170,7 +171,8 @@ struct pci_dev *pcistub_get_pci_dev_by_s if (psdev->dev != NULL && domain == pci_domain_nr(psdev->dev->bus) && bus == psdev->dev->bus->number - && PCI_DEVFN(slot, func) == psdev->dev->devfn) { + && slot == PCI_SLOT(psdev->dev->devfn) + && func == PCI_FUNC(psdev->dev->devfn)) { found_dev = pcistub_device_get_pci_dev(pdev, psdev); break; } @@ -906,11 +908,18 @@ static inline int str_to_quirk(const cha { int err; - err = - sscanf(buf, " %04x:%02x:%02x.%1x-%08x:%1x:%08x", domain, bus, slot, - func, reg, size, mask); + err = sscanf(buf, " %x:%x:%x.%x-%x:%x:%x", domain, bus, slot, func, + reg, size, mask); if (err == 7) return 0; + + /* try again without domain */ + *domain = 0; + err = sscanf(buf, " %x:%x.%x-%x:%x:%x", bus, slot, func, reg, size, + mask); + if (err == 6) + return 0; + return -EINVAL; } @@ -918,7 +927,7 @@ static int pcistub_device_id_add(int dom { struct pcistub_device_id *pci_dev_id; unsigned long flags; - int rc = 0; + int rc = 0, devfn = PCI_DEVFN(slot, func); if (slot < 0) { for (slot = 0; !rc && slot < 32; ++slot) @@ -932,13 +941,23 @@ static int pcistub_device_id_add(int dom return rc; } +#ifdef CONFIG_PCI_DOMAINS + if (domain < 0 || domain > 0xffff +#else + if (domain +#endif + || bus < 0 || bus > 0xff + || PCI_SLOT(devfn) != slot + || PCI_FUNC(devfn) != func) + return -EINVAL; + pci_dev_id = kmalloc(sizeof(*pci_dev_id), GFP_KERNEL); if (!pci_dev_id) return -ENOMEM; pci_dev_id->domain = domain; pci_dev_id->bus = bus; - pci_dev_id->devfn = PCI_DEVFN(slot, func); + pci_dev_id->devfn = devfn; pr_debug("pciback: wants to seize %04x:%02x:%02x.%01x\n", domain, bus, slot, func); @@ -979,14 +998,18 @@ static int pcistub_device_id_remove(int return err; } -static int pcistub_reg_add(int domain, int bus, int slot, int func, int reg, - int size, int mask) +static int pcistub_reg_add(int domain, int bus, int slot, int func, + unsigned int reg, unsigned int size, + unsigned int mask) { int err = 0; struct pcistub_device *psdev; struct pci_dev *dev; struct config_field *field; + if (reg > 0xfff || (size < 4 && (mask >> (size * 8)))) + return -EINVAL; + psdev = pcistub_device_find(domain, bus, slot, func); if (!psdev) { err = -ENODEV; @@ -1153,13 +1176,11 @@ static ssize_t permissive_add(struct dev int err; struct pcistub_device *psdev; struct pciback_dev_data *dev_data; + err = str_to_slot(buf, &domain, &bus, &slot, &func); if (err) goto out; - if (slot < 0 || func < 0) { - err = -EINVAL; - goto out; - } + psdev = pcistub_device_find(domain, bus, slot, func); if (!psdev) { err = -ENODEV;