Skip to content

Commit

Permalink
vhost: Track descriptor chain in private at SVQ
Browse files Browse the repository at this point in the history
The device could have access to modify them, and it definitely have
access when we implement packed vq. Harden SVQ maintaining a private
copy of the descriptor chain. Other fields like buffer addresses are
already maintained sepparatedly.

Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
Message-Id: <20220512175747.142058-2-eperezma@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
  • Loading branch information
eugpermar authored and mstsirkin committed May 13, 2022
1 parent aa69abe commit 495fe3a
Show file tree
Hide file tree
Showing 2 changed files with 13 additions and 5 deletions.
12 changes: 7 additions & 5 deletions hw/virtio/vhost-shadow-virtqueue.c
Expand Up @@ -138,17 +138,18 @@ static void vhost_vring_write_descs(VhostShadowVirtqueue *svq, hwaddr *sg,
for (n = 0; n < num; n++) {
if (more_descs || (n + 1 < num)) {
descs[i].flags = flags | cpu_to_le16(VRING_DESC_F_NEXT);
descs[i].next = cpu_to_le16(svq->desc_next[i]);
} else {
descs[i].flags = flags;
}
descs[i].addr = cpu_to_le64(sg[n]);
descs[i].len = cpu_to_le32(iovec[n].iov_len);

last = i;
i = cpu_to_le16(descs[i].next);
i = cpu_to_le16(svq->desc_next[i]);
}

svq->free_head = le16_to_cpu(descs[last].next);
svq->free_head = le16_to_cpu(svq->desc_next[last]);
}

static bool vhost_svq_add_split(VhostShadowVirtqueue *svq,
Expand Down Expand Up @@ -336,7 +337,6 @@ static void vhost_svq_disable_notification(VhostShadowVirtqueue *svq)
static VirtQueueElement *vhost_svq_get_buf(VhostShadowVirtqueue *svq,
uint32_t *len)
{
vring_desc_t *descs = svq->vring.desc;
const vring_used_t *used = svq->vring.used;
vring_used_elem_t used_elem;
uint16_t last_used;
Expand Down Expand Up @@ -365,7 +365,7 @@ static VirtQueueElement *vhost_svq_get_buf(VhostShadowVirtqueue *svq,
return NULL;
}

descs[used_elem.id].next = svq->free_head;
svq->desc_next[used_elem.id] = svq->free_head;
svq->free_head = used_elem.id;

*len = used_elem.len;
Expand Down Expand Up @@ -540,8 +540,9 @@ void vhost_svq_start(VhostShadowVirtqueue *svq, VirtIODevice *vdev,
svq->vring.used = qemu_memalign(qemu_real_host_page_size(), device_size);
memset(svq->vring.used, 0, device_size);
svq->ring_id_maps = g_new0(VirtQueueElement *, svq->vring.num);
svq->desc_next = g_new0(uint16_t, svq->vring.num);
for (unsigned i = 0; i < svq->vring.num - 1; i++) {
svq->vring.desc[i].next = cpu_to_le16(i + 1);
svq->desc_next[i] = cpu_to_le16(i + 1);
}
}

Expand Down Expand Up @@ -574,6 +575,7 @@ void vhost_svq_stop(VhostShadowVirtqueue *svq)
virtqueue_detach_element(svq->vq, next_avail_elem, 0);
}
svq->vq = NULL;
g_free(svq->desc_next);
g_free(svq->ring_id_maps);
qemu_vfree(svq->vring.desc);
qemu_vfree(svq->vring.used);
Expand Down
6 changes: 6 additions & 0 deletions hw/virtio/vhost-shadow-virtqueue.h
Expand Up @@ -53,6 +53,12 @@ typedef struct VhostShadowVirtqueue {
/* Next VirtQueue element that guest made available */
VirtQueueElement *next_guest_avail_elem;

/*
* Backup next field for each descriptor so we can recover securely, not
* needing to trust the device access.
*/
uint16_t *desc_next;

/* Next head to expose to the device */
uint16_t shadow_avail_idx;

Expand Down

0 comments on commit 495fe3a

Please sign in to comment.