Page 470 - 《软件学报》2026年第3期
P. 470
李志 等: 容器文件系统隔离增强机制 1433
影响, 这是由于漏洞修复手段局限于用户层面, 没有从根本上解决漏洞产生的原因. 目前的修复手段可能引入高性
能开销, 很容易被绕过, 甚至可能引入新的漏洞.
为了防止符号链接解析欺骗的发生, runC 会使用“securejoin”包的 SecureJoinVFS 函数来解析传进来的路径是
否合法, 却忽略了解析检查过程和随后的路径相关操作 (例如复制或挂载) 之间存在竞争条件, 可以通过 TOCTTOU
攻击 [27] 来利用恶意符号链接替换已验证的路径, 导致漏洞 CVE-2018-15664 [28] 、CVE-2021-25741、CVE-2021-
30465、CVE-2022-23648 和 CVE-2023-0778 [29] 等. Podman 为了避免此类竞争漏洞, 在 Podman 访问容器的文件系
统时暂停容器, 然而当 Podman 与冻结的容器交互时, 容器仍然可以访问与其他容器共享的卷并进行 TOCTTOU
攻击 [30] . 此外, 尽管 Podman 开发人员已经尽量避免此类漏洞的发生, Podman 的导出卷 (export volume) 功能还是
发现了一个类似 TOCTTOU 漏洞 CVE-2023-0778, 攻击者可以在导出卷时使用符号链接替换卷中的普通文件, 从
而能够访问主机文件系统上的任意文件.
在修复最早的符号链接欺骗漏洞 CVE-2017-1002101 时, 容器社区的思路是将解析检查过程和路径操作原子
化来消除竞争条件, 确保恶意用户通过 subPath 挂载的路径不是非预期的符号链接. 即使 Kubernetes 已经修复了
该漏洞, 但是其依赖组件中还是存在类似的攻击面, 导致了漏洞 CVE-2021-30465 和 CVE-2022-23648. 并且该修复
方案本身也引入了新的漏洞, 具体来说, 在使用 mount 系统调用之前, Kubernetes 会先使用 openat 打开子路径并验
证这个路径确实位于卷内, 提前验证路径的安全性, 然后 Kubernetes 使用特殊符号链接“/proc/[pid]/fd/[fd]”进行绑
定挂载 (bind mount), 此符号链接始终指向打开文件的文件描述符. 在 kubelet 仍然持有文件描述符的情况下, 即使
原始文件被替换, 这个特殊符号链接仍然会指向原始文件, 从而消除了竞争条件, 避免了类似攻击的发生. 但是这
种原子化能被后续操作调用的第三方可执行文件破坏. 在 Kubernetes 的卷功能中, 解析检查后调用的 Linux 挂载
工具 [31] 默认会解析该特殊链接, 并调用 mount 系统调用挂载解析结果, 这给漏洞 CVE-2021-25741 带来了机会.
CVE-2021-25741 的补丁只是在调用 mount 时传递了--no-canonicalize 参数, 使 mount 系统调用不再解析符号链接.
此外, 所有容器工具都努力避免执行非法文件, 但是仍有许多不可预见的执行隐藏于其功能中. 例如, 执行
Docker 提供的复制命令“docker cp”时使用了一个运行在主机命名空间的 docker-tar 进程 [32] , 为了修复漏洞 CVE-
2018-15664、防止出现符号链接解析问题影响到主机, docker-tar 会 chroot 到容器的根目录再归档其中请求的文
件及目录, 这样能确保所有符号链接都在其目录下被有效地解析. 但是这也为后续更严重的漏洞 CVE-2019-14271 [33]
埋下了伏笔. 一般而言, docker-tar 运行过程中需要从主机文件系统中加载动态链接库, 但是加载前 docker-tar 会
先 chroot 到容器文件系统, 最终导致所加载的动态链接库来源于不可信的容器环境. 此外, 虽然 docker-tar 会
chroot 到容器文件系统, 但是其本身仍运行在主机命名空间且具有 root 权限, 若所加载的容器中动态链接库存在
恶意代码, 该恶意代码将在宿主机上下文中以 root 权限运行, 进而完成容器逃逸. 容器社区通过在复制功能开始时
加载所有动态库来避免此漏洞, 但是 GNU CLibrary (glibc) [34] 的更新对任何容器工具都是透明的, 这一更新使得包
括“nsswitch”在内的 glibc 库在 chroot 触发上下文切换后能够自动重新加载, 可能会使此修复无效. 类似 CVE-2019-
14271 的漏洞还有 Podman 中的 CVE-2022-1227 漏洞 [35] . 该漏洞的原理是 podman top 功能调用了容器中的 nsenter
可执行文件.
2.3 文件描述符泄露漏洞原理及修复
文件描述符泄露漏洞的攻击者通过主机泄露在容器内的主机文件描述符来访问甚至修改对应的主机文件, 实
现容器逃逸, 图 3 展示了该类漏洞的攻击过程.
Proc 文件系统是 Linux 内核信息的抽象文件接口, 用于通过内核访问进程信息. 每个正在运行的进程都在
/proc 中有一个对应的目录, 命名为该进程的 PID. 这些目录包含了进程的各种状态和资源信息 [36] . 其中有一个子
目录/proc/[PID]/fd 包含了该 PID 所属进程打开的所有文件描述符, 通过查看这些文件描述符可以获取进程当前打
开的文件及其路径./proc/[PID]/exe 是一种指向进程自身对应的本地程序文件的特殊符号链接文件, 例如执行 ls 命
令时, /proc/[PID]/exe 会指向/bin/ls. 打开/proc/[PID]/exe 时, 若权限检查通过, 内核会直接返回指向目标文件的文件
描述符, 不需路径查找过程. 在主机与容器交互期间 (执行 docker exec 命令), 容器内的攻击者可能欺骗进入容器

