mirror of
https://codeberg.org/guix/guix.git
synced 2025-10-02 02:15:12 +00:00
environment: Add ‘--writable-root’ and default to read-only root.
This is an incompatible change where the root file system in ‘guix shell -C’ is now read-only by default. * guix/scripts/environment.scm (show-environment-options-help) (%options): Add ‘--writable-root’. * guix/scripts/environment.scm (setup-fhs): Invoke /sbin/ldconfig; moved from… (launch-environment): … here. (launch-environment/container): Add #:writable-root? and pass it to ‘call-with-container’. Move root file system setup to #:populate-file-system. (guix-environment*): Honor ‘--writable-root’. * tests/guix-environment-container.sh: Test it. * doc/guix.texi (Invoking guix shell): Document ‘--writable-root’. (Debugging Build Failures): Mention it before “rm /bin/sh”. Change-Id: I2e8517d6f01eb8093160bffc0f9f56071ad6fee6 Reviewed-by: Maxim Cournoyer <maxim.cournoyer@gmail.com>
This commit is contained in:
parent
7d28e6512c
commit
ce363c1dc7
3 changed files with 76 additions and 46 deletions
|
@ -6481,6 +6481,10 @@ directory within the container. If this is undesirable,
|
||||||
be automatically shared and will change to the user's home directory
|
be automatically shared and will change to the user's home directory
|
||||||
within the container instead. See also @option{--user}.
|
within the container instead. See also @option{--user}.
|
||||||
|
|
||||||
|
@item --writable-root
|
||||||
|
When using @option{--container}, this option makes the root file system
|
||||||
|
writable (it is read-only by default).
|
||||||
|
|
||||||
@item --expose=@var{source}[=@var{target}]
|
@item --expose=@var{source}[=@var{target}]
|
||||||
@itemx --share=@var{source}[=@var{target}]
|
@itemx --share=@var{source}[=@var{target}]
|
||||||
For containers, @option{--expose} (resp. @option{--share}) exposes the
|
For containers, @option{--expose} (resp. @option{--share}) exposes the
|
||||||
|
@ -14125,7 +14129,8 @@ environment, with ungrafted packages (@pxref{Security Updates}, for more
|
||||||
info on grafts).
|
info on grafts).
|
||||||
|
|
||||||
To get closer to a container like that used by the build daemon, we can
|
To get closer to a container like that used by the build daemon, we can
|
||||||
remove @file{/bin/sh}:
|
remove @file{/bin/sh} (you'll first need to pass the
|
||||||
|
@option{--writable-root} option to @command{guix shell}):
|
||||||
|
|
||||||
@example
|
@example
|
||||||
[env]# rm /bin/sh
|
[env]# rm /bin/sh
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
;;; GNU Guix --- Functional package management for GNU
|
;;; GNU Guix --- Functional package management for GNU
|
||||||
;;; Copyright © 2014, 2015, 2018 David Thompson <davet@gnu.org>
|
;;; Copyright © 2014, 2015, 2018 David Thompson <davet@gnu.org>
|
||||||
;;; Copyright © 2015-2024 Ludovic Courtès <ludo@gnu.org>
|
;;; Copyright © 2015-2025 Ludovic Courtès <ludo@gnu.org>
|
||||||
;;; Copyright © 2018 Mike Gerwitz <mtg@gnu.org>
|
;;; Copyright © 2018 Mike Gerwitz <mtg@gnu.org>
|
||||||
;;; Copyright © 2022, 2023 John Kehayias <john.kehayias@protonmail.com>
|
;;; Copyright © 2022, 2023 John Kehayias <john.kehayias@protonmail.com>
|
||||||
;;;
|
;;;
|
||||||
|
@ -120,6 +120,8 @@ shell'."
|
||||||
(display (G_ "
|
(display (G_ "
|
||||||
--no-cwd do not share current working directory with an
|
--no-cwd do not share current working directory with an
|
||||||
isolated container"))
|
isolated container"))
|
||||||
|
(display (G_ "
|
||||||
|
--writable-root make the container's root file system writable"))
|
||||||
|
|
||||||
(display (G_ "
|
(display (G_ "
|
||||||
--share=SPEC for containers, share writable host file system
|
--share=SPEC for containers, share writable host file system
|
||||||
|
@ -261,6 +263,9 @@ use '--preserve' instead~%"))
|
||||||
(option '("no-cwd") #f #f
|
(option '("no-cwd") #f #f
|
||||||
(lambda (opt name arg result)
|
(lambda (opt name arg result)
|
||||||
(alist-cons 'no-cwd? #t result)))
|
(alist-cons 'no-cwd? #t result)))
|
||||||
|
(option '("writable-root") #f #f
|
||||||
|
(lambda (opt name arg result)
|
||||||
|
(alist-cons 'writable-root? #t result)))
|
||||||
(option '("share") #t #f
|
(option '("share") #t #f
|
||||||
(lambda (opt name arg result)
|
(lambda (opt name arg result)
|
||||||
(alist-cons 'file-system-mapping
|
(alist-cons 'file-system-mapping
|
||||||
|
@ -483,7 +488,10 @@ providing a symlink for CC if GCC is in the container PROFILE, and writing
|
||||||
(newline port))
|
(newline port))
|
||||||
;; /lib/nss is needed as Guix's nss puts libraries
|
;; /lib/nss is needed as Guix's nss puts libraries
|
||||||
;; there rather than in the lib directory.
|
;; there rather than in the lib directory.
|
||||||
'("/lib" "/lib/nss")))))
|
'("/lib" "/lib/nss"))))
|
||||||
|
|
||||||
|
;; Create /etc/ld.so.cache.
|
||||||
|
(invoke "/sbin/ldconfig" "-X"))
|
||||||
|
|
||||||
(define (status->exit-code status)
|
(define (status->exit-code status)
|
||||||
"Compute the exit code made from STATUS, a value as returned by 'waitpid',
|
"Compute the exit code made from STATUS, a value as returned by 'waitpid',
|
||||||
|
@ -527,8 +535,7 @@ cache."
|
||||||
(setenv "PATH" (string-append "/bin:/usr/bin:/sbin:/usr/sbin"
|
(setenv "PATH" (string-append "/bin:/usr/bin:/sbin:/usr/sbin"
|
||||||
(if (getenv "PATH")
|
(if (getenv "PATH")
|
||||||
(string-append ":" (getenv "PATH"))
|
(string-append ":" (getenv "PATH"))
|
||||||
"")))
|
""))))
|
||||||
(invoke "ldconfig" "-X"))
|
|
||||||
(apply execlp program program args))
|
(apply execlp program program args))
|
||||||
(lambda _
|
(lambda _
|
||||||
;; Report the error from here because the parent process cannot
|
;; Report the error from here because the parent process cannot
|
||||||
|
@ -735,6 +742,7 @@ regexps in WHITE-LIST."
|
||||||
(define* (launch-environment/container #:key command bash user user-mappings
|
(define* (launch-environment/container #:key command bash user user-mappings
|
||||||
profile manifest link-profile? network?
|
profile manifest link-profile? network?
|
||||||
map-cwd? emulate-fhs? nesting?
|
map-cwd? emulate-fhs? nesting?
|
||||||
|
writable-root?
|
||||||
(setup-hook #f)
|
(setup-hook #f)
|
||||||
(symlinks '()) (white-list '()))
|
(symlinks '()) (white-list '()))
|
||||||
"Run COMMAND within a container that features the software in PROFILE.
|
"Run COMMAND within a container that features the software in PROFILE.
|
||||||
|
@ -881,15 +889,9 @@ WHILE-LIST."
|
||||||
(exit/status
|
(exit/status
|
||||||
(call-with-container file-systems
|
(call-with-container file-systems
|
||||||
(lambda ()
|
(lambda ()
|
||||||
;; Setup global shell.
|
|
||||||
(mkdir-p "/bin")
|
|
||||||
(symlink bash "/bin/sh")
|
|
||||||
|
|
||||||
;; Set a reasonable default PS1.
|
;; Set a reasonable default PS1.
|
||||||
(setenv "PS1" "\\u@\\h \\w [env]\\$ ")
|
(setenv "PS1" "\\u@\\h \\w [env]\\$ ")
|
||||||
|
|
||||||
;; Setup directory for temporary files.
|
|
||||||
(mkdir-p "/tmp")
|
|
||||||
(for-each (lambda (var)
|
(for-each (lambda (var)
|
||||||
(setenv var "/tmp"))
|
(setenv var "/tmp"))
|
||||||
;; The same variables as in Nix's 'build.cc'.
|
;; The same variables as in Nix's 'build.cc'.
|
||||||
|
@ -899,42 +901,9 @@ WHILE-LIST."
|
||||||
(setenv "LOGNAME" logname)
|
(setenv "LOGNAME" logname)
|
||||||
(setenv "USER" logname)
|
(setenv "USER" logname)
|
||||||
|
|
||||||
;; Create a dummy home directory.
|
|
||||||
(mkdir-p home-dir)
|
|
||||||
(setenv "HOME" home-dir)
|
(setenv "HOME" home-dir)
|
||||||
|
|
||||||
;; Create symlinks.
|
|
||||||
(let ((symlink->directives
|
|
||||||
(match-lambda
|
|
||||||
((source '-> target)
|
|
||||||
`((directory ,(dirname source))
|
|
||||||
(,source -> ,(string-append profile "/" target)))))))
|
|
||||||
(for-each (cut evaluate-populate-directive <> ".")
|
|
||||||
(append-map symlink->directives symlinks)))
|
|
||||||
|
|
||||||
;; Call an additional setup procedure, if provided.
|
|
||||||
(when setup-hook
|
|
||||||
(setup-hook profile))
|
|
||||||
|
|
||||||
;; If requested, link $GUIX_ENVIRONMENT to $HOME/.guix-profile;
|
|
||||||
;; this allows programs expecting that path to continue working as
|
|
||||||
;; expected within a container.
|
|
||||||
(when link-profile? (link-environment profile home-dir))
|
|
||||||
|
|
||||||
;; Create a dummy /etc/passwd to satisfy applications that demand
|
|
||||||
;; to read it, such as 'git clone' over SSH, a valid use-case when
|
|
||||||
;; sharing the host's network namespace.
|
|
||||||
(mkdir-p "/etc")
|
|
||||||
(write-passwd (list passwd))
|
|
||||||
(write-group groups)
|
|
||||||
|
|
||||||
(unless network?
|
(unless network?
|
||||||
;; When isolated from the network, provide a minimal /etc/hosts
|
|
||||||
;; to resolve "localhost".
|
|
||||||
(call-with-output-file "/etc/hosts"
|
|
||||||
(lambda (port)
|
|
||||||
(display "127.0.0.1 localhost\n" port)))
|
|
||||||
|
|
||||||
;; Allow local AF_INET communications.
|
;; Allow local AF_INET communications.
|
||||||
(set-network-interface-up "lo"))
|
(set-network-interface-up "lo"))
|
||||||
|
|
||||||
|
@ -959,9 +928,52 @@ WHILE-LIST."
|
||||||
profile)
|
profile)
|
||||||
manifest #:pure? #f
|
manifest #:pure? #f
|
||||||
#:emulate-fhs? emulate-fhs?)))
|
#:emulate-fhs? emulate-fhs?)))
|
||||||
|
#:populate-file-system
|
||||||
|
(lambda ()
|
||||||
|
;; Setup global shell.
|
||||||
|
(mkdir-p "/bin")
|
||||||
|
(symlink bash "/bin/sh")
|
||||||
|
|
||||||
|
;; Setup directory for temporary files.
|
||||||
|
(mkdir-p "/tmp")
|
||||||
|
|
||||||
|
;; Create a dummy home directory.
|
||||||
|
(mkdir-p home-dir)
|
||||||
|
|
||||||
|
;; Create symlinks.
|
||||||
|
(let ((symlink->directives
|
||||||
|
(match-lambda
|
||||||
|
((source '-> target)
|
||||||
|
`((directory ,(dirname source))
|
||||||
|
(,source -> ,(string-append profile "/" target)))))))
|
||||||
|
(for-each (cut evaluate-populate-directive <> ".")
|
||||||
|
(append-map symlink->directives symlinks)))
|
||||||
|
|
||||||
|
;; If requested, link $GUIX_ENVIRONMENT to $HOME/.guix-profile;
|
||||||
|
;; this allows programs expecting that path to continue working as
|
||||||
|
;; expected within a container.
|
||||||
|
(when link-profile? (link-environment profile home-dir))
|
||||||
|
|
||||||
|
;; Create a dummy /etc/passwd to satisfy applications that demand
|
||||||
|
;; to read it, such as 'git clone' over SSH, a valid use-case when
|
||||||
|
;; sharing the host's network namespace.
|
||||||
|
(mkdir-p "/etc")
|
||||||
|
(write-passwd (list passwd))
|
||||||
|
(write-group groups)
|
||||||
|
|
||||||
|
(unless network?
|
||||||
|
;; When isolated from the network, provide a minimal /etc/hosts
|
||||||
|
;; to resolve "localhost".
|
||||||
|
(call-with-output-file "/etc/hosts"
|
||||||
|
(lambda (port)
|
||||||
|
(display "127.0.0.1 localhost\n" port))))
|
||||||
|
|
||||||
|
;; Call an additional setup procedure, if provided.
|
||||||
|
(when setup-hook
|
||||||
|
(setup-hook profile)))
|
||||||
#:guest-uid uid
|
#:guest-uid uid
|
||||||
#:guest-gid gid
|
#:guest-gid gid
|
||||||
#:writable-root? #t ;for backward compatibility
|
#:writable-root? writable-root?
|
||||||
#:namespaces (if network?
|
#:namespaces (if network?
|
||||||
(delq 'net %namespaces) ; share host network
|
(delq 'net %namespaces) ; share host network
|
||||||
%namespaces)))))))
|
%namespaces)))))))
|
||||||
|
@ -1089,6 +1101,7 @@ command-line option processing with 'parse-command-line'."
|
||||||
(symlinks (assoc-ref opts 'symlinks))
|
(symlinks (assoc-ref opts 'symlinks))
|
||||||
(network? (assoc-ref opts 'network?))
|
(network? (assoc-ref opts 'network?))
|
||||||
(no-cwd? (assoc-ref opts 'no-cwd?))
|
(no-cwd? (assoc-ref opts 'no-cwd?))
|
||||||
|
(writable-root? (assoc-ref opts 'writable-root?))
|
||||||
(emulate-fhs? (assoc-ref opts 'emulate-fhs?))
|
(emulate-fhs? (assoc-ref opts 'emulate-fhs?))
|
||||||
(nesting? (assoc-ref opts 'nesting?))
|
(nesting? (assoc-ref opts 'nesting?))
|
||||||
(user (assoc-ref opts 'user))
|
(user (assoc-ref opts 'user))
|
||||||
|
@ -1136,6 +1149,8 @@ command-line option processing with 'parse-command-line'."
|
||||||
(leave (G_ "'--user' cannot be used without '--container'~%")))
|
(leave (G_ "'--user' cannot be used without '--container'~%")))
|
||||||
(when no-cwd?
|
(when no-cwd?
|
||||||
(leave (G_ "--no-cwd cannot be used without '--container'~%")))
|
(leave (G_ "--no-cwd cannot be used without '--container'~%")))
|
||||||
|
(when writable-root?
|
||||||
|
(leave (G_ "'--writable-root' cannot be used without '--container'~%")))
|
||||||
(when emulate-fhs?
|
(when emulate-fhs?
|
||||||
(leave (G_ "'--emulate-fhs' cannot be used without '--container'~%")))
|
(leave (G_ "'--emulate-fhs' cannot be used without '--container'~%")))
|
||||||
(when nesting?
|
(when nesting?
|
||||||
|
@ -1221,6 +1236,7 @@ when using '--container'; doing nothing~%"))
|
||||||
#:link-profile? link-prof?
|
#:link-profile? link-prof?
|
||||||
#:network? network?
|
#:network? network?
|
||||||
#:map-cwd? (not no-cwd?)
|
#:map-cwd? (not no-cwd?)
|
||||||
|
#:writable-root? writable-root?
|
||||||
#:emulate-fhs? emulate-fhs?
|
#:emulate-fhs? emulate-fhs?
|
||||||
#:nesting? nesting?
|
#:nesting? nesting?
|
||||||
#:symlinks symlinks
|
#:symlinks symlinks
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# GNU Guix --- Functional package management for GNU
|
# GNU Guix --- Functional package management for GNU
|
||||||
# Copyright © 2015 David Thompson <davet@gnu.org>
|
# Copyright © 2015 David Thompson <davet@gnu.org>
|
||||||
# Copyright © 2022, 2023 John Kehayias <john.kehayias@protonmail.com>
|
# Copyright © 2022, 2023 John Kehayias <john.kehayias@protonmail.com>
|
||||||
# Copyright © 2023 Ludovic Courtès <ludo@gnu.org>
|
# Copyright © 2023, 2025 Ludovic Courtès <ludo@gnu.org>
|
||||||
#
|
#
|
||||||
# This file is part of GNU Guix.
|
# This file is part of GNU Guix.
|
||||||
#
|
#
|
||||||
|
@ -186,6 +186,15 @@ HOME="$tmpdir" guix environment --bootstrap --container --user=foognu \
|
||||||
-- /bin/sh -c 'test $(pwd) == "/home/foo" -a ! -d '"$tmpdir"
|
-- /bin/sh -c 'test $(pwd) == "/home/foo" -a ! -d '"$tmpdir"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Check that the root file system is read-only by default...
|
||||||
|
guix environment --bootstrap --container --ad-hoc guile-bootstrap \
|
||||||
|
-- guile -c '(mkdir "/whatever")' && false
|
||||||
|
|
||||||
|
# ... and can be made writable.
|
||||||
|
guix environment --bootstrap --container --ad-hoc guile-bootstrap \
|
||||||
|
--writable-root \
|
||||||
|
-- guile -c '(mkdir "/whatever")'
|
||||||
|
|
||||||
# Check the exit code.
|
# Check the exit code.
|
||||||
|
|
||||||
abnormal_exit_code="
|
abnormal_exit_code="
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue