ati_host_data_flush() resets host_data.next only on its success path. When it returns early (unsupported bpp, direction, src_source, or src_datatype), next remains stale at >= 4. The next HOST_DATA write then stores a guest-controlled dword at acc[4+], overflowing the 4-element accumulator array.
Fix this by resetting next unconditionally in the write handler after calling ati_host_data_flush() or ati_host_data_finish(), and removing the reset from inside ati_host_data_flush(). This ensures the write handler owns the full lifecycle of the accumulator index regardless of flush success or failure. Reported-by: Feifan Qian <[email protected]> Resolves: https://lore.kernel.org/qemu-devel/Czyl6yVfL6sHl_o1kRk8N_LpwXMMRVhO9vgz1qCVJFagn9D4nHSKuiux39iOLty0Q3acxQq_FeovPhTQvSKus2htwjI9lTajLZmqovr0Wxs=@proton.me/ Cc: [email protected] Signed-off-by: Junjie Cao <[email protected]> --- hw/display/ati.c | 2 ++ hw/display/ati_2d.c | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/display/ati.c b/hw/display/ati.c index d77589df67..db7e08a462 100644 --- a/hw/display/ati.c +++ b/hw/display/ati.c @@ -1034,8 +1034,10 @@ static void ati_mm_write(void *opaque, hwaddr addr, s->host_data.acc[s->host_data.next++] = data; if (addr == HOST_DATA_LAST) { ati_host_data_finish(s); + s->host_data.next = 0; } else if (s->host_data.next >= 4) { ati_host_data_flush(s); + s->host_data.next = 0; } break; default: diff --git a/hw/display/ati_2d.c b/hw/display/ati_2d.c index 48498677c7..8ef82bb87f 100644 --- a/hw/display/ati_2d.c +++ b/hw/display/ati_2d.c @@ -452,7 +452,6 @@ bool ati_host_data_flush(ATIVGAState *s) } /* Track state of the overall blit for use by the next flush */ - s->host_data.next = 0; s->host_data.row = row; s->host_data.col = col; if (s->host_data.row >= ctx.dst.height) { -- 2.43.0
