Gentoo Archives: gentoo-portage-dev

From: Brian Dolbec <dolsen@g.o>
To: gentoo-portage-dev@l.g.o
Subject: Re: [gentoo-portage-dev] [PATCH] pid-sandbox: execute pid-ns-init as pid 1 (bug 675312)
Date: Mon, 14 Jan 2019 04:57:18
Message-Id: 20190113205712.3b2bb1be@professor-x
In Reply to: [gentoo-portage-dev] [PATCH] pid-sandbox: execute pid-ns-init as pid 1 (bug 675312) by Zac Medico
1 On Sun, 13 Jan 2019 16:27:21 -0800
2 Zac Medico <zmedico@g.o> wrote:
3
4 > Execute pid-ns-init as the first fork after unshare, as
5 > required for it to have pid 1 and become the default reaper
6 > of orphaned descendant processes. In _exec, exec a separate
7 > pid-ns-init process to behave as a supervisor which will
8 > forward signals to init and forward exit status to the parent
9 > process.
10 >
11 > Fixes: a75d5546e3a4 ("Introduce a tiny init replacement for inside
12 > pid namespace") Bug: https://bugs.gentoo.org/670484
13 > ---
14 > bin/pid-ns-init | 44
15 > ++++++++++++++++++++++++++++++++++++++---- lib/portage/process.py |
16 > 26 ++++++++++++++++++------- 2 files changed, 59 insertions(+), 11
17 > deletions(-)
18 >
19 > diff --git a/bin/pid-ns-init b/bin/pid-ns-init
20 > index 843257b70..3792eeaa4 100644
21 > --- a/bin/pid-ns-init
22 > +++ b/bin/pid-ns-init
23 > @@ -1,23 +1,59 @@
24 > #!/usr/bin/env python
25 > -# Copyright 2018 Gentoo Authors
26 > +# Copyright 2018-2019 Gentoo Authors
27 > # Distributed under the terms of the GNU General Public License v2
28 >
29 > +import functools
30 > import os
31 > +import signal
32 > import sys
33 >
34 >
35 > +KILL_SIGNALS = (
36 > + signal.SIGINT,
37 > + signal.SIGTERM,
38 > + signal.SIGHUP,
39 > +)
40 > +
41 > +def forward_kill_signal(main_child_pid, signum, frame):
42 > + os.kill(main_child_pid, signum)
43 > +
44 > +
45 > def main(argv):
46 > if len(argv) < 2:
47 > - return 'Usage: {} <main-child-pid>'.format(argv[0])
48 > - main_child_pid = int(argv[1])
49 > + return 'Usage: {} <main-child-pid> or <binary>
50 > argv0..'.format(argv[0]) +
51 > + if len(argv) == 2:
52 > + # The child process is init (pid 1) in a child pid
53 > namespace, and
54 > + # the current process supervises from within the
55 > global pid namespace
56 > + # (forwarding signals to init and forwarding exit
57 > status to the parent
58 > + # process).
59 > + main_child_pid = int(argv[1])
60 > + else:
61 > + # The current process is init (pid 1) in a child pid
62 > namespace.
63 > + binary = argv[1]
64 > + args = argv[2:]
65 > +
66 > + main_child_pid = os.fork()
67 > + if main_child_pid == 0:
68 > + os.execv(binary, args)
69 > +
70 > + sig_handler = functools.partial(forward_kill_signal,
71 > main_child_pid)
72 > + for signum in KILL_SIGNALS:
73 > + signal.signal(signum, sig_handler)
74 >
75 > # wait for child processes
76 > while True:
77 > - pid, status = os.wait()
78 > + try:
79 > + pid, status = os.wait()
80 > + except OSError as e:
81 > + if e.errno == errno.EINTR:
82 > + continue
83 > + raise
84 > if pid == main_child_pid:
85 > if os.WIFEXITED(status):
86 > return os.WEXITSTATUS(status)
87 > elif os.WIFSIGNALED(status):
88 > + signal.signal(os.WTERMSIG(status),
89 > signal.SIG_DFL) os.kill(os.getpid(), os.WTERMSIG(status))
90 > # go to the unreachable place
91 > break
92 > diff --git a/lib/portage/process.py b/lib/portage/process.py
93 > index 7103b6b31..3e07f806c 100644
94 > --- a/lib/portage/process.py
95 > +++ b/lib/portage/process.py
96 > @@ -564,15 +564,27 @@ def _exec(binary, mycommand, opt_name, fd_pipes,
97 > noiselevel=-1)
98 > else:
99 > if unshare_pid:
100 > - # pid
101 > namespace requires us to become init
102 > - fork_ret =
103 > os.fork()
104 > - if
105 > fork_ret != 0:
106 > -
107 > os.execv(portage._python_interpreter, [
108 > +
109 > main_child_pid = os.fork()
110 > + if
111 > main_child_pid == 0:
112 > + #
113 > pid namespace requires us to become init
114 > +
115 > binary, myargs = portage._python_interpreter, [
116 > +
117 > portage._python_interpreter,
118 > +
119 > os.path.join(portage._bin_path,
120 > + 'pid-ns-init')]
121 > + [binary] + myargs
122 > + else:
123 > + #
124 > Execute a supervisor process which will forward
125 > + #
126 > signals to init and forward exit status to the
127 > + #
128 > parent process. The supervisor process runs in
129 > + #
130 > the global pid namespace, so skip /proc remount
131 > + #
132 > and other setup that's intended only for the
133 > + #
134 > init process.
135 > +
136 > binary, myargs = portage._python_interpreter,
137 > [ portage._python_interpreter, os.path.join(portage._bin_path,
138 > - 'pid-ns-init'),
139 > - '%s'
140 > % fork_ret,
141 > - ])
142 > + 'pid-ns-init'),
143 > str(main_child_pid)] +
144 > +
145 > os.execve(binary, myargs, env) +
146 > if unshare_mount:
147 > # mark the
148 > whole filesystem as slave to avoid # mounts escaping the namespace
149
150 Looks fine, but I defer to floppym, mgorny since this affects systemd

Replies