diff options
Diffstat (limited to 'gnu/build/linux-container.scm')
| -rw-r--r-- | gnu/build/linux-container.scm | 181 |
1 files changed, 87 insertions, 94 deletions
diff --git a/gnu/build/linux-container.scm b/gnu/build/linux-container.scm index 25890ec0a13..ff5449d0b0f 100644 --- a/gnu/build/linux-container.scm +++ b/gnu/build/linux-container.scm | |||
| @@ -263,100 +263,93 @@ that host UIDs (respectively GIDs) map to in the namespace." | |||
| 263 | ;; child process blocks until the parent writes to it. | 263 | ;; child process blocks until the parent writes to it. |
| 264 | (match (socketpair PF_UNIX (logior SOCK_CLOEXEC SOCK_STREAM) 0) | 264 | (match (socketpair PF_UNIX (logior SOCK_CLOEXEC SOCK_STREAM) 0) |
| 265 | ((child . parent) | 265 | ((child . parent) |
| 266 | (let ((flags (namespaces->bit-mask namespaces))) | 266 | (safe-clone |
| 267 | (match (clone flags) | 267 | (namespaces->bit-mask namespaces) |
| 268 | (0 | 268 | (lambda () |
| 269 | ;; Inhibit thread creation until after the unshare call. | 269 | (call-with-clean-exit |
| 270 | (gc-disable) | 270 | (lambda () |
| 271 | (call-with-clean-exit | 271 | (close-port parent) |
| 272 | (lambda () | 272 | ;; Wait for parent to set things up. |
| 273 | (close-port parent) | 273 | (match (read child) |
| 274 | ;; Wait for parent to set things up. | 274 | ('ready |
| 275 | (match (read child) | 275 | (purify-environment) |
| 276 | ('ready | 276 | (when (and (memq 'mnt namespaces) |
| 277 | (purify-environment) | 277 | (not (string=? root "/"))) |
| 278 | (when (and (memq 'mnt namespaces) | 278 | (catch #t |
| 279 | (not (string=? root "/"))) | 279 | (lambda () |
| 280 | (catch #t | 280 | (mount-file-systems root mounts |
| 281 | (lambda () | 281 | #:mount-/proc? (memq 'pid namespaces) |
| 282 | (mount-file-systems root mounts | 282 | #:mount-/sys? (memq 'net |
| 283 | #:mount-/proc? (memq 'pid namespaces) | 283 | namespaces) |
| 284 | #:mount-/sys? (memq 'net | 284 | #:populate-file-system |
| 285 | namespaces) | 285 | (lambda () |
| 286 | #:populate-file-system | 286 | (populate-file-system) |
| 287 | (lambda () | 287 | (when (and (memq 'net namespaces) |
| 288 | (populate-file-system) | 288 | loopback-network?) |
| 289 | (when (and (memq 'net namespaces) | 289 | (set-network-interface-up "lo") |
| 290 | loopback-network?) | 290 | |
| 291 | (set-network-interface-up "lo") | 291 | ;; When isolated from the |
| 292 | 292 | ;; network, provide a minimal | |
| 293 | ;; When isolated from the | 293 | ;; /etc/hosts to resolve |
| 294 | ;; network, provide a minimal | 294 | ;; "localhost". |
| 295 | ;; /etc/hosts to resolve | 295 | (mkdir-p "/etc") |
| 296 | ;; "localhost". | 296 | (call-with-output-file "/etc/hosts" |
| 297 | (mkdir-p "/etc") | 297 | (lambda (port) |
| 298 | (call-with-output-file "/etc/hosts" | 298 | (display "127.0.0.1 localhost\n" port) |
| 299 | (lambda (port) | 299 | (chmod port #o444))))) |
| 300 | (display "127.0.0.1 localhost\n" port) | 300 | #:writable-root? |
| 301 | (chmod port #o444))))) | 301 | (or writable-root? |
| 302 | #:writable-root? | 302 | (not (memq 'mnt namespaces))))) |
| 303 | (or writable-root? | 303 | (lambda args |
| 304 | (not (memq 'mnt namespaces))))) | 304 | ;; Forward the exception to the parent process. |
| 305 | (lambda args | 305 | ;; FIXME: SRFI-35 conditions and non-trivial objects |
| 306 | ;; Forward the exception to the parent process. | 306 | ;; cannot be 'read' so they shouldn't be written as is. |
| 307 | ;; FIXME: SRFI-35 conditions and non-trivial objects | 307 | (write args child) |
| 308 | ;; cannot be 'read' so they shouldn't be written as is. | 308 | (primitive-exit 3)))) |
| 309 | (write args child) | 309 | |
| 310 | (primitive-exit 3)))) | 310 | (when (and lock-mounts? |
| 311 | 311 | (memq 'mnt namespaces) | |
| 312 | (when (and lock-mounts? | 312 | (memq 'user namespaces)) |
| 313 | (memq 'mnt namespaces) | 313 | ;; Create a new mount namespace owned by a new user |
| 314 | (memq 'user namespaces)) | 314 | ;; namespace to "lock" together previous mounts, such that |
| 315 | ;; Create a new mount namespace owned by a new user | 315 | ;; they cannot be unmounted or remounted separately--see |
| 316 | ;; namespace to "lock" together previous mounts, such that | 316 | ;; mount_namespaces(7). |
| 317 | ;; they cannot be unmounted or remounted separately--see | 317 | (let ((uid (getuid)) (gid (getgid))) |
| 318 | ;; mount_namespaces(7). | 318 | (unshare (logior CLONE_NEWUSER CLONE_NEWNS)) |
| 319 | ;; | 319 | (when (file-exists? "/proc/self") |
| 320 | ;; Note: at this point, the process is single-threaded (no | 320 | (initialize-user-namespace (getpid) |
| 321 | ;; GC mark threads, no finalization thread, etc.) which is | 321 | host-uids |
| 322 | ;; why unshare(CLONE_NEWUSER) can be used. | 322 | #:host-uid uid |
| 323 | (let ((uid (getuid)) (gid (getgid))) | 323 | #:host-gid gid |
| 324 | (unshare (logior CLONE_NEWUSER CLONE_NEWNS)) | 324 | #:guest-uid guest-uid |
| 325 | (gc-enable) | 325 | #:guest-gid guest-gid)))) |
| 326 | (when (file-exists? "/proc/self") | 326 | |
| 327 | (initialize-user-namespace (getpid) | 327 | ;; TODO: Manage capabilities. |
| 328 | host-uids | 328 | (write 'ready child) |
| 329 | #:host-uid uid | 329 | (close-port child) |
| 330 | #:host-gid gid | 330 | (thunk)) |
| 331 | #:guest-uid guest-uid | 331 | (_ ;parent died or something |
| 332 | #:guest-gid guest-gid)))) | 332 | (primitive-exit 2)))))) |
| 333 | 333 | (lambda (pid) | |
| 334 | ;; TODO: Manage capabilities. | 334 | (close-port child) |
| 335 | (write 'ready child) | 335 | (when (memq 'user namespaces) |
| 336 | (close-port child) | 336 | (initialize-user-namespace pid host-uids |
| 337 | (thunk)) | 337 | #:guest-uid guest-uid |
| 338 | (_ ;parent died or something | 338 | #:guest-gid guest-gid)) |
| 339 | (primitive-exit 2)))))) | 339 | ;; TODO: Initialize cgroups. |
| 340 | (pid | 340 | (write 'ready parent) |
| 341 | (close-port child) | 341 | (newline parent) |
| 342 | (when (memq 'user namespaces) | 342 | |
| 343 | (initialize-user-namespace pid host-uids | 343 | ;; Check whether the child process' setup phase succeeded. |
| 344 | #:guest-uid guest-uid | 344 | (let ((message (read parent))) |
| 345 | #:guest-gid guest-gid)) | 345 | (close-port parent) |
| 346 | ;; TODO: Initialize cgroups. | 346 | (match message |
| 347 | (write 'ready parent) | 347 | ('ready ;success |
| 348 | (newline parent) | 348 | pid) |
| 349 | 349 | (((? symbol? key) args ...) ;exception | |
| 350 | ;; Check whether the child process' setup phase succeeded. | 350 | (apply throw key args)) |
| 351 | (let ((message (read parent))) | 351 | (_ ;unexpected termination |
| 352 | (close-port parent) | 352 | #f)))))))) |
| 353 | (match message | ||
| 354 | ('ready ;success | ||
| 355 | pid) | ||
| 356 | (((? symbol? key) args ...) ;exception | ||
| 357 | (apply throw key args)) | ||
| 358 | (_ ;unexpected termination | ||
| 359 | #f))))))))) | ||
| 360 | 353 | ||
| 361 | ;; FIXME: This is copied from (guix utils), which we cannot use because it | 354 | ;; FIXME: This is copied from (guix utils), which we cannot use because it |
| 362 | ;; would pull (guix config) and all. | 355 | ;; would pull (guix config) and all. |
