From 6372178a9e294cce43bdd1f27fb801bd9ebf16e7 Mon Sep 17 00:00:00 2001 From: Helmut Grohne Date: Thu, 25 Jan 2024 18:01:54 +0100 Subject: examples/chroottar.py: work when TMPDIR is private When TMPDIR has restrictive permissions, the namespace may be unable to access the leading components. Thus we put the supervisor process handling the cleanup into a different namespace that has all the ids plus the current uid mapped. It'll then be able to perform the cleanup (and the initial chown). --- examples/chroottar.py | 61 +++++++++++++++++++++++++-------------------------- 1 file changed, 30 insertions(+), 31 deletions(-) diff --git a/examples/chroottar.py b/examples/chroottar.py index 0f3066b..e002ed8 100755 --- a/examples/chroottar.py +++ b/examples/chroottar.py @@ -53,39 +53,26 @@ def main() -> None: uidmap = linuxnamespaces.IDAllocation.loadsubid("uid").allocatemap(65536) gidmap = linuxnamespaces.IDAllocation.loadsubid("gid").allocatemap(65536) with tempfile.TemporaryDirectory() as tdir: - with TarFile.open(basetar, "r:*") as tarf: - os.chdir(tdir) - pid = os.getpid() - - @linuxnamespaces.run_in_fork - def setup() -> None: - linuxnamespaces.newidmaps(pid, [uidmap], [gidmap]) - # Craft a namespace that allows us to chown from our current - # user to the first uid/gid from the final mapping, i.e. root. - linuxnamespaces.unshare_user_idmap( - [ - linuxnamespaces.IDMapping(0, os.getuid(), 1), - linuxnamespaces.IDMapping(1, uidmap.outerstart, 1), - ], - [ - linuxnamespaces.IDMapping(0, os.getgid(), 1), - linuxnamespaces.IDMapping(1, gidmap.outerstart, 1), - ], - ) - os.chown(".", 1, 1) - - linuxnamespaces.unshare(linuxnamespaces.CloneFlags.NEWUSER) - setup() - os.setreuid(0, 0) - os.setregid(0, 0) - # "." is now owned by 0:0 inside the namespace. - for tmem in tarf: - if tmem.name.removeprefix("./").startswith("dev/"): - continue - tarf.extract(tmem, numeric_owner=True) + unshareevent = linuxnamespaces.EventFD() + setupevent = linuxnamespaces.EventFD() pid = os.fork() if pid == 0: - linuxnamespaces.unshare(linuxnamespaces.CloneFlags.NEWNS) + with TarFile.open(basetar, "r:*") as tarf: + os.chdir(tdir) + linuxnamespaces.unshare( + linuxnamespaces.CloneFlags.NEWUSER + | linuxnamespaces.CloneFlags.NEWNS + ) + unshareevent.write(1) + setupevent.read() + unshareevent.close() + setupevent.close() + os.setreuid(0, 0) + os.setregid(0, 0) + for tmem in tarf: + if tmem.name.removeprefix("./").startswith("dev/"): + continue + tarf.extract(tmem, numeric_owner=True) linuxnamespaces.bind_mount(".", "/mnt", recursive=True) os.chdir("/mnt") linuxnamespaces.bind_mount("/proc", "proc", recursive=True) @@ -94,6 +81,18 @@ def main() -> None: linuxnamespaces.pivot_root(".", ".") linuxnamespaces.umount(".", linuxnamespaces.UmountFlags.DETACH) os.execlp(os.environ["SHELL"], os.environ["SHELL"]) + os._exit(1) + + unshareevent.read() + unshareevent.close() + linuxnamespaces.newidmaps(pid, [uidmap], [gidmap]) + linuxnamespaces.unshare_user_idmap( + [uidmap, linuxnamespaces.IDMapping(65536, os.getuid(), 1)], + [gidmap, linuxnamespaces.IDMapping(65536, os.getgid(), 1)], + ) + os.chown(tdir, 0, 0) + setupevent.write() + setupevent.close() _, ret = os.waitpid(pid, 0) sys.exit(ret) -- cgit v1.2.3