[PATCH v3 04/18] virtio: pci: Bounds check notification writes

Andrew Scull ascull at google.com
Thu Apr 21 18:11:02 CEST 2022


Make sure virtio notifications are written within their allocated
buffer.

Signed-off-by: Andrew Scull <ascull at google.com>
Reviewed-by: Bin Meng <bmeng.cn at gmail.com>
---
 drivers/virtio/virtio_pci_modern.c | 17 +++++++++++++++--
 1 file 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;
@@ -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.
-- 
2.36.0.rc2.479.g8af0fa9b8e-goog



More information about the U-Boot mailing list