From 7fee5b53973fb4fe049aa0bc5db58093727bdf30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= Date: Tue, 18 Oct 2016 23:22:03 +0200 Subject: [PATCH] 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. --- gnu/build/linux-container.scm | 20 +++++++++++--------- tests/containers.scm | 9 +++++++++ 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/gnu/build/linux-container.scm b/gnu/build/linux-container.scm index 91996d06ca..3fccc9addb 100644 --- a/gnu/build/linux-container.scm +++ b/gnu/build/linux-container.scm @@ -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 diff --git a/tests/containers.scm b/tests/containers.scm index bbcff3f51f..698bef3e47 100644 --- a/tests/containers.scm +++ b/tests/containers.scm @@ -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)