summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xexamples/unschroot.py61
1 files changed, 48 insertions, 13 deletions
diff --git a/examples/unschroot.py b/examples/unschroot.py
index 3e3cc3a..682b5b0 100755
--- a/examples/unschroot.py
+++ b/examples/unschroot.py
@@ -183,6 +183,23 @@ def do_begin_session(args: argparse.Namespace) -> None:
sys.exit(ret)
+def exec_perl_dumb_init(pid: int) -> typing.NoReturn:
+ """Roughly impement dumb-init in perl: Wait for all children until we
+ receive an exit from the given pid and forward its status.
+ """
+ os.execlp(
+ "perl",
+ "perl",
+ "-e",
+ "$r=255<<8;" # exit 255 when we run out of children
+ "do{"
+ "$p=wait;"
+ f"$r=$?,$p=0 if $p=={pid};"
+ "}while($p>0);"
+ "exit(0<$r<256?128|$r:$r>>8);", # sig -> 128+sig; exit -> exit
+ )
+
+
def do_run_session(args: argparse.Namespace) -> None:
"""Run an existing session"""
session = Chroot.searchsession(args.chroot)
@@ -215,7 +232,7 @@ def do_run_session(args: argparse.Namespace) -> None:
linuxnamespaces.populate_dev("/", ".")
linuxnamespaces.pivot_root(".", ".")
linuxnamespaces.umount(".", linuxnamespaces.UmountFlags.DETACH)
- os.chdir(args.directory or "/")
+ os.chdir("/")
if args.user.isdigit():
spw = pwd.getpwuid(int(args.user))
else:
@@ -223,19 +240,37 @@ def do_run_session(args: argparse.Namespace) -> None:
supplementary = [
sgr.gr_gid for sgr in grp.getgrall() if spw.pw_name in sgr.gr_mem
]
- os.setgroups(supplementary)
- os.setgid(spw.pw_gid)
- os.setuid(spw.pw_uid)
- if not args.command:
- args.command.append("bash")
+
childsock.recv(1)
- linuxnamespaces.prctl_set_pdeathsig(signal.SIGTERM)
- if "PATH" not in os.environ:
- if spw.pw_uid == 0:
- os.environ["PATH"] = "/usr/sbin:/sbin:/usr/bin:/bin"
- else:
- os.environ["PATH"] = "/usr/bin:/bin"
- os.execvp(args.command[0], args.command)
+ childsock.close()
+ rfd, wfd = linuxnamespaces.FileDescriptor.pipe(inheritable=False)
+ pid = os.fork()
+ if pid == 0:
+ wfd.close()
+ if args.directory:
+ os.chdir(args.directory)
+ os.setgroups(supplementary)
+ os.setgid(spw.pw_gid)
+ os.setuid(spw.pw_uid)
+ if "PATH" not in os.environ:
+ if spw.pw_uid == 0:
+ os.environ["PATH"] = "/usr/sbin:/sbin:/usr/bin:/bin"
+ else:
+ os.environ["PATH"] = "/usr/bin:/bin"
+ if not args.command:
+ args.command.append("bash")
+ # Wait until Python has handed off to Perl.
+ os.read(rfd, 1)
+ os.execvp(args.command[0], args.command)
+ else:
+ rfd.close()
+ linuxnamespaces.prctl_set_pdeathsig(signal.SIGKILL)
+ os.close(0)
+ # It is important that we now exec to get rid of our previous
+ # execution context that carries pieces such as memory maps from
+ # different namespaces that could allow escalating privileges. The
+ # exec will close wfd and allow the target process to exec.
+ exec_perl_dumb_init(pid)
childsock.close()
mainsock.recv(1)
linuxnamespaces.newidmaps(pid, [uidmap], [gidmap])