Linux 面试题:chroot、pivot_root 与容器根文件系统切换

在 Linux 系统编程和容器技术面试中,根文件系统切换是一个高频考点。很多候选人能说出 chroot 命令的基本用法,但当面试官追问 pivot_root 的区别、容器运行时到底用哪个、以及为什么 chroot 不够安全时,往往就答不完整了。这篇文章从面试题的角度,把这三个概念串起来讲清楚。

为什么需要切换根文件系统

正常情况下,Linux 进程看到的根目录 / 来自内核启动时挂载的根文件系统。但在某些场景下,我们需要让一个进程或一组进程“以为”自己看到了一个全新的根目录:

  • 系统救援:原系统无法正常启动时,从 Live CD 启动后 chroot 到硬盘上的系统进行修复。
  • 服务隔离:让某个服务只能访问特定目录树,限制其可见范围。
  • 容器运行:容器需要拥有独立的根文件系统,与宿主机隔离。
  • 系统构建:在构建新系统时,在目标目录中执行安装和配置命令。

这些场景的共同需求是:改变进程看到的文件系统根。Linux 提供了两种主要机制:chrootpivot_root

chroot:最经典的根切换方式

基本用法

chroot 是一个系统调用(chroot(2)),也有对应的命令行工具:

# 准备一个最小根文件系统
mkdir -p /tmp/newroot/{bin,lib,lib64}
cp /bin/bash /tmp/newroot/bin/
# 复制 bash 依赖的库(略)
chroot /tmp/newroot /bin/bash

执行后,当前 shell 的根目录就变成了 /tmp/newroot,它无法通过 .. 或绝对路径访问原来的根。

面试常问:chroot 安全吗?

不安全。 这是面试官最想听到的回答。chroot 只改变了进程的根目录视图,但存在多个逃逸途径:

  1. root 用户可以直接逃逸:如果进程在 chroot 环境内拥有 CAP_SYS_CHROOT 能力或本身就是 root,它可以创建一个新目录,然后再次调用 chroot 并配合 chdir("..") 跳出。经典逃逸代码:
mkdir("escape", 0755);
chroot("escape");
chdir("../../../../../../../../");
chroot(".");
  1. 未关闭的文件描述符:如果进程在 chroot 之前打开了指向外部目录的文件描述符,可以通过 fchdir 回到外部。

  2. 挂载点泄漏:chroot 不隔离挂载命名空间,进程仍可能看到或访问某些挂载点。

因此,chroot 只适合做“文件系统视图切换”,不能作为安全隔离手段。真正安全的隔离需要配合 mount namespace、PID namespace、capability 限制等。

pivot_root:真正替换根文件系统

它解决什么问题

pivot_rootpivot_root(2) 系统调用,它的设计目标是原子地替换当前进程的根文件系统,并把旧根挂载到新根下的某个目录,之后可以卸载掉。

chroot 的关键区别:

  • pivot_root 要求新根必须是一个挂载点(mount point),不能是普通目录。
  • 它同时改变根目录和当前工作目录,且操作是原子的。
  • 旧根不会被丢弃,而是被挂载到新根下的一个目录,方便后续清理。
  • 通常配合 CLONE_NEWNS(mount namespace)使用,实现真正的隔离。

典型调用流程

// 1. 创建新根目录并挂载
mkdir("/newroot", 0755);
mount("/dev/sda1", "/newroot", "ext4", 0, NULL);

// 2. 创建旧根的挂载点
mkdir("/newroot/oldroot", 0755);

// 3. 切换根
pivot_root("/newroot", "/newroot/oldroot");

// 4. 切换工作目录
chdir("/");

// 5. 卸载旧根
umount2("/oldroot", MNT_DETACH);
rmdir("/oldroot");

面试常问:pivot_root 能完全替代 chroot 吗?

不能完全替代,但它是容器场景下的正确选择。原因:

  • pivot_root 要求新根是挂载点,某些场景下不方便满足(比如只是一个普通目录)。
  • 它通常需要 CAP_SYS_ADMIN 能力。
  • 在 mount namespace 中使用时,它只影响当前命名空间,这正是容器需要的。

容器运行时到底用哪个

这是面试中的“送分题”也是“区分题”。以 Docker、containerd、runc 为代表的容器运行时,实际流程大致是:

  1. 创建新的 mount namespace、PID namespace、UTS namespace 等。
  2. 准备容器的 rootfs(从镜像层叠加而来)。
  3. 优先使用 pivot_root 切换根文件系统,而不是 chroot
  4. 如果 pivot_root 失败(某些特殊环境),才回退到 chroot

runc 的源码中可以看到这个逻辑:在 prepareRootfs 阶段,它会先尝试 pivot_root,失败时再调用 chroot。这样做是因为 pivot_root 能更干净地卸载旧根,避免旧根文件系统被容器进程意外访问。

为什么容器不用 chroot 就够了

因为容器的安全边界不只靠根切换。它依赖的是:

  • namespace:mount、PID、network、UTS、IPC、user、cgroup。
  • cgroup:资源限制。
  • capabilities:能力裁剪。
  • seccomp:系统调用过滤。
  • LSM(SELinux/AppArmor):强制访问控制。

chrootpivot_root 只是其中“文件系统视图”这一环。单独用 chroot 做容器隔离,是极不安全的。

对比总结

特性 chroot pivot_root
系统调用 chroot(2) pivot_root(2)
新根要求 任意目录 必须是挂载点
旧根处理 不可见,但可能逃逸 挂载到新根下可卸载
原子性
安全隔离 弱,可逃逸 强,配合 namespace
容器中使用 回退方案 首选方案
所需权限 CAP_SYS_CHROOT CAP_SYS_ADMIN

面试回答建议

如果面试官问“chroot 和 pivot_root 有什么区别”,可以按这个结构回答:

  1. 先说两者都是切换根文件系统的机制,但设计目标不同。
  2. 说清 pivot_root 要求新根是挂载点、原子切换、旧根可卸载。
  3. 指出 chroot 的安全缺陷和逃逸方式。
  4. 最后落到容器场景:runc 优先用 pivot_root,失败回退 chroot,且根切换只是容器隔离的一环。

这样回答既展示了系统调用层面的理解,也体现了对容器运行时实现的熟悉,基本能覆盖面试官想考察的所有点。

延伸思考

  • 在 user namespace 中,非特权用户能否使用 pivot_root?答案是可以,因为 user namespace 内拥有 CAP_SYS_ADMIN,但受限于该命名空间。
  • chroot 后如何安全地降权?通常先 chroot,再 setuid 到非特权用户,并丢弃 capabilities。
  • 现代容器中 pivot_rootmount --moveopen_tree/move_mount 等新 API 的关系,也是加分项。

掌握这些内容,无论是面试还是实际排查容器根文件系统问题,都能做到心中有数。

未经允许不得转载:任鹏个人博客 » Linux 面试题:chroot、pivot_root 与容器根文件系统切换

赞 (0) 打赏

评论 0

取消
  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏