克隆后使用CLONE_NEWNS标志挂载文件系统

我正在尝试实现以下方案:

>具有CLONE_NEWNS标志的clone()主进程(这意味着新的安装名称空间)
>子进程中的mount()新文件系统
>子进程完成,并且在此进程中创建的所有文件系统均已卸载

但是它没有按我预期的那样工作,我仍然在主进程中看到已挂载的文件系统.我究竟做错了什么?

来源在这里https://github.com/dmitrievanthony/sprat/blob/master/src/container.c#L47

系统是默认的AWS Ubuntu,

ubuntu@ip-172-31-31-112:~/sprat$uname -a
Linux ip-172-31-31-112 4.4.0-53-generic #74-Ubuntu SMP Fri Dec 2 15:59:10 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux

解决方法:

简短的答案:mount propagation的类型似乎设置不正确.

说明

首先,根安装点的传播类型应为MS_SHARED,由systemd在启动时设置.
可以通过查看/ proc / $PID / mountinfo的可选字段来观察.
例如,可能会出现类似这样的情况:

$cat /proc/self/mountinfo
  . . .
25 0 8:6 / / rw,relatime shared:1 - ext4 /dev/sda6 rw,errors=remount-ro,data=ordered
                         ^^^^^^
  . . .

请注意上面带下划线的(对我来说)shared:1字段,指示/挂载点的当前传播类型为MS_SHARED,对等组ID为1(在这种情况下,我们根本不关心对等组ID).

在clone(2)上使用CLONE_NEWNS标志时,将创建一个新的安装名称空间,该名称空间被初始化为调用者的安装名称空间的副本.
新名称空间的新复制复制装入点与其在调用者的装入名称空间中各自的原始装入点加入同一对等组.

父节点的传播类型为MS_SHARED的新安装点的传播类型也为MS_SHARED.因此,当您“包含”的进程在循环设备上对文件系统进行mount()时,默认情况下该安装为MS_SHARED.后来,它下面的所有安装程序也都传播到“主”进程的名称空间,这就是“主”进程可以看到它们的原因.

为了满足您的请求(为了使“主”进程看不到“包含”进程的挂载点),您寻求的挂载传播类型是MS_SLAVE还是MS_PRIVATE,具体取决于您是否希望将“包含”进程的根挂载点设置为是否分别从其他对等方接收传播事件.
显然,MS_PRIVATE提供的隔离度比MS_SLAVE大.

因此,在您的情况下,在挂载其余文件系统之前,将“包含”进程的根挂载点的传播类型更改为MS_PRIVATE或MS_SLAVE就足够了,因此,挂载不会传播到“主”进程的命名空间.

编码

首先,当“包含”进程创建其根安装点时,将尝试正确设置传播类型.

但是,我在man 8 mount(引用)中注意到以下内容:

Note that the Linux kernel does not allow to change multiple
propagation flags with a single mount(2) system call, and the flags
cannot be mixed with other mount options.

Since util-linux 2.23 the mount command allows to use several
propagation flags together and also together with other mount
operations. This feature is EXPERIMENTAL. The propagation flags are
applied by additional mount(2) system calls when the preceding mount
operations were successful.

查看您的代码,即“包含”进程,在将其挂载到循环设备上的文件系统之后,向其发出chroot().此时,您可以通过注入以下mount(2)调用来设置其传播类型:

if (chroot(".") < 0) {
    // handle error
}

if (mount("/", "/", c->fstype, MS_PRIVATE, "") < 0) {
    // handle error
}

if (mkdir(...)) {
    // handle error
}

现在,将传播类型设置为MS_PRIVATE,“包含”进程在/下进行的所有后续挂载将不会被传播,因此在“主”进程的命名空间中将不可见,如您在/ proc / mounts中所观察到的或/ proc / $PID / mountinfo.

资源资源

> Linux内核的Shared Subtrees documentation了解有关挂载传播的更多信息.
> Michael Kerrisk出色的LWN article解释了装载名称空间,这比我能做的更好.

上一篇:用运行docker容器的用户无法访问的php文件构建容器?


下一篇:Docker Command