diff options
author | Andrew Scull <ascull@google.com> | 2022-04-21 19:11:02 +0300 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2022-05-03 22:50:45 +0300 |
commit | c690f64f4c958531fb4bb1b1540931adba022830 (patch) | |
tree | 67ac05620f16a82222c8e8bb93588a2bf99f6994 /drivers | |
parent | 94b28b9158b1ea96b2dbfefe9b79e38fc6a35a9c (diff) | |
download | u-boot-c690f64f4c958531fb4bb1b1540931adba022830.tar.xz |
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')
-rw-r--r-- | drivers/virtio/virtio_pci_modern.c | 17 |
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. |