summaryrefslogtreecommitdiff
path: root/drivers/virtio
diff options
context:
space:
mode:
authorAndrew Scull <ascull@google.com>2022-04-21 16:11:02 +0000
committerTom Rini <trini@konsulko.com>2022-05-03 15:50:45 -0400
commitc690f64f4c958531fb4bb1b1540931adba022830 (patch)
tree67ac05620f16a82222c8e8bb93588a2bf99f6994 /drivers/virtio
parent94b28b9158b1ea96b2dbfefe9b79e38fc6a35a9c (diff)
virtio: pci: Bounds check notification writes
Make sure virtio notifications are written within their allocated buffer. Signed-off-by: Andrew Scull <ascull@google.com> Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Diffstat (limited to 'drivers/virtio')
-rw-r--r--drivers/virtio/virtio_pci_modern.c17
1 files changed, 15 insertions, 2 deletions
diff --git a/drivers/virtio/virtio_pci_modern.c b/drivers/virtio/virtio_pci_modern.c
index bcf9f18997..7dd58aa0f4 100644
--- a/drivers/virtio/virtio_pci_modern.c
+++ b/drivers/virtio/virtio_pci_modern.c
@@ -94,6 +94,7 @@
*
* @common: pci transport device common register block base
* @notify_base: pci transport device notify register block base
+ * @notify_len: pci transport device notify register block length
* @device: pci transport device device-specific register block base
* @device_len: pci transport device device-specific register block length
* @notify_offset_multiplier: multiply queue_notify_off by this value
@@ -101,6 +102,7 @@
struct virtio_pci_priv {
struct virtio_pci_common_cfg __iomem *common;
void __iomem *notify_base;
+ u32 notify_len;
void __iomem *device;
u32 device_len;
u32 notify_offset_multiplier;
@@ -373,11 +375,19 @@ static int virtio_pci_notify(struct udevice *udev, struct virtqueue *vq)
off = ioread16(&priv->common->queue_notify_off);
/*
+ * Check the effective offset is in bounds and leaves space for the
+ * notification, which is just a single 16-bit value since
+ * VIRTIO_F_NOTIFICATION_DATA isn't negotiated by the drivers.
+ */
+ off *= priv->notify_offset_multiplier;
+ if (off > priv->notify_len - sizeof(u16))
+ return -EIO;
+
+ /*
* We write the queue's selector into the notification register
* to signal the other end
*/
- iowrite16(vq->index,
- priv->notify_base + off * priv->notify_offset_multiplier);
+ iowrite16(vq->index, priv->notify_base + off);
return 0;
}
@@ -499,6 +509,9 @@ static int virtio_pci_probe(struct udevice *udev)
return -EINVAL;
}
+ offset = notify + offsetof(struct virtio_pci_cap, length);
+ dm_pci_read_config32(udev, offset, &priv->notify_len);
+
/*
* Device capability is only mandatory for devices that have
* device-specific configuration.