diff options
author | Zac Medico <zmedico@gentoo.org> | 2019-01-13 15:06:35 -0800 |
---|---|---|
committer | Zac Medico <zmedico@gentoo.org> | 2019-01-14 21:45:55 -0800 |
commit | fb406579b1d13c1ba23b28e0bb794c22878a58c0 (patch) | |
tree | a79b7e4530b9575ebf3ee78339c975e20049f42f /bin/pid-ns-init | |
parent | misc-functions.sh: restore canonicalize func (bug 675284) (diff) | |
download | portage-fb406579b1d13c1ba23b28e0bb794c22878a58c0.tar.gz portage-fb406579b1d13c1ba23b28e0bb794c22878a58c0.tar.bz2 portage-fb406579b1d13c1ba23b28e0bb794c22878a58c0.zip |
pid-sandbox: execute pid-ns-init as pid 1 (bug 675312)
Execute pid-ns-init as the first fork after unshare, as
required for it to have pid 1 and become the default reaper
of orphaned descendant processes. In _exec, exec a separate
pid-ns-init process to behave as a supervisor which will
forward signals to init and forward exit status to the parent
process.
Fixes: a75d5546e3a4 ("Introduce a tiny init replacement for inside pid namespace")
Bug: https://bugs.gentoo.org/675312
Reviewed-by: Brian Dolbec <dolsen@gentoo.org>
Signed-off-by: Zac Medico <zmedico@gentoo.org>
Diffstat (limited to 'bin/pid-ns-init')
-rw-r--r-- | bin/pid-ns-init | 44 |
1 files changed, 40 insertions, 4 deletions
diff --git a/bin/pid-ns-init b/bin/pid-ns-init index 843257b70..182d00a43 100644 --- a/bin/pid-ns-init +++ b/bin/pid-ns-init @@ -1,23 +1,59 @@ #!/usr/bin/env python -# Copyright 2018 Gentoo Authors +# Copyright 2018-2019 Gentoo Authors # Distributed under the terms of the GNU General Public License v2 +import functools import os +import signal import sys +KILL_SIGNALS = ( + signal.SIGINT, + signal.SIGTERM, + signal.SIGHUP, +) + +def forward_kill_signal(main_child_pid, signum, frame): + os.kill(main_child_pid, signum) + + def main(argv): if len(argv) < 2: - return 'Usage: {} <main-child-pid>'.format(argv[0]) - main_child_pid = int(argv[1]) + return 'Usage: {} <main-child-pid> or <binary> <argv0> [arg]..'.format(argv[0]) + + if len(argv) == 2: + # The child process is init (pid 1) in a child pid namespace, and + # the current process supervises from within the global pid namespace + # (forwarding signals to init and forwarding exit status to the parent + # process). + main_child_pid = int(argv[1]) + else: + # The current process is init (pid 1) in a child pid namespace. + binary = argv[1] + args = argv[2:] + + main_child_pid = os.fork() + if main_child_pid == 0: + os.execv(binary, args) + + sig_handler = functools.partial(forward_kill_signal, main_child_pid) + for signum in KILL_SIGNALS: + signal.signal(signum, sig_handler) # wait for child processes while True: - pid, status = os.wait() + try: + pid, status = os.wait() + except OSError as e: + if e.errno == errno.EINTR: + continue + raise if pid == main_child_pid: if os.WIFEXITED(status): return os.WEXITSTATUS(status) elif os.WIFSIGNALED(status): + signal.signal(os.WTERMSIG(status), signal.SIG_DFL) os.kill(os.getpid(), os.WTERMSIG(status)) # go to the unreachable place break |