PCI/VPD: Reject resource tags with invalid size
VPD is limited in size by the 15-bit VPD Address field in the VPD Capability. Each resource tag includes a length that determines the overall size of the resource. Reject any resources that would extend past the maximum VPD size. Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Reviewed-by: Hannes Reinecke <hare@suse.de>
This commit is contained in:
parent
4e0d77f8e8
commit
6303049d16
|
@ -72,11 +72,11 @@ EXPORT_SYMBOL(pci_write_vpd);
|
||||||
*/
|
*/
|
||||||
static size_t pci_vpd_size(struct pci_dev *dev, size_t old_size)
|
static size_t pci_vpd_size(struct pci_dev *dev, size_t old_size)
|
||||||
{
|
{
|
||||||
size_t off = 0;
|
size_t off = 0, size;
|
||||||
unsigned char header[1+2]; /* 1 byte tag, 2 bytes length */
|
unsigned char tag, header[1+2]; /* 1 byte tag, 2 bytes length */
|
||||||
|
|
||||||
while (off < old_size && pci_read_vpd(dev, off, 1, header) == 1) {
|
while (off < old_size && pci_read_vpd(dev, off, 1, header) == 1) {
|
||||||
unsigned char tag;
|
size = 0;
|
||||||
|
|
||||||
if (off == 0 && (header[0] == 0x00 || header[0] == 0xff))
|
if (off == 0 && (header[0] == 0x00 || header[0] == 0xff))
|
||||||
goto error;
|
goto error;
|
||||||
|
@ -94,8 +94,11 @@ static size_t pci_vpd_size(struct pci_dev *dev, size_t old_size)
|
||||||
off + 1);
|
off + 1);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
off += PCI_VPD_LRDT_TAG_SIZE +
|
size = pci_vpd_lrdt_size(header);
|
||||||
pci_vpd_lrdt_size(header);
|
if (off + size > PCI_VPD_MAX_SIZE)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
off += PCI_VPD_LRDT_TAG_SIZE + size;
|
||||||
} else {
|
} else {
|
||||||
pci_warn(dev, "invalid large VPD tag %02x at offset %zu\n",
|
pci_warn(dev, "invalid large VPD tag %02x at offset %zu\n",
|
||||||
tag, off);
|
tag, off);
|
||||||
|
@ -103,9 +106,12 @@ static size_t pci_vpd_size(struct pci_dev *dev, size_t old_size)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Short Resource Data Type Tag */
|
/* Short Resource Data Type Tag */
|
||||||
off += PCI_VPD_SRDT_TAG_SIZE +
|
|
||||||
pci_vpd_srdt_size(header);
|
|
||||||
tag = pci_vpd_srdt_tag(header);
|
tag = pci_vpd_srdt_tag(header);
|
||||||
|
size = pci_vpd_srdt_size(header);
|
||||||
|
if (off + size > PCI_VPD_MAX_SIZE)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
off += PCI_VPD_SRDT_TAG_SIZE + size;
|
||||||
if (tag == PCI_VPD_STIN_END) /* End tag descriptor */
|
if (tag == PCI_VPD_STIN_END) /* End tag descriptor */
|
||||||
return off;
|
return off;
|
||||||
}
|
}
|
||||||
|
@ -113,8 +119,8 @@ static size_t pci_vpd_size(struct pci_dev *dev, size_t old_size)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
pci_info(dev, "invalid VPD tag %#04x at offset %zu%s\n",
|
pci_info(dev, "invalid VPD tag %#04x (size %zu) at offset %zu%s\n",
|
||||||
header[0], off, off == 0 ?
|
header[0], size, off, off == 0 ?
|
||||||
"; assume missing optional EEPROM" : "");
|
"; assume missing optional EEPROM" : "");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue