diff options
| author | David Thompson <dthompson2@worcester.edu> | 2015-08-01 21:04:31 -0400 |
|---|---|---|
| committer | David Thompson <dthompson2@worcester.edu> | 2015-08-08 14:04:13 -0400 |
| commit | 831bc1468ea27732ba59d58e4b38a192151aa123 (patch) | |
| tree | 7e6474a505e7721ad27a203ac24ff28a0f12697e /gnu/build/linux-container.scm | |
| parent | 8c812f2aeeed8398a27f1594c20914031d97db58 (diff) | |
build: container: Add #:host-uids argument to call-with-container.
It's not always possible to map 65536 uids when creating a container as the
root user within another user namespace. This is true when building Guix
within the build daemon's container. By using a uid range of 1 by default,
even as the root user, the tests now pass.
* gnu/build/linux-container.scm (initialize-user-namespace, run-container):
Add 'host-uids' argument.
(call-with-container): Add #:host-uids keyword argument.
* tests/containers.scm ("container-excursion"): Update 'run-container' call.
Diffstat (limited to 'gnu/build/linux-container.scm')
| -rw-r--r-- | gnu/build/linux-container.scm | 38 |
1 files changed, 19 insertions, 19 deletions
diff --git a/gnu/build/linux-container.scm b/gnu/build/linux-container.scm index 7a03a29d2ce..af599040a1a 100644 --- a/gnu/build/linux-container.scm +++ b/gnu/build/linux-container.scm | |||
| @@ -120,23 +120,17 @@ to ROOT, then make ROOT the new root directory for the process." | |||
| 120 | (umount "real-root" MNT_DETACH) | 120 | (umount "real-root" MNT_DETACH) |
| 121 | (rmdir "real-root"))) | 121 | (rmdir "real-root"))) |
| 122 | 122 | ||
| 123 | (define (initialize-user-namespace pid) | 123 | (define (initialize-user-namespace pid host-uids) |
| 124 | "Configure the user namespace for PID." | 124 | "Configure the user namespace for PID. HOST-UIDS specifies the number of |
| 125 | host user identifiers to map into the user namespace." | ||
| 125 | (define proc-dir | 126 | (define proc-dir |
| 126 | (string-append "/proc/" (number->string pid))) | 127 | (string-append "/proc/" (number->string pid))) |
| 127 | 128 | ||
| 128 | (define (scope file) | 129 | (define (scope file) |
| 129 | (string-append proc-dir file)) | 130 | (string-append proc-dir file)) |
| 130 | 131 | ||
| 131 | ;; Only root can map more than a single uid/gid. A range of 65536 uid/gids | 132 | (let ((uid (getuid)) |
| 132 | ;; is used to cover 16 bits worth of users and groups, which is sufficient | 133 | (gid (getgid))) |
| 133 | ;; for most cases. | ||
| 134 | ;; | ||
| 135 | ;; See also: http://www.freedesktop.org/software/systemd/man/systemd-nspawn.html#--private-users= | ||
| 136 | (let* ((uid (getuid)) | ||
| 137 | (gid (getgid)) | ||
| 138 | (uid-range (if (zero? uid) 65536 1)) | ||
| 139 | (gid-range (if (zero? gid) 65536 1))) | ||
| 140 | 134 | ||
| 141 | ;; Only root can write to the gid map without first disabling the | 135 | ;; Only root can write to the gid map without first disabling the |
| 142 | ;; setgroups syscall. | 136 | ;; setgroups syscall. |
| @@ -149,10 +143,10 @@ to ROOT, then make ROOT the new root directory for the process." | |||
| 149 | ;; within the container. | 143 | ;; within the container. |
| 150 | (call-with-output-file (scope "/uid_map") | 144 | (call-with-output-file (scope "/uid_map") |
| 151 | (lambda (port) | 145 | (lambda (port) |
| 152 | (format port "0 ~d ~d" uid uid-range))) | 146 | (format port "0 ~d ~d" uid host-uids))) |
| 153 | (call-with-output-file (scope "/gid_map") | 147 | (call-with-output-file (scope "/gid_map") |
| 154 | (lambda (port) | 148 | (lambda (port) |
| 155 | (format port "0 ~d ~d" gid gid-range))))) | 149 | (format port "0 ~d ~d" gid host-uids))))) |
| 156 | 150 | ||
| 157 | (define (namespaces->bit-mask namespaces) | 151 | (define (namespaces->bit-mask namespaces) |
| 158 | "Return the number suitable for the 'flags' argument of 'clone' that | 152 | "Return the number suitable for the 'flags' argument of 'clone' that |
| @@ -167,12 +161,13 @@ corresponds to the symbols in NAMESPACES." | |||
| 167 | ('net CLONE_NEWNET)) | 161 | ('net CLONE_NEWNET)) |
| 168 | namespaces))) | 162 | namespaces))) |
| 169 | 163 | ||
| 170 | (define (run-container root mounts namespaces thunk) | 164 | (define (run-container root mounts namespaces host-uids thunk) |
| 171 | "Run THUNK in a new container process and return its PID. ROOT specifies | 165 | "Run THUNK in a new container process and return its PID. ROOT specifies |
| 172 | the root directory for the container. MOUNTS is a list of file system specs | 166 | the root directory for the container. MOUNTS is a list of file system specs |
| 173 | that specify the mapping of host file systems into the container. NAMESPACES | 167 | that specify the mapping of host file systems into the container. NAMESPACES |
| 174 | is a list of symbols that correspond to the possible Linux namespaces: mnt, | 168 | is a list of symbols that correspond to the possible Linux namespaces: mnt, |
| 175 | ipc, uts, user, and net." | 169 | ipc, uts, user, and net. HOST-UIDS specifies the number of |
| 170 | host user identifiers to map into the user namespace." | ||
| 176 | ;; The parent process must initialize the user namespace for the child | 171 | ;; The parent process must initialize the user namespace for the child |
| 177 | ;; before it can boot. To negotiate this, a pipe is used such that the | 172 | ;; before it can boot. To negotiate this, a pipe is used such that the |
| 178 | ;; child process blocks until the parent writes to it. | 173 | ;; child process blocks until the parent writes to it. |
| @@ -196,26 +191,31 @@ ipc, uts, user, and net." | |||
| 196 | (thunk)))) | 191 | (thunk)))) |
| 197 | (pid | 192 | (pid |
| 198 | (when (memq 'user namespaces) | 193 | (when (memq 'user namespaces) |
| 199 | (initialize-user-namespace pid)) | 194 | (initialize-user-namespace pid host-uids)) |
| 200 | ;; TODO: Initialize cgroups. | 195 | ;; TODO: Initialize cgroups. |
| 201 | (close in) | 196 | (close in) |
| 202 | (write 'ready out) | 197 | (write 'ready out) |
| 203 | (close out) | 198 | (close out) |
| 204 | pid)))))) | 199 | pid)))))) |
| 205 | 200 | ||
| 206 | (define* (call-with-container mounts thunk #:key (namespaces %namespaces)) | 201 | (define* (call-with-container mounts thunk #:key (namespaces %namespaces) |
| 202 | (host-uids 1)) | ||
| 207 | "Run THUNK in a new container process and return its exit status. | 203 | "Run THUNK in a new container process and return its exit status. |
| 208 | MOUNTS is a list of file system specs that specify the mapping of host file | 204 | MOUNTS is a list of file system specs that specify the mapping of host file |
| 209 | systems into the container. NAMESPACES is a list of symbols corresponding to | 205 | systems into the container. NAMESPACES is a list of symbols corresponding to |
| 210 | the identifiers for Linux namespaces: mnt, ipc, uts, pid, user, and net. By | 206 | the identifiers for Linux namespaces: mnt, ipc, uts, pid, user, and net. By |
| 211 | default, all namespaces are used. | 207 | default, all namespaces are used. HOST-UIDS is the number of host user |
| 208 | identifiers to map into the container's user namespace, if there is one. By | ||
| 209 | default, only a single uid/gid, that of the current user, is mapped into the | ||
| 210 | container. The host user that creates the container is the root user (uid/gid | ||
| 211 | 0) within the container. Only root can map more than a single uid/gid. | ||
| 212 | 212 | ||
| 213 | Note that if THUNK needs to load any additional Guile modules, the relevant | 213 | Note that if THUNK needs to load any additional Guile modules, the relevant |
| 214 | module files must be present in one of the mappings in MOUNTS and the Guile | 214 | module files must be present in one of the mappings in MOUNTS and the Guile |
| 215 | load path must be adjusted as needed." | 215 | load path must be adjusted as needed." |
| 216 | (call-with-temporary-directory | 216 | (call-with-temporary-directory |
| 217 | (lambda (root) | 217 | (lambda (root) |
| 218 | (let ((pid (run-container root mounts namespaces thunk))) | 218 | (let ((pid (run-container root mounts namespaces host-uids thunk))) |
| 219 | ;; Catch SIGINT and kill the container process. | 219 | ;; Catch SIGINT and kill the container process. |
| 220 | (sigaction SIGINT | 220 | (sigaction SIGINT |
| 221 | (lambda (signum) | 221 | (lambda (signum) |
