[Stable-11.0.4 107/120] hw/display/virtio-gpu: fix offset wraparound in scanout_blob_to_fb
Michael Tokarev <[email protected]>
| Newsgroups | gmane.comp.emulators.qemu,gmane.comp.emulators.qemu.stable |
|---|---|
| Message-ID | <[email protected]> |
From: Marc-André Lureau <[email protected]> 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. When the sum exceeds UINT32_MAX, silent wraparound lets the guest steer the scanout to an arbitrary in-bounds region of the blob instead of the intended rectangle. Compute the offset in uint64_t, reject values exceeding UINT32_MAX (the width of fb->offset), and only store into fb->offset once both range checks pass. ("[PATCH] hw/display/virtio-gpu: Remove the bytes_pp field") Fixes: 32db3c63ae11 ("virtio-gpu: Add virtio_gpu_set_scanout_blob") Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3871 Based-on: <[email protected]> Reported-by: Cyber_black <[email protected]> Reviewed-by: Akihiko Odaki <[email protected]> Signed-off-by: Marc-André Lureau <[email protected]> Message-ID: <[email protected]> (cherry picked from commit b8ef970532c30da2f3fa8985867a74f898ce96aa) Signed-off-by: Michael Tokarev <[email protected]> diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 86255d6056d..4f5716fdb82 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -777,7 +777,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); @@ -807,18 +807,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.47.3