为什么具有挂载命名空间的子级会影响父级挂载?

为什么具有挂载命名空间的子级会影响父级挂载?

我正在尝试使用具有 root 访问权限的 Debian jessie 服务器来了解 Linux 命名空间。

考虑这个 C 代码:

# /tmp/test.c
#define _GNU_SOURCE
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>

static char child_stack[1048576];

static int my_child() {
  system("/bin/bash");
}

int main() {
  pid_t child_pid = clone(my_child, child_stack+1048576,
                          CLONE_NEWPID | CLONE_NEWNS | SIGCHLD, NULL);
  waitpid(child_pid, NULL, 0);
  return 0;
}

接下来,我在单个终端的单个会话中运行这些命令:

/tmp# id
uid=0(root) gid=0(root) groups=0(root),1093867019
/tmp# echo $$
1804
/tmp# ps -eaf | head
 UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 May08 ?        00:00:01 /sbin/init
root         2     0  0 May08 ?        00:00:00 [kthreadd]
root         3     2  0 May08 ?        00:00:00 [ksoftirqd/0]
root         5     2  0 May08 ?        00:00:00 [kworker/0:0H]
root         7     2  0 May08 ?        00:00:11 [rcu_sched]
root         8     2  0 May08 ?        00:00:00 [rcu_bh]
root         9     2  0 May08 ?        00:00:00 [migration/0]
root        10     2  0 May08 ?        00:00:00 [watchdog/0]
root        11     2  0 May08 ?        00:00:00 [khelper]
/tmp# grep /proc /proc/$$/mountinfo
15 19 0:3 / /proc rw,nosuid,nodev,noexec,relatime shared:12 - proc proc rw
33 15 0:29 / /proc/sys/fs/binfmt_misc rw,relatime shared:20 - autofs systemd-1 rw,fd=22,pgrp=1,timeout=300,minproto=5,maxproto=5,direct
/tmp# gcc test.c
/tmp# ./a.out
/tmp# echo $$
2
/tmp# echo $PPID
1
/tmp# ps -eaf | head
 UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 May08 ?        00:00:01 /sbin/init
root         2     0  0 May08 ?        00:00:00 [kthreadd]
root         3     2  0 May08 ?        00:00:00 [ksoftirqd/0]
root         5     2  0 May08 ?        00:00:00 [kworker/0:0H]
root         7     2  0 May08 ?        00:00:11 [rcu_sched]
root         8     2  0 May08 ?        00:00:00 [rcu_bh]
root         9     2  0 May08 ?        00:00:00 [migration/0]
root        10     2  0 May08 ?        00:00:00 [watchdog/0]
root        11     2  0 May08 ?        00:00:00 [khelper]
tmp# grep /proc /proc/$$/mountinfo
15 19 0:3 / /proc rw,nosuid,nodev,noexec,relatime shared:12 - proc proc rw
33 15 0:29 / /proc/sys/fs/binfmt_misc rw,relatime shared:20 - autofs systemd-1 rw,fd=22,pgrp=0,timeout=300,minproto=5,maxproto=5,direct
/tmp# mount -t proc proc /proc
/tmp# grep /proc /proc/$$/mountinfo
92 70 0:3 / /proc rw,nosuid,nodev,noexec,relatime shared:12 - proc proc rw
93 92 0:29 / /proc/sys/fs/binfmt_misc rw,relatime shared:20 - autofs systemd-1 rw,fd=22,pgrp=0,timeout=300,minproto=5,maxproto=5,direct
97 92 0:34 / /proc rw,relatime shared:27 - proc proc rw
/tmp# ps -eaf
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 07:31 pts/0    00:00:00 ./a.out
root         2     1  0 07:31 pts/0    00:00:00 /bin/bash
root        14     2  0 07:31 pts/0    00:00:00 ps -eaf
/tmp# exit
exit
/tmp# echo $$
1804
/tmp# grep /proc /proc/$$/mountinfo
grep: /proc/1804/mountinfo: No such file or directory
/tmp# ps -eaf
Error, do this: mount -t proc proc /proc
/tmp# mount -t proc proc /proc
/tmp# grep /proc /proc/$$/mountinfo
15 19 0:3 / /proc rw,nosuid,nodev,noexec,relatime shared:12 - proc proc rw
33 15 0:29 / /proc/sys/fs/binfmt_misc rw,relatime shared:20 - autofs systemd-1 rw,fd=22,pgrp=1,timeout=300,minproto=5,maxproto=5,direct
98 15 0:34 / /proc rw,relatime shared:27 - proc proc rw
69 98 0:3 / /proc rw,relatime shared:28 - proc proc rw

为什么子进程退出后,/proc没有挂载?子进程对挂载点所做的任何更改不应该影响父进程的挂载点吗?这似乎与埃米特对这个问题的回答相矛盾https://stackoverflow.com/questions/22889241/linux-understanding-the-mount-namespace-clone-clone-newns-flag

答案1

clone当使用该标志创建子进程时CLONE_NEWNS,子进程将获得自己的挂载命名空间。子命名空间中的挂载操作(mountumountmount --bind等)仅在该命名空间内有效,而父命名空间中的挂载操作仅在新命名空间外有效。

共享安装除外。安装座可以是共享,在这种情况下,操作会影响共享挂载的所有命名空间。共享挂载的典型用例是使可移动驱动器在子命名空间(例如 chroot)中可用。关系类型更多(私有坐骑、不可绑定坐骑);有关更多详细信息,请参阅内核文档

您可以通过检查来检查挂载是否共享:如果该行包含,则挂载是共享的,并且该数字是标识其共享的命名空间集的唯一值。如果该行不包含此类指示,则该安装是私有的。/proc/PID/mountinfoshared:NUMBER

在您的系统上,/proc是共享的。当您在子命名空间中挂载 proc 的新实例时,由于您是在父命名空间上挂载的/proc,因此该新实例也是共享的,因此它在子命名空间和父命名空间中都是可见的。当您退出子命名空间时,第二个实例/proc仍保持挂载状态,因为它与仍然活动的父命名空间共享。

有两件事使您的场景变得复杂:您还创建了一个 PID 命名空间,并且将/proc两者用作实验的主题和观察手段。当ps抱怨时/proc未安装时,它实际上显示了一条误导性的错误消息 -错误的 proc已安装(aproc表示错误的命名空间)。您可以使用ls /proc和来观察这一点cat /proc/1/mountinfo。我建议使用临时文件系统进行实验,这样会更容易理解发生了什么。

父# ./a.out
孩子#回声$$
2
子# ls /proc
这是父级的 proc,/proc/PID 在父级 PID 命名空间中
孩子# ps 1
… 在里面
子# mount -t proc proc /proc
现在子挂载命名空间中的 /proc 用于子 PID 命名空间
孩子# ps 1
…a. 输出
孩子#退出
父级#

到目前为止,私有还是共享并不重要/proc,但现在重要了。如果/proc是私有的,那么此时我们正在观察父级的/proc,它从未受到影响并显示 PID 命名空间。但如果/proc是共享的,那么mount我们之前发出的命令会影响两个命名空间,因此:

父# ls /proc
acpi 声音 buddyinfo ...
父级# ps 1
错误,请执行以下操作:mount -t proc proc /proc
实际上,/proc 已挂载,但它是我们之前创建的 PID 命名空间的 proc,现在运行的进程为零。
父# grep -c ' /proc ' /proc/mounts
2
父级#卸载/proc
我们已经卸载了隐藏父命名空间 /proc 的子 PID 命名空间的 /proc,因此“正常”/proc 再次可见。
父级# ps 1
… 在里面

相关内容