Gentoo Archives: gentoo-portage-dev

From: Zac Medico <zmedico@g.o>
To: gentoo-portage-dev@l.g.o, Brian Dolbec <dolsen@g.o>
Subject: Re: [gentoo-portage-dev] [PATCH] pid-sandbox: execute pid-ns-init as pid 1 (bug 675312)
Date: Tue, 15 Jan 2019 06:37:14
Message-Id: e10af2b2-ece9-6ad1-b4ed-0e43e54b910c@gentoo.org
In Reply to: Re: [gentoo-portage-dev] [PATCH] pid-sandbox: execute pid-ns-init as pid 1 (bug 675312) by Brian Dolbec
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

Attachments

File name MIME type
signature.asc application/pgp-signature