Linux内核动态内存隔离技术解析

本文深入探讨Linux内核动态内存隔离机制如何防御use-after-free漏洞利用,分析SLAB_QUARANTINE的安全特性与性能影响,并揭示针对该保护机制的绕过技术。

Linux内核动态内存隔离机制

2020年12月29日 | Alexander Popov

Linux内核中的释放后使用漏洞

Linux内核中的UAF(use-after-free)漏洞是攻击者最常利用的漏洞类型之一。存在大量公开的UAF内核漏洞利用原型:

  • CVE-2016-8655
  • CVE-2017-6074
  • CVE-2017-2636
  • CVE-2017-15649
  • CVE-2019-18683

利用UAF通常采用堆喷技术(heap spraying),目的是将攻击者控制的数据放置到特定的动态内存区域(称为"堆")。Linux内核中利用UAF的堆喷技术基于kmalloc()调用时,slab分配器返回最近释放的内存地址:

![堆喷技术示意图]

通过创建相同大小的可控内核对象,可以覆盖已释放的易受攻击对象:

![对象覆盖示意图]

技术方案

2020年7月,我产生了对抗Linux内核UAF堆喷技术的想法。8月份开始实验,从KASAN功能中分离出slab分配器的隔离机制,命名为SLAB_QUARANTINE。

启用该机制后,释放的内存分配会被放入隔离队列等待实际释放,因此无法被UAF漏洞利用立即重新分配和覆盖:

![隔离机制示意图]

SLAB_QUARANTINE安全特性

为了研究内核动态内存隔离的安全特性,我开发了两个lkdtm测试:

1. lkdtm_HEAP_SPRAY测试

1
2
3
4
#define SPRAY_LENGTH 400000
addr = kmem_cache_alloc(spray_cache, GFP_KERNEL);
kmem_cache_free(spray_cache, addr);
// ... 分配40万个对象测试

禁用CONFIG_SLAB_QUARANTINE时,释放的对象立即被重新分配:

1
lkdtm: FAIL: attempt 0: freed object is reallocated

启用隔离后,40万次分配不会覆盖释放的对象:

1
lkdtm: OK: original heap spraying hasn't succeeded

2. lkdtm_PUSH_THROUGH_QUARANTINE测试

该测试通过40万次分配释放操作推动对象通过隔离队列,结果显示对象在特定尝试次数后被重新分配:

1
lkdtm: Target object is reallocated at attempt 182994

随机化改进

为了解决重分配尝试次数相对稳定的问题,我开发了隔离随机化机制。对象在隔离区中以"批次"存储,释放时随机选择批次和对象:

1
2
3
lkdtm: Target object is reallocated at attempt 107884
lkdtm: Target object is reallocated at attempt 265641
lkdtm: Target object is NOT reallocated in 400000 attempts

性能测试

在不同配置下进行性能测试:

  1. iperf网络吞吐量测试

    • init_on_free=on 比 off 低28%
    • SLAB_QUARANTINE 比 init_on_free=on 低2%
  2. hackbench调度器负载测试

    • init_on_free=on 慢5.3%
    • SLAB_QUARANTINE 慢91.7%(物理机)/ 44%(虚拟机)
  3. 内核编译测试

    • init_on_free=on 慢1.7%
    • SLAB_QUARANTINE 慢1.1%

绕过攻击

Jann Horn提出了有效的绕过方法:攻击者可以使用其他slab缓存进行大量分配释放操作,冲刷隔离队列使目标对象返回分配器的空闲列表,然后使用标准堆喷技术利用UAF。

结论

虽然未能创建出进入mainline的可靠防护机制,但这项研究提供了有价值的结果和思路,将为后续Linux内核防护工作提供参考。

Quarantine patch version three
Won’t appear. No need.
Let’s exploit use-after-free
Like we always did ;)

— a13xp0p0v

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计