* [gentoo-portage-dev] [PATCH] pid-sandbox: execute pid-ns-init as pid 1 (bug 675312)
@ 2019-01-14 0:27 Zac Medico
2019-01-14 4:57 ` Brian Dolbec
0 siblings, 1 reply; 3+ messages in thread
From: Zac Medico @ 2019-01-14 0:27 UTC (permalink / raw
To: gentoo-portage-dev; +Cc: Zac Medico
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/670484
---
bin/pid-ns-init | 44 ++++++++++++++++++++++++++++++++++++++----
lib/portage/process.py | 26 ++++++++++++++++++-------
2 files changed, 59 insertions(+), 11 deletions(-)
diff --git a/bin/pid-ns-init b/bin/pid-ns-init
index 843257b70..3792eeaa4 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..'.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
diff --git a/lib/portage/process.py b/lib/portage/process.py
index 7103b6b31..3e07f806c 100644
--- a/lib/portage/process.py
+++ b/lib/portage/process.py
@@ -564,15 +564,27 @@ def _exec(binary, mycommand, opt_name, fd_pipes,
noiselevel=-1)
else:
if unshare_pid:
- # pid namespace requires us to become init
- fork_ret = os.fork()
- if fork_ret != 0:
- os.execv(portage._python_interpreter, [
+ main_child_pid = os.fork()
+ if main_child_pid == 0:
+ # pid namespace requires us to become init
+ binary, myargs = portage._python_interpreter, [
+ portage._python_interpreter,
+ os.path.join(portage._bin_path,
+ 'pid-ns-init')] + [binary] + myargs
+ else:
+ # Execute a supervisor process which will forward
+ # signals to init and forward exit status to the
+ # parent process. The supervisor process runs in
+ # the global pid namespace, so skip /proc remount
+ # and other setup that's intended only for the
+ # init process.
+ binary, myargs = portage._python_interpreter, [
portage._python_interpreter,
os.path.join(portage._bin_path,
- 'pid-ns-init'),
- '%s' % fork_ret,
- ])
+ 'pid-ns-init'), str(main_child_pid)]
+
+ os.execve(binary, myargs, env)
+
if unshare_mount:
# mark the whole filesystem as slave to avoid
# mounts escaping the namespace
--
2.18.1
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [gentoo-portage-dev] [PATCH] pid-sandbox: execute pid-ns-init as pid 1 (bug 675312)
2019-01-14 0:27 [gentoo-portage-dev] [PATCH] pid-sandbox: execute pid-ns-init as pid 1 (bug 675312) Zac Medico
@ 2019-01-14 4:57 ` Brian Dolbec
2019-01-15 6:37 ` Zac Medico
0 siblings, 1 reply; 3+ messages in thread
From: Brian Dolbec @ 2019-01-14 4:57 UTC (permalink / raw
To: gentoo-portage-dev
On Sun, 13 Jan 2019 16:27:21 -0800
Zac Medico <zmedico@gentoo.org> wrote:
> 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/670484
> ---
> bin/pid-ns-init | 44
> ++++++++++++++++++++++++++++++++++++++---- lib/portage/process.py |
> 26 ++++++++++++++++++------- 2 files changed, 59 insertions(+), 11
> deletions(-)
>
> diff --git a/bin/pid-ns-init b/bin/pid-ns-init
> index 843257b70..3792eeaa4 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..'.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
> diff --git a/lib/portage/process.py b/lib/portage/process.py
> index 7103b6b31..3e07f806c 100644
> --- a/lib/portage/process.py
> +++ b/lib/portage/process.py
> @@ -564,15 +564,27 @@ def _exec(binary, mycommand, opt_name, fd_pipes,
> noiselevel=-1)
> else:
> if unshare_pid:
> - # pid
> namespace requires us to become init
> - fork_ret =
> os.fork()
> - if
> fork_ret != 0:
> -
> os.execv(portage._python_interpreter, [
> +
> main_child_pid = os.fork()
> + if
> main_child_pid == 0:
> + #
> pid namespace requires us to become init
> +
> binary, myargs = portage._python_interpreter, [
> +
> portage._python_interpreter,
> +
> os.path.join(portage._bin_path,
> + 'pid-ns-init')]
> + [binary] + myargs
> + else:
> + #
> Execute a supervisor process which will forward
> + #
> signals to init and forward exit status to the
> + #
> parent process. The supervisor process runs in
> + #
> the global pid namespace, so skip /proc remount
> + #
> and other setup that's intended only for the
> + #
> init process.
> +
> binary, myargs = portage._python_interpreter,
> [ portage._python_interpreter, os.path.join(portage._bin_path,
> - 'pid-ns-init'),
> - '%s'
> % fork_ret,
> - ])
> + 'pid-ns-init'),
> str(main_child_pid)] +
> +
> os.execve(binary, myargs, env) +
> if unshare_mount:
> # mark the
> whole filesystem as slave to avoid # mounts escaping the namespace
Looks fine, but I defer to floppym, mgorny since this affects systemd
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [gentoo-portage-dev] [PATCH] pid-sandbox: execute pid-ns-init as pid 1 (bug 675312)
2019-01-14 4:57 ` Brian Dolbec
@ 2019-01-15 6:37 ` Zac Medico
0 siblings, 0 replies; 3+ messages in thread
From: Zac Medico @ 2019-01-15 6:37 UTC (permalink / raw
To: gentoo-portage-dev, Brian Dolbec
[-- Attachment #1.1: Type: text/plain, Size: 4971 bytes --]
On 1/13/19 8:57 PM, Brian Dolbec wrote:
> On Sun, 13 Jan 2019 16:27:21 -0800
> Zac Medico <zmedico@gentoo.org> wrote:
>
>> 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/670484
>> ---
>> bin/pid-ns-init | 44
>> ++++++++++++++++++++++++++++++++++++++---- lib/portage/process.py |
>> 26 ++++++++++++++++++------- 2 files changed, 59 insertions(+), 11
>> deletions(-)
>>
>> diff --git a/bin/pid-ns-init b/bin/pid-ns-init
>> index 843257b70..3792eeaa4 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..'.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
>> diff --git a/lib/portage/process.py b/lib/portage/process.py
>> index 7103b6b31..3e07f806c 100644
>> --- a/lib/portage/process.py
>> +++ b/lib/portage/process.py
>> @@ -564,15 +564,27 @@ def _exec(binary, mycommand, opt_name, fd_pipes,
>> noiselevel=-1)
>> else:
>> if unshare_pid:
>> - # pid
>> namespace requires us to become init
>> - fork_ret =
>> os.fork()
>> - if
>> fork_ret != 0:
>> -
>> os.execv(portage._python_interpreter, [
>> +
>> main_child_pid = os.fork()
>> + if
>> main_child_pid == 0:
>> + #
>> pid namespace requires us to become init
>> +
>> binary, myargs = portage._python_interpreter, [
>> +
>> portage._python_interpreter,
>> +
>> os.path.join(portage._bin_path,
>> + 'pid-ns-init')]
>> + [binary] + myargs
>> + else:
>> + #
>> Execute a supervisor process which will forward
>> + #
>> signals to init and forward exit status to the
>> + #
>> parent process. The supervisor process runs in
>> + #
>> the global pid namespace, so skip /proc remount
>> + #
>> and other setup that's intended only for the
>> + #
>> init process.
>> +
>> binary, myargs = portage._python_interpreter,
>> [ portage._python_interpreter, os.path.join(portage._bin_path,
>> - 'pid-ns-init'),
>> - '%s'
>> % fork_ret,
>> - ])
>> + 'pid-ns-init'),
>> str(main_child_pid)] +
>> +
>> os.execve(binary, myargs, env) +
>> if unshare_mount:
>> # mark the
>> whole filesystem as slave to avoid # mounts escaping the namespace
>
> Looks fine,
Thanks, merged:
https://gitweb.gentoo.org/proj/portage.git/commit/?id=fb406579b1d13c1ba23b28e0bb794c22878a58c0
> but I defer to floppym, mgorny since this affects systemd
I not experiencing any problems with systemd here. We've got this patch
to solve the systemd pkg_postinst thing:
https://gitweb.gentoo.org/proj/portage.git/commit/?id=bbfc36befdeed60f29c17d80d7766fd0da402d61
--
Thanks,
Zac
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 981 bytes --]
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2019-01-15 6:37 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2019-01-14 0:27 [gentoo-portage-dev] [PATCH] pid-sandbox: execute pid-ns-init as pid 1 (bug 675312) Zac Medico
2019-01-14 4:57 ` Brian Dolbec
2019-01-15 6:37 ` Zac Medico
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox