UniSan:防止操作系统内核中由未初始化导致的信息泄漏
UniSan: Proactive Kernel Memory Initialization to Eliminate Data Leakages
作者:卢康杰 (佐治亚理工学院)
(注:原文发表在ACM CCS 2016)
操作系统内核作为可信计算基(TCB),其安全性是至关重要的。为保证内核的安全性,多种安全机制已经被普遍应用,其中主要包括kASLR和StackGuard。然而这两种安全机制的有效性的前提是内核中没有信息泄漏。换句话说,如果有信息泄漏,kASLR和StackGuard将会变得没有意义,因为他们所依赖的一些随机值会被泄漏。那么问题来了,内核中信息泄露有吗?多吗?我们通过调研分析发现答案是肯定的:内核中存在大量的信息泄漏漏洞。比如,仅2013年就有近60个有CVE的Linux内核信息泄漏漏洞。我们的进一步研究发现大部分信息泄漏(大约60%)是因为读取未初始化内存(uninitialized data read)导致,如图1所示。
图1:导致Linux 内核信息泄漏原因统计(2013-2016年)
想象一下,如果你建立一个内存对象(memory object)但不去初始化它,那么你读取这个内存对象所得到的数据将会是以前遗留在内存中的一些数据。如果这些数据包含kASLR随机过的地址,StackGuard使用的随机canary,或者是之前用户遗漏的密码等重要信息,那么就会造成这些重要信息的泄漏。而导致读取未初始化内存的原因又分为两种:程序员的疏忽和编译器的优化。编译器的问题导致了一个严重且普遍的问题:即使程序员初始化一个对象中的所有成员,仍然有一些字节没有被初始化。代码1列出了一个例子。在这个例子中程序员初始化了内核堆栈对象“ci”的每一个成员,然而编译器在第二个成员“slow”之后插入的3个填充字节仍然没有初始化,当“copy_to_user”把未初始化字节拷贝给用户空间时导致信息泄漏。目前已经有很多攻击利用这样的信息泄漏来突破kASLR和StackGuard然后实现iOS越狱,Android root等等攻击。虽然这个问题这么严重,然而,目前并没有有效地防止读取未初始化内存的方法或工具。
代码1: 编译器优化插入未初始化的填充字节,导致信息泄漏
为了解决这个严重而又普遍的问题--读取未初始化导致信息安全泄漏,我们提出了一种基于LLVM编译器的方法。简单来说,我们通过细颗粒度的(字节级别),跨函数的,精确的可到达性和初始化性程序分析来检查是否存在这样一些不安全内存对象:存在至少一条程序路径使得一个内存对象在离开内核空间的时候并没有完全被初始化。当我们检测出这样的内存对象以后,我们会在内核中插入一些代码对这些内存对象进行置零初始化。在实现UniSan过程中,我们设计了很多方法来保证我们的程序分析的完全性(也就是没有漏报),比如我们解决了找间接调用对象的问题。目前我们已经基于LLVM实现了UniSan,并且用它来保护最新的Linux内核和Android内核。实验结果显示UniSan保护过的内核运行非常稳定,毫无问题。作为验证,我们发现UniSan能完全防止已有的信息安全漏洞并且发现大量的新漏洞。表1列出了目前已经被Linux和Google确认的19个新的信息泄漏漏洞。
表1:UniSan新发现Linux及Android内核信息泄漏漏洞
从性能角度看,UniSan几乎没有引起任何性能的降低(大多数情况下,性能影响小于0.5%)。综合这些实验结果,UniSan以一种有效的,高性能的,无漏报的方法解决了操作系统内核中由读取未初始化内存导致的普遍的信息泄漏问题。
更多细节请看UniSan文章:http://www.cc.gatech.edu/~klu38/publications/unisan-ccs16.pdf
作者介绍:
卢康杰是佐治亚理工学院一名5年级计算机科学博士生,导师为Wenke Lee和Taesoo Kim。他的研究兴趣是发现并解决系统安全,软件安全,及手机安全领域的根本性安全问题。他的研究成果颇受学术圈认可,目前他已经发表8篇四大顶级安全会议文章。如果对他的研究感兴趣,请看这里:http://www.cc.gatech.edu/~klu38。