1 |
On 11/14/18 12:02 AM, Michał Górny wrote: |
2 |
> @@ -531,6 +543,15 @@ def _exec(binary, mycommand, opt_name, fd_pipes, env, gid, groups, uid, umask, |
3 |
> errno.errorcode.get(ctypes.get_errno(), '?')), |
4 |
> noiselevel=-1) |
5 |
> else: |
6 |
> + if unshare_pid: |
7 |
> + # pid namespace requires us to become init |
8 |
> + # TODO: do init-ty stuff |
9 |
> + # therefore, fork() ASAP |
10 |
> + fork_ret = os.fork() |
11 |
> + if fork_ret != 0: |
12 |
> + pid, status = os.waitpid(fork_ret, 0) |
13 |
> + assert pid == fork_ret |
14 |
> + os._exit(status) |
15 |
> if unshare_mount: |
16 |
> # mark the whole filesystem as private to avoid |
17 |
> # mounts escaping the namespace |
18 |
> @@ -541,6 +562,18 @@ def _exec(binary, mycommand, opt_name, fd_pipes, env, gid, groups, uid, umask, |
19 |
> # TODO: should it be fatal maybe? |
20 |
> writemsg("Unable to mark mounts private: %d\n" % (mount_ret,), |
21 |
> noiselevel=-1) |
22 |
> + if unshare_pid: |
23 |
> + if mount_ret != 0: |
24 |
> + # can't proceed without private mounts |
25 |
> + os._exit(1) |
26 |
|
27 |
For the benefit of anyone not watching |
28 |
https://github.com/gentoo/portage/pull/379, the mount_ret is expected |
29 |
to be non-zero inside a chroot where `mount --make-rprivate /` would |
30 |
fail because / is not a mountpoint, and this is an extremely valuable |
31 |
use case for tools like catalyst that perform builds inside a chroot. |
32 |
|
33 |
Based on /proc/[pid]/mountinfo documentation in the proc(5) manpage, |
34 |
and empirical analysis of /proc/self/mountinfo in various states, |
35 |
it should be reasonable to assume that the current propagation flags |
36 |
are suitable if there is not a shared / or /proc mountpoint found in |
37 |
/proc/self/mountinfo. We can use a function like this to check if the |
38 |
`mount --make-rprivate /` call is needed: |
39 |
|
40 |
def want_make_rprivate(): |
41 |
try: |
42 |
with open('/proc/self/mountinfo', 'rb') as f: |
43 |
if re.match(rb'^\S+ \S+ \S+ \S+ (?P<mountpoint>/|/proc) \S+ (?:\S+:\S+ )*(?P<shared>shared:\S+ )', f.read(), re.MULTILINE) is None: |
44 |
return False |
45 |
except EnvironmentError: |
46 |
pass |
47 |
return True |
48 |
-- |
49 |
Thanks, |
50 |
Zac |