On Thu, Jul 16, 2026 at 12:11 AM <[email protected]> wrote:
>
> From: Marc-André Lureau <[email protected]>
>
> Validate that the framebuffer stride is at least width * bytes_per_pixel
> in both virtio_gpu_scanout_blob_to_fb() and virtio_gpu_do_set_scanout().
>
> A guest can set a very small stride while using a large width. The total
> size check (offset + stride * height <= blob_size) passes because
> stride * height is small, but pixman reads width * bytes_per_pixel per
> row, causing heap OOB reads. The leaked data is rendered to the host
> display.
>
> The check is added in virtio_gpu_do_set_scanout() to cover all paths:
> blob scanout, non-blob scanout and migration post_load. The additional
> early check in virtio_gpu_scanout_blob_to_fb() rejects invalid blob
> configurations early.
>
> Fixes: CVE-2026-63109
> Fixes: 144bd171c837 ("virtio-gpu: Support blob scanout using dmabuf fd")

+

Reported-by: Tristan @TristanInSec

> Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3989
> Signed-off-by: Marc-André Lureau <[email protected]>
> ---
>  hw/display/virtio-gpu.c | 16 ++++++++++++++++
>  1 file changed, 16 insertions(+)
>
> diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
> index 89a73793a42..1d4b8ee4192 100644
> --- a/hw/display/virtio-gpu.c
> +++ b/hw/display/virtio-gpu.c
> @@ -647,6 +647,14 @@ static bool virtio_gpu_do_set_scanout(VirtIOGPU *g,
>          return false;
>      }
>
> +    if (fb->stride < (uint64_t)fb->width * fb->bytes_pp) {
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "%s: stride %u too small for width %u at %u bpp\n",
> +                      __func__, fb->stride, fb->width, fb->bytes_pp);
> +        *error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
> +        return false;
> +    }
> +
>      g->parent_obj.enable = 1;
>
>      if (res->blob) {
> @@ -754,6 +762,14 @@ bool virtio_gpu_scanout_blob_to_fb(struct 
> virtio_gpu_framebuffer *fb,
>      fb->width = ss->width;
>      fb->height = ss->height;
>      fb->stride = ss->strides[0];
> +
> +    if (fb->stride < (uint64_t)fb->width * fb->bytes_pp) {
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "%s: stride %u too small for width %u at %u bpp\n",
> +                      __func__, fb->stride, fb->width, fb->bytes_pp);
> +        return false;
> +    }
> +
>      fb->offset = ss->offsets[0] + ss->r.x * fb->bytes_pp + ss->r.y * 
> fb->stride;
>
>      fbend = fb->offset;
> --
> 2.55.0
>
>

Reply via email to