文/盧康杰
UniSan:防止操作系統內核中由未初始化導致的信息泄漏
文/盧康杰

盧康杰
佐治亞理工學院一名5年級計算機科學博士生,導師為Wenke Lee和Taesoo Kim。他的研究興趣是發現并解決系統安全,軟件安全,及手機安全領域的根本性安全問題。他的研究成果頗受學術圈認可,目前他已經發表8篇四大頂級安全會議的文章。
個人主頁:
http://www.cc.gatech.edu/~klu38。
操作系統內核作為可信計算基(TCB),其安全性是至關重要的。為保證內核的安全性,多種安全機制已經被普遍應用,其中主要包括kASLR和StackGuard。然而這兩種安全機制的有效性的前提是內核中沒有信息泄漏。換句話說,如果有信息泄漏,kASLR和StackGuard將會變得沒有意義,因為它們所依賴的一些隨機值會被泄漏。那么問題來了,內核中是否存在大量的信息泄露?我們通過調研分析發現答案是肯定的:內核中存在大量的信息泄漏漏洞。比如,僅2013年就有近60個有CVE的Linux內核信息漏洞。隨著進一步研究發現大部分信息泄漏(大約60%)是因為讀取未初始化內存(uninitialized data read)導致,如圖1所示。
可以想象一下,如果建立一個內存對象(memory object)但不去初始化它,那么讀取這個內存對象所得到的數據將會是以前遺留在內存中的一些數據。如果這些數據包含kASLR隨機過的地址,StackGuard使用的隨機canary,或者是之前用戶遺漏的密碼等重要信息,那么就會造成這些重要信息的泄漏。而導致讀取未初始化內存的原因又分為兩種:程序員的疏忽和編譯器的優化。編譯器的問題導致了一個嚴重且普遍的問題:即使程序員初始化一個對象中的所有成員,仍然有一些字節沒有被初始化。代碼1列出了一個例子。在這個例子中程序員初始化了內核堆棧對象“ci”的每一個成員,然而編譯器在第二個成員“slow”之后插入的3個填充字節仍然沒有初始化,當“copy_ to_user”把未初始化字節拷貝給用戶空間時導致信息泄漏。目前已經有很多攻擊利用這樣的信息泄漏來突破kASLR和StackGuard然后實現iOS越獄,Android root等等攻擊。雖然這個問題這么嚴重,然而,目前并沒有有效地防止讀取未初始化內存的方法或工具。

圖1 導致Linux 內核信息泄漏原因統計(2013-2016年)
為了解決這個問題讀取未初始化導致信息安全泄漏,我們提出了一種基于LLVM編譯器的方法。簡單來說,需要通過細顆粒度的(字節級別)、跨函數的、精確的可到達性和初始化性程序分析來檢查是否存在這樣一些不安全內存對象:存在至少一條程序路徑使得一個內存對象在離開內核空間的時候并沒有完全被初始化。當檢測出這樣的內存對象以后,我們會在內核中插入一些代碼對這些內存對象進行置零初始化。在實現UniSan過程中,通過設計很多方法來保證程序分析的完全性(也就是沒有漏報),比如解決了找間接調用對象的問題。目前已經基于LLVM實現了UniSan,并且用它來保護最新的Linux內核和Android內核。實驗結果顯示UniSan保護過的內核運行非常穩定,毫無問題。作為驗證,我們發現UniSan能完全防止已有的信息安全漏洞并且發現大量的新漏洞。

代碼1 編譯器優化插入未初始化的填充字節,導致信息泄漏
從性能角度看,UniSan幾乎沒有引起任何性能的降低(大多數情況下,性能影響小于0.5%)。綜合這些實驗結果,UniSan以一種有效的,高性能的,無漏報的方法解決了操作系統內核中由讀取未初始化內存導致的普遍的信息泄漏問題。
(注:原文發表在ACM CCS 2016,更多細節請看UniSan文章:http://www.cc.gatech.edu/~klu38/ publications/unisan-ccs16.pdf)