From nobody Sun Feb 8 09:22:39 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of redhat.com designates 170.10.129.124 as permitted sender) client-ip=170.10.129.124; envelope-from=libvir-list-bounces@redhat.com; helo=us-smtp-delivery-124.mimecast.com; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 170.10.129.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1643989136; cv=none; d=zohomail.com; s=zohoarc; b=IaFN36BQQqGkTkrXpRRrz39GjdFu/8Y7JoeNolAxoWMhe98rcYBrUe47eNNCAJtBUIrIbSVHACiRQT9zTDTR2LOwsH7/m3ci0RdJ0/7QDJQa1qbhuT9eumEUIwatA5RSaTfVLtGQzO10KZlYscaE4Rv91ZqZyZDy1QAgKJs+ukE= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1643989136; h=Content-Type:Content-Transfer-Encoding:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=cNNuRJABYX9PlpCMUpIZnq/NmJMNyygNDx4RZvt2C30=; b=DrbrrqAiEF0qXIybDO9a6zfelxrwnw2Ltgjay0EvZjC8xzgawUzivtle9sRK4nOtpfZgrX6EIbRlP9FC6/HFrLw493q6G4p1Z0N8+sp2w4gnZmlJ8cAbPUaSTO+9qO3A5rkSFSrnJQROiMQaAGfc32hy9ZiYXHYBFBA46GhUXTU= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 170.10.129.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by mx.zohomail.com with SMTPS id 1643989136125268.9351917470336; Fri, 4 Feb 2022 07:38:56 -0800 (PST) Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-227-e9IMZ9JSODqrkVmZECN1tg-1; Fri, 04 Feb 2022 10:38:51 -0500 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 4C02546860; Fri, 4 Feb 2022 15:38:46 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.20]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 2A2F062D52; Fri, 4 Feb 2022 15:38:46 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id EC4BE1809CB9; Fri, 4 Feb 2022 15:38:45 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id 214Fci51008398 for ; Fri, 4 Feb 2022 10:38:45 -0500 Received: by smtp.corp.redhat.com (Postfix) id EEF6F62D52; Fri, 4 Feb 2022 15:38:44 +0000 (UTC) Received: from localhost.localdomain (unknown [10.40.193.218]) by smtp.corp.redhat.com (Postfix) with ESMTP id 72367753D0 for ; Fri, 4 Feb 2022 15:38:44 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1643989135; h=from:from:sender:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:list-id:list-help: list-unsubscribe:list-subscribe:list-post; bh=cNNuRJABYX9PlpCMUpIZnq/NmJMNyygNDx4RZvt2C30=; b=KdPzeiWmk+UjYPj6Yz9URTFZOw33Yqm32EwTbC+B6aRVsx95thW1+2qrnGk/n6QFYyvZqn W4lxY+ss1RwUG/YlqXYo4FnS0IbNBYgLu3Wy4bsSj9pwy2Ph0GFtSAF4xNVfJresTnPOpR rYQZSrIR/LPFSptQG82oDJRsY1fscac= X-MC-Unique: e9IMZ9JSODqrkVmZECN1tg-1 From: Michal Privoznik To: libvir-list@redhat.com Subject: [PATCH 2/2] qemu_process: Start QEMU for caps probing more robustly Date: Fri, 4 Feb 2022 16:38:41 +0100 Message-Id: <5d5a4d92a2bbef708778728b8dbdb79385d32d09.1643988918.git.mprivozn@redhat.com> In-Reply-To: References: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 X-loop: libvir-list@redhat.com X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=libvir-list-bounces@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1643990039645100001 Content-Type: text/plain; charset="utf-8" When probing QEMU capabilities, we look at whatever was specified in the domain XML and execute it with couple of arguments (-daemonize being one of them) Then, we use virCommandSetErrorBuffer() to read stderr of the child process hoping to read possible error message just before the process daemonized itself. Well, this works as long as the emulator binary behaves. If the binary is evil and basically does the following: #!/bin/bash sleep 1h then virCommandRun() called from qemuProcessQMPLaunch() doesn't return for whole hour (because it's stuck in reading stderr of the child process). This behavior of ours is very suboptimal. The solution is to not rely on the binary behaving correctly on -daemonize argument but to daemonize the process ourselves (via virCommandDaemonize()) and then wait for the monitor to show up with a timeout. This in turn means, that we can no longer use virCommandSetErrorBuffer() but we can do the equivalent with virCommandSetErrorFD() and a bit of code. Sure, this doesn't shield us from malicious binaries 100% but helps preventing depletion of worker threads. Signed-off-by: Michal Privoznik --- src/qemu/qemu_process.c | 58 +++++++++++++++++++++++++++++------------ src/qemu/qemu_process.h | 1 - 2 files changed, 42 insertions(+), 17 deletions(-) diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index bb7d02f6c7..9ba7a11676 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -9129,7 +9129,6 @@ qemuProcessQMPFree(qemuProcessQMP *proc) g_free(proc->monpath); g_free(proc->monarg); g_free(proc->pidfile); - g_free(proc->stdErr); g_free(proc); } =20 @@ -9248,7 +9247,9 @@ static int qemuProcessQMPLaunch(qemuProcessQMP *proc) { const char *machine; - int status =3D 0; + VIR_AUTOCLOSE errfd =3D -1; + virTimeBackOffVar timebackoff; + const unsigned long long timeout =3D 30 * 1000; /* ms */ int rc; =20 if (proc->forceTCG) @@ -9273,9 +9274,7 @@ qemuProcessQMPLaunch(qemuProcessQMP *proc) "-nographic", "-machine", machine, "-qmp", proc->monarg, - "-pidfile", proc->pidfile, - "-daemonize", - NULL); + NULL); virCommandAddEnvPassCommon(proc->cmd); virCommandClearCaps(proc->cmd); =20 @@ -9289,26 +9288,53 @@ qemuProcessQMPLaunch(qemuProcessQMP *proc) virCommandSetGID(proc->cmd, proc->runGid); virCommandSetUID(proc->cmd, proc->runUid); =20 - virCommandSetErrorBuffer(proc->cmd, &(proc->stdErr)); + virCommandSetPidFile(proc->cmd, proc->pidfile); + virCommandSetErrorFD(proc->cmd, &errfd); + virCommandDaemonize(proc->cmd); =20 - if (virCommandRun(proc->cmd, &status) < 0) + if (virCommandRun(proc->cmd, NULL) < 0) return -1; =20 - if (status !=3D 0) { - VIR_DEBUG("QEMU %s exited with status %d", proc->binary, status); - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Failed to start QEMU binary %s for probing: %s"), - proc->binary, - proc->stdErr ? proc->stdErr : _("unknown error")); - return -1; - } - if ((rc =3D virPidFileReadPath(proc->pidfile, &proc->pid)) < 0) { virReportSystemError(-rc, _("Failed to read pidfile %s"), proc->pi= dfile); return -1; } =20 + if (virTimeBackOffStart(&timebackoff, 1, timeout) < 0) + goto error; + while (virTimeBackOffWait(&timebackoff)) { + char errbuf[1024] =3D { 0 }; + + if (virFileExists(proc->monpath)) + break; + + if (virProcessKill(proc->pid, 0) =3D=3D 0) + continue; + + ignore_value(saferead(errfd, errbuf, sizeof(errbuf) - 1)); + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to start QEMU binary %s for probing: %s"), + proc->binary, + errbuf[0] ? errbuf : _("unknown error")); + goto error; + } + + if (!virFileExists(proc->monpath)) { + virReportError(VIR_ERR_OPERATION_TIMEOUT, "%s", + _("QEMU monitor did not show up")); + goto error; + } + return 0; + + error: + virCommandAbort(proc->cmd); + if (proc->pid >=3D 0) + virProcessKillPainfully(proc->pid, true); + if (proc->pidfile) + unlink(proc->pidfile); + + return -1; } =20 =20 diff --git a/src/qemu/qemu_process.h b/src/qemu/qemu_process.h index 1b1cc489f0..e1c2c155e9 100644 --- a/src/qemu/qemu_process.h +++ b/src/qemu/qemu_process.h @@ -214,7 +214,6 @@ struct _qemuProcessQMP { char *libDir; uid_t runUid; gid_t runGid; - char *stdErr; char *monarg; char *monpath; char *pidfile; --=20 2.34.1