1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
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()
|