[PATCH] hw/display/virtio-gpu: fix offset truncation in scanout_blob_to_fb

marcandre.lureau@redhat.com posted 1 patch 1 day, 2 hours ago
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/qemu tags/patchew/20260724040126.867935-1-marcandre.lureau@redhat.com
Maintainers: "Alex Bennée" <alex.bennee@linaro.org>, Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>, Dmitry Osipenko <dmitry.osipenko@collabora.com>, "Michael S. Tsirkin" <mst@redhat.com>
hw/display/virtio-gpu.c | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)
[PATCH] hw/display/virtio-gpu: fix offset truncation in scanout_blob_to_fb
Posted by marcandre.lureau@redhat.com 1 day, 2 hours ago
From: Marc-André Lureau <marcandre.lureau@redhat.com>

virtio_gpu_scanout_blob_to_fb() computes the framebuffer offset from
guest-controlled offsets[0], r.x, r.y and stride using uint32_t
arithmetic. The sum can wrap around, so a small fb->offset passes the
fbend > blob_size check even though the real offset lies outside the
blob. The wrapped value is later used as data + fb->offset in
virtio_gpu_do_set_scanout(), letting the guest point the scanout at
host memory beyond the blob.

Compute the offset in uint64_t, reject values wider than UINT32_MAX
(the width of fb->offset), and only store into fb->offset once both
range checks pass.

Fixes: CVE-2026-66019
Fixes: 32db3c63ae11 ("virtio-gpu: Add virtio_gpu_set_scanout_blob")
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3871
Reported-by: Cyber_black <Cyberblackk@proton.me>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 hw/display/virtio-gpu.c | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
index 36d2bd9edee6..d1e32840e223 100644
--- a/hw/display/virtio-gpu.c
+++ b/hw/display/virtio-gpu.c
@@ -784,7 +784,7 @@ bool virtio_gpu_scanout_blob_to_fb(struct virtio_gpu_framebuffer *fb,
                                    struct virtio_gpu_set_scanout_blob *ss,
                                    uint64_t blob_size)
 {
-    uint64_t fbend;
+    uint64_t fbend, offset;
     uint32_t bytes_pp;
 
     fb->format = virtio_gpu_get_pixman_format(ss->format);
@@ -814,18 +814,20 @@ bool virtio_gpu_scanout_blob_to_fb(struct virtio_gpu_framebuffer *fb,
         return false;
     }
 
-    fb->offset = ss->offsets[0] + ss->r.x * bytes_pp + ss->r.y * fb->stride;
+    offset = (uint64_t)ss->offsets[0] + (uint64_t)ss->r.x * bytes_pp +
+             (uint64_t)ss->r.y * fb->stride;
 
-    fbend = fb->offset;
-    fbend += (uint64_t) fb->stride * ss->r.height;
+    fbend = offset + (uint64_t)fb->stride * ss->r.height;
 
-    if (fbend > blob_size) {
+    if (offset > UINT32_MAX || fbend > blob_size) {
         qemu_log_mask(LOG_GUEST_ERROR,
-                      "%s: fb end out of range\n",
+                      "%s: invalid fb bounds\n",
                       __func__);
         return false;
     }
 
+    fb->offset = offset;
+
     return true;
 }
 
-- 
2.55.0


Re: [PATCH] hw/display/virtio-gpu: fix offset truncation in scanout_blob_to_fb
Posted by Akihiko Odaki 22 hours ago
On 2026/07/24 13:01, marcandre.lureau@redhat.com wrote:
> From: Marc-André Lureau <marcandre.lureau@redhat.com>
> 
> virtio_gpu_scanout_blob_to_fb() computes the framebuffer offset from
> guest-controlled offsets[0], r.x, r.y and stride using uint32_t
> arithmetic. The sum can wrap around, so a small fb->offset passes the
> fbend > blob_size check even though the real offset lies outside the
> blob. The wrapped value is later used as data + fb->offset in
> virtio_gpu_do_set_scanout(), letting the guest point the scanout at
> host memory beyond the blob.

fbend is computed from the same wrapped fb->offset that is later used
for data + fb->offset. Since fbend is checked against blob_size, the
wrapped pointer and scanout extent remain within the blob. Wraparound
can select a different in-bounds region, but the described host
out-of-bounds access does not follow.

> 
> Compute the offset in uint64_t, reject values wider than UINT32_MAX
> (the width of fb->offset), and only store into fb->offset once both
> range checks pass.
> 
> Fixes: CVE-2026-66019
> Fixes: 32db3c63ae11 ("virtio-gpu: Add virtio_gpu_set_scanout_blob")
> Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3871
> Reported-by: Cyber_black <Cyberblackk@proton.me>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>   hw/display/virtio-gpu.c | 14 ++++++++------
>   1 file changed, 8 insertions(+), 6 deletions(-)
> 
> diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
> index 36d2bd9edee6..d1e32840e223 100644
> --- a/hw/display/virtio-gpu.c
> +++ b/hw/display/virtio-gpu.c
> @@ -784,7 +784,7 @@ bool virtio_gpu_scanout_blob_to_fb(struct virtio_gpu_framebuffer *fb,
>                                      struct virtio_gpu_set_scanout_blob *ss,
>                                      uint64_t blob_size)
>   {
> -    uint64_t fbend;
> +    uint64_t fbend, offset;
>       uint32_t bytes_pp;
>   
>       fb->format = virtio_gpu_get_pixman_format(ss->format);
> @@ -814,18 +814,20 @@ bool virtio_gpu_scanout_blob_to_fb(struct virtio_gpu_framebuffer *fb,
>           return false;
>       }
>   
> -    fb->offset = ss->offsets[0] + ss->r.x * bytes_pp + ss->r.y * fb->stride;
> +    offset = (uint64_t)ss->offsets[0] + (uint64_t)ss->r.x * bytes_pp +
> +             (uint64_t)ss->r.y * fb->stride;
>   
> -    fbend = fb->offset;
> -    fbend += (uint64_t) fb->stride * ss->r.height;
> +    fbend = offset + (uint64_t)fb->stride * ss->r.height;
>   
> -    if (fbend > blob_size) {
> +    if (offset > UINT32_MAX || fbend > blob_size) {
>           qemu_log_mask(LOG_GUEST_ERROR,
> -                      "%s: fb end out of range\n",
> +                      "%s: invalid fb bounds\n",
>                         __func__);
>           return false;
>       }
>   
> +    fb->offset = offset;
> +
>       return true;
>   }
>   

This patch does not apply to master and appears to be based on:

Based-on: <20260719-bpp-v1-1-9b91946d6cf3@rsg.ci.i.u-tokyo.ac.jp>
("[PATCH] hw/display/virtio-gpu: Remove the bytes_pp field")

The dependency is not declared. Please record the prerequisite.

Regards,
Akihiko Odaki

Re: [PATCH] hw/display/virtio-gpu: fix offset truncation in scanout_blob_to_fb
Posted by Marc-André Lureau 9 hours ago
Hi

On Fri, Jul 24, 2026 at 12:01 PM Akihiko Odaki
<odaki@rsg.ci.i.u-tokyo.ac.jp> wrote:
>
> On 2026/07/24 13:01, marcandre.lureau@redhat.com wrote:
> > From: Marc-André Lureau <marcandre.lureau@redhat.com>
> >
> > virtio_gpu_scanout_blob_to_fb() computes the framebuffer offset from
> > guest-controlled offsets[0], r.x, r.y and stride using uint32_t
> > arithmetic. The sum can wrap around, so a small fb->offset passes the
> > fbend > blob_size check even though the real offset lies outside the
> > blob. The wrapped value is later used as data + fb->offset in
> > virtio_gpu_do_set_scanout(), letting the guest point the scanout at
> > host memory beyond the blob.
>
> fbend is computed from the same wrapped fb->offset that is later used
> for data + fb->offset. Since fbend is checked against blob_size, the
> wrapped pointer and scanout extent remain within the blob. Wraparound
> can select a different in-bounds region, but the described host
> out-of-bounds access does not follow.

Right, I'll drop the CVE and just make is a correctness patch instead.

>
> >
> > Compute the offset in uint64_t, reject values wider than UINT32_MAX
> > (the width of fb->offset), and only store into fb->offset once both
> > range checks pass.
> >
> > Fixes: CVE-2026-66019
> > Fixes: 32db3c63ae11 ("virtio-gpu: Add virtio_gpu_set_scanout_blob")
> > Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3871
> > Reported-by: Cyber_black <Cyberblackk@proton.me>
> > Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> > ---
> >   hw/display/virtio-gpu.c | 14 ++++++++------
> >   1 file changed, 8 insertions(+), 6 deletions(-)
> >
> > diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
> > index 36d2bd9edee6..d1e32840e223 100644
> > --- a/hw/display/virtio-gpu.c
> > +++ b/hw/display/virtio-gpu.c
> > @@ -784,7 +784,7 @@ bool virtio_gpu_scanout_blob_to_fb(struct virtio_gpu_framebuffer *fb,
> >                                      struct virtio_gpu_set_scanout_blob *ss,
> >                                      uint64_t blob_size)
> >   {
> > -    uint64_t fbend;
> > +    uint64_t fbend, offset;
> >       uint32_t bytes_pp;
> >
> >       fb->format = virtio_gpu_get_pixman_format(ss->format);
> > @@ -814,18 +814,20 @@ bool virtio_gpu_scanout_blob_to_fb(struct virtio_gpu_framebuffer *fb,
> >           return false;
> >       }
> >
> > -    fb->offset = ss->offsets[0] + ss->r.x * bytes_pp + ss->r.y * fb->stride;
> > +    offset = (uint64_t)ss->offsets[0] + (uint64_t)ss->r.x * bytes_pp +
> > +             (uint64_t)ss->r.y * fb->stride;
> >
> > -    fbend = fb->offset;
> > -    fbend += (uint64_t) fb->stride * ss->r.height;
> > +    fbend = offset + (uint64_t)fb->stride * ss->r.height;
> >
> > -    if (fbend > blob_size) {
> > +    if (offset > UINT32_MAX || fbend > blob_size) {
> >           qemu_log_mask(LOG_GUEST_ERROR,
> > -                      "%s: fb end out of range\n",
> > +                      "%s: invalid fb bounds\n",
> >                         __func__);
> >           return false;
> >       }
> >
> > +    fb->offset = offset;
> > +
> >       return true;
> >   }
> >
>
> This patch does not apply to master and appears to be based on:
>
> Based-on: <20260719-bpp-v1-1-9b91946d6cf3@rsg.ci.i.u-tokyo.ac.jp>
> ("[PATCH] hw/display/virtio-gpu: Remove the bytes_pp field")
>
> The dependency is not declared. Please record the prerequisite.
>
> Regards,
> Akihiko Odaki
>