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

dmi*_*ony 3 c linux containers mount linux-namespaces

我正在尝试实现以下场景:

  1. clone()CLONE_NEWNS标志的主进程(这意味着新的挂载命名空间)
  2. mount() 子进程中的新文件系统
  3. 子进程完成并且所有在这个进程文件系统中创建的都被卸载

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

来源在这里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
Run Code Online (Sandbox Code Playgroud)

chr*_*hrk 5

简短回答:看起来安装传播的类型设置不正确。


解释

Linux 内核默认所有挂载都为MS_PRIVATE,但为了方便 nspawn ,systemd在早期引导期间将其覆盖MS_SHARED为 。这可以通过观察可以观察到可选字段/proc/$PID/mountinfo。例如,可能会出现这样的情况:

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

注意shared:1上面带下划线的(by me)字段,表明当前/挂载点的传播类型是MS_SHARED,对等组ID 是1(在我们的例子中我们根本不关心对等组 ID)。

CLONE_NEWNSclone(2)新的挂载命名空间上使用该标志时,它被初始化为调用者挂载命名空间的副本。新命名空间的新复制挂载点与调用方挂载命名空间中各自的原始挂载点加入相同的对等组。

一个新的挂载点,其父母的传播类型的传播类型MS_SHARED,是MS_SHARED太。因此,当您的“包含”进程mount()是循环设备上的文件系统时,默认情况下挂载为MS_SHARED。后来,它下面的所有挂载也传播到“main”进程的命名空间,这就是“main”进程可以看到它们的原因。

为了满足您的请求(对于“主”进程看不到“包含”进程的挂载点),您寻求的挂载传播类型是MS_SLAVEMS_PRIVATE,具体取决于您是否希望“包含”进程的根挂载点接收传播分别来自其他对等方的事件与否。显然,MS_PRIVATE提供比MS_SLAVE.

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


编码

起初,当“包含”进程创建其根挂载点时,人们会尝试正确设置传播类型。

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

请注意,Linux 内核不允许通过单个 mount(2) 系统调用更改多个传播标志,并且这些标志不能与其他挂载选项混合使用。

从 util-linux 2.23 开始, mount 命令允许将多个传播标志一起使用,也可以与其他挂载操作一起使用。此功能是实验性的。当前面的挂载操作成功时,额外的 mount(2) 系统调用会应用传播标志。

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

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

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

if (mkdir(...)) {
    // handle error
}
Run Code Online (Sandbox Code Playgroud)

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


资源

  • Linux 内核的共享子树文档以获取有关挂载传播的更多信息。

  • Michael Kerrisk 的优秀LWN 文章比我能更好地解释挂载命名空间。