From nobody Fri May 15 10:50:03 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; dkim=fail; spf=pass (zohomail.com: domain of lists.libvirt.org designates 38.145.34.151 as permitted sender) smtp.mailfrom=devel-bounces@lists.libvirt.org; dmarc=pass(p=reject dis=none) header.from=lists.libvirt.org ARC-Seal: i=1; a=rsa-sha256; t=1778667453; cv=none; d=zohomail.com; s=zohoarc; b=SydFHTtZM/J+ZuesJuK9kifMEvWrXlxnin/aUMPFcs3lN9XuXS1VeHOBpiFSD1ng8zln8Udn10i3JeTnaFA1YAfkMz2v8oaEFUByTBZHv+4pazmIVy5T6+wwP88tUnN93UJ0z3BbA4x+8viaJARjpdU3YhLkDDugy6I3jOJSW7g= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1778667453; h=Content-Type:Content-Transfer-Encoding:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Owner:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Subject:Subject:To:To:Message-Id:Cc; bh=oW4lMTHqL9EnDXtFG/2DrJy9gvUAJKJwpLRVdkCUsic=; b=Y1jNdmoYvnASqPKDPLsrIii+dWh5E6l7v/VXD4ZdlCAMK0R5OdXf1xUfr6GXnWLpATk47BO2BYLIL0bzRXrkp+hij8wwmabNGS7f2jQ1s5q4it0XDL/exo5PlO5+eg481hM4gvXItPn9rGs9xUpo3hXohJ/TONBIEEnZYvOlJCg= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of lists.libvirt.org designates 38.145.34.151 as permitted sender) smtp.mailfrom=devel-bounces@lists.libvirt.org; dmarc=pass header.from= (p=reject dis=none) Return-Path: Received: from lists.libvirt.org (lists.libvirt.org [38.145.34.151]) by mx.zohomail.com with SMTPS id 1778667453043325.4925225893172; Wed, 13 May 2026 03:17:33 -0700 (PDT) Received: by lists.libvirt.org (Postfix, from userid 993) id E4D8B4190D; Wed, 13 May 2026 06:17:31 -0400 (EDT) Received: from [172.19.199.9] (unknown [10.16.107.18]) by lists.libvirt.org (Postfix) with ESMTP id D7DE24193C; Wed, 13 May 2026 06:15:18 -0400 (EDT) Received: by lists.libvirt.org (Postfix, from userid 993) id ED1C841864; Wed, 13 May 2026 06:15:03 -0400 (EDT) Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (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 BDB8F4184B for ; Wed, 13 May 2026 06:15:02 -0400 (EDT) Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-653-SXmFL0DcNPe-6U9vDhkycg-1; Wed, 13 May 2026 06:15:00 -0400 Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id CC2F019560BB for ; Wed, 13 May 2026 10:14:59 +0000 (UTC) Received: from speedmetal.openshiftapps.com (unknown [10.44.22.8]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 0F07E1800576 for ; Wed, 13 May 2026 10:14:58 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-26) on lists.libvirt.org X-Spam-Level: X-Spam-Status: No, score=-2.7 required=5.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,MAILING_LIST_MULTI,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL,SPF_HELO_PASS autolearn=unavailable autolearn_force=no version=4.0.1 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1778667302; h=from:from: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; bh=oW4lMTHqL9EnDXtFG/2DrJy9gvUAJKJwpLRVdkCUsic=; b=VKZZA8nvSo0iw7KelnYPOrqoQIf7t5FG6HaC64P4FRl3AXZvLm/M3mRuURjeVP3io8L1J+ miBAuYeo+u89+0iLhiSEOY694Z6hxB2ROf4txtqOP52TeMcCec0Uz+dteSiNL9ZDN8WMUl MiG2CszKhZP3QogR95FGA8jlwBhw2J8= X-MC-Unique: SXmFL0DcNPe-6U9vDhkycg-1 X-Mimecast-MFC-AGG-ID: SXmFL0DcNPe-6U9vDhkycg_1778667300 To: devel@lists.libvirt.org Subject: [PATCH 1/2] util: command: Extract non-virCommand related bits from virCommandMassClose Date: Wed, 13 May 2026 12:14:55 +0200 Message-ID: <5d1869cac29fb7029073da36a165d0926dec2e24.1778667163.git.pkrempa@redhat.com> In-Reply-To: References: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.111 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: UTfoV5AEqGBztJapn26SK_ysrGZ2Tp7M3c6Bey6Qjm4_1778667300 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable Message-ID-Hash: ZFJFR3B2CU3HOT5FEJBERFHYG7KTWOZB X-Message-ID-Hash: ZFJFR3B2CU3HOT5FEJBERFHYG7KTWOZB X-MailFrom: pkrempa@redhat.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; header-match-devel.lists.libvirt.org-0; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header 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: From: Peter Krempa via Devel Reply-To: Peter Krempa X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1778667453966158500 Content-Type: text/plain; charset="utf-8" From: Peter Krempa Extract the common code used to pass FDs from a virCommand to a child process into virCommandMassClose - a new wrapper - and create 'virCommandFDMassClose' which simply takes a bitmap of FDs to be kept and closes everything else. This will allow reuse of the algorithm in test files where we want to prevent FDs leaked from the environment from breakign the test. Signed-off-by: Peter Krempa --- src/libvirt_private.syms | 1 + src/util/vircommand.c | 101 +++++++++++++++++++++------------------ src/util/vircommand.h | 3 ++ 3 files changed, 59 insertions(+), 46 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index f22b5895db..744932acd8 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -2182,6 +2182,7 @@ virCommandDoAsyncIO; virCommandDryRunTokenFree; virCommandDryRunTokenNew; virCommandExec; +virCommandFDMassClose; virCommandFree; virCommandGetArgList; virCommandGetBinaryPath; diff --git a/src/util/vircommand.c b/src/util/vircommand.c index e871d572a6..07e7040ef8 100644 --- a/src/util/vircommand.c +++ b/src/util/vircommand.c @@ -520,16 +520,12 @@ virCommandMassCloseGetFDs(virBitmap *fds) } static int -virCommandMassCloseFrom(virCommand *cmd, - int childin, - int childout, - int childerr) +virCommandMassCloseFrom(virBitmap *keep) { g_autoptr(virBitmap) fds =3D NULL; int openmax =3D sysconf(_SC_OPEN_MAX); - int lastfd =3D -1; + int lastfd =3D virBitmapLastSetBit(keep); int fd =3D -1; - size_t i; /* In general, it is not safe to call malloc() between fork() and exec= () * because the child might have forked at the worst possible time, i.e. @@ -551,24 +547,14 @@ virCommandMassCloseFrom(virCommand *cmd, if (virCommandMassCloseGetFDs(fds) < 0) return -1; - lastfd =3D MAX(lastfd, childin); - lastfd =3D MAX(lastfd, childout); - lastfd =3D MAX(lastfd, childerr); - - for (i =3D 0; i < cmd->npassfd; i++) - lastfd =3D MAX(lastfd, cmd->passfd[i].fd); - fd =3D virBitmapNextSetBit(fds, 2); for (; fd >=3D 0 && fd <=3D lastfd; fd =3D virBitmapNextSetBit(fds, fd= )) { - if (fd =3D=3D childin || fd =3D=3D childout || fd =3D=3D childerr) + int tmpfd =3D fd; + + if (virBitmapIsBitSet(keep, fd)) continue; - if (!virCommandFDIsSet(cmd, fd)) { - int tmpfd =3D fd; - VIR_MASS_CLOSE(tmpfd); - } else if (virSetInherit(fd, true) < 0) { - virReportSystemError(errno, _("failed to preserve fd %1$d"), f= d); - return -1; - } + + VIR_MASS_CLOSE(tmpfd); } if (virCloseFrom(lastfd + 1) < 0) { @@ -588,33 +574,13 @@ virCommandMassCloseFrom(virCommand *cmd, static int -virCommandMassCloseRange(virCommand *cmd, - int childin, - int childout, - int childerr) +virCommandMassCloseRange(virBitmap *keep) { - g_autoptr(virBitmap) fds =3D virBitmapNew(0); ssize_t first; ssize_t last; - size_t i; - - virBitmapSetBitExpand(fds, childin); - virBitmapSetBitExpand(fds, childout); - virBitmapSetBitExpand(fds, childerr); - - for (i =3D 0; i < cmd->npassfd; i++) { - int fd =3D cmd->passfd[i].fd; - - virBitmapSetBitExpand(fds, fd); - - if (virSetInherit(fd, true) < 0) { - virReportSystemError(errno, _("failed to preserve fd %1$d"), f= d); - return -1; - } - } first =3D 2; - while ((last =3D virBitmapNextSetBit(fds, first)) >=3D 0) { + while ((last =3D virBitmapNextSetBit(keep, first)) >=3D 0) { if (first + 1 =3D=3D last) { first =3D last; continue; @@ -642,17 +608,60 @@ virCommandMassCloseRange(virCommand *cmd, } +/** + * virCommandFDMassClose: + * @keep: bitmap of FDs to be kept open in the child process + * + * Closes all open FDs (in the current process) except those represented by + * set bits in @keep. + * + * Returns 0 on success, -1 on error and reports libvirt errors. + */ +int +virCommandFDMassClose(virBitmap *keep) +{ + if (virCloseRangeIsSupported()) + return virCommandMassCloseRange(keep); + + return virCommandMassCloseFrom(keep); +} + +/** + * virCommandMassClose: + * @cmd: command structure + * @childin: fd passed to child as stdin + * @childout: fd passed to child as stdout + * @childerr: fd passed to child as stderr + * + * Prepares FDs to be passed to the child process spawned by @cmd and clos= es + * every other FD. + */ static int virCommandMassClose(virCommand *cmd, int childin, int childout, int childerr) { - if (virCloseRangeIsSupported()) - return virCommandMassCloseRange(cmd, childin, childout, childerr); + g_autoptr(virBitmap) fds =3D virBitmapNew(0); + size_t i; + + virBitmapSetBitExpand(fds, childin); + virBitmapSetBitExpand(fds, childout); + virBitmapSetBitExpand(fds, childerr); + + for (i =3D 0; i < cmd->npassfd; i++) { + int fd =3D cmd->passfd[i].fd; + + virBitmapSetBitExpand(fds, fd); + + if (virSetInherit(fd, true) < 0) { + virReportSystemError(errno, _("failed to preserve fd %1$d"), f= d); + return -1; + } + } - return virCommandMassCloseFrom(cmd, childin, childout, childerr); + return virCommandFDMassClose(fds); } diff --git a/src/util/vircommand.h b/src/util/vircommand.h index a6e9a9a165..523ad1297d 100644 --- a/src/util/vircommand.h +++ b/src/util/vircommand.h @@ -23,6 +23,7 @@ #include "internal.h" #include "virbuffer.h" +#include "virbitmap.h" typedef struct _virCommandSendBuffer virCommandSendBuffer; struct _virCommandSendBuffer { @@ -32,6 +33,8 @@ struct _virCommandSendBuffer { off_t offset; }; +int virCommandFDMassClose(virBitmap *keep); + typedef struct _virCommand virCommand; /* This will execute in the context of the first child --=20 2.54.0 From nobody Fri May 15 10:50:03 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; dkim=fail; spf=pass (zohomail.com: domain of lists.libvirt.org designates 38.145.34.151 as permitted sender) smtp.mailfrom=devel-bounces@lists.libvirt.org; dmarc=pass(p=reject dis=none) header.from=lists.libvirt.org ARC-Seal: i=1; a=rsa-sha256; t=1778667512; cv=none; d=zohomail.com; s=zohoarc; b=PdyMDwOd2/Y89Rdcw/rq/s8LTSQkd9mjL0CBwRRBqaIejMdXjlunaisvZQ1jf2QpfnHw5YagaiB5eLIo/poUkVG5K1oK8eYFZm5817hRPqqtz5IlgD38po4tnZTMQS8zXwSQ9B/tZOsACKlwe068Z468UpEiCiH+zCkvvT5mi3M= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1778667512; h=Content-Type:Content-Transfer-Encoding:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Owner:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Subject:Subject:To:To:Message-Id:Cc; bh=LyK1jT9YafIF9TBvf3b5EGN7qeMBzv7aiHHlVO60buw=; b=Q9/oll9FAlsJBu5jFHyNW6bXQe2lxeuB5EXh+agmEhl36Anjaa5TdAdc22jmOfSFhJTGR08TR+czdKZSYO5JN9DECULGV1wO7nTDFsWFmYLoTTZrpBZlIi9xlEGYKNcZRcCnf1/WyOgIuNruLKTwSIwtkOeYTp4BD8uWUIB2KwA= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of lists.libvirt.org designates 38.145.34.151 as permitted sender) smtp.mailfrom=devel-bounces@lists.libvirt.org; dmarc=pass header.from= (p=reject dis=none) Return-Path: Received: from lists.libvirt.org (lists.libvirt.org [38.145.34.151]) by mx.zohomail.com with SMTPS id 177866751217545.18524289799291; Wed, 13 May 2026 03:18:32 -0700 (PDT) Received: by lists.libvirt.org (Postfix, from userid 993) id 12E1B418E6; Wed, 13 May 2026 06:18:31 -0400 (EDT) Received: from [172.19.199.9] (unknown [10.16.107.18]) by lists.libvirt.org (Postfix) with ESMTP id 9285841B17; Wed, 13 May 2026 06:15:23 -0400 (EDT) Received: by lists.libvirt.org (Postfix, from userid 993) id 69F5A4185F; Wed, 13 May 2026 06:15:04 -0400 (EDT) Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (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 BC68A41862 for ; Wed, 13 May 2026 06:15:03 -0400 (EDT) Received: from mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-569-524coiNCNdufHK1V201PhA-1; Wed, 13 May 2026 06:15:01 -0400 Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 0CB2B1956089 for ; Wed, 13 May 2026 10:15:01 +0000 (UTC) Received: from speedmetal.openshiftapps.com (unknown [10.44.22.8]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 3E63F180034E for ; Wed, 13 May 2026 10:15:00 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-26) on lists.libvirt.org X-Spam-Level: X-Spam-Status: No, score=-2.7 required=5.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,MAILING_LIST_MULTI,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL,SPF_HELO_PASS autolearn=unavailable autolearn_force=no version=4.0.1 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1778667303; h=from:from: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; bh=LyK1jT9YafIF9TBvf3b5EGN7qeMBzv7aiHHlVO60buw=; b=Ou0D6jKzEPuAgKCT+EB+VfEFZ2cR8Cq2SbtHhgbbGPXtMCVmJavFrHmHdL8uBJrh/e1iCI prhdnUhBfxXlu+UvYmGrTXzTf6zErDh3LQBKVS/OwDRjNnklOqmtZv2iC4muXShCNkE0C1 Ut2XCNOMmBDmC+n8afDTb54pr7TqZYk= X-MC-Unique: 524coiNCNdufHK1V201PhA-1 X-Mimecast-MFC-AGG-ID: 524coiNCNdufHK1V201PhA_1778667301 To: devel@lists.libvirt.org Subject: [PATCH 2/2] testutils: Close FDs leaked into test programs to avoid random breakage Date: Wed, 13 May 2026 12:14:56 +0200 Message-ID: In-Reply-To: References: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.111 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: VhZJo_JtuRyvXmUJq9TUTxwDkvmBV1wksN0YktZ5-NM_1778667301 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable Message-ID-Hash: 3LG2MKJ2XWTZPCFPOOA3KSRLNB3LJFDK X-Message-ID-Hash: 3LG2MKJ2XWTZPCFPOOA3KSRLNB3LJFDK X-MailFrom: pkrempa@redhat.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; header-match-devel.lists.libvirt.org-0; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header 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: From: Peter Krempa via Devel Reply-To: Peter Krempa X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1778667512755158500 Content-Type: text/plain; charset="utf-8" From: Peter Krempa Some test cases (such as cases excercising FD passing in qemuxmlconftest) use dup2 to put FDs on certain numbers to have stable test output. If the environment the test program is run in "leaks"/passes some FDs the test may file in a very obscure way. Since the tests are designed to be standalone we can simply close everything except std(in|out|err) before running the tests to avoid unstable tests. Use virCommandFDMassClose to close everything except stdio. Signed-off-by: Peter Krempa --- tests/testutils.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/testutils.c b/tests/testutils.c index 35571fb2ad..9ce549370b 100644 --- a/tests/testutils.c +++ b/tests/testutils.c @@ -33,6 +33,7 @@ #include "virbuffer.h" #include "virlog.h" #include "virstring.h" +#include "vircommand.h" #define VIR_FROM_THIS VIR_FROM_NONE @@ -840,6 +841,7 @@ int virTestMain(int argc, int (*func)(void), ...) { + g_autoptr(virBitmap) keepfds =3D virBitmapNew(0); const char *lib; va_list ap; int ret; @@ -859,6 +861,14 @@ int virTestMain(int argc, preloads[npreloads] =3D NULL; } + /* Environment may leak FDs into the test which we don't want to use a= nd + * it could break certain test cases which use 'dup2' to put FDs to co= rrect + * numbers to have stable output. */ + virBitmapSetBitExpand(keepfds, STDIN_FILENO); + virBitmapSetBitExpand(keepfds, STDOUT_FILENO); + virBitmapSetBitExpand(keepfds, STDERR_FILENO); + virCommandFDMassClose(keepfds); + va_start(ap, func); while ((lib =3D va_arg(ap, const char *))) { g_autofree char *abs_lib_path =3D g_strdup_printf("%s/%s", abs_bui= lddir, lib); --=20 2.54.0