From: Andrew Scull Date: Thu, 21 Apr 2022 16:11:02 +0000 (+0000) Subject: virtio: pci: Bounds check notification writes X-Git-Url: http://git.dujemihanovic.xyz/img/sics.gif?a=commitdiff_plain;h=c690f64f4c958531fb4bb1b1540931adba022830;p=u-boot.git virtio: pci: Bounds check notification writes Make sure virtio notifications are written within their allocated buffer. Signed-off-by: Andrew Scull Reviewed-by: Bin Meng --- 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; @@ -372,12 +374,20 @@ static int virtio_pci_notify(struct udevice *udev, struct virtqueue *vq) /* get offset of notification word for this 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.