Commit 3f63a1d7 authored by Keir Fraser's avatar Keir Fraser Committed by Michael S. Tsirkin

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: default avatarKeir Fraser <keirf@google.com>
Link: https://lore.kernel.org/r/20220323140727.3499235-1-keirf@google.comSigned-off-by: default avatarMichael S. Tsirkin <mst@redhat.com>
parent eb4cecb4
...@@ -293,7 +293,7 @@ static int virtio_pci_find_shm_cap(struct pci_dev *dev, u8 required_id, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment