daemon: Allow running as non-root with unprivileged user namespaces.

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

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

Reviewed-by: Reepca Russelstein <reepca@russelstein.xyz>
This commit is contained in:
Ludovic Courtès 2025-01-22 23:40:24 +01:00 committed by Ludovic Courtès
parent 40f69b586a
commit ae18b3d9e6
No known key found for this signature in database
GPG key ID: 090B11993D9AEBB5
5 changed files with 264 additions and 55 deletions

View file

@ -79,7 +79,7 @@
;; 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"))