All of lore.kernel.org
 help / color / mirror / Atom feed
From: Andrew Scull <ascull@google.com>
To: u-boot@lists.denx.de
Cc: sjg@chromium.org, trini@konsulko.com, Andrew Scull <ascull@google.com>
Subject: [PATCH v2 03/12] virtio_ring: Maintain a shadow copy of descriptors
Date: Wed, 13 Apr 2022 14:21:28 +0000	[thread overview]
Message-ID: <20220413142137.560987-4-ascull@google.com> (raw)
In-Reply-To: <20220413142137.560987-1-ascull@google.com>

The shared descriptors should only be written by the guest driver,
however, the device is still able to overwrite and corrupt them.
Maintain a private shadow copy of the descriptors for the driver to
use for state tracking, removing the need to read from the shared
descriptors.

Signed-off-by: Andrew Scull <ascull@google.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
---
 drivers/virtio/virtio_ring.c | 49 ++++++++++++++++++++++++------------
 include/virtio_ring.h        | 10 ++++++++
 2 files changed, 43 insertions(+), 16 deletions(-)

diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index 8e0cb3d666..69fd8c6aa0 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -19,13 +19,21 @@
 static unsigned int virtqueue_attach_desc(struct virtqueue *vq, unsigned int i,
 					  struct virtio_sg *sg, u16 flags)
 {
+	struct vring_desc_shadow *desc_shadow = &vq->vring_desc_shadow[i];
 	struct vring_desc *desc = &vq->vring.desc[i];
 
-	desc->addr = cpu_to_virtio64(vq->vdev, (u64)(uintptr_t)sg->addr);
-	desc->len = cpu_to_virtio32(vq->vdev, sg->length);
-	desc->flags = cpu_to_virtio16(vq->vdev, flags);
+	/* Update the shadow descriptor. */
+	desc_shadow->addr = (u64)(uintptr_t)sg->addr;
+	desc_shadow->len = sg->length;
+	desc_shadow->flags = flags;
 
-	return virtio16_to_cpu(vq->vdev, desc->next);
+	/* Update the shared descriptor to match the shadow. */
+	desc->addr = cpu_to_virtio64(vq->vdev, desc_shadow->addr);
+	desc->len = cpu_to_virtio32(vq->vdev, desc_shadow->len);
+	desc->flags = cpu_to_virtio16(vq->vdev, desc_shadow->flags);
+	desc->next = cpu_to_virtio16(vq->vdev, desc_shadow->next);
+
+	return desc_shadow->next;
 }
 
 int virtqueue_add(struct virtqueue *vq, struct virtio_sg *sgs[],
@@ -67,7 +75,8 @@ int virtqueue_add(struct virtqueue *vq, struct virtio_sg *sgs[],
 		i = virtqueue_attach_desc(vq, i, sgs[n], flags);
 	}
 	/* Last one doesn't continue */
-	desc[prev].flags &= cpu_to_virtio16(vq->vdev, ~VRING_DESC_F_NEXT);
+	vq->vring_desc_shadow[prev].flags &= ~VRING_DESC_F_NEXT;
+	desc[prev].flags = cpu_to_virtio16(vq->vdev, vq->vring_desc_shadow[prev].flags);
 
 	/* We're using some buffers from the free list. */
 	vq->num_free -= descs_used;
@@ -136,17 +145,16 @@ void virtqueue_kick(struct virtqueue *vq)
 static void detach_buf(struct virtqueue *vq, unsigned int head)
 {
 	unsigned int i;
-	__virtio16 nextflag = cpu_to_virtio16(vq->vdev, VRING_DESC_F_NEXT);
 
 	/* Put back on free list: unmap first-level descriptors and find end */
 	i = head;
 
-	while (vq->vring.desc[i].flags & nextflag) {
-		i = virtio16_to_cpu(vq->vdev, vq->vring.desc[i].next);
+	while (vq->vring_desc_shadow[i].flags & VRING_DESC_F_NEXT) {
+		i = vq->vring_desc_shadow[i].next;
 		vq->num_free++;
 	}
 
-	vq->vring.desc[i].next = cpu_to_virtio16(vq->vdev, vq->free_head);
+	vq->vring_desc_shadow[i].next = vq->free_head;
 	vq->free_head = head;
 
 	/* Plus final descriptor */
@@ -199,8 +207,7 @@ void *virtqueue_get_buf(struct virtqueue *vq, unsigned int *len)
 		virtio_store_mb(&vring_used_event(&vq->vring),
 				cpu_to_virtio16(vq->vdev, vq->last_used_idx));
 
-	return (void *)(uintptr_t)virtio64_to_cpu(vq->vdev,
-						  vq->vring.desc[i].addr);
+	return (void *)(uintptr_t)vq->vring_desc_shadow[i].addr;
 }
 
 static struct virtqueue *__vring_new_virtqueue(unsigned int index,
@@ -209,6 +216,7 @@ static struct virtqueue *__vring_new_virtqueue(unsigned int index,
 {
 	unsigned int i;
 	struct virtqueue *vq;
+	struct vring_desc_shadow *vring_desc_shadow;
 	struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(udev);
 	struct udevice *vdev = uc_priv->vdev;
 
@@ -216,10 +224,17 @@ static struct virtqueue *__vring_new_virtqueue(unsigned int index,
 	if (!vq)
 		return NULL;
 
+	vring_desc_shadow = calloc(vring.num, sizeof(struct vring_desc_shadow));
+	if (!vring_desc_shadow) {
+		free(vq);
+		return NULL;
+	}
+
 	vq->vdev = vdev;
 	vq->index = index;
 	vq->num_free = vring.num;
 	vq->vring = vring;
+	vq->vring_desc_shadow = vring_desc_shadow;
 	vq->last_used_idx = 0;
 	vq->avail_flags_shadow = 0;
 	vq->avail_idx_shadow = 0;
@@ -237,7 +252,7 @@ static struct virtqueue *__vring_new_virtqueue(unsigned int index,
 	/* Put everything in free lists */
 	vq->free_head = 0;
 	for (i = 0; i < vring.num - 1; i++)
-		vq->vring.desc[i].next = cpu_to_virtio16(vdev, i + 1);
+		vq->vring_desc_shadow[i].next = i + 1;
 
 	return vq;
 }
@@ -290,6 +305,7 @@ struct virtqueue *vring_create_virtqueue(unsigned int index, unsigned int num,
 void vring_del_virtqueue(struct virtqueue *vq)
 {
 	free(vq->vring.desc);
+	free(vq->vring_desc_shadow);
 	list_del(&vq->list);
 	free(vq);
 }
@@ -335,11 +351,12 @@ void virtqueue_dump(struct virtqueue *vq)
 	printf("\tlast_used_idx %u, avail_flags_shadow %u, avail_idx_shadow %u\n",
 	       vq->last_used_idx, vq->avail_flags_shadow, vq->avail_idx_shadow);
 
-	printf("Descriptor dump:\n");
+	printf("Shadow descriptor dump:\n");
 	for (i = 0; i < vq->vring.num; i++) {
-		printf("\tdesc[%u] = { 0x%llx, len %u, flags %u, next %u }\n",
-		       i, vq->vring.desc[i].addr, vq->vring.desc[i].len,
-		       vq->vring.desc[i].flags, vq->vring.desc[i].next);
+		struct vring_desc_shadow *desc = &vq->vring_desc_shadow[i];
+
+		printf("\tdesc_shadow[%u] = { 0x%llx, len %u, flags %u, next %u }\n",
+		       i, desc->addr, desc->len, desc->flags, desc->next);
 	}
 
 	printf("Avail ring dump:\n");
diff --git a/include/virtio_ring.h b/include/virtio_ring.h
index 6fc0593b14..52cbe77c0a 100644
--- a/include/virtio_ring.h
+++ b/include/virtio_ring.h
@@ -55,6 +55,14 @@ struct vring_desc {
 	__virtio16 next;
 };
 
+/* Shadow of struct vring_desc in guest byte order. */
+struct vring_desc_shadow {
+	u64 addr;
+	u32 len;
+	u16 flags;
+	u16 next;
+};
+
 struct vring_avail {
 	__virtio16 flags;
 	__virtio16 idx;
@@ -89,6 +97,7 @@ struct vring {
  * @index: the zero-based ordinal number for this queue
  * @num_free: number of elements we expect to be able to fit
  * @vring: actual memory layout for this queue
+ * @vring_desc_shadow: guest-only copy of descriptors
  * @event: host publishes avail event idx
  * @free_head: head of free buffer list
  * @num_added: number we've added since last sync
@@ -102,6 +111,7 @@ struct virtqueue {
 	unsigned int index;
 	unsigned int num_free;
 	struct vring vring;
+	struct vring_desc_shadow *vring_desc_shadow;
 	bool event;
 	unsigned int free_head;
 	unsigned int num_added;
-- 
2.35.1.1178.g4f1659d476-goog


  parent reply	other threads:[~2022-04-13 14:22 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-04-13 14:21 [PATCH v2 00/12] virtio: Harden and test vring Andrew Scull
2022-04-13 14:21 ` [PATCH v2 01/12] virtio_ring: Merge identical variables Andrew Scull
2022-04-22  8:55   ` Bin Meng
2022-04-13 14:21 ` [PATCH v2 02/12] virtio_ring: Add helper to attach vring descriptor Andrew Scull
2022-04-22  9:07   ` Bin Meng
2022-04-13 14:21 ` Andrew Scull [this message]
2022-04-13 14:21 ` [PATCH v2 04/12] virtio_ring: Check used descriptors are chain heads Andrew Scull
2022-04-13 14:21 ` [PATCH v2 05/12] dm: test: virtio: Test the virtio ring Andrew Scull
2022-04-13 14:21 ` [PATCH v2 06/12] virtio: sandbox: Fix device features bitfield Andrew Scull
2022-04-13 14:21 ` [PATCH v2 07/12] test: dm: virtio: Test notify before del_vqs Andrew Scull
2022-04-13 14:21 ` [PATCH v2 08/12] test: dm: virtio: Split out virtio device tests Andrew Scull
2022-04-13 14:21 ` [PATCH v2 09/12] virtio: sandbox: Bind RNG rather than block device Andrew Scull
2022-04-13 14:21 ` [PATCH v2 10/12] test: dm: virtio: Test virtio device driver probing Andrew Scull
2022-04-13 14:21 ` [PATCH v2 11/12] virtio: rng: Check length before copying Andrew Scull
2022-04-13 14:21 ` [PATCH v2 12/12] test: dm: virtio_rng: Test virtio-rng with faked device Andrew Scull

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220413142137.560987-4-ascull@google.com \
    --to=ascull@google.com \
    --cc=sjg@chromium.org \
    --cc=trini@konsulko.com \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.