From: Marc-André Lureau <[email protected]>
Cap iov_cnt at 16384 in virtio_gpu_load() and virtio_gpu_blob_load()
to match the existing limit enforced in virtio_gpu_create_mapping_iov().
An unbounded iov_cnt from the migration stream drives two g_new()
allocations whose combined size can exceed available memory, causing
GLib to abort the process.
Fixes: 0c244e50ee12 ("virtio-gpu: add live migration support")
Fixes: f66767f75c9c ("virtio-gpu: add virtio-gpu/blob vmstate subsection")
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3753
Reported-by: Feifan Qian <[email protected]>
Signed-off-by: Marc-André Lureau <[email protected]>
---
hw/display/virtio-gpu.c | 18 +++++++++++++++---
1 file changed, 15 insertions(+), 3 deletions(-)
diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
index 88526051a99..6289bff9f3b 100644
--- a/hw/display/virtio-gpu.c
+++ b/hw/display/virtio-gpu.c
@@ -34,6 +34,7 @@
#include "qemu/error-report.h"
#define VIRTIO_GPU_VM_VERSION 1
+#define VIRTIO_GPU_MAX_IOVEC 16384
static struct virtio_gpu_simple_resource *
virtio_gpu_find_check_resource(VirtIOGPU *g, uint32_t resource_id,
@@ -820,10 +821,10 @@ int virtio_gpu_create_mapping_iov(VirtIOGPU *g,
size_t esize, s;
int e, v;
- if (nr_entries > 16384) {
+ if (nr_entries > VIRTIO_GPU_MAX_IOVEC) {
qemu_log_mask(LOG_GUEST_ERROR,
- "%s: nr_entries is too big (%d > 16384)\n",
- __func__, nr_entries);
+ "%s: nr_entries is too big (%d > %d)\n",
+ __func__, nr_entries, VIRTIO_GPU_MAX_IOVEC);
return -1;
}
@@ -1323,6 +1324,11 @@ static int virtio_gpu_load(QEMUFile *f, void *opaque,
size_t size,
res->format = qemu_get_be32(f);
res->iov_cnt = qemu_get_be32(f);
+ if (res->iov_cnt > VIRTIO_GPU_MAX_IOVEC) {
+ g_free(res);
+ return -EINVAL;
+ }
+
/* allocate */
pformat = virtio_gpu_get_pixman_format(res->format);
if (!pformat) {
@@ -1424,6 +1430,12 @@ static int virtio_gpu_blob_load(QEMUFile *f, void
*opaque, size_t size,
res->resource_id = resource_id;
res->blob_size = qemu_get_be32(f);
res->iov_cnt = qemu_get_be32(f);
+
+ if (res->iov_cnt > VIRTIO_GPU_MAX_IOVEC) {
+ g_free(res);
+ return -EINVAL;
+ }
+
res->addrs = g_new(uint64_t, res->iov_cnt);
res->iov = g_new(struct iovec, res->iov_cnt);
--
2.55.0