Gentoo Archives: gentoo-portage-dev

From: Zac Medico <zmedico@g.o>
To: gentoo-portage-dev@l.g.o
Cc: Arfrever Frehtes Taifersar Arahesis <Arfrever@××××××.Org>, Zac Medico <zmedico@g.o>
Subject: [gentoo-portage-dev] [PATCH] pid-sandbox: run pid-ns-init as root (bug 675868)
Date: Tue, 22 Jan 2019 08:32:58
Message-Id: 20190122083034.2624-1-zmedico@gentoo.org
1 From: Arfrever Frehtes Taifersar Arahesis <Arfrever@××××××.Org>
2
3 Drop permissions only for subprocess of pid-ns-init but not pid-ns-init
4 itself. With FEATURES="pid-sandbox userpriv", pid-ns-init should be
5 run with unchanged permissions (usually UID=0, GID=0).
6
7 Bug: https://bugs.gentoo.org/675868
8 Signed-off-by: Arfrever Frehtes Taifersar Arahesis <Arfrever@××××××.Org>
9 Signed-off-by: Zac Medico <zmedico@g.o>
10 ---
11 bin/pid-ns-init | 49 ++++++++++++++++++++++++++----------------
12 lib/portage/process.py | 12 +++++++++--
13 2 files changed, 40 insertions(+), 21 deletions(-)
14
15 diff --git a/bin/pid-ns-init b/bin/pid-ns-init
16 index f9b8cc4f3..486fd13da 100644
17 --- a/bin/pid-ns-init
18 +++ b/bin/pid-ns-init
19 @@ -11,21 +11,6 @@ import subprocess
20 import sys
21
22
23 -if sys.version_info.major < 3 or platform.python_implementation() != 'CPython':
24 - def signal_disposition_preexec():
25 - for signum in (
26 - signal.SIGHUP,
27 - signal.SIGINT,
28 - signal.SIGPIPE,
29 - signal.SIGQUIT,
30 - signal.SIGTERM,
31 - ):
32 - signal.signal(signum, signal.SIG_DFL)
33 -else:
34 - # CPython >= 3 subprocess.Popen handles this internally.
35 - signal_disposition_preexec = None
36 -
37 -
38 KILL_SIGNALS = (
39 signal.SIGINT,
40 signal.SIGTERM,
41 @@ -37,9 +22,31 @@ def forward_kill_signal(main_child_pid, signum, frame):
42 os.kill(main_child_pid, signum)
43
44
45 +def preexec_fn(uid, gid, groups, umask):
46 + if gid is not None:
47 + os.setgid(gid)
48 + if groups is not None:
49 + os.setgroups(groups)
50 + if uid is not None:
51 + os.setuid(uid)
52 + if umask is not None:
53 + os.umask(umask)
54 +
55 + # CPython >= 3 subprocess.Popen handles this internally.
56 + if sys.version_info.major < 3 or platform.python_implementation() != 'CPython':
57 + for signum in (
58 + signal.SIGHUP,
59 + signal.SIGINT,
60 + signal.SIGPIPE,
61 + signal.SIGQUIT,
62 + signal.SIGTERM,
63 + ):
64 + signal.signal(signum, signal.SIG_DFL)
65 +
66 +
67 def main(argv):
68 if len(argv) < 2:
69 - return 'Usage: {} <main-child-pid> or <pass_fds> <binary> <argv0> [arg]..'.format(argv[0])
70 + return 'Usage: {} <main-child-pid> or <uid> <gid> <groups> <umask> <pass_fds> <binary> <argv0> [arg]..'.format(argv[0])
71
72 if len(argv) == 2:
73 # The child process is init (pid 1) in a child pid namespace, and
74 @@ -50,13 +57,17 @@ def main(argv):
75 proc = None
76 else:
77 # The current process is init (pid 1) in a child pid namespace.
78 - pass_fds, binary, args = tuple(int(fd) for fd in argv[1].split(',')), argv[2], argv[3:]
79 + uid, gid, groups, umask, pass_fds, binary, args = argv[1], argv[2], argv[3], argv[4], tuple(int(fd) for fd in argv[5].split(',')), argv[6], argv[7:]
80 + uid = int(uid) if uid else None
81 + gid = int(gid) if gid else None
82 + groups = tuple(int(group) for group in groups.split(',')) if groups else None
83 + umask = int(umask) if umask else None
84
85 popen_kwargs = {}
86 + popen_kwargs['preexec_fn'] = functools.partial(preexec_fn, uid, gid, groups, umask)
87 if sys.version_info.major > 2:
88 popen_kwargs['pass_fds'] = pass_fds
89 - proc = subprocess.Popen(args, executable=binary,
90 - preexec_fn=signal_disposition_preexec, **popen_kwargs)
91 + proc = subprocess.Popen(args, executable=binary, **popen_kwargs)
92 main_child_pid = proc.pid
93
94 sig_handler = functools.partial(forward_kill_signal, main_child_pid)
95 diff --git a/lib/portage/process.py b/lib/portage/process.py
96 index dd3d58ddc..0dba55de3 100644
97 --- a/lib/portage/process.py
98 +++ b/lib/portage/process.py
99 @@ -1,5 +1,5 @@
100 # portage.py -- core Portage functionality
101 -# Copyright 1998-2018 Gentoo Authors
102 +# Copyright 1998-2019 Gentoo Authors
103 # Distributed under the terms of the GNU General Public License v2
104
105
106 @@ -467,7 +467,7 @@ def _exec(binary, mycommand, opt_name, fd_pipes,
107 @param gid: Group ID to run the process under
108 @type gid: Integer
109 @param groups: Groups the Process should be in.
110 - @type groups: Integer
111 + @type groups: List
112 @param uid: User ID to run the process under
113 @type uid: Integer
114 @param umask: an int representing a unix umask (see man chmod for umask details)
115 @@ -571,8 +571,16 @@ def _exec(binary, mycommand, opt_name, fd_pipes,
116 portage._python_interpreter,
117 os.path.join(portage._bin_path,
118 'pid-ns-init'),
119 + _unicode_encode('' if uid is None else str(uid)),
120 + _unicode_encode('' if gid is None else str(gid)),
121 + _unicode_encode('' if groups is None else ','.join(str(group) for group in groups)),
122 + _unicode_encode('' if umask is None else str(umask)),
123 _unicode_encode(','.join(str(fd) for fd in fd_pipes)),
124 binary] + myargs
125 + uid = None
126 + gid = None
127 + groups = None
128 + umask = None
129 else:
130 # Execute a supervisor process which will forward
131 # signals to init and forward exit status to the
132 --
133 2.18.1