如何使用 Linux 命名空间执行 chroot?

koa*_*alo 16 chroot namespace

在阅读了 Linux 命名空间之后,我的印象是,在许多其他功能中,它们是 chroot 的替代品。例如,在这篇文章中

[名称空间] 的其他用途包括 [...] chroot() 式将进程隔离到单个目录层次结构的一部分。

但是,当我克隆 mount 命名空间时,例如使用以下命令,我仍然看到整个原始根树。

unshare --mount -- /bin/bash
Run Code Online (Sandbox Code Playgroud)

我知道我现在能够在不与原始命名空间共享的新命名空间中执行额外的挂载,因此这提供了隔离,但它仍然是同一个根,例如/etc两个命名空间仍然相同。我还需要chroot更改根目录还是有其他选择?

我期待这个问题会提供答案,但答案chroot再次仅使用, 。

编辑#1

有一条现已删除的评论提到pivot_root。由于这实际上是 的一部分linux/fs/namespace.c,因此它实际上是名称空间实现的一部分。这表明仅使用unshare和更改根目录mount是不可能的,但命名空间提供了一个自己的——更聪明的—— chroot. chroot即使在阅读源代码之后(例如在安全性或更好的隔离的意义上),我仍然不明白这种方法的主要思想,这使得它与 根本不同。

编辑#2

这不是这个问题的重复。执行完答案中的所有命令后,我有单独的 /tmp/tmp.vyM9IwnKuY(或类似的),但根目录仍然相同!

sou*_*edi 18

在设置 之前输入挂载命名空间chroot,可让您避免使用其他挂载(例如 for /proc. 您可以chroot在 mount 命名空间内使用作为一个不错的简单技巧。

我认为理解 有优势pivot_root,但它有一点学习曲线。该文档并没有完全解释所有内容......尽管man 8 pivot_root(对于shell命令)中有一个用法示例。 man 2 pivot_root(对于系统调用)如果这样做的话可能会更清楚,并且包含一个示例 C 程序。

如何使用pivot_root

紧接着进入 mount 命名空间后,你还需要mount --make-rslave /或者等价的。否则,所有挂载更改都会传播到原始命名空间中的挂载,包括pivot_root. 你不想要那个:)。

如果您使用了该unshare --mount命令,请注意它被记录为mount --make-rprivate默认应用。AFAICS 这是一个糟糕的默认设置,您不希望在生产代码中使用它。例如,此时,它将停止eject在主机命名空间中安装的 DVD 或 USB 上工作。DVD 或 USB 将保持挂载在私有挂载树中,内核不会让您弹出 DVD。

完成后,您可以挂载例如/proc您将使用的目录。与您对chroot.

与使用时不同chrootpivot_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 .
Run Code Online (Sandbox Code Playgroud)

的的postitionchroot这个顺序又是一个微妙的细节。虽然重点pivot_root是重新排列挂载命名空间,但内核代码似乎通过查看每个进程的根来找到要移动的根文件系统,这就是chroot设置。

为什么要使用 pivot_root

原则上,pivot_root用于安全和隔离是有意义的。我喜欢思考基于能力的安全理论。您传入所需特定资源的列表,该进程无法访问其他资源。在这种情况下,我们讨论的是传递给挂载命名空间的文件系统。这个想法通常适用于 Linux 的“命名空间”功能,尽管我可能没有很好地表达它。

chroot只设置进程根,但进程仍然引用完整的挂载命名空间。如果一个进程保留了执行权限chroot,那么它可以遍历备份文件系统命名空间。如 中所述man 2 chroot,“超级用户可以通过……从 'chroot jail' 中逃脱”。

另一种发人深省的撤消方式chrootnsenter --mount=/proc/self/ns/mnt. 这也许是该原则的一个更有力的论据。 nsenter/setns()必须从挂载命名空间的根目录重新加载进程根目录......尽管当两者引用不同的物理目录时这有效,但可能被认为是内核错误。(技术说明:在根目录中可能有多个文件系统彼此重叠安装;setns()使用顶部,最近安装的一个)。

这说明了将挂载命名空间与“PID 命名空间”相结合的一个优势。位于 PID 命名空间内会阻止您进入未受限进程的挂载命名空间。它还可以防止您进入不受限制的进程 ( /proc/$PID/root)的根目录。当然,PID 命名空间还可以防止您杀死它之外的任何进程:-)。

  • 最近,[pivot_root(2) 手册页](http://man7.org/linux/man-pages/man2/pivot_root.2.html) 进行了更新,其中包含一些说明,现在包含一个示例程序。您可能想更新您的答案以反映这一点?手册页现在还解释了很好的 `pivot_root(".", ".")` 技巧,这实际上是在大多数情况下使用 `pivot_root` 的最简单方法(不需要 `chroot`)。 (3认同)