aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Hajnoczi <stefanha@redhat.com>2016-09-21 16:52:26 +0100
committerMichael S. Tsirkin <mst@redhat.com>2016-09-23 19:03:56 +0300
commitfb1131b674e492a5f91abd77b9fcc9a9e2b88eb7 (patch)
tree45d5ff959cfe2e064150b64eb198d862a2c2d71c
parent4355c1abcaedd64a18d627284a3b7e54acb00714 (diff)
virtio: handle virtqueue_get_head() errors
Stop processing the vring if virtqueue_get_head() fetches an out-of-bounds head index. Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> Reviewed-by: Cornelia Huck <cornelia.huck@de.ibm.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com> Reviewed-by: Cornelia Huck <cornelia.huck@de.ibm.com>
-rw-r--r--hw/virtio/virtio.c27
1 files changed, 17 insertions, 10 deletions
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index b7ac356629..18ce333457 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -360,21 +360,20 @@ static int virtqueue_num_heads(VirtQueue *vq, unsigned int idx)
return num_heads;
}
-static unsigned int virtqueue_get_head(VirtQueue *vq, unsigned int idx)
+static bool virtqueue_get_head(VirtQueue *vq, unsigned int idx,
+ unsigned int *head)
{
- unsigned int head;
-
/* Grab the next descriptor number they're advertising, and increment
* the index we've seen. */
- head = vring_avail_ring(vq, idx % vq->vring.num);
+ *head = vring_avail_ring(vq, idx % vq->vring.num);
/* If their number is silly, that's a fatal mistake. */
- if (head >= vq->vring.num) {
- error_report("Guest says index %u is available", head);
- exit(1);
+ if (*head >= vq->vring.num) {
+ virtio_error(vq->vdev, "Guest says index %u is available", *head);
+ return false;
}
- return head;
+ return true;
}
enum {
@@ -426,7 +425,11 @@ void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes,
max = vq->vring.num;
num_bufs = total_bufs;
- i = virtqueue_get_head(vq, idx++);
+
+ if (!virtqueue_get_head(vq, idx++, &i)) {
+ goto err;
+ }
+
desc_pa = vq->vring.desc;
vring_desc_read(vdev, &desc, desc_pa, i);
@@ -660,11 +663,15 @@ void *virtqueue_pop(VirtQueue *vq, size_t sz)
return NULL;
}
- i = head = virtqueue_get_head(vq, vq->last_avail_idx++);
+ if (!virtqueue_get_head(vq, vq->last_avail_idx++, &head)) {
+ return NULL;
+ }
+
if (virtio_vdev_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX)) {
vring_set_avail_event(vq, vq->last_avail_idx);
}
+ i = head;
vring_desc_read(vdev, &desc, desc_pa, i);
if (desc.flags & VRING_DESC_F_INDIRECT) {
if (desc.len % sizeof(VRingDesc)) {