ui/vnc: fix OOB write in vnc_refresh_lossy_rect

vnc_refresh_lossy_rect() always marks a full VNC_STAT_RECT (64) rows
as dirty when refreshing a lossy tile. When the display height is not
a multiple of VNC_STAT_RECT (e.g. VNC_MAX_HEIGHT = 2160), the bottom
tile is partial -- the last tile at y=2112 has only 48 valid rows.
The unclamped loop writes to vs->dirty[2160..2175], past the end of
the VNC_MAX_HEIGHT-sized array.

Clamp the row count to the actual surface height so partial bottom
tiles only mark valid dirty bitmap entries.

Fixes: CVE-2026-48002
Fixes: 7d964c9d2f ("vnc: refresh lossy rect after a given timeout")
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3950
Reported-by: huntr bubble
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Signed-off-by: Marc-Andre Lureau <marcandre.lureau@redhat.com>
This commit is contained in:
Marc-André Lureau 2026-07-06 12:45:31 +04:00
parent 40cdadfefd
commit 3543c2b855

View file

@ -3004,10 +3004,18 @@ static int vnc_refresh_lossy_rect(VncDisplay *vd, int x, int y)
int sty = y / VNC_STAT_RECT;
int stx = x / VNC_STAT_RECT;
int has_dirty = 0;
int height = MIN(pixman_image_get_height(vd->guest.fb),
pixman_image_get_height(vd->server));
int rows;
y = QEMU_ALIGN_DOWN(y, VNC_STAT_RECT);
x = QEMU_ALIGN_DOWN(x, VNC_STAT_RECT);
rows = MIN(VNC_STAT_RECT, height - y);
if (rows <= 0) {
return 0;
}
QTAILQ_FOREACH(vs, &vd->clients, next) {
VncConnection *vc = container_of(vs, VncConnection, vs);
int j;
@ -3022,7 +3030,7 @@ static int vnc_refresh_lossy_rect(VncDisplay *vd, int x, int y)
}
vc->worker.lossy_rect[sty][stx] = 0;
for (j = 0; j < VNC_STAT_RECT; ++j) {
for (j = 0; j < rows; ++j) {
bitmap_set(vs->dirty[y + j],
x / VNC_DIRTY_PIXELS_PER_BIT,
VNC_STAT_RECT / VNC_DIRTY_PIXELS_PER_BIT);