From: "Marc-André Lureau" <marcandre.lureau@redhat.com>
To: qemu-devel@nongnu.org
Cc: Stefan Hajnoczi <stefanha@redhat.com>
Subject: [GIT PULL 04/23] hw/display/qxl: unregister vm_change_state handler and BHs
Date: Mon, 27 Jul 2026 15:51:13 +0400 [thread overview]
Message-ID: <20260727-fix-v1-4-ca3fa3851347@redhat.com> (raw)
In-Reply-To: <20260727-fix-v1-0-ca3fa3851347@redhat.com>
From: Haotian Jiang <sundayjiang@tencent.com>
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>
---
hw/display/qxl.h | 1 +
hw/display/qxl.c | 16 +++++++++++++++-
2 files changed, 16 insertions(+), 1 deletion(-)
diff --git a/hw/display/qxl.h b/hw/display/qxl.h
index ad8a9128785e..48d664f77736 100644
--- a/hw/display/qxl.h
+++ b/hw/display/qxl.h
@@ -83,6 +83,7 @@ struct PCIQXLDevice {
/* thread signaling */
QEMUBH *update_irq;
+ VMChangeStateEntry *vmstate_handler;
/* ram pci bar */
QXLRam *ram;
diff --git a/hw/display/qxl.c b/hw/display/qxl.c
index 3df796175c29..b7d871b9ee33 100644
--- a/hw/display/qxl.c
+++ b/hw/display/qxl.c
@@ -2203,7 +2203,8 @@ static void qxl_realize_common(PCIQXLDevice *qxl, Error **errp)
error_report_err(err);
}
- qemu_add_vm_change_state_handler(qxl_vm_change_state_handler, qxl);
+ qxl->vmstate_handler =
+ qemu_add_vm_change_state_handler(qxl_vm_change_state_handler, qxl);
qxl->update_irq = qemu_bh_new_guarded(qxl_update_irq_bh, qxl,
&DEVICE(qxl)->mem_reentrancy_guard);
@@ -2475,6 +2476,18 @@ static const Property qxl_properties[] = {
DEFINE_PROP_UINT32("yres", PCIQXLDevice, yres, 0),
};
+static void qxl_exit(PCIDevice *dev)
+{
+ PCIQXLDevice *qxl = PCI_QXL(dev);
+
+ /* TODO: complete cleanup, error paths etc */
+ g_clear_pointer(&qxl->vmstate_handler, qemu_del_vm_change_state_handler);
+ g_clear_pointer(&qxl->update_irq, qemu_bh_delete);
+ g_clear_pointer(&qxl->update_area_bh, qemu_bh_delete);
+ g_clear_pointer(&qxl->ssd.cursor_bh, qemu_bh_delete);
+ g_clear_pointer(&qxl->guest_surfaces.cmds, g_free);
+}
+
static void qxl_pci_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -2482,6 +2495,7 @@ static void qxl_pci_class_init(ObjectClass *klass, const void *data)
k->vendor_id = REDHAT_PCI_VENDOR_ID;
k->device_id = QXL_DEVICE_ID_STABLE;
+ k->exit = qxl_exit;
set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
device_class_set_legacy_reset(dc, qxl_reset_handler);
dc->vmsd = &qxl_vmstate;
--
2.55.0
next prev parent reply other threads:[~2026-07-27 11:52 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-27 11:51 [GIT PULL 00/23] Fixes for 11.1-rc2 Marc-André Lureau
2026-07-27 11:51 ` [GIT PULL 01/23] hw/display/virtio-gpu: Remove the bytes_pp field Marc-André Lureau
2026-07-27 11:51 ` [GIT PULL 02/23] hw/display/vhost-user-gpu: validate message payload sizes Marc-André Lureau
2026-07-27 11:51 ` [GIT PULL 03/23] ui/vnc: remove redundant rows computation Marc-André Lureau
2026-07-27 11:51 ` Marc-André Lureau [this message]
2026-07-27 11:51 ` [GIT PULL 05/23] net/colo: fix g_hash_table_destroy assertion on uninitialized filter Marc-André Lureau
2026-07-27 11:51 ` [GIT PULL 06/23] target/i386/sev: fix MemoryRegion reference leaks in gpa2hva callers Marc-André Lureau
2026-07-27 11:51 ` [GIT PULL 07/23] virtio-gpu: fix NULL deref in rutabaga set_scanout Marc-André Lureau
2026-07-27 11:51 ` [GIT PULL 08/23] docs/hyperv: fix misleading hv-crash shutdown description Marc-André Lureau
2026-07-27 11:51 ` [GIT PULL 09/23] hw/display/virtio-gpu: Fix empty blob discrimination Marc-André Lureau
2026-07-27 11:51 ` [GIT PULL 10/23] hw/display/virtio-gpu: Initialize blob mapping for ATTACH_BACKING Marc-André Lureau
2026-07-27 11:51 ` [GIT PULL 11/23] hw/display/virtio-gpu: Avoid leaking migration blocker Marc-André Lureau
2026-07-27 11:51 ` [GIT PULL 12/23] hw/display/virtio-gpu: Block Rutabaga migration Marc-André Lureau
2026-07-27 11:51 ` [GIT PULL 13/23] hw/display/virtio-gpu-rutabaga: zero-init capset info response Marc-André Lureau
2026-07-27 11:51 ` [GIT PULL 14/23] hw/cxl: fix invalid free on early return Marc-André Lureau
2026-07-27 11:51 ` [GIT PULL 15/23] hw/hexagon: fix machine->fdt leak in qom-test Marc-André Lureau
2026-07-27 11:51 ` [GIT PULL 16/23] block/blkio: fix compiler false-positive warning Marc-André Lureau
2026-07-27 11:51 ` [GIT PULL 17/23] monitor: annotate monitor_qmp_dispatcher_pop_any() as coroutine Marc-André Lureau
2026-07-27 11:51 ` [GIT PULL 18/23] migration: fix qemu_get_counted_string annotation Marc-André Lureau
2026-07-27 11:51 ` [GIT PULL 19/23] io: add missing coroutine annotation Marc-André Lureau
2026-07-27 11:51 ` [GIT PULL 20/23] block: " Marc-André Lureau
2026-07-27 11:51 ` [GIT PULL 21/23] qcow2: remove invalid qcow2_check_refcounts calls Marc-André Lureau
2026-07-27 11:51 ` [GIT PULL 22/23] hw/9pfs: annotate V9fsTransport callbacks as coroutine_fn Marc-André Lureau
2026-07-27 11:51 ` [GIT PULL 23/23] migration/rdma: annotate and simplify wait_comp_channel() Marc-André Lureau
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260727-fix-v1-4-ca3fa3851347@redhat.com \
--to=marcandre.lureau@redhat.com \
--cc=qemu-devel@nongnu.org \
--cc=stefanha@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.