From be42cb03f8616f00fbb4cba29f98eee8d1878056 Mon Sep 17 00:00:00 2001 From: Helmut Grohne Date: Thu, 18 Jan 2024 22:46:35 +0100 Subject: add userchroot.py example --- examples/userchroot.py | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100755 examples/userchroot.py 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 +# 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() -- cgit v1.2.3