summaryrefslogtreecommitdiff
path: root/gnu
diff options
context:
space:
mode:
Diffstat (limited to 'gnu')
-rw-r--r--gnu/build/linux-container.scm181
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.