@samitouri / QOSamiQemu / commits / 76dcc0832c

hw/display/virtio-gpu: Remove the bytes_pp field

virtio_gpu_do_set_scanout() validates the stride field of struct virtio_gpu_framebuffer against the bytes_pp field, but bytes_pp in the migration stream may be inconsistent with the format field, which pixman_image_create_bits() uses when it accesses the framebuffer. That validation is therefore incomplete. To avoid the trouble of synchronizing the two fields, remove bytes_pp, and always derive its value from format. Removing bytes_pp is safe because no released version of QEMU uses its migrated value. Fixes: 7b5574225429 ("hw/display: check frame buffer can hold blob") Cc: qemu-stable@nongnu.org Reviewed-by: Dmitry Osipenko <dmitry.osipenko@collabora.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com> [ Marc-André - fix rebase conflict ] Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp> Message-ID: <20260719-bpp-v1-1-9b91946d6cf3@rsg.ci.i.u-tokyo.ac.jp>

Akihiko Odaki committed Jul 19, 2026 at 20:35 UTC 76dcc0832c5caac25ac887f235b547ed947b5734
2 files changed +17 -11
hw/display/virtio-gpu.c
+17 -10
@@ -617,6 +617,11 @@ void virtio_gpu_update_scanout(VirtIOGPU *g,
617 scanout->fb = *fb;
618 }
619
620 +static uint32_t virtio_gpu_format_bytes_pp(pixman_format_code_t format)
621 +{
622 + return DIV_ROUND_UP(PIXMAN_FORMAT_BPP(format), 8);
623 +}
624 +
625 static bool virtio_gpu_do_set_scanout(VirtIOGPU *g,
626 uint32_t scanout_id,
627 struct virtio_gpu_framebuffer *fb,
@@ -625,6 +630,7 @@ static bool virtio_gpu_do_set_scanout(VirtIOGPU *g,
630 uint32_t *error)
631 {
632 struct virtio_gpu_scanout *scanout;
633 + uint32_t bytes_pp = virtio_gpu_format_bytes_pp(fb->format);
634 uint8_t *data;
635
636 scanout = &g->parent_obj.scanout[scanout_id];
@@ -646,10 +652,10 @@ static bool virtio_gpu_do_set_scanout(VirtIOGPU *g,
652 return false;
653 }
654
649 - if (fb->stride < (uint64_t)fb->width * fb->bytes_pp) {
655 + if (fb->stride < (uint64_t)fb->width * bytes_pp) {
656 qemu_log_mask(LOG_GUEST_ERROR,
657 "%s: stride %u too small for width %u at %u bpp\n",
652 - __func__, fb->stride, fb->width, fb->bytes_pp);
658 + __func__, fb->stride, fb->width, bytes_pp);
659 *error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
660 return false;
661 }
@@ -720,6 +726,7 @@ static void virtio_gpu_set_scanout(VirtIOGPU *g,
726 struct virtio_gpu_simple_resource *res;
727 struct virtio_gpu_framebuffer fb = { 0 };
728 struct virtio_gpu_set_scanout ss;
729 + uint32_t bytes_pp;
730
731 VIRTIO_GPU_FILL_CMD(ss);
732 virtio_gpu_bswap_32(&ss, sizeof(ss));
@@ -745,11 +752,11 @@ static void virtio_gpu_set_scanout(VirtIOGPU *g,
752 }
753
754 fb.format = pixman_image_get_format(res->image);
748 - fb.bytes_pp = DIV_ROUND_UP(PIXMAN_FORMAT_BPP(fb.format), 8);
755 + bytes_pp = virtio_gpu_format_bytes_pp(fb.format);
756 fb.width = pixman_image_get_width(res->image);
757 fb.height = pixman_image_get_height(res->image);
758 fb.stride = pixman_image_get_stride(res->image);
752 - fb.offset = ss.r.x * fb.bytes_pp + ss.r.y * fb.stride;
759 + fb.offset = ss.r.x * bytes_pp + ss.r.y * fb.stride;
760
761 virtio_gpu_do_set_scanout(g, ss.scanout_id,
762 &fb, res, &ss.r, &cmd->error);
@@ -760,6 +767,7 @@ bool virtio_gpu_scanout_blob_to_fb(struct virtio_gpu_framebuffer *fb,
767 uint64_t blob_size)
768 {
769 uint64_t fbend;
770 + uint32_t bytes_pp;
771
772 fb->format = virtio_gpu_get_pixman_format(ss->format);
773 if (!fb->format) {
@@ -769,15 +777,15 @@ bool virtio_gpu_scanout_blob_to_fb(struct virtio_gpu_framebuffer *fb,
777 return false;
778 }
779
772 - fb->bytes_pp = DIV_ROUND_UP(PIXMAN_FORMAT_BPP(fb->format), 8);
780 + bytes_pp = virtio_gpu_format_bytes_pp(fb->format);
781 fb->width = ss->width;
782 fb->height = ss->height;
783 fb->stride = ss->strides[0];
784
777 - if (fb->stride < (uint64_t)fb->width * fb->bytes_pp) {
785 + if (fb->stride < (uint64_t)fb->width * bytes_pp) {
786 qemu_log_mask(LOG_GUEST_ERROR,
787 "%s: stride %u too small for width %u at %u bpp\n",
780 - __func__, fb->stride, fb->width, fb->bytes_pp);
788 + __func__, fb->stride, fb->width, bytes_pp);
789 return false;
790 }
791
@@ -788,7 +796,7 @@ bool virtio_gpu_scanout_blob_to_fb(struct virtio_gpu_framebuffer *fb,
796 return false;
797 }
798
791 - fb->offset = ss->offsets[0] + ss->r.x * fb->bytes_pp + ss->r.y * fb->stride;
799 + fb->offset = ss->offsets[0] + ss->r.x * bytes_pp + ss->r.y * fb->stride;
800
801 fbend = fb->offset;
802 fbend += (uint64_t) fb->stride * ss->r.height;
@@ -1238,8 +1246,7 @@ static const VMStateDescription vmstate_virtio_gpu_scanout = {
1246 VMSTATE_UINT32(cursor.pos.y, struct virtio_gpu_scanout),
1247 VMSTATE_UINT32_TEST(fb.format, struct virtio_gpu_scanout,
1248 scanout_vmstate_after_v2),
1241 - VMSTATE_UINT32_TEST(fb.bytes_pp, struct virtio_gpu_scanout,
1242 - scanout_vmstate_after_v2),
1249 + VMSTATE_UNUSED_TEST(scanout_vmstate_after_v2, 4),
1250 VMSTATE_UINT32_TEST(fb.width, struct virtio_gpu_scanout,
1251 scanout_vmstate_after_v2),
1252 VMSTATE_UINT32_TEST(fb.height, struct virtio_gpu_scanout,
include/hw/virtio/virtio-gpu.h
-1
@@ -66,7 +66,6 @@ struct virtio_gpu_simple_resource {
66
67 struct virtio_gpu_framebuffer {
68 pixman_format_code_t format;
69 - uint32_t bytes_pp;
69 uint32_t width, height;
70 uint32_t stride;
71 uint32_t offset;