diff options
author | Helmut Grohne <helmut@subdivi.de> | 2024-01-18 22:46:35 +0100 |
---|---|---|
committer | Helmut Grohne <helmut@subdivi.de> | 2024-01-18 22:46:35 +0100 |
commit | be42cb03f8616f00fbb4cba29f98eee8d1878056 (patch) | |
tree | 07ba8e9ba2a744bfb5aa7b8371bc365aac45ce88 | |
parent | 5e004a85dd660d41ae7c3519679d2cfae8919e77 (diff) | |
download | python-linuxnamespaces-be42cb03f8616f00fbb4cba29f98eee8d1878056.tar.gz |
add userchroot.py example
-rwxr-xr-x | examples/userchroot.py | 63 |
1 files changed, 63 insertions, 0 deletions
diff --git a/examples/userchroot.py b/examples/userchroot.py new file mode 100755 index 0000000..315a437 --- /dev/null +++ b/examples/userchroot.py @@ -0,0 +1,63 @@ +#!/usr/bin/python3 +# Copyright 2024 Helmut Grohne <helmut@subdivi.de> +# 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 open_tree_clone_rec( + path: linuxnamespaces.PathConvertible, +) -> linuxnamespaces.AtLocation: + return linuxnamespaces.open_tree( + path, + linuxnamespaces.OpenTreeFlags.OPEN_TREE_CLONE + | linuxnamespaces.OpenTreeFlags.AT_RECURSIVE, + ) + + +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, 0) + gidmap = subgids.allocatemap(65536, 0) + + 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(chrootdir / "proc", "/proc", recursive=True) + linuxnamespaces.bind_mount(chrootdir / "sys", "/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() |