在阅读了有关 Linux 命名空间的内容后,我的印象是,除了许多其他功能之外,它们是 chroot 的替代品。例如,在本文:
[命名空间] 的其他用途包括 [...] chroot() 式的进程与单个目录层次结构的一部分的隔离。
但是,当我克隆挂载命名空间时,例如使用以下命令,我仍然看到整个原始根树。
unshare --mount -- /bin/bash
我知道我现在能够在新命名空间中执行不与原始命名空间共享的附加安装,因此这提供了隔离,但它仍然是相同的根,例如/etc
两个命名空间仍然相同。我还需要chroot
更改根目录还是有其他选择?
我正期待着这个问题会提供答案,但答案仅chroot
再次使用 , 。
编辑#1
有一条评论提到 ,现已删除pivot_root
。因为这实际上是linux/fs/namespace.c
,它实际上是命名空间实现的一部分。这表明仅使用unshare
和更改根目录mount
是不可能的,但是名称空间提供了一个自己的更聪明的版本chroot
。chroot
即使在阅读了源代码之后(例如在安全性或更好的隔离意义上),我仍然不明白这种方法的主要思想,即它与 的根本不同。
编辑#2
这不是重复的这个问题。执行答案中的所有命令后,我有单独的 /tmp/tmp.vyM9IwnKuY (或类似的),但根目录仍然相同!
答案1
在设置 之前输入挂载命名空间chroot
,可以避免主机命名空间因其他挂载(例如/proc
.您可以chroot
在挂载命名空间内使用作为一个很好且简单的技巧。
我认为理解有好处pivot_root
,但有一点学习曲线。该文档并没有完全解释所有内容...尽管man 8 pivot_root
(对于 shell 命令) 中有一个使用示例。 man 2 pivot_root
(对于系统调用)如果执行相同的操作并包含一个示例 C 程序,可能会更清楚。
如何使用pivot_root
进入挂载命名空间后,您还需要立即执行mount --make-rslave /
或等效操作。否则,所有挂载更改都会传播到原始命名空间中的挂载,包括pivot_root
.你不希望这样:)。
如果您使用了该unshare --mount
命令,请注意它被记录mount --make-rprivate
为默认应用。 AFAICS 这是一个错误的默认值,您不希望在生产代码中使用它。例如,此时,它将停止eject
在主机命名空间中安装的 DVD 或 USB 上工作。 DVD 或 USB 将保留安装在专用安装树内,并且内核不会让您弹出 DVD。
完成此操作后,您可以安装例如/proc
您将使用的目录。与您的方式相同chroot
。
与使用时不同chroot
,pivot_root
要求新的根文件系统是安装点。如果还不是,您可以通过简单地应用绑定安装来满足这一点:mount --rbind new_root new_root
。
使用pivot_root
- ,然后使用umount
旧的根文件系统,以及-l
/MNT_DETACH
选项。 (您不需要umount -R
,这可能需要更长的时间。)。
从技术上讲,使用通常也pivot_root
需要涉及使用;chroot
这不是“非此即彼”。
根据man 2 pivot_root
,它仅定义为交换挂载命名空间的根。它没有被定义为更改进程根指向的物理目录。或当前工作目录 ( /proc/self/cwd
)。碰巧它做这样做,但这是处理内核线程的技巧。手册页说,将来可能会改变。
通常你想要这个序列:
chdir(new_root); // cd new_root
pivot_root(".", put_old); // pivot_root . put_old
chroot("."); // chroot .
在这个序列中的位置chroot
是另一个微妙的细节。尽管重点pivot_root
是重新排列挂载命名空间,但内核代码似乎通过查看每个进程的根来找到要移动的根文件系统,这是设置的chroot
。
为什么要使用pivot_root
pivot_root
原则上,用于安全和隔离是有意义的。我喜欢思考以下理论基于能力的安全。您传入所需的特定资源列表,并且该进程无法访问其他资源。在本例中,我们讨论的是传递到挂载命名空间的文件系统。这个想法通常适用于 Linux“命名空间”功能,尽管我可能没有很好地表达它。
chroot
只设置进程根,但进程仍然引用完整的挂载命名空间。如果进程保留执行权限chroot
,则它可以遍历备份文件系统名称空间。正如 中详细描述的man 2 chroot
,“超级用户可以通过……逃离‘chroot 监狱’”。
另一种发人深省的撤销方法chroot
是nsenter --mount=/proc/self/ns/mnt
。这也许是对该原则更有力的论证。 nsenter
/setns()
必须从挂载命名空间的根重新加载进程根...虽然当两者引用不同的物理目录时这有效,但可能被认为是内核错误。 (技术说明:根目录下可能有多个文件系统彼此叠置;setns()
使用顶部的、最近安装的一个)。
这说明了将安装命名空间与“PID命名空间”相结合的一个优点。位于 PID 命名空间内会阻止您进入不受限制的进程的挂载命名空间。它还可以防止您进入不受限制的进程的根目录 ( /proc/$PID/root
)。当然,PID 命名空间还可以防止您终止其外部的任何进程:-)。