diff options
author | Helmut Grohne <helmut@subdivi.de> | 2024-01-25 18:01:54 +0100 |
---|---|---|
committer | Helmut Grohne <helmut@subdivi.de> | 2024-01-25 18:03:46 +0100 |
commit | 6372178a9e294cce43bdd1f27fb801bd9ebf16e7 (patch) | |
tree | 3ff1733b4484dd7b64ac79683b6ba8e6a2c065b2 /examples | |
parent | 611a5ee4070e8b07dceabbad79ffaf3f540910d0 (diff) | |
download | python-linuxnamespaces-6372178a9e294cce43bdd1f27fb801bd9ebf16e7.tar.gz |
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).
Diffstat (limited to 'examples')
-rwxr-xr-x | examples/chroottar.py | 61 |
1 files 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) |