Docker 29.5.1 刚发布,核心改动只有一个但分量很重——堵上了 docker cp 命令中一个能让恶意容器以主机 root 身份执行任意代码的漏洞(CVE-2026-41567)。如果你在生产环境用 docker cp 从容器拷贝文件,尤其是以 root 运行 Docker daemon 的场景,这个版本必须跟进。
漏洞原理:PATH 解析被容器劫持
docker cp 在把容器内的文件拷出到主机时,需要对归档做解压处理。解压会调用主机上的工具,比如 xz、unpigz 等。Docker 的实现方式是通过 PATH 查找这些二进制文件。
问题出在这里:解压进程的 PATH 查找顺序会先扫容器文件系统。恶意容器可以在自己的 /usr/local/bin/xz 或类似路径放一个伪装的二进制。当主机 root 执行 docker cp 时,解压逻辑先在容器内找到了这个伪装的 xz,于是以主机 root 权限执行了容器植入的任意代码。
攻击链路简洁:
- 恶意镜像在容器内
/usr/local/bin/放一个名为xz(或unpigz)的可执行文件。 - 管理员在主机上以 root 运行
docker cp container:/some/file ./。 - Docker daemon 在解压归档时,PATH 优先命中容器内的伪装
xz。 - 伪装二进制以主机 root PID 运行——容器逃逸完成。
这意味着任何能让你执行 docker cp 的场景(CI 流水线、运维脚本、调试操作)都可能成为入口。
影响范围与严重性
- 前提条件:Docker daemon 以 root 运行(这是默认且最常见的部署方式)。
- 触发动作:对恶意容器执行
docker cp拷出文件。 - 后果:主机 root 权限的任意代码执行,等于完全控制宿主机。
Rootless Docker 不受此漏洞影响,因为 daemon 本身没有 root 权限,PATH 劫持也无法获得主机 root。但 rootless 部署目前仍是少数。
升级与验证
最直接的修复就是升级到 Docker 29.5.1:
# 查看当前版本
docker version --format '{{.Server.Version}}'
# Ubuntu/Debian:升级 Docker Engine
sudo apt-get update
sudo apt-get install docker-ce=29.5.1-1~ubuntu.$(lsb_release -cs)
# CentOS/RHEL
sudo yum install docker-ce-29.5.1-1.el9
# 升级后确认版本
docker version --format '{{.Server.Version}}'
# 期望输出:29.5.1
如果暂时无法升级,可以采取临时缓解措施:
# 方案一:确保主机 PATH 中解压工具的路径在容器路径之前
# 检查主机上 xz 和 unpigz 的位置
which xz unpigz
# 方案二:避免对不受信任的容器执行 docker cp
# 用替代方式拷出文件——在容器内主动推送,而不是从主机侧拉取
docker exec trusted-container cat /path/to/file > ./local-file
# 方案三:切换到 rootless Docker(长期方案)
# 安装 rootless docker
dockerd-rootless-setuptool.sh install
方案二的思路是反转操作方向:不再让 daemon 主动进入容器文件系统解压,而是让容器内部把内容吐出来,daemon 只做接收,不触发归档解压的 PATH 查找。
自检:你的环境是否暴露
跑一个快速检查脚本,确认风险面:
#!/usr/bash
# docker-cp-risk-check.sh — 快速评估 docker cp 漏洞风险
echo "=== Docker 版本 ==="
docker version --format 'Server: {{.Server.Version}}'
echo "=== Daemon 运行用户 ==="
ps -o user= -p $(cat /var/run/docker.pid 2>/dev/null || echo 1) 2>/dev/null || echo "无法获取"
echo "=== 主机解压工具路径 ==="
for tool in xz unpigz gzip; do
path=$(which $tool 2>/dev/null)
if [ -n "$path" ]; then
echo "$tool -> $path"
else
echo "$tool -> 未安装"
fi
done
echo "=== 近期 docker cp 使用记录 ==="
# 从审计日志或 bash history 中查找
grep -c 'docker cp' /var/log/audit/audit.log 2>/dev/null || echo "无 auditd 日志"
grep -c 'docker cp' ~/.bash_history 2>/dev/null || echo "history 中无记录"
echo "=== 建议 ==="
server_ver=$(docker version --format '{{.Server.Version}}' 2>/dev/null)
if [ "$server_ver" != "29.5.1" ]; then
echo "⚠ 当前版本 $server_ver 不等于 29.5.1,建议立即升级"
else
echo "✓ 已为安全版本 29.5.1"
fi
chmod +x docker-cp-risk-check.sh
sudo ./docker-cp-risk-check.sh
升级之外的长期防线
单次升级堵住了这一个 PATH 解析问题,但同类风险可能还有其他变体。几个值得固化的习惯:
- CI/CD 中禁止对随机镜像执行
docker cp。流水线需要从容器取文件时,改用docker exec让容器主动输出,或用 volume mount 替代拷贝。 - 审计 docker cp 调用。在启用了 auditd 的主机上加一条规则:
# 记录所有 docker cp 调用
sudo auditctl -a always,exit -F path=/usr/bin/docker -F perm=x -k docker-cp
# 查看记录
sudo ausearch -k docker-cp | aureport -x
- 向 rootless Docker 迁移。这是从根本上消除"daemon 以 root 运行"这一大类漏洞的路径。Docker 官方已将 rootless 模式标记为稳定可用,新部署值得优先考虑。
- 镜像准入检查。在拉取第三方镜像前,扫一遍里面有没有可疑的 PATH 路径覆盖:
# 检查镜像内 /usr/local/bin 是否包含 xz/unpigz 等解压工具名
docker run --rm suspicious-image:tag \
find /usr/local/bin -name 'xz' -o -name 'unpigz' -o -name 'gzip' 2>/dev/null
# 如果有输出,说明镜像在覆盖系统解压工具——高度可疑
小结
CVE-2026-41567 的攻击路径短、前提条件常见(root daemon + docker cp)、后果严重(主机 root 逃逸)。升级到 29.5.1 是必须动作;短期内改用 docker exec cat 替代 docker cp 拷出文件是有效缓解;长期向 rootless Docker 迁移和加强镜像准入审计才是同类问题的系统性防线。