@samitouri / QOSamiQemu / commits / c035d5eadf

virtio-gpu: fix overflow check when allocating 2d image

The calc_image_hostmem() comment says pixman_image_create_bits() checks for overflow. However, this relied on the facts that "bits" was NULL and it performed it when it was introduced. Since commit 9462ff4695aa, the "bits" argument can be provided and the check is no longer applied. Promotes the computation to uint64_t and adds an explicit overflow check to avoid potential later OOB read/write on the image data. Fixes: CVE-2026-3886 Fixes: ZDI-CAN-27578 Fixes: 9462ff4695aa ("virtio-gpu/win32: allocate shareable 2d resources/images") Reported-by: Zero Day Initiative <zdi-disclosures@trendmicro.com> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Reviewed-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp> Message-Id: <20260311-cve-v1-1-f72b4c7c1ab2@redhat.com>

Marc-André Lureau committed Mar 11, 2026 at 01:26 UTC c035d5eadf400670593a76778f98f052d7482968
1 file changed +25 -11
hw/display/virtio-gpu.c
+25 -11
@@ -227,16 +227,20 @@ void virtio_gpu_get_edid(VirtIOGPU *g,
227 virtio_gpu_ctrl_response(g, cmd, &edid.hdr, sizeof(edid));
228 }
229
230 -static uint32_t calc_image_hostmem(pixman_format_code_t pformat,
231 - uint32_t width, uint32_t height)
230 +static bool calc_image_hostmem(pixman_format_code_t pformat,
231 + uint32_t width, uint32_t height,
232 + uint32_t *hostmem)
233 {
233 - /* Copied from pixman/pixman-bits-image.c, skip integer overflow check.
234 - * pixman_image_create_bits will fail in case it overflow.
235 - */
234 + uint64_t bpp = PIXMAN_FORMAT_BPP(pformat);
235 + uint64_t stride = (((uint64_t)width * bpp + 0x1f) >> 5) * sizeof(uint32_t);
236 + uint64_t size = (uint64_t)height * stride;
237
237 - int bpp = PIXMAN_FORMAT_BPP(pformat);
238 - int stride = ((width * bpp + 0x1f) >> 5) * sizeof(uint32_t);
239 - return height * stride;
238 + if (size > UINT32_MAX) {
239 + return false;
240 + }
241 +
242 + *hostmem = size;
243 + return true;
244 }
245
246 static void virtio_gpu_resource_create_2d(VirtIOGPU *g,
@@ -246,6 +250,7 @@ static void virtio_gpu_resource_create_2d(VirtIOGPU *g,
250 pixman_format_code_t pformat;
251 struct virtio_gpu_simple_resource *res;
252 struct virtio_gpu_resource_create_2d c2d;
253 + uint32_t hostmem;
254
255 VIRTIO_GPU_FILL_CMD(c2d);
256 virtio_gpu_bswap_32(&c2d, sizeof(c2d));
@@ -284,7 +289,12 @@ static void virtio_gpu_resource_create_2d(VirtIOGPU *g,
289 return;
290 }
291
287 - res->hostmem = calc_image_hostmem(pformat, c2d.width, c2d.height);
292 + if (!calc_image_hostmem(pformat, c2d.width, c2d.height, &hostmem)) {
293 + qemu_log_mask(LOG_GUEST_ERROR, "%s: image dimensions overflow\n",
294 + __func__);
295 + goto end;
296 + }
297 + res->hostmem = hostmem;
298 if (res->hostmem + g->hostmem < g->conf_max_hostmem) {
299 if (!qemu_pixman_image_new_shareable(
300 &res->image,
@@ -1292,7 +1302,7 @@ static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size,
1302 VirtIOGPU *g = opaque;
1303 Error *err = NULL;
1304 struct virtio_gpu_simple_resource *res;
1295 - uint32_t resource_id, pformat;
1305 + uint32_t resource_id, pformat, hostmem;
1306 int i, ret;
1307
1308 g->hostmem = 0;
@@ -1318,7 +1328,11 @@ static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size,
1328 return -EINVAL;
1329 }
1330
1321 - res->hostmem = calc_image_hostmem(pformat, res->width, res->height);
1331 + if (!calc_image_hostmem(pformat, res->width, res->height, &hostmem)) {
1332 + g_free(res);
1333 + return -EINVAL;
1334 + }
1335 + res->hostmem = hostmem;
1336 if (!qemu_pixman_image_new_shareable(&res->image,
1337 &res->share_handle,
1338 "virtio-gpu res",