~ruther/guix-local

7fee5b53973fb4fe049aa0bc5db58093727bdf30 — Ludovic Courtès 9 years ago 99df12c
container: Allow 'container-excursion' to the same namespaces.

Before that, 'container-excursion' would call 'setns' even when the
target namespace is the one the caller is already in, which would fail.

* gnu/build/linux-container.scm (container-excursion): Introduce
'source' and 'target'.  Compare the result of 'readlink' on these
instead of comparing file descriptors to decide whether to call
'setns'.
* tests/containers.scm ("container-excursion, same namespace"): New test.
2 files changed, 20 insertions(+), 9 deletions(-)

M gnu/build/linux-container.scm
M tests/containers.scm
M gnu/build/linux-container.scm => gnu/build/linux-container.scm +11 -9
@@ 291,15 291,17 @@ return the exit status."
     (call-with-clean-exit
      (lambda ()
        (for-each (lambda (ns)
                    (call-with-input-file (namespace-file (getpid) ns)
                      (lambda (current-ns-port)
                        (call-with-input-file (namespace-file pid ns)
                          (lambda (new-ns-port)
                            ;; Joining the namespace that the process
                            ;; already belongs to would throw an error.
                            (unless (= (port->fdes current-ns-port)
                                       (port->fdes new-ns-port))
                              (setns (port->fdes new-ns-port) 0)))))))
                    (let ((source (namespace-file (getpid) ns))
                          (target (namespace-file pid ns)))
                      ;; Joining the namespace that the process already
                      ;; belongs to would throw an error so avoid that.
                      ;; XXX: This /proc interface leads to TOCTTOU.
                      (unless (string=? (readlink source) (readlink target))
                        (call-with-input-file source
                          (lambda (current-ns-port)
                            (call-with-input-file target
                              (lambda (new-ns-port)
                                (setns (fileno new-ns-port) 0))))))))
                  ;; It's important that the user namespace is joined first,
                  ;; so that the user will have the privileges to join the
                  ;; other namespaces.  Furthermore, it's important that the

M tests/containers.scm => tests/containers.scm +9 -0
@@ 162,4 162,13 @@
          (waitpid pid)
          (zero? result)))))))

(skip-if-unsupported)
(test-equal "container-excursion, same namespaces"
  42
  ;; The parent and child are in the same namespaces.  'container-excursion'
  ;; should notice that and avoid calling 'setns' since that would fail.
  (container-excursion (getpid)
    (lambda ()
      (primitive-exit 42))))

(test-end)