[PATCH 2/3] scripts: environment: Add --user.

DoneSubmitted by Mike Gerwitz.
2 participants
  • Ludovic Courtès
  • Mike Gerwitz
Mike Gerwitz wrote on 26 Jan 2018 04:29
(address . guix-patches@gnu.org)
This change allows overriding the home directory of all filesystem mappings tohelp hide the identity of the calling user in a container.
* doc/guix.texi (Invoking guix environment)[--container]: Mention --user.[--user]: Add item.* guix/scripts/environment.scm (show-help): Add --user.(%options): Add --user.(launch-environment/container) Add 'user' parameter. Update doc. Override'user-mappings' using 'override-user-mappings'. Consider override for chdir.(mock-passwd, user-override-home, overrid-euser-dir): New procedures.(guix-environment): Disallow --user without --container. Provide user to'launch-environment/container'.* tests/guix-environment.sh: Add user test.--- doc/guix.texi | 34 ++++++++++-- guix/scripts/environment.scm | 122 ++++++++++++++++++++++++++++++++++--------- tests/guix-environment.sh | 10 ++++ 3 files changed, 137 insertions(+), 29 deletions(-)
Toggle diff (279 lines)diff --git a/doc/guix.texi b/doc/guix.texiindex 3b6ae1ab9..8218c6637 100644--- a/doc/guix.texi+++ b/doc/guix.texi@@ -7156,10 +7156,11 @@ Attempt to build for @var{system}---e.g., @code{i686-linux}. @cindex container Run @var{command} within an isolated container. The current working directory outside the container is mapped inside the container.-Additionally, a dummy home directory is created that matches the current-user's home directory, and @file{/etc/passwd} is configured accordingly.-The spawned process runs as the current user outside the container, but-has root privileges in the context of the container.+Additionally, unless overridden with @code{--user}, a dummy home+directory is created that matches the current user's home directory, and+@file{/etc/passwd} is configured accordingly. The spawned process runs+as the current user outside the container, but has root privileges in+the context of the container. @item --network @itemx -N@@ -7183,6 +7184,31 @@ example, the @code{fontconfig} package inspects @code{--link-profile} allows these programs to behave as expected within the environment. +@item --user=@var{user}+@itemx -u @var{user}+For containers, use the username @var{user} in place of the current+user. The generated @file{/etc/passwd} entry within the container will+contain the name @var{user}; the home directory will be+@file{/home/USER}; and no user GECOS data will be copied. @var{user}+need not exist on the system.++Additionally, any shared or exposed path (see @code{--share} and+@code{--expose} respectively) whose target is within the current user's+home directory will be remapped relative to @file{/home/USER}; this+includes the automatic mapping of the current working directory.++@example+# will expose paths as /home/foo/wd, /home/foo/test, and /home/foo/target+cd $HOME/wd+guix environment --container --user=foo \+ --expose=$HOME/test \+ --expose=/tmp/target=$HOME/target+@end example++While this will limit the leaking of user identity through home paths+and each of the user fields, this is only one useful component of a+broader privacy/anonymity solution---not one in and of itself.+ @item --expose=@var{source}[=@var{target}] For containers, expose the file system @var{source} from the host system as the read-only file system @var{target} within the container. Ifdiff --git a/guix/scripts/environment.scm b/guix/scripts/environment.scmindex 771574c15..f50018faf 100644--- a/guix/scripts/environment.scm+++ b/guix/scripts/environment.scm@@ -161,6 +161,10 @@ COMMAND or an interactive shell in that environment.\n")) (display (G_ " -P, --link-profile link environment profile to ~/.guix-profile within an isolated container"))+ (display (G_ "+ -u, --user=USER instead of copying the name and home of the current+ user into an isolated container, use the name USER+ with home directory /home/USER")) (display (G_ " --share=SPEC for containers, share writable host file system according to SPEC"))@@ -243,6 +247,10 @@ COMMAND or an interactive shell in that environment.\n")) (option '(#\P "link-profile") #f #f (lambda (opt name arg result) (alist-cons 'link-profile? #t result)))+ (option '(#\u "user") #t #f+ (lambda (opt name arg result)+ (alist-cons 'user arg+ (alist-delete 'user result eq?)))) (option '("share") #t #f (lambda (opt name arg result) (alist-cons 'file-system-mapping@@ -390,43 +398,50 @@ environment variables are cleared before setting the new ones." (pid (match (waitpid pid) ((_ . status) status))))) -(define* (launch-environment/container #:key command bash user-mappings+(define* (launch-environment/container #:key command bash user user-mappings profile paths link-profile? network?) "Run COMMAND within a container that features the software in PROFILE. Environment variables are set according to PATHS, a list of native search paths. The global shell is BASH, a file name for a GNU Bash binary in the store. When NETWORK?, access to the host system network is permitted. USER-MAPPINGS, a list of file system mappings, contains the user-specified-host file systems to mount inside the container. LINK-PROFILE? creates a-symbolic link from ~/.guix-profile to the environment profile."+host file systems to mount inside the container. If USER is not #f, each+target of USER-MAPPINGS will be re-written relative to '/home/USER', and USER+will be used for the passwd entry. LINK-PROFILE? creates a symbolic link from+~/.guix-profile to the environment profile." (mlet %store-monad ((reqs (inputs->requisites (list (direct-store-path bash) profile)))) (return (let* ((cwd (getcwd))- (passwd (getpwuid (getuid)))+ (home (getenv "HOME"))+ (passwd (mock-passwd (getpwuid (getuid))+ user+ bash)) (home-dir (passwd:dir passwd)) ;; Bind-mount all requisite store items, user-specified mappings, ;; /bin/sh, the current working directory, and possibly networking ;; configuration files within the container. (mappings- (append user-mappings- ;; Current working directory.- (list (file-system-mapping- (source cwd)- (target cwd)- (writable? #t)))- ;; When in Rome, do as Nix build.cc does: Automagically- ;; map common network configuration files.- (if network?- %network-file-mappings- '())- ;; Mappings for the union closure of all inputs.- (map (lambda (dir)- (file-system-mapping- (source dir)- (target dir)- (writable? #f)))- reqs)))+ (override-user-mappings+ user home+ (append user-mappings+ ;; Current working directory.+ (list (file-system-mapping+ (source cwd)+ (target cwd)+ (writable? #t)))+ ;; When in Rome, do as Nix build.cc does: Automagically+ ;; map common network configuration files.+ (if network?+ %network-file-mappings+ '())+ ;; Mappings for the union closure of all inputs.+ (map (lambda (dir)+ (file-system-mapping+ (source dir)+ (target dir)+ (writable? #f)))+ reqs)))) (file-systems (append %container-file-systems (map file-system-mapping->bind-mount mappings))))@@ -447,8 +462,7 @@ symbolic link from ~/.guix-profile to the environment profile." ;; The same variables as in Nix's 'build.cc'. '("TMPDIR" "TEMPDIR" "TMP" "TEMP")) - ;; Create a dummy home directory under the same name as on the- ;; host.+ ;; Create a dummy home directory. (mkdir-p home-dir) (setenv "HOME" home-dir) @@ -475,7 +489,7 @@ symbolic link from ~/.guix-profile to the environment profile." ;; For convenience, start in the user's current working ;; directory rather than the root directory.- (chdir cwd)+ (chdir (override-user-dir user home cwd)) (primitive-exit/status ;; A container's environment is already purified, so no need to@@ -485,6 +499,60 @@ symbolic link from ~/.guix-profile to the environment profile." (delq 'net %namespaces) ; share host network %namespaces))))))) +(define (mock-passwd passwd user-override shell)+ "Generate mock information for '/etc/passwd'. If USER-OVERRIDE is not '#f',+it is expected to be a string representing the mock username; it will produce+a user of that name, with a home directory of '/home/USER-OVERRIDE', and no+GECOS field. If USER-OVERRIDE is '#f', data will be inherited from PASSWD.+In either case, the shadow password and UID/GID are cleared, since the user+runs as root within the container. SHELL will always be used in place of the+shell in PASSWD.++The resulting vector is suitable for use with Guile's POSIX user procedures.++See passwd(5) for more information each of the fields."+ (if user-override+ (vector+ user-override+ "x" "0" "0" ;; no shadow, user is now root+ "" ;; no personal information+ (user-override-home user-override)+ shell)+ (vector+ (passwd:name passwd)+ "x" "0" "0" ;; no shadow, user is now root+ (passwd:gecos passwd)+ (passwd:dir passwd)+ shell)))++(define (user-override-home user)+ "Return home directory for override user USER."+ (string-append "/home/" user))++(define (override-user-mappings user home mappings)+ "If a username USER is provided, rewrite each HOME prefix in file system+mappings MAPPINGS to a home directory determined by 'override-user-dir';+otherwise, return MAPPINGS."+ (if (not user)+ mappings+ (map (lambda (mapping)+ (let ((target (file-system-mapping-target mapping)))+ (if (string-prefix? home target)+ (file-system-mapping+ (source (file-system-mapping-source mapping))+ (target (override-user-dir user home target))+ (writable? (file-system-mapping-writable? mapping)))+ mapping)))+ mappings)))++(define (override-user-dir user home dir)+ "If username USER is provided, overwrite string prefix HOME in DIR with a+directory determined by 'user-override-home'; otherwise, return DIR."+ (if (and user (string-prefix? home dir))+ (string-append (user-override-home user)+ (substring dir (string-length home)))+ dir))+ (define (link-environment profile home-dir) "Create a symbolic link from HOME-DIR/.guix-profile to PROFILE." (let ((profile-dir (string-append home-dir "/.guix-profile")))@@ -572,6 +640,7 @@ message if any test fails." (container? (assoc-ref opts 'container?)) (link-prof? (assoc-ref opts 'link-profile?)) (network? (assoc-ref opts 'network?))+ (user (assoc-ref opts 'user)) (bootstrap? (assoc-ref opts 'bootstrap?)) (system (assoc-ref opts 'system)) (command (or (assoc-ref opts 'exec)@@ -606,6 +675,8 @@ message if any test fails." (when (and (not container?) link-prof?) (leave (G_ "--link-prof cannot be used without --container~%")))+ (when (and (not container?) user)+ (leave (G_ "--user cannot be used without --container~%"))) (with-store store (set-build-options-from-command-line store opts)@@ -653,6 +724,7 @@ message if any test fails." "/bin/sh")))) (launch-environment/container #:command command #:bash bash-binary+ #:user user #:user-mappings mappings #:profile profile #:paths pathsdiff --git a/tests/guix-environment.sh b/tests/guix-environment.shindex e995636df..a1ce96579 100644--- a/tests/guix-environment.sh+++ b/tests/guix-environment.sh@@ -74,6 +74,16 @@ guix environment --bootstrap --ad-hoc guile-bootstrap --pure \ -- guile -c "$linktest" ) +# Test that user can be mocked.+usertest='(exit (and (string=? (getenv "HOME") "/home/foognu")+ (string=? (passwd:name (getpwuid 0)) "foognu")+ (file-exists? "/home/foognu/umock")))'+touch "$tmpdir/umock"+HOME="$tmpdir" guix environment --bootstrap --container --user=foognu \+ --ad-hoc guile-bootstrap --pure \+ --share="$tmpdir/umock" \+ -- guile -c "$usertest"+ # Make sure '-r' works as expected. rm -f "$gcroot" expected="`guix environment --bootstrap --ad-hoc guile-bootstrap \-- 2.15.1
-----BEGIN PGP SIGNATURE-----Version: GnuPG v2
iQIcBAEBCgAGBQJaaqCcAAoJEIyRe39dxRuiCZcP/0VEvCAiwTsb96+j8KGKZeDS3pErm7SbPR5pNkipDzyp1qqyGTreWXSnLBy3N9ChXV+j35dHdZ3VhOVS6OUJMiJvCxdG7y86naxbSidQzxMmX0eujUxOvL2xmhemVuiOuKmbHana1eI2NG216pneNaeszwngRmALoB2M9nvNjadKgtWtyMasOJpy6ZfeW9Zze4W521WJnn8KOqAKzJbqraCNqmAxkg80DoVLKlIW6VHetcYmN3WEw+XqV1vw8PFofiKwkIjBZlCh28AK7h5eweFiMGXFbFTifwQg2asLDT4vpBek+DcE+4PyLid5hZMVsiAKEbLP9dHRJCbNUcSeCLQsNWxkks/hMEg1QddReuLzgUsOhyGW2RpVWRhh7+L+YIkL18yRfW63viTdbO2+ucfayJGiUrmlgAk64lYiV0oDSgq36CgBlhdeUVchLgBEv9AgqMBUZtF4sc6AfnilASHM8Flv/pcBhz0JJ0M/8YjrzlUCz6b7KnkAKycxOQgvpyq8Qu9VoOE5XN7c1qEJ4ypELIKbiMdoH77ySqyd8B4X/fXiqyIGaUq7Umv1ii/g4PImeqxWjrwgAVkFMAwZFIRKCKASx4p+1+zQKONs93cYyHoTzxaNEC9TJCxnRD6Lioqos8wuGVBV0Pi7G/OFSmu7xktWhFqAE9HRI/SJZIDs=OLI8-----END PGP SIGNATURE-----
Ludovic Courtès wrote on 2 Mar 2018 11:33
(name . Mike Gerwitz)(address . mtg@gnu.org)(address . 30257@debbugs.gnu.org)
Mike Gerwitz <mtg@gnu.org> skribis:
Toggle quote (14 lines)> This change allows overriding the home directory of all filesystem mappings to> help hide the identity of the calling user in a container.>> * doc/guix.texi (Invoking guix environment)[--container]: Mention --user.> [--user]: Add item.> * guix/scripts/environment.scm (show-help): Add --user.> (%options): Add --user.> (launch-environment/container) Add 'user' parameter. Update doc. Override> 'user-mappings' using 'override-user-mappings'. Consider override for chdir.> (mock-passwd, user-override-home, overrid-euser-dir): New procedures.> (guix-environment): Disallow --user without --container. Provide user to> 'launch-environment/container'.> * tests/guix-environment.sh: Add user test.
Awesome, I moved the test to guix-environment-container.sh and applied.
Ludovic Courtès wrote on 3 Mar 2018 22:21
control message for bug #30257
(address . control@debbugs.gnu.org)
tags 30257 fixedclose 30257
Your comment

This issue is archived.

To comment on this conversation send email to 30257@debbugs.gnu.org