Commit e45da653 authored by Jason Wang's avatar Jason Wang Committed by Michael S. Tsirkin
Browse files

virtio: validate address space cache during init



We don't check the return value of address_space_cache_init(), this
may lead buggy driver use incorrect region caches. Instead of
triggering an assert, catch and warn this early in
virtio_init_region_cache().

Cc: Cornelia Huck <cornelia.huck@de.ibm.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Reviewed-by: default avatarCornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: default avatarJason Wang <jasowang@redhat.com>
Reviewed-by: default avatarMichael S. Tsirkin <mst@redhat.com>
Signed-off-by: default avatarMichael S. Tsirkin <mst@redhat.com>
parent e0e2d644
Loading
Loading
Loading
Loading
+27 −6
Original line number Diff line number Diff line
@@ -131,6 +131,7 @@ static void virtio_init_region_cache(VirtIODevice *vdev, int n)
    VRingMemoryRegionCaches *new;
    hwaddr addr, size;
    int event_size;
    int64_t len;

    event_size = virtio_vdev_has_feature(vq->vdev, VIRTIO_RING_F_EVENT_IDX) ? 2 : 0;

@@ -140,21 +141,41 @@ static void virtio_init_region_cache(VirtIODevice *vdev, int n)
    }
    new = g_new0(VRingMemoryRegionCaches, 1);
    size = virtio_queue_get_desc_size(vdev, n);
    address_space_cache_init(&new->desc, vdev->dma_as,
    len = address_space_cache_init(&new->desc, vdev->dma_as,
                                   addr, size, false);
    if (len < size) {
        virtio_error(vdev, "Cannot map desc");
        goto err_desc;
    }

    size = virtio_queue_get_used_size(vdev, n) + event_size;
    address_space_cache_init(&new->used, vdev->dma_as,
    len = address_space_cache_init(&new->used, vdev->dma_as,
                                   vq->vring.used, size, true);
    if (len < size) {
        virtio_error(vdev, "Cannot map used");
        goto err_used;
    }

    size = virtio_queue_get_avail_size(vdev, n) + event_size;
    address_space_cache_init(&new->avail, vdev->dma_as,
    len = address_space_cache_init(&new->avail, vdev->dma_as,
                                   vq->vring.avail, size, false);
    if (len < size) {
        virtio_error(vdev, "Cannot map avail");
        goto err_avail;
    }

    atomic_rcu_set(&vq->vring.caches, new);
    if (old) {
        call_rcu(old, virtio_free_region_cache, rcu);
    }
    return;

err_avail:
    address_space_cache_destroy(&new->used);
err_used:
    address_space_cache_destroy(&new->desc);
err_desc:
    g_free(new);
}

/* virt queue functions */