This commit saves the file descriptor of /proc/self/{root,cwd} before entering into the new mount namespace. When restoring the previous mount namespace, it restores /proc/self/{root,cwd} based on the saved file descriptors.
Without this change, catalyst cannot be run in a chroot when using the recent changes regarding mount namespaces: After the mount namespace has been exited, /proc/self/root points to the "/" of the host system, not the "/" of the chroot. Therefore, the cleanup phase of catalyst runs outside of the chroot. The code is similar to how nsenter(1) sets root and cwd: https://git.kernel.org/pub/scm/utils/util-linux/util-linux.git/tree/sys-utils/nsenter.c#n452 Tested in a Gentoo chroot and in Gentoo VM (non-chroot). Signed-off-by: Felix Bier <felix.b...@rohde-schwarz.com> --- catalyst/context.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/catalyst/context.py b/catalyst/context.py index 8a58f33d..01a6d930 100644 --- a/catalyst/context.py +++ b/catalyst/context.py @@ -16,11 +16,21 @@ def namespace(mount=False, uts=False, ipc=False, net=False, pid=False, (user, "user"): None, } + dirs = { + "root": None, + "cwd": None, + } + # Save fds of current namespaces for ns in [ns for ns in namespaces if ns[0]]: fp = open(f"/proc/self/ns/{ns[1]}") namespaces[ns] = fp + # Save fds of current directories + if mount: + for d in dirs: + dirs[d] = os.open(f"/proc/self/{d}", os.O_RDONLY) + simple_unshare(mount=mount, uts=uts, ipc=ipc, net=net, pid=pid, user=user, hostname=hostname) try: @@ -30,3 +40,15 @@ def namespace(mount=False, uts=False, ipc=False, net=False, pid=False, fp = namespaces[ns] setns(fp.fileno(), 0) fp.close() + + if mount: + # Restore original root and cwd. Since we cannot directly chroot to + # a fd, first change the current directory to the fd of the + # original root, then chroot to "." + + os.fchdir(dirs["root"]) + os.chroot(".") + os.fchdir(dirs["cwd"]) + + for fd in dirs.values(): + os.close(fd) -- 2.29.2