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: Cornelia Huck <cornelia.huck@de.ibm.com> Signed-off-by: Jason Wang <jasowang@redhat.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
parent
e0e2d64409
commit
e45da65322
|
@ -131,6 +131,7 @@ static void virtio_init_region_cache(VirtIODevice *vdev, int n)
|
||||||
VRingMemoryRegionCaches *new;
|
VRingMemoryRegionCaches *new;
|
||||||
hwaddr addr, size;
|
hwaddr addr, size;
|
||||||
int event_size;
|
int event_size;
|
||||||
|
int64_t len;
|
||||||
|
|
||||||
event_size = virtio_vdev_has_feature(vq->vdev, VIRTIO_RING_F_EVENT_IDX) ? 2 : 0;
|
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);
|
new = g_new0(VRingMemoryRegionCaches, 1);
|
||||||
size = virtio_queue_get_desc_size(vdev, n);
|
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);
|
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;
|
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);
|
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;
|
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);
|
vq->vring.avail, size, false);
|
||||||
|
if (len < size) {
|
||||||
|
virtio_error(vdev, "Cannot map avail");
|
||||||
|
goto err_avail;
|
||||||
|
}
|
||||||
|
|
||||||
atomic_rcu_set(&vq->vring.caches, new);
|
atomic_rcu_set(&vq->vring.caches, new);
|
||||||
if (old) {
|
if (old) {
|
||||||
call_rcu(old, virtio_free_region_cache, rcu);
|
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 */
|
/* virt queue functions */
|
||||||
|
|
Loading…
Reference in a new issue