public inbox for gentoo-portage-dev@lists.gentoo.org
 help / color / mirror / Atom feed
* [gentoo-portage-dev] [PATCH] pid-sandbox: run pid-ns-init as root (bug 675868)
@ 2019-01-22  8:30 Zac Medico
  0 siblings, 0 replies; only message in thread
From: Zac Medico @ 2019-01-22  8:30 UTC (permalink / raw
  To: gentoo-portage-dev; +Cc: Arfrever Frehtes Taifersar Arahesis, Zac Medico

From: Arfrever Frehtes Taifersar Arahesis <Arfrever@Apache.Org>

Drop permissions only for subprocess of pid-ns-init but not pid-ns-init
itself. With FEATURES="pid-sandbox userpriv", pid-ns-init should be
run with unchanged permissions (usually UID=0, GID=0).

Bug: https://bugs.gentoo.org/675868
Signed-off-by: Arfrever Frehtes Taifersar Arahesis <Arfrever@Apache.Org>
Signed-off-by: Zac Medico <zmedico@gentoo.org>
---
 bin/pid-ns-init        | 49 ++++++++++++++++++++++++++----------------
 lib/portage/process.py | 12 +++++++++--
 2 files changed, 40 insertions(+), 21 deletions(-)

diff --git a/bin/pid-ns-init b/bin/pid-ns-init
index f9b8cc4f3..486fd13da 100644
--- a/bin/pid-ns-init
+++ b/bin/pid-ns-init
@@ -11,21 +11,6 @@ import subprocess
 import sys
 
 
-if sys.version_info.major < 3 or platform.python_implementation() != 'CPython':
-	def signal_disposition_preexec():
-		for signum in (
-			signal.SIGHUP,
-			signal.SIGINT,
-			signal.SIGPIPE,
-			signal.SIGQUIT,
-			signal.SIGTERM,
-			):
-			signal.signal(signum, signal.SIG_DFL)
-else:
-	# CPython >= 3 subprocess.Popen handles this internally.
-	signal_disposition_preexec = None
-
-
 KILL_SIGNALS = (
 	signal.SIGINT,
 	signal.SIGTERM,
@@ -37,9 +22,31 @@ def forward_kill_signal(main_child_pid, signum, frame):
 	os.kill(main_child_pid, signum)
 
 
+def preexec_fn(uid, gid, groups, umask):
+	if gid is not None:
+		os.setgid(gid)
+	if groups is not None:
+		os.setgroups(groups)
+	if uid is not None:
+		os.setuid(uid)
+	if umask is not None:
+		os.umask(umask)
+
+	# CPython >= 3 subprocess.Popen handles this internally.
+	if sys.version_info.major < 3 or platform.python_implementation() != 'CPython':
+		for signum in (
+			signal.SIGHUP,
+			signal.SIGINT,
+			signal.SIGPIPE,
+			signal.SIGQUIT,
+			signal.SIGTERM,
+			):
+			signal.signal(signum, signal.SIG_DFL)
+
+
 def main(argv):
 	if len(argv) < 2:
-		return 'Usage: {} <main-child-pid> or <pass_fds> <binary> <argv0> [arg]..'.format(argv[0])
+		return 'Usage: {} <main-child-pid> or <uid> <gid> <groups> <umask> <pass_fds> <binary> <argv0> [arg]..'.format(argv[0])
 
 	if len(argv) == 2:
 		# The child process is init (pid 1) in a child pid namespace, and
@@ -50,13 +57,17 @@ def main(argv):
 		proc = None
 	else:
 		# The current process is init (pid 1) in a child pid namespace.
-		pass_fds, binary, args = tuple(int(fd) for fd in argv[1].split(',')), argv[2], argv[3:]
+		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:]
+		uid = int(uid) if uid else None
+		gid = int(gid) if gid else None
+		groups = tuple(int(group) for group in groups.split(',')) if groups else None
+		umask = int(umask) if umask else None
 
 		popen_kwargs = {}
+		popen_kwargs['preexec_fn'] = functools.partial(preexec_fn, uid, gid, groups, umask)
 		if sys.version_info.major > 2:
 			popen_kwargs['pass_fds'] = pass_fds
-		proc = subprocess.Popen(args, executable=binary,
-			preexec_fn=signal_disposition_preexec, **popen_kwargs)
+		proc = subprocess.Popen(args, executable=binary, **popen_kwargs)
 		main_child_pid = proc.pid
 
 	sig_handler = functools.partial(forward_kill_signal, main_child_pid)
diff --git a/lib/portage/process.py b/lib/portage/process.py
index dd3d58ddc..0dba55de3 100644
--- a/lib/portage/process.py
+++ b/lib/portage/process.py
@@ -1,5 +1,5 @@
 # portage.py -- core Portage functionality
-# Copyright 1998-2018 Gentoo Authors
+# Copyright 1998-2019 Gentoo Authors
 # Distributed under the terms of the GNU General Public License v2
 
 
@@ -467,7 +467,7 @@ def _exec(binary, mycommand, opt_name, fd_pipes,
 	@param gid: Group ID to run the process under
 	@type gid: Integer
 	@param groups: Groups the Process should be in.
-	@type groups: Integer
+	@type groups: List
 	@param uid: User ID to run the process under
 	@type uid: Integer
 	@param umask: an int representing a unix umask (see man chmod for umask details)
@@ -571,8 +571,16 @@ def _exec(binary, mycommand, opt_name, fd_pipes,
 									portage._python_interpreter,
 									os.path.join(portage._bin_path,
 										'pid-ns-init'),
+									_unicode_encode('' if uid is None else str(uid)),
+									_unicode_encode('' if gid is None else str(gid)),
+									_unicode_encode('' if groups is None else ','.join(str(group) for group in groups)),
+									_unicode_encode('' if umask is None else str(umask)),
 									_unicode_encode(','.join(str(fd) for fd in fd_pipes)),
 									binary] + myargs
+								uid = None
+								gid = None
+								groups = None
+								umask = None
 							else:
 								# Execute a supervisor process which will forward
 								# signals to init and forward exit status to the
-- 
2.18.1



^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2019-01-22  8:32 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2019-01-22  8:30 [gentoo-portage-dev] [PATCH] pid-sandbox: run pid-ns-init as root (bug 675868) Zac Medico

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox