From nobody Sat Jul 25 12:02:51 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1784515792; cv=none; d=zohomail.com; s=zohoarc; b=jOVePGTyOPFKHKkdDY/bx5+eIYczye+QrGZtQnXkflSxSqUdNwCXn71Uui6JqxZoyH64ejvjV+eGl7kLdyn+DwKUHOixld5e6Ut38hCoCw7hvbfI7vX7eGVsLfb2y2b5PeqV/U8SftPlBkMR28pwpKz2EqfTLYLvWDhWi7zrU6o= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1784515792; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=m8lltpzLlvYxzHjHcmkKzoMmUMZ6AAvTk0ePIiurVHc=; b=UIjSwF36bVQPFvprm96S/EBvRLHDqhTmfpgf1EP2u73jJtq50HqPLn9E/2O+ag+oJRRPIRb7oa6qGT/WagCRBAIHtH8k5YpewE65RKAQPCm/2/b0Ov/r4kuwiqx0Lb9KNNzF5iJgd1c2QF/+KiPc3FAwLwUmbvF74pPaFZxceZ0= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1784515792672918.1108898133717; Sun, 19 Jul 2026 19:49:52 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wle4F-0004mt-SI; Sun, 19 Jul 2026 22:49:19 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wle4C-0004mH-8M for qemu-devel@nongnu.org; Sun, 19 Jul 2026 22:49:16 -0400 Received: from mail-pj2-x0a.google.com ([2607:f8b0:4864:39::a]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1wle4A-0001X9-Fe for qemu-devel@nongnu.org; Sun, 19 Jul 2026 22:49:15 -0400 Received: by mail-pj2-x0a.google.com with SMTP id d9443c01a7336-2cf49dc298bso14586185ad.0 for ; Sun, 19 Jul 2026 19:49:14 -0700 (PDT) Received: from VM-210-252-ubuntu.. ([14.22.11.168]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2cf347554a2sm48885115ad.73.2026.07.19.19.49.09 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 19 Jul 2026 19:49:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1784515753; x=1785120553; darn=nongnu.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to:content-type; bh=m8lltpzLlvYxzHjHcmkKzoMmUMZ6AAvTk0ePIiurVHc=; b=pzQELLBHPHRkSBolH9F8LAtTNUb89LN0qkICRXUmGzFBgmmfRbvSxXQA/cQVggiMrZ P+J4CxPNUgXYNsBxIvsv7zgzYtyCYLxkdgEt6jGCkXKElc+RWhINppru0/JHTf91y6p0 D7IIt9wPOKTQhRknvMDPxtZEFNsqrLcfmt0Ejk4/nznuJT841nDtVbdIug3kN/VVddzY vKUm+8CUzbRplpjh5++J2RHLjC4MrbTWbkNj4oK99IisuOpiiArkGyPUWthe/81uIvSP Iy1ugFUpMJW78fMtmLdJWAT3r+sfXB/964ScmW7cSky5jhx235Mb0ntcz2OMPljLBR/t 5Oyg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1784515753; x=1785120553; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=m8lltpzLlvYxzHjHcmkKzoMmUMZ6AAvTk0ePIiurVHc=; b=dgUyXaJu2m1lXBF5O3CcyH2vETIkm3Bzj4dnH+WTb3iKTjHPXEHoYpX2CJ6YB4Dfq/ efswHxMMSWXQm9DplRMAlXBZit2cqBUYEnlqyCidCxANhpQsDuhO3ibQsoQxUn5n7zmG aqJGNb4T0Ds2jsBNuNUgxOTjSyGXY2aU3UXLjDtcNoScY8U4tfgNtaN9qJrw+eWdYIrw LXuM6WfVM6GG1rgWvwDR5UAdxR0U724tIeXsE6mlIB4wQUFAder1F9ls/neFZRE21CbE OD4OxvMcnZQmTozDuD7tVGUeC1U1Ffy54EqC6T7FkUS87v3ZLW24s6OqQcpzU4kB99TZ ny8A== X-Gm-Message-State: AOJu0YzWcc2q03gRxC38XgueP8hTOHUrYLtJp8MLYEc78i1ml03MtXmF j+13uDgZypiE9+sWbAZf6CCa/E6o+ov1Dq/Za6c2lLj4i1Bz6RNcpg5Zn+LWgtubsFhAx2Xm X-Gm-Gg: AfdE7ck2Knceazbwg2HprmOcusHyeMXOcdW5pVSYZ/9d0HCRVNviCAoLL1q8OTegFCH XmYMaNa1OpIL6A1jT286WloZXggAnuS5KMW4Yhgc+Szg4ZP5E9/gLjdm49A0PfGgNhh2HwZsN5Z R4ooXqXpPHGwVR3NZTAG+G7g32Y4OQpW6MXksTYOxWKLljjhVtIZOsZgXZntQNHxSpzsNmTXlPI Ec6HLgv017lbYSivv+CaamQTORItAqB1jdKb53cVzJW78u5zqEOqpebhi28mRQYjYn0MX6VKh7c fv/6G7XExgPtECR3/Lb9GQrhTSVHQcBshyIe8uKp2mrFpZk1XRPUbFoEXGqZggsvtUQ02BJv2y0 0za2K+Oe+EP4MF+L3lX1hlAdxt/WLegAsbk9kLzxM56xSvFjPHfRUsXsMXAEmJmXxRE9I5kq3MY eWiqV9/MP5Cz9Ze+/4KaIqH5SQ2knicj1H2klY1apaF9PgrEZ8PAoUcDppdIVpTF7oCy+8KAgYN VmgFI++tBLDRIychCboZSHdi4tk X-Received: by 2002:a17:903:1a43:b0:2cc:7d4a:3f5a with SMTP id d9443c01a7336-2cf3487711cmr143468335ad.20.1784515752770; Sun, 19 Jul 2026 19:49:12 -0700 (PDT) From: jianghaotian.sunday@gmail.com To: qemu-devel@nongnu.org Cc: marcandre.lureau@redhat.com, philmd@mailo.com, vsementsov@yandex-team.ru, thuth@redhat.com, farosas@suse.de, qemu-stable@nongnu.org, Haotian Jiang , Haotian Jiang of Tencent Security Subject: [PATCH] hw/display/qxl: unregister vm_change_state handler and BHs on device exit (CVE-2026-63322) Date: Mon, 20 Jul 2026 10:48:55 +0800 Message-Id: <20260720024855.3757499-1-jianghaotian.sunday@gmail.com> X-Mailer: git-send-email 2.34.1 MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=2607:f8b0:4864:39::a; envelope-from=jianghaotian.sunday@gmail.com; helo=mail-pj2-x0a.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @gmail.com) X-ZM-MESSAGEID: 1784515794936158500 Content-Type: text/plain; charset="utf-8" From: Haotian Jiang 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 Reported-by: Haotian Jiang of Tencent Security (Yunding Lab) Signed-off-by: Haotian Jiang Cc: qemu-stable@nongnu.org Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3607 Reviewed-by: Marc-Andr=C3=A9 Lureau --- hw/display/qxl.c | 15 ++++++++++++++- hw/display/qxl.h | 1 + 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/hw/display/qxl.c b/hw/display/qxl.c index 74258afa58..c9323672a6 100644 --- a/hw/display/qxl.c +++ b/hw/display/qxl.c @@ -2203,7 +2203,8 @@ static void qxl_realize_common(PCIQXLDevice *qxl, Err= or **errp) error_report_err(err); } =20 - qemu_add_vm_change_state_handler(qxl_vm_change_state_handler, qxl); + qxl->vmstate_handler =3D + qemu_add_vm_change_state_handler(qxl_vm_change_state_handler, qxl); =20 qxl->update_irq =3D qemu_bh_new_guarded(qxl_update_irq_bh, qxl, &DEVICE(qxl)->mem_reentrancy_gua= rd); @@ -2475,6 +2476,17 @@ static const Property qxl_properties[] =3D { DEFINE_PROP_UINT32("yres", PCIQXLDevice, yres, 0), }; =20 +static void qxl_exit(PCIDevice *dev) +{ + PCIQXLDevice *qxl =3D PCI_QXL(dev); + + g_clear_pointer(&qxl->vmstate_handler, qemu_del_vm_change_state_handle= r); + 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 =3D DEVICE_CLASS(klass); @@ -2482,6 +2494,7 @@ static void qxl_pci_class_init(ObjectClass *klass, co= nst void *data) =20 k->vendor_id =3D REDHAT_PCI_VENDOR_ID; k->device_id =3D QXL_DEVICE_ID_STABLE; + k->exit =3D qxl_exit; set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); device_class_set_legacy_reset(dc, qxl_reset_handler); dc->vmsd =3D &qxl_vmstate; diff --git a/hw/display/qxl.h b/hw/display/qxl.h index ad8a912878..48d664f777 100644 --- a/hw/display/qxl.h +++ b/hw/display/qxl.h @@ -83,6 +83,7 @@ struct PCIQXLDevice { =20 /* thread signaling */ QEMUBH *update_irq; + VMChangeStateEntry *vmstate_handler; =20 /* ram pci bar */ QXLRam *ram; --=20 Changes v1 -> v2: - Use g_clear_pointer() for cleanup per Marc-Andre Lureau's suggestion - Simplifies the code by removing redundant NULL checks and assignments 2.34.1