aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZac Medico <zmedico@gentoo.org>2019-01-13 15:06:35 -0800
committerZac Medico <zmedico@gentoo.org>2019-01-14 21:45:55 -0800
commitfb406579b1d13c1ba23b28e0bb794c22878a58c0 (patch)
treea79b7e4530b9575ebf3ee78339c975e20049f42f /bin/pid-ns-init
parentmisc-functions.sh: restore canonicalize func (bug 675284) (diff)
downloadportage-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-init44
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