#!/usr/bin/python3 # Copyright 2024 Helmut Grohne # SPDX-License-Identifier: GPL-3 """Perform something like an unprivileged chroot via a user and mount namespace. This is similar to "unshare --map-auto --mount-proc --root=$1", but it also mounts /sys and /dev and performs a full pivot_root that cannot be escaped using chroot. """ import os import pathlib import sys if __file__.split("/")[-2:-1] == ["examples"]: sys.path.insert(0, "/".join(__file__.split("/")[:-2])) import linuxnamespaces def main() -> None: chrootdir = pathlib.Path(sys.argv[1]) assert chrootdir.is_dir() subuids = linuxnamespaces.IDAllocation.loadsubid("uid") subgids = linuxnamespaces.IDAllocation.loadsubid("gid") uidmap = subuids.allocatemap(65536) gidmap = subgids.allocatemap(65536) linuxnamespaces.unshare_user_idmap( [uidmap], [gidmap], linuxnamespaces.CloneFlags.NEWUSER | linuxnamespaces.CloneFlags.NEWNS, ) os.setregid(0, 0) os.setreuid(0, 0) linuxnamespaces.bind_mount(chrootdir, "/mnt", recursive=True) linuxnamespaces.bind_mount("/proc", "/mnt/proc", recursive=True) linuxnamespaces.bind_mount("/sys", "/mnt/sys", recursive=True) linuxnamespaces.populate_dev("/", "/mnt", pidns=False) os.chdir("/mnt") linuxnamespaces.pivot_root(".", ".") linuxnamespaces.umount(".", linuxnamespaces.UmountFlags.DETACH) if len(sys.argv) > 2: os.execvp(sys.argv[2], sys.argv[2:]) else: os.execvp(os.environ["SHELL"], [os.environ["SHELL"]]) if __name__ == "__main__": main()