On Thu, Sep 3, 2026 at 11:26 PM Denis V. Lunev <[email protected]> wrote:
>
> From: Denis V. Lunev <[email protected]>
>
> qxl_spice_reset_cursor() unrefs qxl->ssd.cursor and installs the hidden
> cursor without holding qxl->ssd.lock. Every other writer of that field
> takes it: qxl_render_cursor(), display_mouse_define() and
> qemu_spice_cursor_refresh_bh().
>
> The unlocked path runs on a vCPU thread, reached from ioport_write() on
> QXL_IO_DESTROY_PRIMARY and QXL_IO_DESTROY_PRIMARY_ASYNC, and holds only
> the BQL, which the SPICE display worker never takes. Unlike
> qxl_hard_reset(), it leaves that worker running.
> spice_qxl_reset_cursor() does round trip through the dispatcher, but the
> worker is free again as soon as it returns, so it can enter
> qxl_render_cursor() and unref the same QEMUCursor a few instructions
> later. Both threads then drop one reference for what is a single
> reference, freeing a cursor that another user still holds. The store to
> ssd.cursor races the same way, and a guest that keeps this up also ends
> up waiting forever in qxl_fence_wait().
>
> A guest reaches this by switching QXL mode while it also updates the
> pointer shape.
>
> Fixes: 958c2bceba06 ("qxl: fix cursor reset")
> Cc: [email protected]
> Cc: Marc-André Lureau <[email protected]>
> Signed-off-by: Denis V. Lunev <[email protected]>

Reviewed-by: Marc-André Lureau <[email protected]>

thanks

> ---
>  hw/display/qxl.c | 2 ++
>  1 file changed, 2 insertions(+)
>
> diff --git a/hw/display/qxl.c b/hw/display/qxl.c
> index 384b8767b8..c4f547e88b 100644
> --- a/hw/display/qxl.c
> +++ b/hw/display/qxl.c
> @@ -294,10 +294,12 @@ void qxl_spice_reset_cursor(PCIQXLDevice *qxl)
>      qemu_mutex_lock(&qxl->track_lock);
>      qxl->guest_cursor = 0;
>      qemu_mutex_unlock(&qxl->track_lock);
> +    qemu_mutex_lock(&qxl->ssd.lock);
>      if (qxl->ssd.cursor) {
>          cursor_unref(qxl->ssd.cursor);
>      }
>      qxl->ssd.cursor = cursor_builtin_hidden();
> +    qemu_mutex_unlock(&qxl->ssd.lock);
>  }
>
>  static uint32_t qxl_crc32(const uint8_t *p, unsigned len)
> --
> 2.53.0
>


Reply via email to