Cross cache Attack技术细节分析
字数 2035 2025-08-22 12:22:54
Cross Cache Attack 技术深度分析与实践指南
1. 技术概述
Cross Cache Attack(跨缓存攻击)是一种针对Linux内核SLUB分配器的高级利用技术,通过精心控制slab页面的分配与释放过程,实现将目标slab页面释放回伙伴系统(buddy system),然后重新申请该页面用于其他用途的攻击方法。
2. 前置知识
2.1 SLUB分配器核心概念
- slab:内存管理的基本单位,由单个或多个连续页面组成
- object:slab中分配的实际内存单元
- cpu_partial:每个CPU部分空闲slab链表的最大数量阈值
- objs_per_slab:每个slab中包含的object数量
- partial list:部分空闲的slab链表
2.2 关键数据结构
struct kmem_cache {
unsigned int cpu_partial; // 每个CPU partial列表中的最大slab数量
struct kmem_cache_order_objects oo; // 包含order和objects_per_slab信息
// ... 其他字段
};
struct page {
void *freelist; // 空闲对象链表
unsigned counters; // 包含inuse、frozen等状态
// ... 其他字段
};
3. 攻击原理与技术细节
3.1 核心攻击流程
- 释放slab page:通过特定操作将目标slab释放回伙伴系统
- 重新申请页面:从伙伴系统中重新获取该页面用于其他目的
- 实现跨缓存控制:利用页面重用实现不同类型对象间的控制
3.2 关键技术步骤
步骤1:申请(cpu_partial+1) * objs_per_slab个objects
- 目的:占用足够多的slab,为后续操作做准备
- 计算公式:
(cpu_partial + 1) * objs_per_slab - 结果:占用14个完整slab,第15个slab不满
步骤2:申请objs_per_slab-1个objects
- 目的:使部分slab接近满状态
- 操作:继续申请直到一个slab几乎满
步骤3:申请UAF object
- 目的:创建待利用的对象
- 位置:该对象位于第16个slab中
- 关键点:记录该对象及其所在页面的地址
步骤4:申请objs_per_slab + 1个objects
- 目的:使UAF object所在的slab页满载
- 效果:确保后续释放操作能触发特定路径
步骤5:释放UAF object
- 关键行为:触发
put_cpu_partial()但未达到阈值 - 结果:slab被挂载到partial链上
步骤6:释放UAF object所在页的所有object
- 目的:使目标slab变为空状态
- 操作:释放该页面上所有其他object
步骤7:释放1-14 slabs中各一个object
- 关键机制:
- 每个释放操作触发
put_cpu_partial() - 达到
cpu_partial阈值(13)后触发unfreeze_partials() - 空slab被
discard_slab()释放回伙伴系统
- 每个释放操作触发
4. 代码实现分析
4.1 关键内核API
// 创建专用缓存
kmem_cache_create("name", size, align, flags, ctor);
// 从缓存分配对象
kmem_cache_alloc(cachep, flags);
// 释放对象回缓存
kmem_cache_free(cachep, obj);
// 从伙伴系统分配页面
alloc_pages(GFP_KERNEL, order);
// 获取页面虚拟地址
page_address(page);
4.2 攻击演示代码关键部分
// 步骤1:初始分配
for (i = 0; i < (cpu_partial + 1) * objs_per_slab; i++) {
ds_list[ds_sp++] = kmem_cache_alloc(my_cache_ptr, GFP_KERNEL);
}
// 步骤3:创建UAF对象
uaf_object = kmem_cache_alloc(my_cache_ptr, GFP_KERNEL);
target_page_virt = (void*)((unsigned long)uaf_object & ~(unsigned long)(page_size - 1));
// 步骤5-7:精心控制的释放过程
kmem_cache_free(my_cache_ptr, uaf_object);
// ... 其他释放操作
// 重新申请目标页面
realloc_page = alloc_pages(GFP_KERNEL, page_order);
realloc_page_virt = page_address(realloc_page);
5. 内核源码关键路径分析
5.1 释放路径调用链
kmem_cache_free()
slab_free()
do_slab_free()
__slab_free()
put_cpu_partial()
unfreeze_partials()
discard_slab()
free_slab()
__free_pages() // 最终释放到伙伴系统
5.2 关键函数逻辑
__slab_free():
- 检查slab状态(frozen, inuse等)
- 决定是否进入
put_cpu_partial() - 处理满slab释放第一个object的情况
put_cpu_partial():
- 维护per-CPU partial链表
- 检查
pobjects > slub_cpu_partial(s)阈值 - 触发
unfreeze_partials()当超过阈值时
unfreeze_partials():
- 将partial slabs转移到节点列表
- 对空slab(
!new.inuse)调用discard_slab() - 需要满足
n->nr_partial >= s->min_partial
6. 防御与缓解措施
-
SLUB加固选项:
CONFIG_SLUB_DEBUG:启用调试检查CONFIG_SLUB_HARDENED:强化安全性
-
内核参数调整:
- 增加
cpu_partial阈值 - 调整
min_partial值
- 增加
-
代码审计重点:
__slab_free()中的状态转换unfreeze_partials()的空slab处理逻辑
7. 实际应用场景
- 类型混淆攻击
- Use-after-free漏洞利用
- 内核提权漏洞利用
- 容器逃逸攻击
8. 相关CVE案例
- CVE-2022-29582
- CVE-2021-20226 (io_uring权限提升)
9. 扩展思考
- 与页表攻击的结合:如何利用该技术实现页表控制
- 在多核环境下的变种:针对SMP系统的优化攻击
- 新型防御机制的绕过:针对现有防护措施的对抗技术
10. 实验环境搭建建议
- 内核版本:5.15.0-122(与示例代码兼容)
- 调试工具:
slabinfo查看slab状态gdb内核调试crash工具分析内存状态
- 测试模块:确保可加载内核模块功能开启
通过深入理解Cross Cache Attack的技术细节,安全研究人员可以更好地评估内核内存管理的安全性,并开发更有效的防御机制。