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