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.
This commit is contained in:
Ludovic Courtès 2016-10-18 23:22:03 +02:00
parent 99df12cd19
commit 7fee5b5397
No known key found for this signature in database
GPG Key ID: 090B11993D9AEBB5
2 changed files with 20 additions and 9 deletions

View File

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

View File

@ -162,4 +162,13 @@
(waitpid pid) (waitpid pid)
(zero? result))))))) (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) (test-end)