Message ID | cover.1742230219.git.ludo@gnu.org |
---|---|
Headers |
Return-Path: <guix-patches-bounces+patchwork=mira.cbaines.net@gnu.org> X-Original-To: patchwork@mira.cbaines.net Delivered-To: patchwork@mira.cbaines.net Received: by mira.cbaines.net (Postfix, from userid 113) id 9621627BBE9; Mon, 17 Mar 2025 17:04:42 +0000 (GMT) X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on mira.cbaines.net X-Spam-Level: X-Spam-Status: No, score=-7.6 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,MAILING_LIST_MULTI,RCVD_IN_DNSWL_BLOCKED, RCVD_IN_VALIDITY_CERTIFIED,RCVD_IN_VALIDITY_RPBL,RCVD_IN_VALIDITY_SAFE, SPF_HELO_PASS autolearn=ham autolearn_force=no version=3.4.6 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mira.cbaines.net (Postfix) with ESMTPS id A3E7027BBEA for <patchwork@mira.cbaines.net>; Mon, 17 Mar 2025 17:04:41 +0000 (GMT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from <guix-patches-bounces@gnu.org>) id 1tuDso-0004Dn-4B; Mon, 17 Mar 2025 13:04:11 -0400 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 <Debian-debbugs@debbugs.gnu.org>) id 1tuDsj-00048x-Na for guix-patches@gnu.org; Mon, 17 Mar 2025 13:04:06 -0400 Received: from debbugs.gnu.org ([2001:470:142:5::43]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from <Debian-debbugs@debbugs.gnu.org>) id 1tuDsi-0005CN-Ux for guix-patches@gnu.org; Mon, 17 Mar 2025 13:04:05 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=debbugs.gnu.org; s=debbugs-gnu-org; h=MIME-Version:Date:From:To:In-Reply-To:References:Subject; bh=w34Dg0lx8HR0/NDPhk/qpYHbFLdvAG5Ej+OMGuq/kXU=; b=bg8n/g4Y7rdPdlosgt4GWiOUmXVR4Cdw2Crsop3Or4SWYkq4LYnUrJT0CTdMmyuqbxOwaQgNoP9q4qpIlZI1hspgHpMFCIyoNklRdWF3XFptCBg7XniIbsCQiWWt2WRR9Dr+3FPtEb8meg0S/0e2sciavJgNFXV0NWY89PXhZr5qzLJbiwJCm0FaYHWiCxok9PDJ+giqcBPm5NViWixyXG0TiSGt6iQTR898b2N8AJj87nmYV2PhgiSfjQhV1q1FeRkLomI/KVqgqVU8CyvFbq2qu2c9hlfjVZB7HKYN81Ic5mKVnx4OwEOwkurDZE4tGpa1rQAfiJ8JPnDtjauIlA==; Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from <Debian-debbugs@debbugs.gnu.org>) id 1tuDsi-0002cl-5t for guix-patches@gnu.org; Mon, 17 Mar 2025 13:04:04 -0400 X-Loop: help-debbugs@gnu.org Subject: [bug#75810] [PATCH v6 00/16] Rootless guix-daemon References: <cover.1737738362.git.ludo@gnu.org> In-Reply-To: <cover.1737738362.git.ludo@gnu.org> Resent-From: Ludovic =?utf-8?q?Court=C3=A8s?= <ludo@gnu.org> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces@debbugs.gnu.org> Resent-CC: guix-patches@gnu.org Resent-Date: Mon, 17 Mar 2025 17:04:04 +0000 Resent-Message-ID: <handler.75810.B75810.17422310349972@debbugs.gnu.org> Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 75810 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: 75810@debbugs.gnu.org Cc: Ludovic =?utf-8?q?Court=C3=A8s?= <ludo@gnu.org>, Reepca Russelstein <reepca@russelstein.xyz> Received: via spool by 75810-submit@debbugs.gnu.org id=B75810.17422310349972 (code B ref 75810); Mon, 17 Mar 2025 17:04:04 +0000 Received: (at 75810) by debbugs.gnu.org; 17 Mar 2025 17:03:54 +0000 Received: from localhost ([127.0.0.1]:60634 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces@debbugs.gnu.org>) id 1tuDsR-0002Ze-Dg for submit@debbugs.gnu.org; Mon, 17 Mar 2025 13:03:53 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:42100) by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.84_2) (envelope-from <ludo@gnu.org>) id 1tuDsH-0002Wt-3s for 75810@debbugs.gnu.org; Mon, 17 Mar 2025 13:03:40 -0400 Received: from fencepost.gnu.org ([2001:470:142:3::e]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from <ludo@gnu.org>) id 1tuDs8-00052T-BH; Mon, 17 Mar 2025 13:03:28 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org; s=fencepost-gnu-org; h=MIME-Version:Date:Subject:To:From:in-reply-to: references; bh=w34Dg0lx8HR0/NDPhk/qpYHbFLdvAG5Ej+OMGuq/kXU=; b=UdyILmrQjrY9JN v7apXpPLIqXgcudI3qOZVguDBwouAukds4wvFcnkxoIB2Mbot+KHybNcL0bSge5B7IbUgvRMwE7+Z JQ3Ft+UhMgwxJsZsmxDXtDL5vIBSTfqr8hzLob09nBRHya4v5VsQRj9jvhlB7vwizg3RYbdOvBC84 sDHQ+iNwuNvRrbiivFQcLVWOo43zcRXkYV/Vzf8JIWSSx7an42ydNz8MKM01RC+6btMmYfV46cu/y g/WqTjl0nsbZfpdJtGsdHCmVY542sw1ECqN+fUQ2tm51YT7TlUsRYXQHhaF6h3gHl8ybWUOcx5npi 07gL5xfP/3FCL7s+990Q==; From: Ludovic =?utf-8?q?Court=C3=A8s?= <ludo@gnu.org> Date: Mon, 17 Mar 2025 18:02:43 +0100 Message-ID: <cover.1742230219.git.ludo@gnu.org> X-Mailer: git-send-email 2.48.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: guix-patches@gnu.org List-Id: <guix-patches.gnu.org> List-Unsubscribe: <https://lists.gnu.org/mailman/options/guix-patches>, <mailto:guix-patches-request@gnu.org?subject=unsubscribe> List-Archive: <https://lists.gnu.org/archive/html/guix-patches> List-Post: <mailto:guix-patches@gnu.org> List-Help: <mailto:guix-patches-request@gnu.org?subject=help> List-Subscribe: <https://lists.gnu.org/mailman/listinfo/guix-patches>, <mailto:guix-patches-request@gnu.org?subject=subscribe> Errors-To: guix-patches-bounces+patchwork=mira.cbaines.net@gnu.org Sender: guix-patches-bounces+patchwork=mira.cbaines.net@gnu.org X-getmail-retrieved-from-mailbox: Patches |
Series |
Rootless guix-daemon
|
|
Message
Ludovic Courtès
March 17, 2025, 5:02 p.m. UTC
Hello, This new version addresses Reepca’s latest comments¹: • Close the read end of ‘logPipe’ in ‘commonChildInit’. • Explicitly close the ‘readiness’ pipe. • Fix ‘--disable-chroot’ warning in the manual that was misleading. • Have ‘test-env’ check whether user namespaces are supported at all, which fixes non-Linux support (where it would previously fail to pass ‘--disable-chroot’.) • Change ‘unprivileged-user-namespace-supported?’ similarly. • Fix “build root cannot be made world-readable” test, which could not possibly fail and was exposing users unnecessarily. • Change ‘guix-install.sh’ on systemd machines: warn when unprivileged user namespaces are disabled, attempt to enable them, and error out if we failed to enable them. Hopefully I didn’t forget anything. I checked that the “debian-install” and “guix-daemon” system tests still pass. Thanks, Ludo’. ¹ https://issues.guix.gnu.org/75810#91 Ludovic Courtès (16): daemon: Use ‘close_range’ where available. daemon: Close the read end of the logging pipe. daemon: Bind-mount /etc/nsswitch.conf & co. only if it exists. daemon: Bind-mount all the inputs, not just directories. daemon: Remount inputs as read-only. daemon: Remount root directory as read-only. daemon: Allow running as non-root with unprivileged user namespaces. daemon: Create /var/guix/profiles/per-user unconditionally. daemon: Drop Linux ambient capabilities before executing builder. daemon: Move comments where they belong. linux-container: ‘unprivileged-user-namespace-supported?’ returns #f on non-Linux. tests: Add missing derivation inputs. tests: Run in a chroot and unprivileged user namespaces. etc: systemd services: Run ‘guix-daemon’ as an unprivileged user. guix-install.sh: Support the unprivileged daemon where possible. DRAFT gnu: guix: Update to 07c5b1b build-aux/test-env.in | 18 +- config-daemon.ac | 5 +- doc/guix.texi | 102 ++++++++--- etc/gnu-store.mount.in | 3 +- etc/guix-daemon.service.in | 22 ++- etc/guix-install.sh | 124 +++++++++++--- gnu/build/linux-container.scm | 4 +- gnu/packages/package-management.scm | 6 +- guix/substitutes.scm | 2 +- nix/libstore/build.cc | 251 +++++++++++++++++++++------- nix/libstore/local-store.cc | 26 ++- nix/libutil/util.cc | 26 ++- tests/derivations.scm | 24 ++- tests/packages.scm | 13 +- tests/processes.scm | 9 +- tests/store.scm | 247 +++++++++++++++++++++++---- 16 files changed, 698 insertions(+), 184 deletions(-) base-commit: 0c497c87ac47206b3e8c6dfa2e1e9b5f3e452292
Comments
Ludovic Courtès <ludo@gnu.org> writes: > @@ -2013,23 +2057,36 @@ void DerivationGoal::runChild() > > _writeToStderr = 0; > > + if (readiness.writeSide > 0) readiness.writeSide.close(); > + > + if (readiness.readSide > 0) { > + /* Wait for the parent process to initialize the UID/GID mapping > + of our user namespace. */ > + char str[20] = { '\0' }; > + readFull(readiness.readSide, (unsigned char*)str, 3); > + if (strcmp(str, "go\n") != 0) > + throw Error("failed to initialize process in unprivileged user namespace"); > + } > + > restoreAffinity(); (in patch 7/16, in nix/libstore/build.cc) Strictly speaking we should check whether the fds are >= 0, not > 0, since 0 is technically a valid file descriptor, and we use -1 to indicate the absence of a file descriptor. Also, readiness.readSide isn't explicitly closed in the child after we're done with it. > + > + # The unprivileged daemon cannot create the log directory by itself. > + mkdir /var/log/guix > + chown guix-daemon:guix-daemon /var/log/guix > + chmod 755 /var/log/guix (in patch 15/16, in etc/guix-install.sh) Should this be 'mkdir -p' or some other conditional creation? If I understand correctly this will fail when overwriting an existing install using GUIX_ALLOW_OVERWRITE. Concerning guix-install.sh, to be clear, is the intent to specifically not support installing the rootful daemon on systemd systems? For my two cents, I do think that it's still a tradeoff - not just because of the reliance on different kernel mechanisms for security, but also because the rootless daemon currently causes visible changes to the build environment (EROFS on /, and nothing owned by root, for example). Which one should we consider the "canonical" build environment going forward? I decided to do some searching for container escapes / vulnerabilities online, just to be extra careful, and found one that relies on the container entry point being run as the user that owns the program that execs the container entry point: CVE-2019-5736. It exploits the fact that /proc/self/exe, despite being displayed like a symlink in the output of ls, does not actually act like a symlink, and indeed acts more like a hardlink that readlink happens to have some associated data for. The demo, modified for guix circumstances, would go something like this: 1. A derivation is created whose builder is /proc/self/exe, and whose LD_PRELOAD environment variable points into a malicious store item for one of its shared libraries - for example, libc. 2. The daemon reads this in, and, to my knowledge, does no verification of the builder string. Note that this aspect isn't actually necessary, as the builder could also be a symlink to /proc/self/exe from the store. 3. The daemon sets up the build environment, and execs /proc/self/exe. 4. An attacker-controlled load-time function gets run. 5. It opens /proc/self/exe, initially read-only because it can't be opened writable while a process is executing it. It then execs another attacker-controlled process, which inherits the open file descriptor and subsequently opens it via /proc/self/fd/<fd>, this time read-write (it can do this because it owns the file, and even if it's not writable, a quick fchmod will fix that, and the filesystem it was originally opened from isn't read-only, because guix-daemon starts before gnu-store.mount bind-mounts /gnu/store to itself prior to making it read-only). It then overwrites the resulting file descriptor with whatever contents it wants. 6. The next time guix-daemon is started outside the container, it runs attacker-controlled code. There are several points at which that particular attack could be stopped, and I'd like to try to stop it at as many of them as possible. A good start would be canonicalizing the builder prior to executing it and then checking to make sure it is in the store. A more general solution could look like writing out and then executing a tiny binary, something like /tmp/runbuilder, that does nothing but unlink itself and then exec the actual program. Here's a writeup of the CVE in question: https://unit42.paloaltonetworks.com/breaking-docker-via-runc-explaining-cve-2019-5736/ Aside from all that, it looks good to me. - reepca