Package: guix-patches;
Reported by: Ludovic Courtès <ludo <at> gnu.org>
Date: Wed, 26 Mar 2025 16:50:01 UTC
Severity: normal
Tags: patch
To reply to this bug, email your comments to 77288 AT debbugs.gnu.org.
Toggle the display of automated, internal messages from the tracker.
View this report as an mbox folder, status mbox, maintainer mbox
pelzflorian <at> pelzflorian.de, julien <at> lepiller.eu, guix-patches <at> gnu.org
:bug#77288
; Package guix-patches
.
(Wed, 26 Mar 2025 16:50:02 GMT) Full text and rfc822 format available.Ludovic Courtès <ludo <at> gnu.org>
:pelzflorian <at> pelzflorian.de, julien <at> lepiller.eu, guix-patches <at> gnu.org
.
(Wed, 26 Mar 2025 16:50:02 GMT) Full text and rfc822 format available.Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):
From: Ludovic Courtès <ludo <at> gnu.org> To: guix-patches <at> gnu.org Cc: Ludovic Courtès <ludo <at> gnu.org>, Reepca Russelstein <reepca <at> russelstein.xyz> Subject: [PATCH 0/6] Rootless guix-daemon on Guix System Date: Wed, 26 Mar 2025 17:48:38 +0100
Hello Guix, This is a followup to <https://issues.guix.gnu.org/75810>, which also depends on <https://issues.guix.gnu.org/77189>, allowing us to run ‘guix-daemon’ without root privileges on Guix System. It is the second step of the migration path outlined in <https://issues.guix.gnu.org/75810#111-lineno40>. This is made difficult by the fact that all this is stateful: if I switch my system to unprivileged mode, then the store and all the data files of the daemon must have their owner changed to ‘guix-daemon’. This is implemented by an intermediate ‘guix-ownership’ one-shot service, which completes instantaneously in the normal case and chowns if when switching from privileged to unprivileged and vice versa. This service remains in ‘starting’ state until it is done. Another complication is that of /gnu/store being mounted read-only. To provide the ‘guix-ownership’ and ‘guix-daemon’ processes write access to the store, they are started by a wrapper that creates a new mount namespace and remounts the store read-write (similar to ‘makeStoreWritable’ in the daemon). An open issue is ‘--keep-failed’: currently /tmp/guix-build-* directories will remain owned by ‘guix-daemon’ as was discussed in the initial message at <https://issues.guix.gnu.org/75810>. It’s a regression, but maybe it’s acceptable if we consider that this feature is primarily used on single-user machines. For now, the installation procedure creates /gnu/store, /var/guix, etc. with root:root ownership. Eventually, if/when we settle on unprivileged guix-daemon, we should change that code to have guix-daemon:guix-daemon as the owner. Ludovic Courtès (6): syscalls: Add ‘unshare’. services: account: Create /var/guix/profiles/per-user/$USER. tests: guix-daemon: Send system log output to /dev/console. tests: guix-daemon: Wait for the ‘guix-daemon’ service to be up. services: guix: Allow ‘guix-daemon’ to run without root privileges. DRAFT news: Add entry about unprivileged guix-daemon on Guix System. doc/guix.texi | 30 +++++++ etc/news.scm | 24 ++++++ gnu/services/base.scm | 187 ++++++++++++++++++++++++++++++++++++---- gnu/system/shadow.scm | 19 +++- gnu/tests/base.scm | 60 +++++++++++-- guix/build/syscalls.scm | 18 ++++ tests/syscalls.scm | 9 ++ 7 files changed, 325 insertions(+), 22 deletions(-) base-commit: 1a69acce515de9be9b95df04c553a47a808e5034 -- 2.49.0
guix-patches <at> gnu.org
:bug#77288
; Package guix-patches
.
(Wed, 26 Mar 2025 16:52:01 GMT) Full text and rfc822 format available.Message #8 received at 77288 <at> debbugs.gnu.org (full text, mbox):
From: Ludovic Courtès <ludo <at> gnu.org> To: 77288 <at> debbugs.gnu.org Cc: Ludovic Courtès <ludo <at> gnu.org> Subject: [PATCH 2/6] services: account: Create /var/guix/profiles/per-user/$USER. Date: Wed, 26 Mar 2025 17:51:03 +0100
* gnu/system/shadow.scm (account-shepherd-service): Create /var/guix/profiles/per-user/$USER in ‘user-homes’ service. Change-Id: I22e66e8a34d63686df9bae64c68df65c8889e72a --- gnu/system/shadow.scm | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/gnu/system/shadow.scm b/gnu/system/shadow.scm index b68a818871..d0f1b6b2b1 100644 --- a/gnu/system/shadow.scm +++ b/gnu/system/shadow.scm @@ -1,5 +1,5 @@ ;;; GNU Guix --- Functional package management for GNU -;;; Copyright © 2013-2020, 2022, 2023 Ludovic Courtès <ludo <at> gnu.org> +;;; Copyright © 2013-2020, 2022-2023, 2025 Ludovic Courtès <ludo <at> gnu.org> ;;; Copyright © 2016 Alex Griffin <a <at> ajgrf.com> ;;; Copyright © 2020 Jan (janneke) Nieuwenhuizen <janneke <at> gnu.org> ;;; Copyright © 2020, 2023 Efraim Flashner <efraim <at> flashner.co.il> @@ -460,6 +460,12 @@ (define (account-shepherd-service accounts+groups) (define accounts (filter user-account? accounts+groups)) + (define regular-account-names + (filter-map (lambda (account) + (and (not (user-account-system? account)) + (user-account-name account))) + accounts)) + ;; Create home directories only once 'file-systems' is up. This makes sure ;; they are created in the right place if /home lives on a separate ;; partition. @@ -480,6 +486,17 @@ (define (account-shepherd-service accounts+groups) (activate-user-home (map sexp->user-account (list #$@(map user-account->gexp accounts)))) + + ;; Create the user's profile directory upfront: + ;; guix-daemon lacks permissions to create it when it is + ;; running as an unprivileged user. + (for-each (lambda (account) + (let ((profile (in-vicinity + "/var/guix/profiles/per-user" + account)) + (owner (getpwnam account))) + (mkdir-p/perms profile owner #o755))) + '#$regular-account-names) #t))) ;success (documentation "Create user home directories.")))) -- 2.49.0
guix-patches <at> gnu.org
:bug#77288
; Package guix-patches
.
(Wed, 26 Mar 2025 16:52:02 GMT) Full text and rfc822 format available.Message #11 received at 77288 <at> debbugs.gnu.org (full text, mbox):
From: Ludovic Courtès <ludo <at> gnu.org> To: 77288 <at> debbugs.gnu.org Cc: Ludovic Courtès <ludo <at> gnu.org> Subject: [PATCH 1/6] syscalls: Add ‘unshare’. Date: Wed, 26 Mar 2025 17:51:02 +0100
* guix/build/syscalls.scm (unshare): New procedure. Change-Id: I344273b8bdeaa9366334e6e20ee7efc37eb6c8f7 --- guix/build/syscalls.scm | 18 ++++++++++++++++++ tests/syscalls.scm | 9 +++++++++ 2 files changed, 27 insertions(+) diff --git a/guix/build/syscalls.scm b/guix/build/syscalls.scm index 42232fc7f1..cf09cae3a4 100644 --- a/guix/build/syscalls.scm +++ b/guix/build/syscalls.scm @@ -145,6 +145,7 @@ (define-module (guix build syscalls) CLONE_NEWPID CLONE_NEWNET clone + unshare setns kexec-load-file @@ -1213,6 +1214,23 @@ (define clone (list err)) ret))))) +(define unshare + (let ((proc (syscall->procedure int "unshare" (list int)))) + (lambda (flags) + "Disassociate the current process from parts of its execution context +according to FLAGS, which must be a logical or of CLONE_NEW* constants. + +Note that CLONE_NEWUSER requires that the calling process be single-threaded, +which is possible if and only if libgc is running a single marker thread; this +can be achieved by setting the GC_MARKERS environment variable to 1. If the +calling process is multi-threaded, this throws to 'system-error' with EINVAL." + (let-values (((ret err) + (without-automatic-finalization (proc flags)))) + (unless (zero? ret) + (throw 'system-error "unshare" "~a: ~A" + (list flags (strerror err)) + (list err))))))) + (define setns ;; Some systems may be using an old (pre-2.14) version of glibc where there ;; is no 'setns' function available. diff --git a/tests/syscalls.scm b/tests/syscalls.scm index d2848879d7..879c3e4f25 100644 --- a/tests/syscalls.scm +++ b/tests/syscalls.scm @@ -149,6 +149,15 @@ (define perform-container-tests? ((_ . status) (= 42 (status:exit-val status)))))))) +(test-equal "unshare" + EPERM + ;; Unless running as root, (unshare CLONE_NEWNS) returns EPERM. + (catch 'system-error + (lambda () + (unshare CLONE_NEWNS)) + (lambda args + (system-error-errno args)))) + (unless perform-container-tests? (test-skip 1)) (test-assert "setns" -- 2.49.0
guix-patches <at> gnu.org
:bug#77288
; Package guix-patches
.
(Wed, 26 Mar 2025 16:52:02 GMT) Full text and rfc822 format available.Message #14 received at 77288 <at> debbugs.gnu.org (full text, mbox):
From: Ludovic Courtès <ludo <at> gnu.org> To: 77288 <at> debbugs.gnu.org Cc: Ludovic Courtès <ludo <at> gnu.org> Subject: [PATCH 3/6] tests: guix-daemon: Send system log output to /dev/console. Date: Wed, 26 Mar 2025 17:51:04 +0100
* gnu/tests/base.scm (%daemon-os): New variable. (%test-guix-daemon): Use it. Change-Id: Iea31808cc59e94971ea4cbc12d565c94348bf7a4 --- gnu/tests/base.scm | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/gnu/tests/base.scm b/gnu/tests/base.scm index a7f8a5bf7c..0f7fb543a7 100644 --- a/gnu/tests/base.scm +++ b/gnu/tests/base.scm @@ -994,6 +994,10 @@ (define %test-activation ;;; Build daemon. ;;; +(define %daemon-os + (operating-system-with-console-syslog + (simple-operating-system))) + (define (manifest-entry-without-grafts entry) "Return ENTRY with grafts disabled on its contents." (manifest-entry @@ -1168,7 +1172,7 @@ (define %test-guix-daemon (let ((os (marionette-operating-system (operating-system (inherit (operating-system-with-gc-roots - %simple-os + %daemon-os (list (profile (name "hello-build-dependencies") (content %hello-dependencies-manifest))))) -- 2.49.0
guix-patches <at> gnu.org
:bug#77288
; Package guix-patches
.
(Wed, 26 Mar 2025 16:52:02 GMT) Full text and rfc822 format available.Message #17 received at 77288 <at> debbugs.gnu.org (full text, mbox):
From: Ludovic Courtès <ludo <at> gnu.org> To: 77288 <at> debbugs.gnu.org Cc: Ludovic Courtès <ludo <at> gnu.org> Subject: [PATCH 4/6] tests: guix-daemon: Wait for the ‘guix-daemon’ service to be up. Date: Wed, 26 Mar 2025 17:51:05 +0100
* gnu/tests/base.scm (run-guix-daemon-test): Add “guix-daemon service is up” test. Change-Id: I4d44a1248599fec45c854c285d4da201c30eb00c --- gnu/tests/base.scm | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/gnu/tests/base.scm b/gnu/tests/base.scm index 0f7fb543a7..83e047f7e6 100644 --- a/gnu/tests/base.scm +++ b/gnu/tests/base.scm @@ -1157,6 +1157,13 @@ (define (run-guix-daemon-test os) (test-runner-current (system-test-runner #$output)) (test-begin "guix-daemon") + (test-assert "guix-service is running" + ;; Wait for 'guix-daemon' to be up. + (marionette-eval '(begin + (use-modules (gnu services herd)) + (start-service 'guix-daemon)) + marionette)) + #$(guix-daemon-test-cases #~marionette) (test-end)))) -- 2.49.0
pelzflorian <at> pelzflorian.de, julien <at> lepiller.eu, guix-patches <at> gnu.org
:bug#77288
; Package guix-patches
.
(Wed, 26 Mar 2025 16:52:03 GMT) Full text and rfc822 format available.Message #20 received at 77288 <at> debbugs.gnu.org (full text, mbox):
From: Ludovic Courtès <ludo <at> gnu.org> To: 77288 <at> debbugs.gnu.org Cc: Ludovic Courtès <ludo <at> gnu.org> Subject: [PATCH 6/6] DRAFT news: Add entry about unprivileged guix-daemon on Guix System. Date: Wed, 26 Mar 2025 17:51:07 +0100
DRAFT: Temporary commit. * etc/news.scm: Add it. Change-Id: I28eae7f7b4305225b13281b99458cbedda3c3b94 --- etc/news.scm | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/etc/news.scm b/etc/news.scm index 4b3da44540..840f5cea53 100644 --- a/etc/news.scm +++ b/etc/news.scm @@ -37,6 +37,30 @@ (channel-news (version 0) + (entry (commit "XXX") + (title + (en "Guix System can run @command{guix-daemon} without root +privileges")) + (body + (en "On Guix System, @code{guix-service-type} can now be configured +to run the build daemon, @command{guix-daemon}, without root privileges. In +that configuration, the daemon runs with the authority of the +@code{guix-daemon} user, which we think can reduce the impact of some classes +of vulnerabilities that could affect it. + +For now, this is opt-in: you have to change @code{guix-configuration} to set +the @code{privileged?} field to @code{#f}. When you do this, all the files in +@file{/gnu/store}, @file{/var/guix}, etc. will have their ownership changed to +the @code{guix-daemon} user (instead of @code{root}); this can take a while, +especially if the store is big. To learn more about it, run: + +@example +info guix --index-search=guix-service-type +@end example + +Eventually running @command{guix-daemon} without root privileges may become +the default."))) + (entry (commit "0e51c6547ffdaf91777f7383da4a52a1a07b7286") (title (en "Incompatible upgrade of the Syncthing service")) -- 2.49.0
ludo <at> gnu.org, maxim.cournoyer <at> gmail.com, guix-patches <at> gnu.org
:bug#77288
; Package guix-patches
.
(Wed, 26 Mar 2025 16:52:03 GMT) Full text and rfc822 format available.Message #23 received at 77288 <at> debbugs.gnu.org (full text, mbox):
From: Ludovic Courtès <ludo <at> gnu.org> To: 77288 <at> debbugs.gnu.org Cc: Ludovic Courtès <ludo <at> gnu.org> Subject: [PATCH 5/6] services: guix: Allow ‘guix-daemon’ to run without root privileges. Date: Wed, 26 Mar 2025 17:51:06 +0100
* gnu/services/base.scm (run-with-writable-store) (guix-ownership-change-program): New procedures. (<guix-configuration>)[privileged?]: New field. (guix-shepherd-service): Rename to… (guix-shepherd-services): … this. Add the ‘guix-ownership’ service. Change ‘guix-daemon’ service to depend on it; when unprivileged, prefix ‘daemon-command’ by ‘run-with-writable-store’ and omit ‘--build-users-group’; adjust socket activation endpoints. (guix-accounts): When unprivileged, create the “guix-daemon” user and group. (guix-service-type)[extensions]: Adjust to name change. * gnu/tests/base.scm (run-guix-daemon-test): Add ‘name’ parameter. (%test-guix-daemon): Adjust accordingly. (%test-guix-daemon-unprivileged): New test. * doc/guix.texi (Base Services): Document ‘privileged?’. Change-Id: I28a9a22e617416c551dccb24e43a253b544ba163 --- doc/guix.texi | 30 +++++++ gnu/services/base.scm | 187 ++++++++++++++++++++++++++++++++++++++---- gnu/tests/base.scm | 47 +++++++++-- 3 files changed, 244 insertions(+), 20 deletions(-) diff --git a/doc/guix.texi b/doc/guix.texi index 5af41830ca..f58688f57a 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -20046,6 +20046,36 @@ Base Services The Guix package to use. @xref{Customizing the System-Wide Guix} to learn how to provide a package with a pre-configured set of channels. +@cindex unprivileged @command{guix-daemon} +@cindex rootless @command{guix-daemon} +@item @code{privileged?} (default: @code{#t}) +Whether to run @command{guix-daemon} as root. + +When true, @command{guix-daemon} runs with root privileges and build +processes run under unprivileged user accounts as specified by +@code{build-group} and @code{build-accounts} (see below); when false, +@command{guix-daemon} run as the @code{guix-daemon} user, which is +unprivileged, and so do build processes. The unprivileged or +``rootless'' mode can reduce the impact of some classes of +vulnerabilities that could affect the daemon. + +The default is currently @code{#t} (@command{guix-daemon} runs with root +privileges) but may eventually be changed to @code{#f}. + +@quotation Warning +When changing this option, @file{/gnu/store}, @file{/var/guix}, and +@file{/etc/guix} have their ownership automatically changed by the +@code{guix-ownership} service to either the @code{guix-daemon} user or +the @code{root} user. + +This can take a while, especially if @file{/gnu/store} is big; it cannot +be interrupted and @command{guix-daemon} cannot be used until it has +completed. +@end quotation + +@xref{Build Environment Setup}, for more information on the two ways to +run @command{guix-daemon}. + @item @code{build-group} (default: @code{"guixbuild"}) Name of the group for build user accounts. diff --git a/gnu/services/base.scm b/gnu/services/base.scm index 9a9dfdb304..8f66f54e74 100644 --- a/gnu/services/base.scm +++ b/gnu/services/base.scm @@ -1917,6 +1917,100 @@ (define (guix-machines-files-installation machines) #$machines)) machines-file)))) +(define (run-with-writable-store) + "Return a wrapper that runs the given command under the specified UID and +GID in a context where the store is writable, even if it was bind-mounted +read-only via %IMMUTABLE-STORE (this wrapper must run as root)." + (program-file "run-with-writable-store" + (with-imported-modules (source-module-closure + '((guix build syscalls))) + #~(begin + (use-modules (guix build syscalls) + (ice-9 match)) + + (define (ensure-writable-store store) + ;; Create a new mount namespace and remount STORE with + ;; write permissions if it's read-only. + (unshare CLONE_NEWNS) + (let ((fs (statfs store))) + (unless (zero? (logand (file-system-mount-flags fs) + ST_RDONLY)) + (mount store store "none" + (logior MS_BIND MS_REMOUNT))))) + + (match (command-line) + ((_ user group command args ...) + (ensure-writable-store #$(%store-prefix)) + (let ((uid (or (string->number user) + (passwd:uid (getpwnam user)))) + (gid (or (string->number group) + (group:gid (getgrnam group))))) + (setgroups #()) + (setgid gid) + (setuid uid) + (apply execl command command args)))))))) + +(define (guix-ownership-change-program) + "Return a program that changes ownership of the store and other data files +of Guix to the given UID and GID." + (program-file "validate-guix-ownership" + (with-imported-modules (source-module-closure + '((guix build utils))) + #~(begin + (use-modules (guix build utils) + (ice-9 ftw) + (ice-9 match)) + + (define (lchown file uid gid) + (let ((parent (open (dirname file) O_DIRECTORY))) + (chown-at parent (basename file) uid gid + AT_SYMLINK_NOFOLLOW) + (close-port parent))) + + (define (change-ownership directory uid gid) + ;; chown -R UID:GID DIRECTORY + (file-system-fold (const #t) ;enter? + (lambda (file stat result) ;leaf + (if (eq? 'symlink (stat:type stat)) + (lchown file uid gid) + (chown file uid gid))) + (const #t) ;down + (lambda (directory stat result) ;up + (chown directory uid gid)) + (const #t) ;skip + (lambda (file stat errno result) + (format (current-error-port) "i/o error: ~a: ~a~%" + file (strerror errno)) + #f) + #t ;seed + directory + lstat)) + + (define (claim-data-ownership uid gid) + (format #t "Changing file ownership for /gnu/store \ +and data directories to ~a:~a...~%" + uid gid) + (change-ownership #$(%store-prefix) uid gid) + (let ((excluded '("." ".." "profiles" "userpool"))) + (for-each (lambda (directory) + (change-ownership (in-vicinity "/var/guix" directory) + uid gid)) + (scandir "/var/guix" + (lambda (file) + (not (member file + excluded)))))) + (chown "/var/guix" uid gid) + (change-ownership "/etc/guix" uid gid) + (mkdir-p "/var/log/guix") + (change-ownership "/var/log/guix" uid gid)) + + (match (command-line) + ((_ (= string->number (? integer? uid)) + (= string->number (? integer? gid))) + (setlocale LC_ALL "C.UTF-8") ;for file name decoding + (setvbuf (current-output-port) 'line) + (claim-data-ownership uid gid))))))) + (define-record-type* <guix-configuration> guix-configuration make-guix-configuration guix-configuration? @@ -1958,6 +2052,8 @@ (define-record-type* <guix-configuration> (default #f)) (tmpdir guix-tmpdir ;string | #f (default #f)) + (privileged? guix-configuration-privileged? + (default #t)) (build-machines guix-configuration-build-machines ;list of gexps | '() (default '())) (environment guix-configuration-environment ;list of strings @@ -2020,7 +2116,7 @@ (define shepherd-discover-action (environ environment) #t))))) -(define (guix-shepherd-service config) +(define (guix-shepherd-services config) "Return a <shepherd-service> for the Guix daemon service with CONFIG." (define locales (let-system (system target) @@ -2029,16 +2125,57 @@ (define (guix-shepherd-service config) glibc-utf8-locales))) (match-record config <guix-configuration> - (guix build-group build-accounts chroot? authorize-key? authorized-keys + (guix privileged? + build-group build-accounts chroot? authorize-key? authorized-keys use-substitutes? substitute-urls max-silent-time timeout log-compression discover? extra-options log-file http-proxy tmpdir chroot-directories environment socket-directory-permissions socket-directory-group socket-directory-user) (list (shepherd-service + (provision '(guix-ownership)) + (requirement '(user-processes user-homes)) + (one-shot? #t) + (start #~(lambda () + (let* ((store #$(%store-prefix)) + (stat (lstat store)) + (privileged? #$(guix-configuration-privileged? + config)) + (change-ownership #$(guix-ownership-change-program)) + (with-writable-store #$(run-with-writable-store))) + ;; Check whether we're switching from privileged to + ;; unprivileged guix-daemon, or vice versa, and adjust + ;; file ownership accordingly. Spawn a child process + ;; if and only if something needs to be changed. + ;; + ;; Note: This service remains in 'starting' state for + ;; as long as CHANGE-OWNERSHIP is running. That way, + ;; 'guix-daemon' starts only once we're done. + (cond ((and (not privileged?) + (or (zero? (stat:uid stat)) + (zero? (stat:gid stat)))) + (let ((user (getpwnam "guix-daemon"))) + (format #t "Changing to unprivileged guix-daemon.~%") + (zero? + (system* with-writable-store "0" "0" + change-ownership + (number->string (passwd:uid user)) + (number->string (passwd:gid user)))))) + ((and privileged? + (and (not (zero? (stat:uid stat))) + (not (zero? (stat:gid stat))))) + (format #t "Changing to privileged guix-daemon.~%") + (zero? (system* with-writable-store "0" "0" + change-ownership "0" "0"))) + (else #t))))) + (documentation "Ensure that the store and other data files used by +guix-daemon have the right ownership.")) + + (shepherd-service (documentation "Run the Guix daemon.") (provision '(guix-daemon)) (requirement `(user-processes + guix-ownership ,@(if discover? '(avahi-daemon) '()))) (actions (list shepherd-set-http-proxy-action shepherd-discover-action)) @@ -2062,8 +2199,15 @@ (define (guix-shepherd-service config) (or (getenv "discover") #$discover?)) (define daemon-command - (cons* #$(file-append guix "/bin/guix-daemon") - "--build-users-group" #$build-group + (cons* #$@(if privileged? + #~() + #~(#$(run-with-writable-store) + "guix-daemon" "guix-daemon")) + + #$(file-append guix "/bin/guix-daemon") + #$@(if privileged? + #~("--build-users-group" #$build-group) + #~()) "--max-silent-time" #$(number->string max-silent-time) "--timeout" #$(number->string timeout) @@ -2144,9 +2288,11 @@ (define (guix-shepherd-service config) "/var/guix/daemon-socket/socket") #:name "socket" #:socket-owner - (or #$socket-directory-user 0) + (or #$socket-directory-user + #$(if privileged? 0 "guix-daemon")) #:socket-group - (or #$socket-directory-group 0) + (or #$socket-directory-group + #$(if privileged? 0 "guix-daemon")) #:socket-directory-permissions #$socket-directory-permissions))) ((make-systemd-constructor daemon-command @@ -2161,15 +2307,26 @@ (define (guix-shepherd-service config) (define (guix-accounts config) "Return the user accounts and user groups for CONFIG." - (cons (user-group - (name (guix-configuration-build-group config)) - (system? #t) + (if (guix-configuration-privileged? config) + (cons (user-group + (name (guix-configuration-build-group config)) + (system? #t) - ;; Use a fixed GID so that we can create the store with the right - ;; owner. - (id 30000)) - (guix-build-accounts (guix-configuration-build-accounts config) - #:group (guix-configuration-build-group config)))) + ;; Use a fixed GID so that we can create the store with the right + ;; owner. + (id 30000)) + (guix-build-accounts (guix-configuration-build-accounts config) + #:group (guix-configuration-build-group + config))) + (list (user-group (name "guix-daemon") (system? #t)) + (user-account + (name "guix-daemon") + (group "guix-daemon") + (system? #t) + (supplementary-groups '("kvm")) + (comment "Guix Daemon User") + (home-directory "/var/empty") + (shell (file-append shadow "/sbin/nologin")))))) (define (guix-activation config) "Return the activation gexp for CONFIG." @@ -2227,7 +2384,7 @@ (define guix-service-type (service-type (name 'guix) (extensions - (list (service-extension shepherd-root-service-type guix-shepherd-service) + (list (service-extension shepherd-root-service-type guix-shepherd-services) (service-extension account-service-type guix-accounts) (service-extension activation-service-type guix-activation) (service-extension profile-service-type diff --git a/gnu/tests/base.scm b/gnu/tests/base.scm index 83e047f7e6..12d4e70ee5 100644 --- a/gnu/tests/base.scm +++ b/gnu/tests/base.scm @@ -1,5 +1,5 @@ ;;; GNU Guix --- Functional package management for GNU -;;; Copyright © 2016-2020, 2022, 2024 Ludovic Courtès <ludo <at> gnu.org> +;;; Copyright © 2016-2020, 2022, 2024-2025 Ludovic Courtès <ludo <at> gnu.org> ;;; Copyright © 2018 Clément Lassieur <clement <at> lassieur.org> ;;; Copyright © 2022 Maxim Cournoyer <maxim.cournoyer <at> gmail.com> ;;; Copyright © 2022 Marius Bakke <marius <at> gnu.org> @@ -63,7 +63,8 @@ (define-module (gnu tests base) %hello-dependencies-manifest guix-daemon-test-cases - %test-guix-daemon)) + %test-guix-daemon + %test-guix-daemon-unprivileged)) (define %simple-os (simple-operating-system)) @@ -1121,7 +1122,7 @@ (define (guix-daemon-test-cases marionette) (system-error-errno args))) #$marionette)))) -(define (run-guix-daemon-test os) +(define (run-guix-daemon-test os name) (define test-image (image (operating-system os) (format 'compressed-qcow2) @@ -1161,6 +1162,12 @@ (define (run-guix-daemon-test os) ;; Wait for 'guix-daemon' to be up. (marionette-eval '(begin (use-modules (gnu services herd)) + (start-service 'guix-daemon) + + ;; XXX: Do it a second time to work around + ;; <https://issues.guix.gnu.org/77274> and its + ;; effect on the 'guix-ownership' service. + ;; TODO: Remove when Shepherd 1.0.4 is out. (start-service 'guix-daemon)) marionette)) @@ -1168,7 +1175,7 @@ (define (run-guix-daemon-test os) (test-end)))) - (gexp->derivation "guix-daemon-test" test)) + (gexp->derivation name test)) (define %test-guix-daemon (system-test @@ -1190,4 +1197,34 @@ (define %test-guix-daemon %base-user-accounts))) #:imported-modules '((gnu services herd) (guix combinators))))) - (run-guix-daemon-test os))))) + (run-guix-daemon-test os "guix-daemon-test"))))) + +(define %test-guix-daemon-unprivileged + (system-test + (name "guix-daemon-unprivileged") + (description + "Test 'guix-daemon' behavior on a multi-user system, where 'guix-daemon' +runs unprivileged.") + (value + (let ((os (marionette-operating-system + (let ((base (operating-system-with-gc-roots + %daemon-os + (list (profile + (name "hello-build-dependencies") + (content %hello-dependencies-manifest)))))) + (operating-system + (inherit base) + (kernel-arguments '("console=ttyS0")) + (users (cons (user-account + (name "user") + (group "users")) + %base-user-accounts)) + (services + (modify-services (operating-system-user-services base) + (guix-service-type + config => (guix-configuration + (inherit config) + (privileged? #f))))))) + #:imported-modules '((gnu services herd) + (guix combinators))))) + (run-guix-daemon-test os "guix-daemon-unprivileged-test"))))) -- 2.49.0
guix-patches <at> gnu.org
:bug#77288
; Package guix-patches
.
(Thu, 27 Mar 2025 13:28:03 GMT) Full text and rfc822 format available.Message #26 received at 77288 <at> debbugs.gnu.org (full text, mbox):
From: "pelzflorian (Florian Pelz)" <pelzflorian <at> pelzflorian.de> To: Ludovic Courtès <ludo <at> gnu.org> Cc: Julien Lepiller <julien <at> lepiller.eu>, 77288 <at> debbugs.gnu.org, Reepca Russelstein <reepca <at> russelstein.xyz> Subject: Re: [bug#77288] [PATCH 6/6] DRAFT news: Add entry about unprivileged guix-daemon on Guix System. Date: Thu, 27 Mar 2025 14:27:33 +0100
[Message part 1 (text/plain, inline)]
Rootless daemon is an important change, though I have not tested yet... Ludovic Courtès <ludo <at> gnu.org> writes: > +Eventually running @command{guix-daemon} without root privileges may become > +the default."))) > + I dislike the word “may” in this last sentence. How about “likely will” or some such thing, even if we have not reviewed bugfreeness of Linux here? Can you tell foreign distro users about their rootless options in the news, too? Could you add this German translation?
[german-rootless-news.scm (text/plain, inline)]
(entry (commit "XXX") (title (en "Guix System can run @command{guix-daemon} without root privileges") (de "Guix System kann @command{guix-daemon} ohne root-Berechtigungen ausführen")) (body (en "On Guix System, @code{guix-service-type} can now be configured to run the build daemon, @command{guix-daemon}, without root privileges. In that configuration, the daemon runs with the authority of the @code{guix-daemon} user, which we think can reduce the impact of some classes of vulnerabilities that could affect it. For now, this is opt-in: you have to change @code{guix-configuration} to set the @code{privileged?} field to @code{#f}. When you do this, all the files in @file{/gnu/store}, @file{/var/guix}, etc. will have their ownership changed to the @code{guix-daemon} user (instead of @code{root}); this can take a while, especially if the store is big. To learn more about it, run: @example info guix --index-search=guix-service-type @end example Eventually running @command{guix-daemon} without root privileges may become the default.") (de "Auf Guix System kann @code{guix-service-type} jetzt so konfiguriert werden, dass der Erstellungs-Daemon @command{guix-daemon} ohne root-Berechtigungen ausgeführt wird. In dieser Konfiguration läuft der Daemon mit den Berechtigungen des Benutzers @code{guix-daemon}, wovon wir glauben, dass es die Auswirkungen mancher Schwachstellen-Kategorien verringert, die ihn betreffen könnten. Fürs Erste bleibt es Ihnen überlassen: Sie müssen @code{guix-configuration} anpassen und dort das Feld @code{privileged?} auf @code{#f} setzen. Wenn Sie das tun, wird der Besitzer aller Dateien in @file{/gnu/store}, @file{/var/guix}, usw.@: auf den Benutzer @code{guix-daemon} geändert (anstelle von @code{root}); das kann eine Weile dauern, besonders wenn der Store groß ist. Um mehr zu erfahren, führen Sie aus: @example info guix --index-search=guix-service-type @end example Schließlich wird das Ausführen von @command{guix-daemon} ohne root-Berechtigungen vielleicht die Vorgabe werden.")))
[Message part 3 (text/plain, inline)]
Regards, Florian
guix-patches <at> gnu.org
:bug#77288
; Package guix-patches
.
(Thu, 27 Mar 2025 13:40:05 GMT) Full text and rfc822 format available.Message #29 received at 77288 <at> debbugs.gnu.org (full text, mbox):
From: Ludovic Courtès <ludo <at> gnu.org> To: "pelzflorian (Florian Pelz)" <pelzflorian <at> pelzflorian.de> Cc: Julien Lepiller <julien <at> lepiller.eu>, 77288 <at> debbugs.gnu.org, Reepca Russelstein <reepca <at> russelstein.xyz> Subject: Re: [bug#77288] [PATCH 6/6] DRAFT news: Add entry about unprivileged guix-daemon on Guix System. Date: Thu, 27 Mar 2025 14:38:54 +0100
Hi Florian, "pelzflorian (Florian Pelz)" <pelzflorian <at> pelzflorian.de> skribis: > Rootless daemon is an important change, though I have not tested yet... > > Ludovic Courtès <ludo <at> gnu.org> writes: >> +Eventually running @command{guix-daemon} without root privileges may become >> +the default."))) >> + > > I dislike the word “may” in this last sentence. How about “likely > will” or some such thing, even if we have not reviewed bugfreeness of > Linux here? Sure; I view “may” and “likely will” as synonymous, but maybe there are subtleties that escape me. > Can you tell foreign distro users about their rootless options in the > news, too? This news item is specifically about Guix System (announced upfront), but I guess we can add a sentence toward the end. (Thing is, the situation will be simpler on foreign distros: we won’t support switching between privileged and unprivileged, so either you get one or the other.) Thanks for the comments and for the translation! Ludo’.
guix-patches <at> gnu.org
:bug#77288
; Package guix-patches
.
(Fri, 28 Mar 2025 07:41:01 GMT) Full text and rfc822 format available.Message #32 received at 77288 <at> debbugs.gnu.org (full text, mbox):
From: "pelzflorian (Florian Pelz)" <pelzflorian <at> pelzflorian.de> To: Ludovic Courtès <ludo <at> gnu.org> Cc: Julien Lepiller <julien <at> lepiller.eu>, 77288 <at> debbugs.gnu.org, Reepca Russelstein <reepca <at> russelstein.xyz> Subject: Re: [bug#77288] [PATCH 6/6] DRAFT news: Add entry about unprivileged guix-daemon on Guix System. Date: Fri, 28 Mar 2025 08:39:14 +0100
Hi Ludo. Ludovic Courtès <ludo <at> gnu.org> writes: > "pelzflorian (Florian Pelz)" <pelzflorian <at> pelzflorian.de> skribis: >> Ludovic Courtès <ludo <at> gnu.org> writes: >>> +Eventually running @command{guix-daemon} without root privileges may become >>> +the default."))) >>> + >> >> I dislike the word “may” in this last sentence. How about “likely >> will” or some such thing, even if we have not reviewed bugfreeness of >> Linux here? > > Sure; I view “may” and “likely will” as synonymous, but maybe there are > subtleties that escape me. > I had understood “likely” to be “probably”. With more thinking and Wiktionary reading, “likely” can also mean “plausibly”, though not in this context, I think. The word “may” you had used means “possibly”, which sounds indecisive/uncommitted and if even Guix does not know yet if rootless is a good idea, how should a news-reading user know? I thought you wrote it for this purpose, because distros had been wary of USERNS some time ago, or something. This is why I translated to German as „vielleicht” (maybe). Apparently some people want to banish the word “may” for its suppossed ambiguity; it can mean “possibly” and “have permission to”, according to Wiktionary. This subtlety is news to me; I think context makes clear what “may” means. But perhaps it really is better to use unambiguous adverbs, adjectives like “probably”. In case you write this “probably” or “likely”, I would translate in German as „wahrscheinlich” (probably). >> Can you tell foreign distro users about their rootless options in the >> news, too? > > This news item is specifically about Guix System (announced upfront), > but I guess we can add a sentence toward the end. (Thing is, the > situation will be simpler on foreign distros: we won’t support switching > between privileged and unprivileged, so either you get one or the > other.) > Yes, please! That sentence in parentheses explains the situation, but needs rewording for etc/news.scm of course. > Thanks for the comments and for the translation! > > Ludo’. :) I also now notice it is impossible to translate info guix --index-search=guix-service-type as info guix.de --index-search=guix-service-type although info guix.fr --index-search=guix-service-type works fine. No idea why; both texi files look the same here. But since the rootless documentation is not translated yet anyway, please leave info guix --index-search=guix-service-type Regards, Florian
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.