linux内存管理中的缓存失效漏洞
字数 1837 2025-08-20 18:18:17

Linux内存管理中的缓存失效漏洞分析与利用教学

漏洞概述

CVE-2018-17182是Linux内核从3.16版本开始存在的一个VMA(虚拟内存区域)缓存失效漏洞。该漏洞存在于内核的虚拟内存管理子系统中,特别是与VMA缓存机制相关,可能导致use-after-free情况,最终可能被利用来提升权限。

漏洞背景

VMA缓存机制

Linux内核使用VMA(虚拟内存区域,struct vm_area_struct)来管理进程的虚拟内存空间。为了提高性能,内核实现了两种查找VMA的路径:

  1. 慢路径:通过红黑树查找VMA
  2. 快路径:使用per-thread的VMA缓存

从3.15版本开始,Linux使用有四个插槽的per-thread VMA缓存,在mm/vmacache.cinclude/linux/vmacache.h中实现。

缓存失效机制

当VMA被释放时,必须使所有线程的VMA缓存失效。为了避免性能问题,系统使用序列号机制:

  • struct mm_struct和per-thread的struct vmacache都有序列号
  • current->vmacache.seqnumcurrent->mm->vmacache_seqnum不匹配时,擦除当前线程的VMA缓存

序列号长度为32位,可能溢出。当current->mm->vmacache_seqnum溢出归零时,会调用vmacache_flush_all()来擦除所有相关VMA缓存。

漏洞根源

在3.16版本中引入了一个优化:如果mm_struct只与单个线程关联,则vmacache_flush_all()不执行任何操作。这个优化不正确,因为:

  1. 单线程进程在mm_struct序列号归零后立即创建新线程
  2. 第一个线程的VMA缓存序列号仍为0xffffffff
  3. 第二个线程可以再次驱动mm_struct序列号到0xffffffff
  4. 此时第一个线程的VMA缓存(可能包含空指针)将再次被视为有效

漏洞利用

利用前提

  1. 能够运行足够长时间来溢出引用计数器(约1小时)
  2. 能够使用mmap()/munmap()clone()
  3. 这些系统调用在大多数seccomp沙箱中都可用

利用步骤

  1. 增加序列号

    • 创建跨越三个页面的匿名VMA
    • 使用MAP_FIXEDmmap()重复替换中间页面
    • 每次操作导致两个序列号增量
  2. 替换VMA

    • 释放vm_area_struct使其回到页面分配器
    • 使用BPF maps重新分配页面并放置受控数据
  3. 从dmesg泄露指针

    • 触发WARN_ON_ONCE()获取寄存器转储
    • 从转储中提取:
      • mm_struct地址(RDI)
      • use-after-free的VMA地址(RAX)
      • 内核代码地址(R8)
  4. 构造伪VMA

    • 使用泄露的指针构造包含正确mm_struct指针的伪VMA
    • 填充其他必要字段
  5. JOP(跳转导向编程)利用

    • 通过控制的VMA结构获得指令指针控制
    • 使用JOP链控制执行流
    • 最终调用run_cmd()生成root特权用户模式助手

漏洞修复

修复方案:

  1. 将序列号改为64位,消除溢出可能性
  2. 删除溢出处理逻辑

修复时间线:

  • 2018-09-12:漏洞报告
  • 2018-09-14:上游内核修复
  • 2018-09-19:向后移植到稳定内核(4.18.9, 4.14.71, 4.9.128, 4.4.157, 3.16.58)

安全影响与缓解

影响因素

  1. 内核配置:

    • kernel.panic_on_oops:控制BUG_ON()是否导致内核崩溃
    • kernel.dmesg_restrict:控制非root用户访问dmesg日志
  2. 默认配置:

    • Ubuntu等发行版默认不限制dmesg访问
    • 允许攻击者读取崩溃信息进行二次攻击

缓解措施

  1. 启用kernel.dmesg_restrict
  2. 考虑启用kernel.panic_on_oops
  3. 及时更新内核

教学总结

  1. 漏洞本质:由于VMA缓存序列号处理不当导致的use-after-free
  2. 利用关键
    • 序列号溢出触发条件
    • 信息泄露通过dmesg
    • JOP控制执行流
  3. 防御要点
    • 合理的内核配置
    • 及时的安全更新
    • 限制调试信息访问

此漏洞展示了内核内存管理子系统中看似微小的优化可能引入严重安全问题,也体现了安全与性能之间的权衡需要考虑周全。

Linux内存管理中的缓存失效漏洞分析与利用教学 漏洞概述 CVE-2018-17182是Linux内核从3.16版本开始存在的一个VMA(虚拟内存区域)缓存失效漏洞。该漏洞存在于内核的虚拟内存管理子系统中,特别是与VMA缓存机制相关,可能导致use-after-free情况,最终可能被利用来提升权限。 漏洞背景 VMA缓存机制 Linux内核使用VMA(虚拟内存区域,struct vm_ area_ struct)来管理进程的虚拟内存空间。为了提高性能,内核实现了两种查找VMA的路径: 慢路径 :通过红黑树查找VMA 快路径 :使用per-thread的VMA缓存 从3.15版本开始,Linux使用有四个插槽的per-thread VMA缓存,在 mm/vmacache.c 和 include/linux/vmacache.h 中实现。 缓存失效机制 当VMA被释放时,必须使所有线程的VMA缓存失效。为了避免性能问题,系统使用序列号机制: struct mm_struct 和per-thread的 struct vmacache 都有序列号 当 current->vmacache.seqnum 和 current->mm->vmacache_seqnum 不匹配时,擦除当前线程的VMA缓存 序列号长度为32位,可能溢出。当 current->mm->vmacache_seqnum 溢出归零时,会调用 vmacache_flush_all() 来擦除所有相关VMA缓存。 漏洞根源 在3.16版本中引入了一个优化:如果 mm_struct 只与单个线程关联,则 vmacache_flush_all() 不执行任何操作。这个优化不正确,因为: 单线程进程在 mm_struct 序列号归零后立即创建新线程 第一个线程的VMA缓存序列号仍为0xffffffff 第二个线程可以再次驱动 mm_struct 序列号到0xffffffff 此时第一个线程的VMA缓存(可能包含空指针)将再次被视为有效 漏洞利用 利用前提 能够运行足够长时间来溢出引用计数器(约1小时) 能够使用 mmap() / munmap() 和 clone() 这些系统调用在大多数seccomp沙箱中都可用 利用步骤 增加序列号 : 创建跨越三个页面的匿名VMA 使用 MAP_FIXED 的 mmap() 重复替换中间页面 每次操作导致两个序列号增量 替换VMA : 释放 vm_area_struct 使其回到页面分配器 使用BPF maps重新分配页面并放置受控数据 从dmesg泄露指针 : 触发 WARN_ON_ONCE() 获取寄存器转储 从转储中提取: mm_struct 地址(RDI) use-after-free的VMA地址(RAX) 内核代码地址(R8) 构造伪VMA : 使用泄露的指针构造包含正确 mm_struct 指针的伪VMA 填充其他必要字段 JOP(跳转导向编程)利用 : 通过控制的VMA结构获得指令指针控制 使用JOP链控制执行流 最终调用 run_cmd() 生成root特权用户模式助手 漏洞修复 修复方案: 将序列号改为64位,消除溢出可能性 删除溢出处理逻辑 修复时间线: 2018-09-12:漏洞报告 2018-09-14:上游内核修复 2018-09-19:向后移植到稳定内核(4.18.9, 4.14.71, 4.9.128, 4.4.157, 3.16.58) 安全影响与缓解 影响因素 内核配置: kernel.panic_on_oops :控制BUG_ ON()是否导致内核崩溃 kernel.dmesg_restrict :控制非root用户访问dmesg日志 默认配置: Ubuntu等发行版默认不限制dmesg访问 允许攻击者读取崩溃信息进行二次攻击 缓解措施 启用 kernel.dmesg_restrict 考虑启用 kernel.panic_on_oops 及时更新内核 教学总结 漏洞本质 :由于VMA缓存序列号处理不当导致的use-after-free 利用关键 : 序列号溢出触发条件 信息泄露通过dmesg JOP控制执行流 防御要点 : 合理的内核配置 及时的安全更新 限制调试信息访问 此漏洞展示了内核内存管理子系统中看似微小的优化可能引入严重安全问题,也体现了安全与性能之间的权衡需要考虑周全。