hw/display/qxl: unregister vm_change_state handler and BHs
qxl_realize_common() registers a vm_change_state handler via qemu_add_vm_change_state_handler() and creates three bottom halves (update_irq, update_area_bh, cursor_bh), but none are ever cleaned up. The return value of qemu_add_vm_change_state_handler() is discarded, so the handler is never removed from the global list, and there is no PCIDeviceClass.exit callback to delete the BHs. When a secondary QXL device (hotpluggable by default) is hot-unplugged via device_del, the PCIQXLDevice memory is freed but the vm_state handler and BH entries remain with dangling opaque pointers. On the next VM state change (stop/cont/migrate) or BH dispatch, the callback dereferences freed memory, causing a use-after-free. Fix this by storing the VMChangeStateEntry returned by qemu_add_vm_change_state_handler() and adding a qxl_exit() callback that deletes the vm_state handler, all three BHs, and the guest_surfaces.cmds allocation before the device memory is freed. Fixes: a19cbfb34642 ("spice: add qxl device") Fixes: CVE-2026-63322 Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3607 Signed-off-by: Haotian Jiang <jianghaotian.sunday@gmail.com> Cc: qemu-stable@nongnu.org [ Marc-André - tweak commit message, add TODO ] Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com> Message-ID: <20260720024855.3757499-1-jianghaotian.sunday@gmail.com>