From 10a14536366350fdd2d14af1981d9e3d8cb3c524 Mon Sep 17 00:00:00 2001 From: Andrew Scull Date: Mon, 16 May 2022 10:41:31 +0000 Subject: virtio_ring: Maintain a shadow copy of descriptors 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 Reviewed-by: Simon Glass --- include/virtio_ring.h | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'include') diff --git a/include/virtio_ring.h b/include/virtio_ring.h index 6fc0593b14b..52cbe77c0a2 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; -- cgit v1.3.1 From fbef3f53d4a1ccdcbec46c923c9d208d6cbb50aa Mon Sep 17 00:00:00 2001 From: Andrew Scull Date: Mon, 16 May 2022 10:41:32 +0000 Subject: virtio_ring: Check used descriptors are chain heads When the device returns used buffers, it should refer to the descriptor that is the head of the descriptor chain for that buffer. Confirm this to be the case by tracking the head of descriptor chains that have been made available to the device. Signed-off-by: Andrew Scull Reviewed-by: Simon Glass --- drivers/virtio/virtio_ring.c | 12 ++++++++++++ include/virtio_ring.h | 2 ++ 2 files changed, 14 insertions(+) (limited to 'include') diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c index 73671d79daf..f71bab78477 100644 --- a/drivers/virtio/virtio_ring.c +++ b/drivers/virtio/virtio_ring.c @@ -82,6 +82,9 @@ int virtqueue_add(struct virtqueue *vq, struct virtio_sg *sgs[], /* Update free pointer */ vq->free_head = i; + /* Mark the descriptor as the head of a chain. */ + vq->vring_desc_shadow[head].chain_head = true; + /* * Put entry in available array (but don't update avail->idx * until they do sync). @@ -144,6 +147,9 @@ static void detach_buf(struct virtqueue *vq, unsigned int head) { unsigned int i; + /* Unmark the descriptor as the head of a chain. */ + vq->vring_desc_shadow[head].chain_head = false; + /* Put back on free list: unmap first-level descriptors and find end */ i = head; @@ -194,6 +200,12 @@ void *virtqueue_get_buf(struct virtqueue *vq, unsigned int *len) return NULL; } + if (unlikely(!vq->vring_desc_shadow[i].chain_head)) { + printf("(%s.%d): id %u is not a head\n", + vq->vdev->name, vq->index, i); + return NULL; + } + detach_buf(vq, i); vq->last_used_idx++; /* diff --git a/include/virtio_ring.h b/include/virtio_ring.h index 52cbe77c0a2..c77c212cffd 100644 --- a/include/virtio_ring.h +++ b/include/virtio_ring.h @@ -61,6 +61,8 @@ struct vring_desc_shadow { u32 len; u16 flags; u16 next; + /* Metadata about the descriptor. */ + bool chain_head; }; struct vring_avail { -- cgit v1.3.1