1 |
commit: ec654122c0eb191c90ffb2c191403d342dbc361e |
2 |
Author: Zac Medico <zmedico <AT> gentoo <DOT> org> |
3 |
AuthorDate: Sun Mar 1 05:58:00 2020 +0000 |
4 |
Commit: Zac Medico <zmedico <AT> gentoo <DOT> org> |
5 |
CommitDate: Sun Mar 1 05:58:46 2020 +0000 |
6 |
URL: https://gitweb.gentoo.org/proj/portage.git/commit/?id=ec654122 |
7 |
|
8 |
fetch: drop privileges early for NFS root_squash (bug 601252) |
9 |
|
10 |
Drop privileges prior to fetch function calls, so that |
11 |
all necessary operations can succeed when DISTDIR is |
12 |
on NFS with root_squash enabled. |
13 |
|
14 |
Bug: https://bugs.gentoo.org/601252 |
15 |
Signed-off-by: Zac Medico <zmedico <AT> gentoo.org> |
16 |
|
17 |
lib/_emerge/EbuildFetcher.py | 12 +++++++++++- |
18 |
lib/portage/package/ebuild/doebuild.py | 22 +++++++++++++++++----- |
19 |
lib/portage/package/ebuild/fetch.py | 31 +++++++++++++++++++++++++++++++ |
20 |
3 files changed, 59 insertions(+), 6 deletions(-) |
21 |
|
22 |
diff --git a/lib/_emerge/EbuildFetcher.py b/lib/_emerge/EbuildFetcher.py |
23 |
index c9e03dc97..d315d4f02 100644 |
24 |
--- a/lib/_emerge/EbuildFetcher.py |
25 |
+++ b/lib/_emerge/EbuildFetcher.py |
26 |
@@ -12,7 +12,12 @@ from portage import _unicode_encode |
27 |
from portage import _unicode_decode |
28 |
from portage.checksum import _hash_filter |
29 |
from portage.elog.messages import eerror |
30 |
-from portage.package.ebuild.fetch import _check_distfile, fetch |
31 |
+from portage.package.ebuild.fetch import ( |
32 |
+ _check_distfile, |
33 |
+ _drop_privs_userfetch, |
34 |
+ _want_userfetch, |
35 |
+ fetch, |
36 |
+) |
37 |
from portage.util._async.AsyncTaskFuture import AsyncTaskFuture |
38 |
from portage.util._async.ForkProcess import ForkProcess |
39 |
from portage.util.futures.compat_coroutine import coroutine |
40 |
@@ -239,6 +244,11 @@ class _EbuildFetcherProcess(ForkProcess): |
41 |
portage.output.havecolor = self._settings.get('NOCOLOR') \ |
42 |
not in ('yes', 'true') |
43 |
|
44 |
+ # For userfetch, drop privileges for the entire fetch call, in |
45 |
+ # order to handle DISTDIR on NFS with root_squash for bug 601252. |
46 |
+ if _want_userfetch(self._settings): |
47 |
+ _drop_privs_userfetch(self._settings) |
48 |
+ |
49 |
rval = 1 |
50 |
allow_missing = self._get_manifest().allow_missing or \ |
51 |
'digest' in self._settings.features |
52 |
|
53 |
diff --git a/lib/portage/package/ebuild/doebuild.py b/lib/portage/package/ebuild/doebuild.py |
54 |
index 92e9d755c..71e3a74ce 100644 |
55 |
--- a/lib/portage/package/ebuild/doebuild.py |
56 |
+++ b/lib/portage/package/ebuild/doebuild.py |
57 |
@@ -1,4 +1,4 @@ |
58 |
-# Copyright 2010-2019 Gentoo Authors |
59 |
+# Copyright 2010-2020 Gentoo Authors |
60 |
# Distributed under the terms of the GNU General Public License v2 |
61 |
|
62 |
from __future__ import unicode_literals |
63 |
@@ -30,7 +30,7 @@ portage.proxy.lazyimport.lazyimport(globals(), |
64 |
'portage.package.ebuild.config:check_config_instance', |
65 |
'portage.package.ebuild.digestcheck:digestcheck', |
66 |
'portage.package.ebuild.digestgen:digestgen', |
67 |
- 'portage.package.ebuild.fetch:fetch', |
68 |
+ 'portage.package.ebuild.fetch:_drop_privs_userfetch,_want_userfetch,fetch', |
69 |
'portage.package.ebuild.prepare_build_dirs:_prepare_fake_distdir', |
70 |
'portage.package.ebuild._ipc.QueryCommand:QueryCommand', |
71 |
'portage.dep._slot_operator:evaluate_slot_operator_equal_deps', |
72 |
@@ -83,6 +83,7 @@ from portage.util.cpuinfo import get_cpu_count |
73 |
from portage.util.lafilefixer import rewrite_lafile |
74 |
from portage.util.compression_probe import _compressors |
75 |
from portage.util.futures import asyncio |
76 |
+from portage.util.futures.executor.fork import ForkExecutor |
77 |
from portage.util.path import first_existing |
78 |
from portage.util.socks5 import get_socks5_proxy |
79 |
from portage.versions import _pkgsplit |
80 |
@@ -1082,9 +1083,20 @@ def doebuild(myebuild, mydo, _unused=DeprecationWarning, settings=None, debug=0, |
81 |
dist_digests = None |
82 |
if mf is not None: |
83 |
dist_digests = mf.getTypeDigests("DIST") |
84 |
- if not fetch(fetchme, mysettings, listonly=listonly, |
85 |
- fetchonly=fetchonly, allow_missing_digests=False, |
86 |
- digests=dist_digests): |
87 |
+ |
88 |
+ def _fetch_subprocess(fetchme, mysettings, listonly, dist_digests): |
89 |
+ # For userfetch, drop privileges for the entire fetch call, in |
90 |
+ # order to handle DISTDIR on NFS with root_squash for bug 601252. |
91 |
+ if _want_userfetch(mysettings): |
92 |
+ _drop_privs_userfetch(mysettings) |
93 |
+ |
94 |
+ return fetch(fetchme, mysettings, listonly=listonly, |
95 |
+ fetchonly=fetchonly, allow_missing_digests=False, |
96 |
+ digests=dist_digests) |
97 |
+ |
98 |
+ loop = asyncio._safe_loop() |
99 |
+ if not loop.run_until_complete(loop.run_in_executor(ForkExecutor(loop=loop), |
100 |
+ _fetch_subprocess, fetchme, mysettings, listonly, dist_digests)): |
101 |
# Since listonly mode is called by emerge --pretend in an |
102 |
# asynchronous context, spawn_nofetch would trigger event loop |
103 |
# recursion here, therefore delegate execution of pkg_nofetch |
104 |
|
105 |
diff --git a/lib/portage/package/ebuild/fetch.py b/lib/portage/package/ebuild/fetch.py |
106 |
index 06118b1a6..f7984130f 100644 |
107 |
--- a/lib/portage/package/ebuild/fetch.py |
108 |
+++ b/lib/portage/package/ebuild/fetch.py |
109 |
@@ -69,6 +69,37 @@ _userpriv_spawn_kwargs = ( |
110 |
def _hide_url_passwd(url): |
111 |
return re.sub(r'//(.+):.+@(.+)', r'//\1:*password*@\2', url) |
112 |
|
113 |
+ |
114 |
+def _want_userfetch(settings): |
115 |
+ """ |
116 |
+ Check if it's desirable to drop privileges for userfetch. |
117 |
+ |
118 |
+ @param settings: portage config |
119 |
+ @type settings: portage.package.ebuild.config.config |
120 |
+ @return: True if desirable, False otherwise |
121 |
+ """ |
122 |
+ return ('userfetch' in settings.features and |
123 |
+ portage.data.secpass >= 2 and os.getuid() == 0) |
124 |
+ |
125 |
+ |
126 |
+def _drop_privs_userfetch(settings): |
127 |
+ """ |
128 |
+ Drop privileges for userfetch, and update portage.data.secpass |
129 |
+ to correspond to the new privilege level. |
130 |
+ """ |
131 |
+ spawn_kwargs = dict(_userpriv_spawn_kwargs) |
132 |
+ try: |
133 |
+ _ensure_distdir(settings, settings['DISTDIR']) |
134 |
+ except PortageException: |
135 |
+ if not os.path.isdir(settings['DISTDIR']): |
136 |
+ raise |
137 |
+ os.setgid(int(spawn_kwargs['gid'])) |
138 |
+ os.setgroups(spawn_kwargs['groups']) |
139 |
+ os.setuid(int(spawn_kwargs['uid'])) |
140 |
+ os.umask(spawn_kwargs['umask']) |
141 |
+ portage.data.secpass = 1 |
142 |
+ |
143 |
+ |
144 |
def _spawn_fetch(settings, args, **kwargs): |
145 |
""" |
146 |
Spawn a process with appropriate settings for fetching, including |