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 @@ (define (namespace-file pid namespace)
(call-with-clean-exit
(lambda ()
(for-each (lambda (ns)
(call-with-input-file (namespace-file (getpid) ns)
(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 (namespace-file pid ns)
(call-with-input-file target
(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)))))))
(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

View File

@ -162,4 +162,13 @@ (define (namespaces pid)
(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)