vga_draw_text() and vga_draw_graphic() share last_width/last_height
but store them in different units (chars vs pixels). A graphics
frame leaving values equal to a following text frame's char counts
makes the text resize predicate compare equal, skipping the console
resize; the glyph loop then paints out of bounds of the surface.
Commit 95687639e6 (CVE-2026-17516) fixed the graphics-path consumer
of this confusion but not the text path. Give vga_draw_text() its
own cache fields.
Fixes: CVE-2026-77913
Cc: qemu-stable@nongnu.org
Signed-off-by: Warisjeet Singh (sin99xx) <sinxx198@gmail.com>
---
hw/display/vga.c | 10 +++++++---
hw/display/vga_int.h | 3 ++-
2 files changed, 9 insertions(+), 4 deletions(-)
diff --git a/hw/display/vga.c b/hw/display/vga.c
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -1241,7 +1241,7 @@
return;
}
- if (width != s->last_width || height != s->last_height ||
+ if (width != s->last_text_width || height != s->last_text_height ||
cw != s->last_cw || cheight != s->last_ch || s->last_depth) {
s->last_scr_width = width * cw;
s->last_scr_height = height * cheight;
@@ -1249,8 +1249,8 @@
surface = qemu_console_surface(s->con);
qemu_console_text_resize(s->con, width, height);
s->last_depth = 0;
- s->last_width = width;
- s->last_height = height;
+ s->last_text_width = width;
+ s->last_text_height = height;
s->last_ch = cheight;
s->last_cw = cw;
full_update = 1;
@@ -1845,6 +1845,8 @@
s->last_width = -1;
s->last_height = -1;
+ s->last_text_width = -1;
+ s->last_text_height = -1;
}
void vga_common_reset(VGACommonState *s)
@@ -1887,6 +1889,8 @@
s->last_ch = 0;
s->last_width = 0;
s->last_height = 0;
+ s->last_text_width = 0;
+ s->last_text_height = 0;
s->last_scr_width = 0;
s->last_scr_height = 0;
s->cursor_start = 0;
diff --git a/hw/display/vga_int.h b/hw/display/vga_int.h
--- a/hw/display/vga_int.h
+++ b/hw/display/vga_int.h
@@ -122,7 +122,8 @@
uint32_t plane_updated;
uint32_t last_line_offset;
uint8_t last_cw, last_ch;
- uint32_t last_width, last_height; /* in chars or pixels */
+ uint32_t last_width, last_height; /* in pixels (graphics renderer) */
+ uint32_t last_text_width, last_text_height; /* in chars (text renderer) */
uint32_t last_scr_width, last_scr_height; /* in pixels */
uint32_t last_depth; /* in bits */
bool last_byteswap;