virtio: pci: check bar values read from virtio config space
virtio pci config structures may in future have non-standard bar values in the bar field. We should anticipate this by skipping any structures containing such a reserved value. The bar value should never change: check for harmful modified values we re-read it from the config space in vp_modern_map_capability(). Also clean up an existing check to consistently use PCI_STD_NUM_BARS. Signed-off-by: Keir Fraser <keirf@google.com> Link: https://lore.kernel.org/r/20220323140727.3499235-1-keirf@google.com Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
parent
eb4cecb453
commit
3f63a1d7f6
|
@ -293,7 +293,7 @@ static int virtio_pci_find_shm_cap(struct pci_dev *dev, u8 required_id,
|
||||||
|
|
||||||
for (pos = pci_find_capability(dev, PCI_CAP_ID_VNDR); pos > 0;
|
for (pos = pci_find_capability(dev, PCI_CAP_ID_VNDR); pos > 0;
|
||||||
pos = pci_find_next_capability(dev, pos, PCI_CAP_ID_VNDR)) {
|
pos = pci_find_next_capability(dev, pos, PCI_CAP_ID_VNDR)) {
|
||||||
u8 type, cap_len, id;
|
u8 type, cap_len, id, res_bar;
|
||||||
u32 tmp32;
|
u32 tmp32;
|
||||||
u64 res_offset, res_length;
|
u64 res_offset, res_length;
|
||||||
|
|
||||||
|
@ -315,9 +315,14 @@ static int virtio_pci_find_shm_cap(struct pci_dev *dev, u8 required_id,
|
||||||
if (id != required_id)
|
if (id != required_id)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Type, and ID match, looks good */
|
|
||||||
pci_read_config_byte(dev, pos + offsetof(struct virtio_pci_cap,
|
pci_read_config_byte(dev, pos + offsetof(struct virtio_pci_cap,
|
||||||
bar), bar);
|
bar), &res_bar);
|
||||||
|
if (res_bar >= PCI_STD_NUM_BARS)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Type and ID match, and the BAR value isn't reserved.
|
||||||
|
* Looks good.
|
||||||
|
*/
|
||||||
|
|
||||||
/* Read the lower 32bit of length and offset */
|
/* Read the lower 32bit of length and offset */
|
||||||
pci_read_config_dword(dev, pos + offsetof(struct virtio_pci_cap,
|
pci_read_config_dword(dev, pos + offsetof(struct virtio_pci_cap,
|
||||||
|
@ -337,6 +342,7 @@ static int virtio_pci_find_shm_cap(struct pci_dev *dev, u8 required_id,
|
||||||
length_hi), &tmp32);
|
length_hi), &tmp32);
|
||||||
res_length |= ((u64)tmp32) << 32;
|
res_length |= ((u64)tmp32) << 32;
|
||||||
|
|
||||||
|
*bar = res_bar;
|
||||||
*offset = res_offset;
|
*offset = res_offset;
|
||||||
*len = res_length;
|
*len = res_length;
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,13 @@ vp_modern_map_capability(struct virtio_pci_modern_device *mdev, int off,
|
||||||
pci_read_config_dword(dev, off + offsetof(struct virtio_pci_cap, length),
|
pci_read_config_dword(dev, off + offsetof(struct virtio_pci_cap, length),
|
||||||
&length);
|
&length);
|
||||||
|
|
||||||
|
/* Check if the BAR may have changed since we requested the region. */
|
||||||
|
if (bar >= PCI_STD_NUM_BARS || !(mdev->modern_bars & (1 << bar))) {
|
||||||
|
dev_err(&dev->dev,
|
||||||
|
"virtio_pci: bar unexpectedly changed to %u\n", bar);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (length <= start) {
|
if (length <= start) {
|
||||||
dev_err(&dev->dev,
|
dev_err(&dev->dev,
|
||||||
"virtio_pci: bad capability len %u (>%u expected)\n",
|
"virtio_pci: bad capability len %u (>%u expected)\n",
|
||||||
|
@ -120,7 +127,7 @@ static inline int virtio_pci_find_capability(struct pci_dev *dev, u8 cfg_type,
|
||||||
&bar);
|
&bar);
|
||||||
|
|
||||||
/* Ignore structures with reserved BAR values */
|
/* Ignore structures with reserved BAR values */
|
||||||
if (bar > 0x5)
|
if (bar >= PCI_STD_NUM_BARS)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (type == cfg_type) {
|
if (type == cfg_type) {
|
||||||
|
|
Loading…
Reference in New Issue