summary refs log tree commit diff
path: root/gnu/build
diff options
context:
space:
mode:
authorLudovic Courtès <ludo@gnu.org>2016-05-30 22:44:58 +0200
committerLudovic Courtès <ludo@gnu.org>2016-05-31 00:11:04 +0200
commitc06f6db7a424fd47e3cd2625dbfda2367316f3bd (patch)
tree025d18dd2ed6d4f6a62cc09aa9633161c7d7edc8 /gnu/build
parent4c14d4eaa7ee9d5d89c04a41adb50c7c532d14e1 (diff)
downloadguix-c06f6db7a424fd47e3cd2625dbfda2367316f3bd.tar.gz
container: Gracefully report mount errors in the child process.
Fixes <http://bugs.gnu.org/23306>.

* gnu/build/linux-container.scm (run-container): Use 'socketpair'
instead of 'pipe'.  Rename 'in' to 'child' and 'out' to 'parent'.  Send
a 'ready message or an exception argument list from the child to the
parent; adjust the parent accordingly.
* tests/containers.scm ("call-with-container, mnt namespace, wrong bind
mount"): New test.
* tests/guix-environment-container.sh: Add test with
--expose=/does-not-exist.
Diffstat (limited to 'gnu/build')
-rw-r--r--gnu/build/linux-container.scm42
1 files changed, 30 insertions, 12 deletions
diff --git a/gnu/build/linux-container.scm b/gnu/build/linux-container.scm
index 562d50bcc7..91996d06ca 100644
--- a/gnu/build/linux-container.scm
+++ b/gnu/build/linux-container.scm
@@ -205,35 +205,53 @@ host user identifiers to map into the user namespace."
   ;; The parent process must initialize the user namespace for the child
   ;; before it can boot.  To negotiate this, a pipe is used such that the
   ;; child process blocks until the parent writes to it.
-  (match (pipe)
-    ((in . out)
+  (match (socketpair PF_UNIX SOCK_STREAM 0)
+    ((child . parent)
      (let ((flags (namespaces->bit-mask namespaces)))
        (match (clone flags)
          (0
           (call-with-clean-exit
            (lambda ()
-             (close out)
+             (close-port parent)
              ;; Wait for parent to set things up.
-             (match (read in)
+             (match (read child)
                ('ready
-                (close in)
                 (purify-environment)
                 (when (memq 'mnt namespaces)
-                  (mount-file-systems root mounts
-                                      #:mount-/proc? (memq 'pid namespaces)
-                                      #:mount-/sys?  (memq 'net namespaces)))
+                  (catch #t
+                    (lambda ()
+                      (mount-file-systems root mounts
+                                          #:mount-/proc? (memq 'pid namespaces)
+                                          #:mount-/sys?  (memq 'net
+                                                               namespaces)))
+                    (lambda args
+                      ;; Forward the exception to the parent process.
+                      (write args child)
+                      (primitive-exit 3))))
                 ;; TODO: Manage capabilities.
+                (write 'ready child)
+                (close-port child)
                 (thunk))
                (_                                 ;parent died or something
                 (primitive-exit 2))))))
          (pid
+          (close-port child)
           (when (memq 'user namespaces)
             (initialize-user-namespace pid host-uids))
           ;; TODO: Initialize cgroups.
-          (close in)
-          (write 'ready out)
-          (close out)
-          pid))))))
+          (write 'ready parent)
+          (newline parent)
+
+          ;; Check whether the child process' setup phase succeeded.
+          (let ((message (read parent)))
+            (close-port parent)
+            (match message
+              ('ready                             ;success
+               pid)
+              (((? symbol? key) args ...)         ;exception
+               (apply throw key args))
+              (_                                  ;unexpected termination
+               #f)))))))))
 
 (define* (call-with-container mounts thunk #:key (namespaces %namespaces)
                               (host-uids 1))