賈巧雯 馬昊玉 厲 嚴 王哲宇 石文昌
1(中國科學院軟件研究所 北京 100190) 2(中國科學院大學 北京 100049) 3(西安電子科技大學網絡與信息安全學院 西安 710126) 4(中國人民大學信息學院 北京 100872)
長期以來,基于漏洞利用和惡意代碼的攻擊一直是計算機軟件與操作系統安全所面臨的主要威脅之一.在各類計算機系統當中,嵌入式操作系統(如車載系統、部分互聯網關鍵節點和一些能源/制造業關鍵設備等),以及在該類平臺上運行的應用軟件,是漏洞利用和惡意代碼攻擊所關注的高價值目標.因此,建立針對嵌入式操作系統的可信計算平臺,對于推進面向未來的互聯網安全生態有著重要的意義.
1)完整性度量架構及其研究現狀
在與漏洞利用及其后續可能發起的惡意代碼植入攻擊的對抗中,完整性度量架構(integrity mea-surement architecture, IMA)是為計算平臺可信性提供保護的重要技術之一.2004年,文獻[1]采用了IMA的概念,并提出了一種以可信計算組織(trusted computing group, TCG)規范(1)TCG Specification Architecture Overview Revision 1.4, https://trustedcomputinggroup.org/wp-content/uploads/TCG_1_4_Architecture_Overview.pdf為基礎的IMA方案.在此方案基礎上,后續研究通過引入權限分級的訪問控制策略或采用經過哈希運算和加密處理的壓縮度量值等方式[2-3],進一步降低了實施IMA對系統負載的壓力,形成了多種較為完備的靜態完整性度量方法.然而,基于文件的完整性度量機制僅能夠在文件加載至內存時驗證其當前完整性狀態,這使得該類IMA系統無法對針對內存的運行時完整性損害予以響應,包括:
① 針對駐留內存的代碼文本的篡改行為.如基于hooking的控制流篡改、自修改代碼(self-modifying code)等.
② 不依賴靜態文件、直接向內存注入惡意代碼的攻擊行為.例如,利用緩沖區溢出漏洞、以數據形態注入惡意代碼、再借助代碼重用攻擊(code-reuse attack)修改頁面權限使所注入代碼可被執行的惡意代碼動態載入攻擊.
因此,動態完整性度量架構作為一種改進策略被提出[4-10].現有該類方案往往利用系統內核機制(如Linux系統的內核全鏡像機制[6])或特定硬件(如輔助處理器[7])的支持,對駐留在內存中的系統關鍵完整性狀態進行運行時驗證.除了系統內核的代碼文本外,一些方案還支持對系統中各進程所維護的關鍵上下文狀態和環境參數的完整性予以監控[8-10],或通過與用戶態進程的交互實現對其運行時完整性的驗證[6,8,10].目前,IMA技術已經被擴展應用至基于hypervisor的虛擬化環境[11-13]、軟件虛擬機[14-15]以及軟件控制流完整性驗證(control flow integrity, CFI)[16]等多個有關系統完整性驗證的安全應用場景中.
近兩年來,一些針對嵌入式設備及系統的動態完整性度量架構方案被陸續提出[17-21].Wehbe等人[17]利用獨立硬件芯片對嵌入式系統各進程內的可執行文本實施基于頁面的運行時度量和驗證.Qin等人[18]和Ling等人[19]各自提出了一種基于可信執行環境(trusted execution environment, TEE)的物聯網設備運行時完整性保護系統.其中,文獻[18]通過代碼插樁攔截用戶進程發起的函數調用及其返回等控制流行為,并在提供代碼完整性驗證的同時支持CFI功能;文獻[19]則在TrustZone機制的支持下周期性地對用戶代碼實施基于頁面的完整性度量.Duan等人[20]提出了一種基于TEE虛擬化架構的系統完整性度量方案,通過在TEE-visor層部署度量組件,實現同時對多個虛擬TEE環境以及正常執行環境內的系統代碼和系統調用的可信完整性校驗.Cheng等人[21]提出了一種針對航空片上系統(system-on-a-chip, SoC)的可信控制架構,通過專用的監控硬件架構為系統提供動態完整性度量保護.
然而,現有動態/靜態IMA方案在應用于計算資源有限、同時又對運行性能較為敏感的嵌入式設備時,往往存在3方面的局限性:
① 針對位置無關代碼所依賴的重定位和動態鏈接信息,現有IMA方案缺乏有效的校驗策略.以Linux為例,其ELF文件的重定位由過程鏈接表(procedure linkage table, PLT)和全局偏移表(global offset table, GOT)配合完成.其中,GOT由動態鏈接器在文件加載時實時填充,全過程均在用戶態完成,這使得針對GOT的完整性度量問題成為IMA技術的一個兩難困境:若嚴格服從權限隔離原則并將IMA部署于內核空間或可信平臺模塊(trusted platform module, TPM)中,則將因缺乏適當的態勢感知手段而難以及時地捕捉到用戶進程中文件重定位和動態鏈接行為的發生時機,因而無法及時算得GOT載入完成后的完整性基線、難以實現對其進行動態完整性驗證的目標;反之,若在用戶進程空間內部署輔助接口、以插樁動態鏈接器等方式直接在用戶空間內攔截動態鏈接行為并為GOT生成完整性基線,又將不可避免地將負責實施該功能的IMA組件直接暴露在攻擊者視野中,使得IMA架構的整體可信任性產生瑕疵.
② 現有IMA方案無法與包括代碼熱修復(hot-fix)在內的一些特殊的運行時代碼加載/改寫場景實現有效的兼容.具體來說,由于主流代碼熱修復方法在實現原理上與基于hooking的惡意代碼動態載入基本一致,僅憑通用的常規技術無法將兩者加以區分.這意味著應用IMA功能的系統可能無法同時啟用熱修復機制,這將有可能嚴重地限制系統對0-day漏洞的應急響應能力.
③ 對于嵌入式系統而言,現有IMA造成的性能開銷往往超出了工程實踐可以接受的范疇.例如,文獻[18]引入了細粒度動態插樁和CFI等保護機制,使得單個應用程序由此承受了十幾甚至上百倍的運行時性能開銷.文獻[17]和文獻[19]所采用的基于頁面的完整性度量機制則占用了大量運行內存空間以維護針對具體內存頁面的完整性基線.以glibc為例,該基本系統庫的2.3.2版本在加載后的代碼段大小為1 208 KB,對應302個頁面,在考慮使用SHA256等安全哈希算法的情況下,僅該系統庫一例,即需要占用9 KB內存以維護其代碼完整性基線,這還未將運行時如何實現對海量基線的索引問題納入考慮范疇.由于嵌入式系統受到物理約束的限制,所能夠利用的硬件資源,包括CPU主頻、CPU核心數量、運行內存大小等往往極為有限,并需要在滿足最小軟硬件需求的情況下保證實時性.故在性能開銷方面,多數嵌入式系統很可能并不具備現有的大多數IMA方案所需的擴展空間.
2)創新點與貢獻
針對現有IMA方案存在的完備性不足、無法兼容軟件熱修復、性能開銷較大等問題,本文提出了一種應用于嵌入式Linux系統的高性能內核級動態完整性度量架構(dymamic integrity measurement architecture at kernel-level, DIMAK).利用Linux內核自身定義的進程空間和頁面管理機制,DIMAK將自身組件完全部署在系統內核空間,并通過攔截與代碼加載/改寫行為、進程創建行為以及系統shell命令執行有關的關鍵系統調用等方式,實現以虛擬地址映射分段為基本度量單元、面向運行內存而非文件存儲的運行時完整性驗證.根據進程參數、代碼文本、重定位和動態鏈接數據等各種被度量實體所具有的不同初始化時機,DIMAK確立了一套動態/靜態基線相結合、基于最小信任根的逐級信任擴展策略.在上述底層設計基礎上,DIMAK方案的一個核心創新點在于提出了一種內核級的“進取型動態鏈接預測技術”,使其能夠在不暴露于用戶空間且無需動態鏈接器主動配合的情況下正確地計算出用戶態位置無關代碼所對應重定位和動態鏈接信息的完整性基線.這一機制允許DIMAK在與用戶空間保持完全權限隔離的情況下,將針對用戶進程的完整性保護擴展到與可執行行為完整性相關的所有要素上,從而實現了現有方案無法達成的高度完備性.此外,DIMAK的另一個關鍵創新點是將軟件熱修復行為納入系統內核的標準內存管理,從而在完整性驗證過程中有效地將該場景與惡意代碼篡改行為加以區分.通過提供專用系統調用,DIMAK以其內核態組件接管了軟件熱修復過程中所涉及的補丁代碼加載、被修復程序改寫等工作,確保所涉及的完整性基線能夠被及時地生成和更新,實現了將軟件熱修復納入系統運行時信任依賴的范疇中這一安全目標.
簡而言之,本文所述DIMAK方案的主要創新性貢獻可總結為:
① 在技術層面上.DIMAK通過其進取型動態鏈接預測技術,解決了過往IMA方案因缺乏針對重定位和動態鏈接信息的完整性基線獲取手段而存在的完備性缺陷,即無法完全部署在內核態.
② 在工程層面上.DIMAK在不損害系統安全性的前提下,實現了IMA方案對代碼熱修復場景的支持,在實用安全性能方面實現了零的突破.
模擬環境和真機測試顯示,DIMAK主要工作于系統日常運行過程中占比極低的代碼加載階段,故其運行時總體性能開銷和內存占用均顯著低于現有同類方案,并能良好地適應嵌入式設備可能具有的硬件配置情況.
現有各類IMA方案在適配嵌入式系統時所存在的一些實用性方面的不足,究其原因,在于當前針對IMA等可信計算概念的研究往往傾向于設置越來越高的安全目標以使得所設計的方案能夠“兼容并包”地對抗多種類型的威脅對手.為此,相關方案不斷引入開銷較大的度量機制,所采用的度量策略則向著高度實時、細粒度化的方向發展[9-10,18].然而,不同于通用系統,嵌入式系統的應用場景往往比較單一,其體量也相對較小,故嵌入式系統對IMA方案的需求也有所不同.
1)應用場景單一使得嵌入式系統所受的攻擊面較小,且無需考慮通用系統可能面臨的諸多不確定性,如安裝/卸載任意應用帶來的不可預測的系統完整性基線變更等.
2)體量較小,意味著嵌入式系統要求IMA方案必須在計算資源極為有限的情況下仍具備可用性;否則,無論其預期安全目標如何強大,還是難免因無法部署而成為無本之木.
特別需要指出的是,現有IMA方案中額外引入的細粒度執行狀態度量等機制(如CFI等)主要以不確定性系統環境中的任意執行行為和以代碼重用為代表的高級漏洞利用編碼技術為防護對象.然而,代碼重用本質上是一種漏洞利用手段而非后果,其對目標系統的潛在影響也并未脫離傳統漏洞利用方法的威脅模型范疇.例如,當通過漏洞利用實施權限提升攻擊時,無論是否以代碼重用為載荷編碼手段,攻擊者最終仍需要修改系統內核參數(如進程權限)并啟動一個高權限shell.因此,即使不具有細粒度動態執行監控能力,IMA仍可通過對內核關鍵數據的完整性驗證來檢測并響應上述篡改.這就使得現有IMA方案在應用于嵌入式系統時顯得過猶不及:一方面,它們所采用的安全機制在實際有效性上很可能并無顯著提升;另一方面,它們卻肯定會因為這些機制而給目標系統造成不可承受的性能負擔.因此,本文所提出的DIMAK所考慮的威脅模型主要針對可能對系統完整性造成破壞的攻擊類型,包括(但不限于):
1)惡意代碼/進程的動態載入和內存駐留;
2)權限提升攻擊;
3)基于hooking等技術的函數調用劫持.
考慮到嵌入式Linux系統在實際應用中的安全需求,針對上述威脅模型,DIMAK主要期望達成的安全目標包括:
1)為嵌入式Linux系統內核及用戶空間內的所有可執行文本(包括shell腳本)提供運行時完整性校驗;
2)為用戶態位置無關代碼加載后的動態鏈接和重定位信息提供運行時完整性校驗;
3)為用戶進程可能應用的代碼熱修復功能提供完整性校驗支持;
4)除實時校驗外,支持對系統內全部待度量內容實施人工或計劃性的全量掃描;
5)對系統運行中發生的進程/子進程創建等敏感行為同樣予以實時合法性驗證.
上述安全目標的邏輯在于對目標系統同時應用兩套校驗策略,既支持對系統日常運行中的潛在安全威脅予以實時響應,又能夠在計劃性全量掃描中實施“查漏補缺”.為了在性能開銷方面更有可能適應嵌入式系統和設備的實際計算資源狀況,上述安全目標的實現不應依賴于用戶應用程序的侵入式改寫,例如文獻[18]中所采用的動態插樁,或依賴于對執行行為的即時(just-in-time)跟蹤等性能開銷較大的操作.
考慮到嵌入式系統所具有的專用性和以應用為中心等特點,DIMAK假設目標系統運行一組相對固定的內核KO模塊及用戶應用程序,并因此具有穩定的代碼完整性基線.在安全性方面,DIMAK的主要目標在于保護嵌入式系統運行過程中的完整性狀態,故本文假設部署DIMAK的操作系統已經具備某種可信啟動技術,使得DIMAK總是能夠在系統處于同一確定的可信狀態時予以接管.另外,DIMAK還假設目標系統在用戶和內核空間均已應用了地址空間布局隨機化(address space layout randomization, ASLR)、數據執行保護(data execution protection, DEP)等現代操作系統的基本安全機制.由于ASLR機制的存在,DIMAK進一步假設目標系統在加載動態鏈接庫時采用立即綁定模式;否則,用戶進程在運行時將具有與程序控制流相關的非靜態結構化數據(如GOT將變為可讀寫),使得決定進程完整性的部分要素無法被有效地度量.
整體上,DIMAK由部署在Linux內核空間內的主校驗模塊、部署在TEE環境內的根模塊以及由TPM維護的完整性基線組構成.通過應用這一部署策略,DIMAK建立了自身與系統用戶空間之間的完全權限隔離,同時也在根模塊與可能從內核空間發起的潛在威脅(如驅動程序等)之間建立了可信的入侵檢測機制,使得框架整體的信任邏輯具有良好的完備性.
如圖1所示,當DIMAK啟動時,其主校驗模塊在第一時間對內核空間內的一組系統調用函數實施代碼插樁(code instrumentation),由此建立一個位于內核空間的狀態感知界面.此設計使得DIMAK能夠實時探測發生在系統內核及用戶空間內的完整性狀態變更事件,包括進程創建/終止、代碼加載/卸載、代碼改寫以及shell命令執行等.通過復用Linux自身的進程和內存管理機制,DIMAK主校驗模塊能夠直接獲取用戶態進程內下列內容所對應的物理頁面并計算其完整性度量:
1)用戶進程空間內的所有代碼段;
2)附屬于任一代碼段的結構化數據段(主要為相關代碼的重定位、動態鏈接信息等).
而對于內核空間中的Linux內核鏡像和KO模塊等內容,DIMAK主校驗模塊可以直接使用虛擬地址予以訪問和度量.利用狀態感知界面,DIMAK還能夠偵測來自遠程管理員的人工指示,并根據具體命令對系統實施單次或周期性的全量掃描,即一次性對系統內的所有代碼和結構化數據區段予以檢驗.此外,自DIMAK啟動時起,其根模塊即開始對主校驗模塊以及狀態感知界面所涉及的內核指令實施周期性掃描,確保DIMAK自身始終處在可信的運行狀態下.最后,在與實時完整性驗證或全量掃描時所測得的完整性度量實施比對時,DIMAK的主校驗模塊與根模塊均通過TPM安全地訪問其完整性基線組.
不難看出,狀態感知界面是DIMAK方案是否能夠實現其安全目標的一個關鍵點.但除此之外,針對不同類型的被度量實體所采用的具體完整性基線生成策略,以及面對多種特殊的系統完整性變更事件時所采用的創新性度量方法和系統設計約定,同樣是DIMAK達成有效性和完備性的重要保障.因此,2.2節將詳細闡述DIMAK狀態感知界面的具體設計;針對各類被度量實體的完整性基線維護策略,特別是針對用戶態位置無關代碼所對應的重定位和動態鏈接信息等關鍵結構化數據的可信基線生成方法,將在2.3節中介紹;2.4節將詳細解釋DIMAK對于軟件熱修復這一特殊應用場景的完整性度量支持及其具體協議設計.
由于在架構部署策略上建立了不同地址空間上的權限隔離,DIMAK需要能夠在處于內核態的情況下實時地感知用戶空間內發生的系統完整性關鍵事件,這一任務由其在啟動時所建立的內核態狀態感知界面來完成.從過往研究以及工業界實踐中可以初步總結出該狀態感知界面所需監測的用戶態程序行為主要包括:
1)進程的創建和終止行為.這是由于對用戶進程的惡意攻擊有可能會為后續惡意載荷的執行創建新的子進程.
2)代碼的加載和修改行為.典型代表是惡意載荷的注入以及對用戶態代碼的控制流篡改,它們是IMA所需考慮的主要威脅.
3)請求執行shell腳本的行為.這是由于對用戶空間進程的惡意攻擊還有可能通過執行特定的shell命令來達成某些攻擊目的,如權限提升等.
此外,作為一個特殊情形,由用戶空間進程發起的內核KO模塊加載行為同樣也需要納入狀態感知界面的監測范圍.
上述關鍵事件的執行過程均依賴于Linux內核所提供的系統調用支持,故如2.1節所述,DIMAK通過對這些系統調用實施代碼插樁的方式實現在所需監測的關鍵事件發生時攔截并獲取控制的目的.另外,利用所設置的插樁點,DIMAK還能夠直接訪問Linux內核用于文件、進程和內存管理的一系列關鍵變量,從而實現對全系統范圍內被度量實體的定位和訪問.圖2示意了DIMAK為構建狀態感知界面所采用的內核函數攔截面,以及藉此能夠訪問的關鍵內核數據結構.
圖2中需要說明4方面:
1)利用系統調用實例do_fork()與do_exit(),可攔截用戶進程的創建/終止事件;
2)利用實施內存映射所需的關鍵系統調用實例mmap_region()以及加載KO模塊時所使用的內核函數load_module(),可監控到系統范圍內所有ELF文件的加載事件;
3)利用系統調用實例mprotect_fixup()函數,并在其目標權限參數為可執行或只讀時觸發響應,用戶空間內的任意代碼改寫和控制流劫持行為均可被攔截;
4)利用文件執行操作的內核入口函數do_execve(),shell腳本的執行請求事件可以被感知,且通過該函數的參數還可以獲取到被執行腳本的文件路徑以實現對被度量實體的定位.
通過上述任一被插樁函數,DIMAK均可訪問系統內核所維護的task_struct類型(Linux進程管理數據結構)變量current以獲知引發相應關鍵事件的用戶進程信息.較為特殊的情況是,在執行外部shell命令或shell腳本時,程序往往會為該次執行單獨創建子進程,故在感知此類行為時,DIMAK除獲取當前進程信息外,還需回溯父進程信息以確定行為來源.最后,上述狀態感知界面的設計還能夠為DIMAK所期望實現的面向運行內存的完整性驗證功能提供支持.具體地,前述Linux進程管理數據結構task_struct內部維護有指向進程內存映射的對象指針mm(類型為mm_struct),mm進一步指向一個描述該進程空間內所有虛擬內存段的vm_area_struct類型雙鏈表vma,表內的每個對象均與進程空間內的一個虛擬內存段相對應,且維護該內存段的虛擬地址范圍和對應文件指針.利用vma鏈表所提供的參數,DIMAK可以在內核態遍歷位于各用戶進程空間內的諸如ELF文件代碼段、靜態變量段和只讀結構化數據段等被度量實體的對應虛擬內存描述符,進而結合其所給出的虛擬地址和對Linux頁表的解析尋獲被度量實體所駐留的物理頁面,實現對實際運行內存狀態而非抽象文件內容的完整性驗證.
最后,利用上述狀態感知界面,DIMAK進一步實現了對人工/計劃性全量掃描功能的控制.通過在Linux的標準shell命令行范疇外額外約定一組自定義的shell命令行,DIMAK可在其位于do_execve()函數內的攔截點檢測到shell命令行執行行為時判斷被捕獲參數是否為自定義命令行,并在匹配成功時觸發全量掃描事件.與前述的vma鏈表類似,Linux的進程管理機制還將用戶空間內的活動進程在總體上組織為以task_struct結構體為基本元素的雙鏈表.因此,在觸發全量掃描時,DIMAK可由指向當前用戶進程的current指針出發,對task_struct雙鏈表進行遍歷以訪問所有用戶進程,并使用各進程的vma鏈表以遍歷掃描其地址空間內的所有被度量實體.同時,由于DIMAK的主校驗模塊本身部署于系統內核空間,故可以直接通過虛擬地址遍歷掃描內核鏡像本身以及內核KO模塊列表.
針對系統中不同類型的被度量實體,DIMAK使用了靜態/動態相結合的雙完整性基線組模式,以確保在面對所有可能發生的完整性狀態變更時總是能夠做出正確的判斷.
2.3.1 靜態基線組
在眾多類型的被度量實體中,DIMAK應用純靜態基線予以保護包括ELF文件內的靜態變量區段、用戶進程的元數據信息及其請求執行的shell腳本.值得注意的是,盡管用戶進程在每次啟動時所獲得的標識符是動態生成的,但Linux的task_struct結構體通過內嵌的mm_struct結構體關聯進程所對應的主可執行文件(參考圖2中通過mm_struct索引的exe_file變量),故DIMAK可利用上述關聯生成針對進程信息的靜態基線.
2.3.2 動態基線組
由于用戶所加載的ELF文件采用位置無關代碼的編碼形態,使得該類文件在加載后需由動態鏈接器進行符號解析、修改其重定位表及GOT以維持程序控制流的正確性.因此,承載這些重定位和動態鏈接信息的結構化數據段只在用戶進程的單個生命周期內具有穩定的完整性基線.該基線在ELF文件加載時動態生成,并隨其卸載而失效.此外,對于全局描述符表(global descriptor table, GDT)、系統調用表(system call table)等操作系統內核所依賴的關鍵動態數據,DIMAK同樣只能在系統啟動后為其維護動態基線.
2.3.3 靜態/動態雙基線組
較為特殊的是,由于內核KO模塊所對應的ELF文件并不使用位置無關代碼,故在內核ASLR啟用的情況下,KO模塊的每次加載時所加載的具體代碼文本都會有所改變.因此,當KO模塊加載時,DIMAK需要驗證其可執行文件的靜態完整性;但在實施計劃性的全量掃描時,DIMAK又需要驗證KO模塊所駐留運行內存的動態完整性.此外,由于DIMAK本身需要通過對Linux內核鏡像實施inline hooking以建立狀態感知界面,使得其對內核鏡像的完整性驗證存在同樣的問題.因此,對于上述2種情形,DIMAK在KO模塊首次加載/系統啟動時首先應用離線生成的靜態基線實施完整性驗證,隨后生成并在系統運行的剩余周期內轉而應用動態完整性基線.
另一個可能需要應用靜態/動態雙基線的被度量實體類型是位于用戶空間內的ELF文件代碼文本.這是因為DIMAK需要考慮兼容代碼熱修復機制,且現有代碼熱修復技術在實施過程中均需要對已加載的可執行文件進行inline hooking來實現對被修復函數的重定向(至其補丁版本所在的位置).因此,盡管DIMAK在所有用戶態ELF文件的首次加載時均使用離線生成靜態基線予以驗證,但每當一次熱修復操作完成后,DIMAK就必須對受到影響的ELF文件代碼段進行完整性基線的更新,并轉而在其之后的生命周期內應用動態基線;而對于未受到熱修復影響的ELF文件,DIMAK則始終在對其代碼段的完整性驗證中應用靜態基線.
2.3.4 動態基線的生成機制
表1列出了當前DIMAK所考慮的所有被度量實體類型及其各自對應的完整性基線組.其中,歸屬于靜態/動態雙基線組的3類被度量實體均具有可從內核空間內準確感知的基線轉換時機.然而,用戶態ELF文件所附帶的動態鏈接和重定位信息是在其加載過程中經動態鏈接器處理后寫入的,期間系統內核僅在內存分配和頁面權限改寫時有所參與.這就使得主校驗模塊完全位于內核空間的DIMAK很難捕捉到動態鏈接器完成上述結構化數據寫入的

Table 1 Grouping Strategy of DIMAK’s Integrity Baselines
確切時機,因而無法僅憑被動的狀態感知建立可信的動態基線.針對這一問題,DIMAK創新性地采用了一種進取型動態鏈接預測技術,在用戶態ELF文件尚未完全加載時主動“模擬”動態鏈接器的行為,從而預測正在載入的ELF文件最終的重定位和動態鏈接狀態.
圖3示意了DIMAK所采用的動態鏈接預測技術的工作原理.當Linux系統加載一個用戶態ELF文件時,其動態鏈接器會在符號解析時首先判斷該文件是否依賴于尚未加載的其他ELF文件.例如,Linux在為應用程序創建進程時總是首先加載后綴為.o的主可執行文件,然后根據符號解析獲取到的依賴關系遞歸地加載該程序所需要的其他ELF文件(如共享類庫等).利用動態鏈接過程的這一特點,DIMAK借助狀態感知界面對mmap_region()的攔截點(參見2.2節),在任意用戶態ELF文件加載時主動介入、搶先解析其文件依賴關系,并將被加載文件所依賴但尚未加載的其他ELF文件添加至一個動態列表.在此之后,每當DIMAK感知到新的用戶態ELF文件加載時,即檢查該文件的存儲路徑及所屬進程等信息是否存在于當前處于活動狀態的某個依賴關系列表內,若是則從相應列表中刪除該項.當一次表項刪除導致DIMAK所維護的某一依賴關系列表為空時,即意味著該列表對應的ELF文件所需的依賴文件已經全部載入內存、即將進入動態鏈接階段.因此,DIMAK得以在該時機介入并依照動態鏈接器的工作規則搶先為相應的ELF文件計算動態鏈接和重定位信息.到這一步,DIMAK已經能夠在用戶態ELF文件的加載和動態鏈接過程尚未完成時為其只讀結構化數據段生成正確的動態基線.
上述進取型動態鏈接預測技術的存在,使得DIMAK即使處在系統內核空間中也能夠及時(確切地說,是搶先)且正確地維護與用戶態位置無關代碼相關聯的所有關鍵控制流完整性信息,無需修改動態鏈接器或對其動態插樁,也無需將自身任何組件探入用戶進程空間.截止目前,該安全目標尚未在現有IMA方案中真正實現過,是DIMAK在系統完整性度量的完備性方面的一次創新性突破.
盡管代碼熱修復是一種工業界常見的軟件工程需求,但對于IMA技術而言,實現對該功能的兼容所面臨的最大困難在于代碼熱修復在技術本質上與惡意代碼注入行為的界限十分模糊.事實上,若不對熱修復所注入的代碼文本進行格式上的事先約定,則無法僅憑兩者對內核函數的調用特征將其加以區分.借鑒了Android平臺所采用的APK簽名驗證機制,DIMAK采用了一種類似的代碼熱補丁格式與簽名規范約定,結合其狀態感知界面所利用的Linux進程空間管理機制,首次實現了對代碼熱修復功能的可信驗證支持.
圖4示意了DIMAK所采用的可信熱補丁格式約定.該格式以一個固定長度的頭部為起始,依次容納了一個補丁位圖以及一個或多個補丁段(即允許對用戶進程內的多個可執行文件同時進行熱修復).其中,補丁頭部包含了魔數字符、補丁區所容納的補丁段總數、補丁位圖大小等關鍵信息以幫助DIMAK對補丁包進行識別和解析.此外,補丁頭部內還寫入了補丁包的簽名信息以及全體補丁段的總和校驗和.緊接在頭部之后的補丁位圖給出了后續補丁段以及段內各補丁函數的索引,并給出了每個補丁函數的修復對象所在的可執行文件名,使得DIMAK可以判斷該次熱修復對系統當前基線組的具體影響狀況.
除圖4所示的格式約定外,DIMAK進一步規定:在可信的熱修復過程中,補丁包必須先將符合格式約定的熱補丁載入內存并設為可執行權限,并等待該操作成功后方能對進程內已經加載的其他代碼段進行修改.按照這一設計,DIMAK對軟件熱修復功能的支持可由4個流程描述:
1)當DIMAK在運行時檢測到某一用戶進程正在加載一個具有可執行權限、但未被該進程的vma鏈表收錄的虛擬內存段時,即對該段首地址進行魔數識別以判斷該次加載是否可能為一次可信的熱補丁行為.
2)若魔數識別成功,則DIMAK通過補丁位圖確定被加載虛擬內存段內部的各補丁段界限,并對全體補丁段的總和校驗和進行完整性驗證.
3)若驗證通過,DIMAK將前一步驟所使用的總和校驗和作為當前補丁包的完整性基線納入靜態基線組,并為該補丁包創建2個新的vm_area_struct結構體.其中,第1個融合了補丁包內的所有補丁代碼段并被賦予可執行權限;而第2個則被映射到補丁頭部和位圖區段,并被賦予只讀權限.
4)DIMAK根據補丁位圖信息定位到進程空間內即將被修改的所有代碼段,允許對這些代碼段各實施一次改寫,并在該次改寫完成后更新相應代碼段的完整性基線.
1)~4)設計使得DIMAK能夠保證正常的代碼熱修復過程所涉及的所有用戶態代碼(包括補丁本身以及被修復的運行代碼段)在該過程的任意時刻總是具有可信的完整性基線,從而保證系統整體在熱修復發生時全程處于可度量狀態.值得一提的是,該設計的DIMAK除要求用戶態應用程序依照其格式約定編碼補丁包之外,對代碼熱修復功能的支持無需額外的用戶/內核代碼組件的協助.
在整體信任擴展邏輯的構建方面,DIMAK所采用的分層權限隔離的架構設計(如2.1節所述),使得除DIMAK根模塊外,系統各地址空間內的程序模塊——包括DIMAK自身的主校驗模塊及用戶空間狀態感知界面——均由權限更高的DIMAK模塊予以校驗.
首先,對于處在用戶地址空間內的各應用程序而言,DIMAK的所有組件均位于系統內核空間或具有更高權限的安全執行環境內,且不依賴于任何用戶態輔助組件.因此,當用戶空間內的某一程序進程中出現惡意執行行為時,其所擁有的權限不足以對DIMAK本身實施篡改或欺騙.因此,只要部署于內核中的各組件能夠被信任,則經過DIMAK驗證的用戶空間可被認為得到了有效的信任擴展.
其次,由于DIMAK通過部署在TEE內的根模塊為其主校驗模塊提供完整性驗證,故只要該根模塊能夠被信任,則可以認為受到其周期性驗證的DIMAK主校驗模塊也得到了有效的信任擴展,其執行行為因而可以被信任.
最后,DIMAK的主校驗模塊與系統內核鏡像、KO模塊等組件同處于內核空間內,故當系統遭到源自驅動程序等同樣位于內核空間的第三方組件的惡意行為時,攻擊方確實具有破壞DIMAK各內核態組件完整性的可能性.然而,由于DIMAK的主校驗模塊得到了根模塊的背書,故該模塊較之內核空間中的其他代碼組件具有更高的信任等級.此外,由于DIMAK在主校驗模塊啟動后由該模塊負責驗證系統內核鏡像及其加載的其他內核KO模塊的動態完整性,故在主校驗模塊能夠被信任的情況下,即可以認為:經該模塊驗證的其他內核空間組件均得到了有效的信任擴展.
綜上可以認為,當假設部署于TEE內的根模塊為可信時,DIMAK能夠基于此信任根、憑借操作系統的地址空間層次實現逐級的信任擴展,使得其對系統內所有組件的完整性驗證均可得到更高權限的可信模塊之背書.而無論是位于用戶空間或是內核空間的潛在攻擊者,均無法完全規避、欺騙或破壞包括根模塊在內的所有DIMAK組件,故無法繞過該架構的信任邏輯.
在3.1節所述的信任邏輯基礎上,DIMAK所采用的狀態感知界面這一設計(如2.2節所述),使其能夠從基線生成時機和實時完整性驗證的觸發機制2個方面保證自身行為的正確性.
由于采用了靜態/動態雙基線組的設計,DIMAK得以依賴其動態基線組對系統中部分正當的運行時代碼/數據改寫需求提供有效的可信計算支持(如2.3節、2.4節所述).這一機制是決定該方案正確性的主要因素之一.而狀態感知界面使得DIMAK能夠在適當的時機介入此類運行時的改寫行為,由此保證與之相關的動態基線生成過程始終滿足兩項原則:
1)任意一項動態完整性基線的生成均得到了某項與之相關的靜態基線的完整性背書.例如,在內核KO模塊的加載中,DIMAK在加載前后分別介入、首先引導一次基于靜態基線的完整性驗證以確認待加載模塊的對應文件是否具有可信的靜態度量,隨后才會在KO加載完成后生成并切換至動態基線.由此,DIMAK使得內核KO模塊所對應ELF文件的靜態基線成為其運行時動態基線的完整性背書.在其他動態基線場景中,
① 用戶態ELF文件內的動態鏈接/重定位信息的生成發生在其代碼文本的加載過程中,故代碼文本的靜態基線天然地成為該類信息動態基線的完整性背書;
② 類似地,用戶代碼的熱修復行為也得到了補丁包以及被修復代碼段二者所對應靜態基線的雙重完整性背書.
2)狀態感知界面的存在,保證了任一動態完整性基線的生成均發生在對應被度量實體所發生的完整性狀態變更實際生效之前.例如,在為用戶態ELF文件的動態鏈接/重定位信息生成動態基線時,DIMAK所選擇的攔截點為mmap_region()這一代碼加載行為的必經系統調用,而在該系統調用執行時,所加載代碼的重定位和動態鏈接過程甚至尚未開始.類似地,在KO模塊加載過程和用戶代碼熱修復過程中,相關動態基線同樣在對應代碼文本被標記為可執行之前即生成完畢.
此外,在面對各種可能造成系統完整性狀態變更的事件時,DIMAK所選擇的各內核攔截點同樣保證了對應的完整性校驗發生在事件生效之前.以shell腳本執行行為為例,如圖2所示,當用戶空間內進程發起一次shell腳本執行時,DIMAK的狀態感知界面通過do_execve()攔截該請求,并通過輸入參數獲取到腳本名稱及路徑,進而引導其主校驗模塊對腳本完整性實施驗證.而被請求的腳本在這一時刻甚至尚未被解析,故其執行行為在完整性校驗發生時顯然尚未生效.
上述特點,決定了DIMAK在其基線維護及實施完整性驗證的過程中不會遺留下檢查與使用時差(TOCTTOU)漏洞:DIMAK在任意一次完整性驗證中總是能夠獲取到被度量實體所對應的正確基線值;同時,在DIMAK對任一被度量實體的完整性驗證完成之后到該對象被變更為可執行、只讀等生效權限狀態之間,攻擊者難以獲得對該對象實施不受控改寫的時間窗口.綜上可以認為,DIMAK架構的設計具有完整的正確性邏輯.
在IMA技術的有效性評估方面,存在的一個主要問題是:不同的IMA方案往往因工作原理上的顯著差異,使得其在有效性方面難以形成可比性.然而本文認為:仍然可以從IMA方案的完備性設計入手,對現有的不同IMA方案進行有效性層面上的比較.針對IMA技術的完備性指標主要包括:
1)驗證對象的范圍,即IMA方案能夠將軟件系統環境內的哪些資源和對象納入其“保護傘”之下;
2)基線類型,即IMA方案采用何種完整性基線以支持其對系統的驗證行為;
3)干預時機,即IMA方案能夠在軟件系統啟動及運行過程中的哪些時機介入并實施其保護行為.
4)對正常軟件功能的支持/限制,應被視為IMA方案完備性的一個指標.顯然,如果軟件系統的部分功能不能在一個IMA方案啟動的狀態下被正常地實現,則該IMA方案應該被認為在完備性上存在缺陷.具體來說,是否能夠支持對軟件的熱修復功能,是本文主要考慮的一個屬于此類型的完備性指標.
5)完整性度量過程是否需要對被度量實體實施侵入式改寫(如動態代碼插樁等),應被視為IMA方案完備性的另一個指標.這是因為基于侵入式改寫的完整性驗證措施自身在本質上屬于對被改寫軟件完整性的侵犯.因此,一些軟件很可能出于性能、正確性或隱私保護等因素的考慮而無法在真實應用場景中允許來自外部的該類行為.
上述1)~3)為現有關于IMA技術的研究工作中廣泛采用的完備性指標.在此基礎上,本文則進一步認為IMA技術的完備性還應額外體現在指標4)和5)兩個方面.表2從完備性指標的5個方面出發,對本文所提出DIMAK方案與現有學術研究及工業實踐所提出或應用的IMA方案進行了完備性層面的對比.可以看到,相比早期一些僅關注內核完整性的IMA方案[5-7],DIMAK具有更為完備的驗證范圍,且在干預時機方面有效地覆蓋了系統運行過程中的主要關鍵節點.而與近年來新出現的一些以用戶態進程完整性為主要目標的IMA方案[8,18-19]相比,DIMAK在功能實現上并不需要通過對用戶進程實施主動插樁或其他改寫,且在校驗時機方面兼具最優的實時性.最后,除DIMAK外,現有IMA方案均未考慮到熱修復等實用軟件場景與惡意攻擊的區分問題.綜上,可以認為較之現有同類技術,DIMAK具有較好的完備性.

Table 2 Completeness Feature Comparison of DIMAK and the Existing IMA Schemes
此外,我們測試了DIMAK面對不同類型的漏洞利用攻擊時的實際防御效果,包括:
1)利用用戶進程漏洞發起的返回導向編程,攻擊目標包括篡改進程代碼段、GOT以及執行自定義的shell腳本;
2)利用驅動程序漏洞發起的內核注入,攻擊目標包括篡改內核參數、破壞DIMAK主校驗模塊和狀態感知界面等.
測試顯示,在面對上述攻擊時,DIMAK均能有效地發現系統完整性狀態遭到破壞的事實,并對遭到破壞的被度量實體予以準確定位.該測試進一步證明了DIMAK方案在面對潛在惡意攻擊時具有良好的完備性.
需要指出的是,基于3.3節所述的完備性差異的原因,不同的IMA方案很難在性能開銷方面形成具有可比性的對照評估.因此,本文主要對受DIMAK保護的Linux系統與同版本的標準Linux系統進行性能層面上的對比分析.
3.4.1 執行時間開銷
從設計原理出發可以初步判斷,DIMAK可能引起執行時間方面的性能開銷的操作主要包括:
1)系統啟動過程中,校驗內核鏡像及載入的KO模塊,并為二者更新動態基線;
2)進程創建時,或在進程執行過程中發生共享庫動態加載時,對被加載的可執行文件進行校驗,并為其動態鏈接/重定位信息生成動態基線.
其他可能引起執行時間開銷的操作還包括DIMAK在進程執行過程中發生動態代碼改寫(包括惡意篡改行為和正常的軟件熱修復)時的校驗和基線更新/維護行為.然而,考慮到此類事件并非嵌入式系統運行時出現的常態行為,故本文不將其視作DIMAK的常規性能開銷.此外,對于占軟件系統運行周期主要部分的進程執行階段,DIMAK并不產生可測量范圍內的常規開銷.
本文對執行時間開銷的測試采用了一臺搭載8核1.35 GHz主頻的ARM v7處理器、具有6 GB運行內存、搭載內核版本5.1.0的Linux系統的嵌入式接入設備作為真機測試對象.本文進行的第一項實驗分別測試了上述測試設備分別在DIMAK功能啟用和禁用狀態下的系統啟動時間、用戶態進程創建時間和單個共享類庫的動態載入時間.其中,選自開源嵌入式測試集MiBench的9個實例dijkstra,patricia,blowfish,SHA,adpcm,CRC32,FFT,basicmath和qsort被用于測試用戶態進程創建時間,而標準系統庫glibc則被用于測量單個共享類庫的載入時長.
如表3所示,可以看到DIMAK所引入的執行時間開銷主要分布于用戶態進程的創建過程以及運行時單個共享庫的動態載入過程.這主要可以歸因于該架構通過對ELF文件動態鏈接/重定位信息的搶先預測以更新和維護其只讀結構化數據段動態基線的功能設計.盡管如此,經過DIMAK驗證的進程創建和單個共享庫動態載入過程的總體時間開銷仍然處于毫秒級,且DIMAK在未涉及到動態鏈接行為的系統啟動過程中所引起的開銷僅為7.532%.考慮到多數嵌入式系統中所運行的用戶態進程具有較高的穩定性,即進程不會頻繁地被創建/終止,可以認為:通過將主要性能瓶頸從運行時轉嫁到加載時,DIMAK有效地降低了其保護功能為系統帶來的性能負擔.
在此基礎上,本文所進行的第2項實驗進一步測試了各MiBench實例在DIMAK功能啟用/禁用狀態下的實際執行性能,以此評估DIMAK可能為嵌入式系統中運行的用戶應用程序所帶來的執行性能開銷.其中,對于每個被測MiBench實例,實驗中采用其自帶的大型測試數據集作為運行輸入,并測量其在DIMAK啟用/禁用情況下的各10次完整執行所消耗的平均執行時間.如表4所示,實測中各MiBench實例在DIMAK啟用/禁用狀態下的平均執行時間相差均在1%以下.這一結果進一步支持了前述結論,即:由于DIMAK的主要開銷發生在應用程序加載過程中,其對嵌入式系統帶來的實際性能負擔幾乎可以忽略.

Table 3 Runtime Overhead of DIMAK in Cases of System Booting, Process Creating and Dynamic Library Loading

Table 4 Runtime Overhead of DIMAK During the Execution of User Processes
3.4.2 運行內存開銷
由于嵌入式系統往往傾向于最大化利用計算資源,故其為附加安全功能預留的可擴展空間通常極為有限,使得運行內存開銷成為一個IMA架構是否適合嵌入式系統的重要指標.而從DIMAK的設計原理觸發,可以判斷其運行內存開銷主要包括3個方面:
1)對靜態/動態基線組的維護,是DIMAK的一項常規內存開銷;
2)在對任意被度量實體實施完整性驗證時,所需要的緩沖區、環境變量等關鍵數據是DIMAK的一項臨時內存開銷;
3)在對用戶態ELF文件實施動態鏈接/重定位信息的搶先預測時,DIMAK所需維護的諸如依賴文件列表等關鍵數據是其另一項臨時內存開銷.
為了解上述運行內存開銷可能給嵌入式系統帶來的實際性能負擔,本文采用與3.4.1節相同的嵌入式接入設備為測試對象,對DIMAK進行了兩項真機測試,分別模擬了其總體性能開銷最大的系統全量掃描過程(即對系統環境內的所有被度量實體進行遍歷完整性驗證)和可以視為性能開銷基本單元的單個共享庫動態載入過程.結果顯示:
1)常規狀態下,DIMAK的自身代碼占用內存共計為3 120 KB;
2)在全量掃描中,DIMAK對總計3 481 MB的運行數據實施了完整性檢驗,其自身的運行內存占用僅為2 MB;
3)在共享庫動態載入時,DIMAK的平均內存開銷僅為4.1 KB.
上述數據充分顯示了DIMAK在內存開銷方面的設計優勢,我們有充分的理由相信:即使被應用于硬件性能更為有限的其他嵌入式設備,DIMAK仍然能夠以極低的內存占用實現對系統的運行時完整性驗證保護.
本文提出了一種針對嵌入式Linux操作系統的實用化完整性度量架構DIMAK.DIMAK在設計上采用了依托系統內核空間與TEE環境的逐級信任擴展機制,并根據位于內核及用戶空間內的可執行文本、靜態數據以及動態鏈接信息等各種被度量實體的不同類型,采用了靈活的靜態/動態雙基線組的完整性基線維護策略.通過對Linux內核代碼內的關鍵函數實施inline hooking的方式,DIMAK所建立的狀態感知界面能夠在不探入用戶空間的情況下感知并介入由用戶進程發起的、可能影響系統完整性狀態的程序行為,從而保證了該架構完整性驗證行為的正確性.此外,借助專門的私有協議設計,DIMAK還能夠在無需用戶/內核代碼協助的情況下實現對用戶態軟件熱修復功能的支持.真機測試顯示,本文所述的完整性度量架構產生的性能開銷完全可以滿足嵌入式設備場景下的實際應用要求,同時在安全特性方面優于現有同類技術.
作者貢獻聲明:賈巧雯和馬昊玉負責方案設計與論文撰寫;厲嚴和王哲宇負責實驗與數據整理;石文昌負責方案和實驗指導.