1 |
Drop privileges prior to fetch function calls, so that |
2 |
all necessary operations can succeed when DISTDIR is |
3 |
on NFS with root_squash enabled. |
4 |
|
5 |
Bug: https://bugs.gentoo.org/601252 |
6 |
Signed-off-by: Zac Medico <zmedico@g.o> |
7 |
--- |
8 |
lib/_emerge/EbuildFetcher.py | 12 +++++++++++- |
9 |
lib/portage/package/ebuild/doebuild.py | 20 +++++++++++++++---- |
10 |
lib/portage/package/ebuild/fetch.py | 27 ++++++++++++++++++++++++++ |
11 |
3 files changed, 54 insertions(+), 5 deletions(-) |
12 |
|
13 |
diff --git a/lib/_emerge/EbuildFetcher.py b/lib/_emerge/EbuildFetcher.py |
14 |
index ad5109c28..b9dc3a10c 100644 |
15 |
--- a/lib/_emerge/EbuildFetcher.py |
16 |
+++ b/lib/_emerge/EbuildFetcher.py |
17 |
@@ -12,7 +12,12 @@ from portage import _unicode_encode |
18 |
from portage import _unicode_decode |
19 |
from portage.checksum import _hash_filter |
20 |
from portage.elog.messages import eerror |
21 |
-from portage.package.ebuild.fetch import _check_distfile, fetch |
22 |
+from portage.package.ebuild.fetch import ( |
23 |
+ _check_distfile, |
24 |
+ _drop_privs_userfetch, |
25 |
+ _want_userfetch, |
26 |
+ fetch, |
27 |
+) |
28 |
from portage.util._async.AsyncTaskFuture import AsyncTaskFuture |
29 |
from portage.util._async.ForkProcess import ForkProcess |
30 |
from portage.util._pty import _create_pty_or_pipe |
31 |
@@ -229,6 +234,11 @@ class _EbuildFetcherProcess(ForkProcess): |
32 |
self._settings = None |
33 |
|
34 |
def _run(self): |
35 |
+ # For userfetch, drop privileges for the entire fetch call, in |
36 |
+ # order to handle DISTDIR on NFS with root_squash for bug 601252. |
37 |
+ if _want_userfetch(self._settings): |
38 |
+ _drop_privs_userfetch(self._settings) |
39 |
+ |
40 |
# Force consistent color output, in case we are capturing fetch |
41 |
# output through a normal pipe due to unavailability of ptys. |
42 |
portage.output.havecolor = self._settings.get('NOCOLOR') \ |
43 |
diff --git a/lib/portage/package/ebuild/doebuild.py b/lib/portage/package/ebuild/doebuild.py |
44 |
index 92e9d755c..be4a6019d 100644 |
45 |
--- a/lib/portage/package/ebuild/doebuild.py |
46 |
+++ b/lib/portage/package/ebuild/doebuild.py |
47 |
@@ -30,7 +30,7 @@ portage.proxy.lazyimport.lazyimport(globals(), |
48 |
'portage.package.ebuild.config:check_config_instance', |
49 |
'portage.package.ebuild.digestcheck:digestcheck', |
50 |
'portage.package.ebuild.digestgen:digestgen', |
51 |
- 'portage.package.ebuild.fetch:fetch', |
52 |
+ 'portage.package.ebuild.fetch:_drop_privs_userfetch,_want_userfetch,fetch', |
53 |
'portage.package.ebuild.prepare_build_dirs:_prepare_fake_distdir', |
54 |
'portage.package.ebuild._ipc.QueryCommand:QueryCommand', |
55 |
'portage.dep._slot_operator:evaluate_slot_operator_equal_deps', |
56 |
@@ -83,6 +83,7 @@ from portage.util.cpuinfo import get_cpu_count |
57 |
from portage.util.lafilefixer import rewrite_lafile |
58 |
from portage.util.compression_probe import _compressors |
59 |
from portage.util.futures import asyncio |
60 |
+from portage.util.futures.executor.fork import ForkExecutor |
61 |
from portage.util.path import first_existing |
62 |
from portage.util.socks5 import get_socks5_proxy |
63 |
from portage.versions import _pkgsplit |
64 |
@@ -1082,9 +1083,20 @@ def doebuild(myebuild, mydo, _unused=DeprecationWarning, settings=None, debug=0, |
65 |
dist_digests = None |
66 |
if mf is not None: |
67 |
dist_digests = mf.getTypeDigests("DIST") |
68 |
- if not fetch(fetchme, mysettings, listonly=listonly, |
69 |
- fetchonly=fetchonly, allow_missing_digests=False, |
70 |
- digests=dist_digests): |
71 |
+ |
72 |
+ def _fetch_subprocess(fetchme, mysettings, listonly, dist_digests): |
73 |
+ # For userfetch, drop privileges for the entire fetch call, in |
74 |
+ # order to handle DISTDIR on NFS with root_squash for bug 601252. |
75 |
+ if _want_userfetch(mysettings): |
76 |
+ _drop_privs_userfetch(mysettings) |
77 |
+ |
78 |
+ return fetch(fetchme, mysettings, listonly=listonly, |
79 |
+ fetchonly=fetchonly, allow_missing_digests=False, |
80 |
+ digests=dist_digests) |
81 |
+ |
82 |
+ loop = asyncio._safe_loop() |
83 |
+ if not loop.run_until_complete(loop.run_in_executor(ForkExecutor(loop=loop), |
84 |
+ _fetch_subprocess, fetchme, mysettings, listonly, dist_digests)): |
85 |
# Since listonly mode is called by emerge --pretend in an |
86 |
# asynchronous context, spawn_nofetch would trigger event loop |
87 |
# recursion here, therefore delegate execution of pkg_nofetch |
88 |
diff --git a/lib/portage/package/ebuild/fetch.py b/lib/portage/package/ebuild/fetch.py |
89 |
index 06118b1a6..6189c0245 100644 |
90 |
--- a/lib/portage/package/ebuild/fetch.py |
91 |
+++ b/lib/portage/package/ebuild/fetch.py |
92 |
@@ -69,6 +69,33 @@ _userpriv_spawn_kwargs = ( |
93 |
def _hide_url_passwd(url): |
94 |
return re.sub(r'//(.+):.+@(.+)', r'//\1:*password*@\2', url) |
95 |
|
96 |
+ |
97 |
+def _want_userfetch(settings): |
98 |
+ """ |
99 |
+ Check if it's desirable to drop privileges for userfetch. |
100 |
+ |
101 |
+ @param settings: portage config |
102 |
+ @type settings: portage.package.ebuild.config.config |
103 |
+ @return: True if desirable, False otherwise |
104 |
+ """ |
105 |
+ return ('userfetch' in settings.features and |
106 |
+ portage.data.secpass >= 2 and os.getuid() == 0) |
107 |
+ |
108 |
+ |
109 |
+def _drop_privs_userfetch(settings): |
110 |
+ """ |
111 |
+ Drop privileges for userfetch, and update portage.data.secpass |
112 |
+ to correspond to the new privilege level. |
113 |
+ """ |
114 |
+ spawn_kwargs = dict(_userpriv_spawn_kwargs) |
115 |
+ _ensure_distdir(settings, settings['DISTDIR']) |
116 |
+ os.setgid(int(spawn_kwargs['gid'])) |
117 |
+ os.setgroups(spawn_kwargs['groups']) |
118 |
+ os.setuid(int(spawn_kwargs['uid'])) |
119 |
+ os.umask(spawn_kwargs['umask']) |
120 |
+ portage.data.secpass = 1 |
121 |
+ |
122 |
+ |
123 |
def _spawn_fetch(settings, args, **kwargs): |
124 |
""" |
125 |
Spawn a process with appropriate settings for fetching, including |
126 |
-- |
127 |
2.24.1 |