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
|
import contextlib
import os
from snakeoil.process.namespaces import setns, simple_unshare
@contextlib.contextmanager
def namespace(mount=False, uts=False, ipc=False, net=False, pid=False,
user=False, hostname=None):
namespaces = {
(mount, "mnt"): None,
(uts, "uts"): None,
(ipc, "ipc"): None,
(net, "net"): None,
(pid, "pid"): None,
(user, "user"): None,
}
dirs = {
"root": None,
"cwd": None,
}
# Save fds of current namespaces
for ns in [ns for ns in namespaces if ns[0]]:
fp = open(f"/proc/self/ns/{ns[1]}")
namespaces[ns] = fp
# Save fds of current directories
if mount:
for d in dirs:
dirs[d] = os.open(f"/proc/self/{d}", os.O_RDONLY)
simple_unshare(mount=mount, uts=uts, ipc=ipc, net=net, pid=pid, user=user,
hostname=hostname)
try:
yield
finally:
for ns in [ns for ns in namespaces if ns[0]]:
fp = namespaces[ns]
setns(fp.fileno(), 0)
fp.close()
if mount:
# Restore original root and cwd. Since we cannot directly chroot to
# a fd, first change the current directory to the fd of the
# original root, then chroot to "."
os.fchdir(dirs["root"])
os.chroot(".")
os.fchdir(dirs["cwd"])
for fd in dirs.values():
os.close(fd)
|