From nobody Sat Jul 25 20:48:46 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.libvirt.org designates 38.145.34.151 as permitted sender) client-ip=38.145.34.151; envelope-from=devel-bounces@lists.libvirt.org; helo=lists.libvirt.org; Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of lists.libvirt.org designates 38.145.34.151 as permitted sender) smtp.mailfrom=devel-bounces@lists.libvirt.org Return-Path: Received: from lists.libvirt.org (lists.libvirt.org [38.145.34.151]) by mx.zohomail.com with SMTPS id 1784275579432868.2818604748427; Fri, 17 Jul 2026 01:06:19 -0700 (PDT) Received: by lists.libvirt.org (Postfix, from userid 993) id 3830941B8E; Fri, 17 Jul 2026 04:06:18 -0400 (EDT) Received: from [172.19.199.10] (unknown [10.16.107.18]) by lists.libvirt.org (Postfix) with ESMTP id D590241DF7; Fri, 17 Jul 2026 04:04:59 -0400 (EDT) Received: by lists.libvirt.org (Postfix, from userid 993) id 223D341BAE; Mon, 13 Jul 2026 13:29:23 -0400 (EDT) Received: from pidgin.makrotopia.org (pidgin.makrotopia.org [IPv6:2a07:2ec0:3002::65]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (3072 bits) server-digest SHA256) (No client certificate requested) by lists.libvirt.org (Postfix) with ESMTPS id D8B9641B8E for ; Mon, 13 Jul 2026 13:29:21 -0400 (EDT) Received: from local by pidgin.makrotopia.org with esmtpsa (TLS1.3:TLS_AES_256_GCM_SHA384:256) (Exim 4.99) (envelope-from ) id 1wjKDd-0000000085d-2q7Z for devel@lists.libvirt.org; Mon, 13 Jul 2026 17:13:25 +0000 X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-26) on lists.libvirt.org X-Spam-Level: X-Spam-Status: No, score=-2.6 required=5.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI,SPF_HELO_NONE autolearn=unavailable autolearn_force=no version=4.0.1 X-Greylist: delayed 946 seconds by postgrey-1.37 at lists.libvirt.org; Mon, 13 Jul 2026 13:29:21 EDT Date: Mon, 13 Jul 2026 18:13:22 +0100 From: Daniel Golle To: devel@lists.libvirt.org Subject: [PATCH] qemu: Pass driver to qemuDomainRestoreInternal explicitly Message-ID: MIME-Version: 1.0 Content-Disposition: inline X-MailFrom: daniel@makrotopia.org X-Mailman-Rule-Hits: nonmember-moderation X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; header-match-devel.lists.libvirt.org-0; emergency; member-moderation Message-ID-Hash: BZ6G6XTIGZZMY222UOLW7UOKW3T3ID32 X-Message-ID-Hash: BZ6G6XTIGZZMY222UOLW7UOKW3T3ID32 X-Mailman-Approved-At: Fri, 17 Jul 2026 08:04:52 +0000 X-Mailman-Version: 3.3.10 Precedence: list List-Id: Development discussions about the libvirt library & tools Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: X-ZM-MESSAGEID: 1784275581449158500 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" qemuAutostartDomain() starts domains with conn=3DNULL as there is no client connection during driver initialisation. Since the managed save restore path of qemuDomainObjStart() was switched to qemuDomainRestoreInternal(), which obtains the driver by dereferencing conn->privateData, any domain with both a managed save image and the autostart (or autostart-once) flag crashes virtqemud/libvirtd with SIGSEGV on daemon startup. The session daemon's auto-shutdown feature creates exactly this combination on logout with a running VM (auto_shutdown_try_save saves the domain and auto_shutdown_restore marks it autostart-once), so the first daemon start of every subsequent boot segfaults and clients such as GNOME Boxes fail with "Cannot recv data: Connection reset by peer", showing an empty machine list. Pass the driver as an explicit parameter, as qemuDomainObjRestore() did before it was merged into qemuDomainRestoreInternal(), and keep @conn only for use by the ACL check callbacks, which are not used in the autostart code path. Fixes: 0e2ab427782c ("qemu: driver: Merge 'qemuDomainRestoreInternal' and '= qemuDomainObjRestore'") Signed-off-by: Daniel Golle --- Observed with libvirt 12.5.0 and QEMU 11.0.2 on Arch Linux; the code in current git master is identical. Reproducer (any session domain, regular autostart takes the same path): $ virsh -c qemu:///session managedsave DOMAIN $ virsh -c qemu:///session autostart DOMAIN --once # simulate the first daemon start of a boot: $ rm "$XDG_RUNTIME_DIR/libvirt/qemu/run/autostarted" $ pkill -x virtqemud $ virsh -c qemu:///session list --all error: failed to connect to the hypervisor error: Cannot recv data: Connection reset by peer Backtrace of the crashing thread (12.5.0, distro debug symbols): #0 qemuDomainRestoreInternal (conn=3Dconn@entry=3D0x0, ...) at ../src/qemu/qemu_driver.c:5940 #1 qemuDomainObjStart.constprop.0 (conn=3Dconn@entry=3D0x0, ...) at ../src/qemu/qemu_driver.c:6509 #2 qemuAutostartDomain at ../src/qemu/qemu_driver.c:185 #3 virDomainDriverAutoStartOne at ../src/hypervisor/domain_driver.c:700 #7 virDomainDriverAutoStart at ../src/hypervisor/domain_driver.c:728 #8 qemuStateInitialize at ../src/qemu/qemu_driver.c:962 #9 virStateInitialize at ../src/libvirt.c:667 Tested on current master in an isolated session environment with a minimal diskless domain: unpatched, the daemon reproducibly segfaults on startup after the steps above; patched, it starts cleanly and restores the domain from its managed save image. The explicit restore APIs (virDomainRestore*) behave as before. src/qemu/qemu_driver.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 3d57de38..d478d383 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -5901,7 +5901,8 @@ qemuNodeGetSecurityModel(virConnectPtr conn, =20 /** * qemuDomainRestoreInternal: - * @conn: connection object + * @driver: QEMU driver + * @conn: connection object (optional if @ensureACL is NULL) * @vmRestore: Domain object (optional; see below) * @path: path to the save image file * @unlink_corrupt: remove corrupted save image file @path @@ -5926,7 +5927,8 @@ qemuNodeGetSecurityModel(virConnectPtr conn, * corrupted image was removed 1 is returned. */ static int -qemuDomainRestoreInternal(virConnectPtr conn, +qemuDomainRestoreInternal(virQEMUDriver *driver, + virConnectPtr conn, virDomainObj *vmRestore, const char *path, bool unlink_corrupt, @@ -5937,7 +5939,6 @@ qemuDomainRestoreInternal(virConnectPtr conn, int (*ensureACL)(virConnectPtr, virDomainDef *), virDomainAsyncJob asyncJob) { - virQEMUDriver *driver =3D conn->privateData; qemuDomainObjPrivate *priv =3D NULL; g_autoptr(virDomainDef) def =3D NULL; virDomainObj *vm =3D NULL; @@ -6096,7 +6097,8 @@ qemuDomainRestoreFlags(virConnectPtr conn, { virCheckFlags(QEMU_DOMAIN_RESTORE_FLAGS, -1); =20 - return qemuDomainRestoreInternal(conn, NULL, path, false, dxml, NULL, = 0, + return qemuDomainRestoreInternal(conn->privateData, conn, NULL, path, + false, dxml, NULL, 0, flags, virDomainRestoreFlagsEnsureACL, VIR_ASYNC_JOB_START); } @@ -6105,7 +6107,8 @@ static int qemuDomainRestore(virConnectPtr conn, const char *path) { - return qemuDomainRestoreInternal(conn, NULL, path, false, NULL, NULL, = 0, + return qemuDomainRestoreInternal(conn->privateData, conn, NULL, path, + false, NULL, NULL, 0, 0, virDomainRestoreEnsureACL, VIR_ASYNC_JOB_START); } @@ -6141,7 +6144,8 @@ qemuDomainRestoreParams(virConnectPtr conn, return -1; } =20 - ret =3D qemuDomainRestoreInternal(conn, NULL, path, false, dxml, param= s, nparams, + ret =3D qemuDomainRestoreInternal(conn->privateData, conn, NULL, path, + false, dxml, params, nparams, flags, virDomainRestoreParamsEnsureACL, VIR_ASYNC_JOB_START); return ret; @@ -6506,7 +6510,7 @@ qemuDomainObjStart(virConnectPtr conn, restore_flags |=3D bypass_cache ? VIR_DOMAIN_SAVE_BYPASS_CACHE= : 0; restore_flags |=3D reset_nvram ? VIR_DOMAIN_SAVE_RESET_NVRAM := 0; =20 - ret =3D qemuDomainRestoreInternal(conn, vm, managed_save, true= , NULL, NULL, 0, + ret =3D qemuDomainRestoreInternal(driver, conn, vm, managed_sa= ve, true, NULL, NULL, 0, restore_flags, NULL, asyncJob); =20 --=20 2.55.0