1 概述
CET(Control-flow Enforcement Technology)機制是 Intel提出基于硬件的?于緩解 ROP/JOP/COP的新技術(shù)。特別強調(diào)下,他是基于硬件?持的解決?案。從Intel的Tigerlake (11th gen),Alderlake (12th gen)/Sapphire-Rapid起,粗顆粒度地旨在預防前向( call/jmp )和后向( ret )控制流指令劫持來御防ROP的攻擊。
因此針對防御對象不同,CET技術(shù)又分為CET-SS用于針對ROP的ret指令和CET-IBT用于針對JOP/COP的jmp/call指令,見圖1 功守道。
圖1 功守之道
2 CET為何而生
在安全世界里,總是希望魔高一尺道高一丈。說到防御者CET,就不得不提他的進攻者ROP了。什么是ROP? 來看?個例?,假設程序中正常執(zhí)行如下代碼?段,注意此時其中不含ret或call指令。
圖2 正常執(zhí)行流
但是,如果稍加偏移?下解釋代碼的地址時,就會導致出現(xiàn)完全不?樣的指令,如下圖所示:
圖3 RET CALL的gadget
如果按照紅框中的順序解釋這些指令的時候,那么將會產(chǎn)??代碼預期的結(jié)果,會出現(xiàn)原代碼中未出現(xiàn)過的 ret 指令以及 call 指令,這些指令序列被稱為 gadget 。
通過仔細構(gòu)造這些由ret指令終?的指令集,攻擊者可以執(zhí)?原程序中?預期的任意惡意代碼,這種新產(chǎn)生ret攻擊被稱為 ROP 攻擊,同理還有COP/JOP(call/jmp)攻擊。
為了防御這種此類ROP攻擊,Intel工程師在2016年起在硬件機制上推出了CET緩解機制,針對不同的攻擊行為分為CET-SS(影子棧)和CET-IBT(間接跳轉(zhuǎn)跟蹤),即圖1 功守道所示。
3 CET
CET-SS和CET-IBT 在實現(xiàn)機制上屬于CPU內(nèi)部異常,這里就涉及到中斷機制。當執(zhí)行啟動CET發(fā)現(xiàn)執(zhí)行執(zhí)行流中沒有endbr64或函數(shù)返回ret和影子棧中shandow stack保存的ret不一致時,CPU內(nèi)部出發(fā)異常,這里CET占用的中斷向量21號,觸發(fā)#CP并歸為陷阱執(zhí)行中斷處理程序exc_control_protection(),對CET-SS CET-IBT分情況進行報錯。CET-IBT -> "traps: Missing ENDBR: xxx", CET-SS-> #CP(control protect)。
這里提一下CPU的異常,當CPU執(zhí)行中發(fā)現(xiàn)ROP/JOP/COP后,CPU給自己發(fā)送中斷信號。注意異常不一定是錯誤,只要是異于平常就都是異常。有些異常不但不是錯誤,它還是實現(xiàn)內(nèi)核重要功能的方法。CPU異常分為3類:
1.陷阱(trap),陷阱并不是錯誤,而是想要陷入內(nèi)核來執(zhí)行一些操作,中斷處理完成后繼續(xù)執(zhí)行之前的下一條指令;
2.故障(fault),故障是程序遇到了問題需要修復,問題不一定是錯誤,如果問題能夠修復,那么中斷處理完成后會重新執(zhí)行之前的指令,如果問題無法修復那就是錯誤,當前進程將會被殺死;
3.中止(abort),系統(tǒng)遇到了很嚴重的錯誤,無法修改,一般系統(tǒng)會崩潰。CET歸為陷阱。
圖4 CET中斷異常處理流程
3.1 CET-SS(Shadow Stack)
3.1.1 原理分析
Intel 提出了?種基于硬件的 CET 解決?案,其中之?的 shadow stack 機制?于緩解 ROP 攻擊。前?圖2可以得知 ROP 依賴于 ret 指令,其中要執(zhí)?的后續(xù)指令地址從堆棧中獲得。因此 ROP 攻擊的前提是攻擊者能夠在堆棧中構(gòu)造數(shù)據(jù)。那么再來看 shadow stack 機制是怎么?作的。
CET 使操作系統(tǒng)能夠創(chuàng)建?個 shadow stack (影?棧)。正常情況下,當執(zhí)? call 指令時,會將 call 指令后?條指令地址壓棧。當啟?了 shadow stack 后,會同時在普通數(shù)據(jù)棧和 shadow stack 中壓?返回地址,隨后在執(zhí)? ret 返回時,會將 shadow stack 中的返回地址和普通數(shù)據(jù)棧中的返回地址做對?,如匹配,則正常執(zhí)?,如不匹配,則觸發(fā)#CP(Controlflow Protection) 異常。如下圖所示:
圖5 CET-SS針對ret指令觸發(fā)#cp異常
3.1.2 驗證方法
圖6 CET-SS test
以上內(nèi)核代碼以ko的形式進行加載,然后通過用戶空間的app觸發(fā)系統(tǒng)調(diào)用,這里的app被名字也命為shadow_test_fork(內(nèi)核函數(shù)和app名字一致了,容易產(chǎn)生混淆,請大家理解)。系統(tǒng)調(diào)用最終調(diào)到圖6中的shadow_test_fork()函數(shù)。發(fā)生如下異常報錯,見圖7。
圖7 CET-SS test result #CP
3.2 CET-IBT(Indirect Branch Tracking)
JOP/COP 攻擊?法與 ROP 類似,只不過是把 ROP 中以 ret 指令做跳板的關鍵點替換成了 call/jmp 指令。還是拿講述 ROP章節(jié)的兩幅圖(圖2 圖3)舉例,圖3中偏移解釋字節(jié)碼后出現(xiàn)了不同的指令,包含了:
圖8 CET-IBT call指令攻擊
這?指令序列,這就是 COP 中的 gadget ,以 call 指令為跳板,也就不需要 ret 指令的輔助了。這種不需要 ret 指令的攻擊場景下,前?所說的 shadow stack 機制就失效了。這種情況下, CET 的第?種機制 IBT(Indirect Branch Tracking) 就應運??了。
3.2.1原理分析
IBT(Indirect Branch Tracking),間接跳轉(zhuǎn)跟蹤"希望能防止攻擊者讓間接跳轉(zhuǎn)(例如,通過指針變量進行的函數(shù)調(diào)用)進入一個不應該走到的地方。功守道之中是為了應對JOP/COP的。
IBT 是為了防御面向跳轉(zhuǎn)編程的(jump-oriented programming);工作原理是試圖確保每個 indirect branch 的目標確實都是適合作為跳轉(zhuǎn)目標的。IBT 的方法有很多,每一種都有自己的優(yōu)勢和劣勢。例如,內(nèi)核在 5.13 開發(fā)周期中支持了編譯器實現(xiàn)的 IBT 機制。
在這種模式下,編譯器通過一個 "jump table, 跳轉(zhuǎn)表" 來完成每一個間接跳轉(zhuǎn),不僅確保目標是要供間接跳轉(zhuǎn)使用的,而且要確保被調(diào)用函數(shù)的原型與調(diào)用者所期望的一致。這種方法是很有效的,但要增加很多編譯、運行時的開銷。
英特爾的 IBT 方法相當簡單,但優(yōu)點是得到了硬件的支持,因此速度更快.如果 IBT 被啟用,那么 CPU 將確保每個間接跳轉(zhuǎn)都落在一條特殊指令(endbr32 或 endbr64)上(見圖9),該指令執(zhí)行時跟 no-op 效果一致。如果發(fā)現(xiàn)意外,那么處理器將引發(fā)一次 control-protection(#CP)exception。
圖9 CET-IBT ENDBR標志嵌入輔助檢測
3.3.2測試方法
圖10 內(nèi)核測試函數(shù)
圖11 CET-IBT 運行測試結(jié)果
3.3 硬件機制.
CPU 是如何實現(xiàn)這種校驗機制的呢?答案是?了 ENDBRANCH 狀態(tài)機。
CPU 在?戶態(tài)和內(nèi)核態(tài)分別設有?個 ENDBRANCH 狀態(tài)機,狀態(tài)機共有兩個狀態(tài),為 IDLE 和WAIT_FOR_ENDBRANCH 。初始狀態(tài)都為 IDLE ,當執(zhí)?間接跳轉(zhuǎn) call 的時候,狀態(tài)機會從 IDLE變?yōu)閃AIT_FOR_ENDBRANCH ,這時候就意味著下?條指令就必須為 endbr32/64 ,如果是 endbr32/64 ,狀態(tài)機就會從 WAIT_FOR_ENDBRANCH 變回 IDLE ,如果不是則會觸發(fā) #CP 異常。
圖12 狀態(tài)機
3.4 其他objtool
需要在所有的間接跳轉(zhuǎn)目標地址都添加 endbr 指令,這就為今后造成了一個潛在的陷阱:開發(fā)者可能會添加匯編函數(shù)但是忘記了這個指令。如果他們在沒有啟用 IBT 的情況下進行測試,那么這個問題就不會被注意到,可能直到有問題的代碼被合并后的某個讓人非常不爽的時間點才突然暴露出來。為了防止這種情況的發(fā)生,開發(fā)者加強了內(nèi)核的 objtool 工具來檢查所有的間接跳轉(zhuǎn),并確保所有的目標都恰當?shù)貥俗ⅲ╝nnotated)好了。
不過,有了這種檢查之后,還可以采取另一個步驟:objtool 還可以列出所有包含 endbr 指令但是永遠不會通過間接跳轉(zhuǎn)到達的函數(shù)。這些函數(shù)不需要進行標注,沒有它們的話,內(nèi)核會更安全一些。因此,內(nèi)核 build 的過程會從 objtool 中獲取該列表,并通過用 nop4 指令覆蓋 endbr 來 "封印" 這些函數(shù)。這就減少了攻擊者在啟用 IBT 時仍然可以選擇的攻擊目標。
正如 Peter Zijlstra 所指出的,刪除不需要的 endbr 指令還有一個也許是令人驚訝的好處。內(nèi)核限制了 loadable module 所能使用的函數(shù),而那些專有的(proprietary)module 則受限更多。那些專有的 module 經(jīng)常使用一個技術(shù)就是在內(nèi)核的符號表中查找到它們需要的、未 export 的函數(shù),然后通過間接跳轉(zhuǎn)來調(diào)用它們,從而繞過內(nèi)核的限制。但是,在啟用 IBT 后,任何缺乏 endbr 指令的函數(shù)都不再能以這種方式調(diào)用了。
4 性能分析
圖13 遞歸調(diào)用
圖14 CET性能分析
圖15 CET 性能分析
5 內(nèi)核開發(fā)進度
內(nèi)核開發(fā)者已經(jīng)努力了一段時間,希望能讓英特爾 IBT 功能進入 Linux 內(nèi)核。實現(xiàn)這個功能的第一個 patch(針對用戶空間代碼而不是針對內(nèi)核)是由 Yu-cheng Yu 在 2018 年發(fā)布的。然后,這項工作似乎成了那些不斷穿越郵件列表的飛行荷蘭人(flying-Dutchman)patch 之一,從未能夠進入 mainline;第 30 版是 2021 年 8 月發(fā)布的,也沒有達到能夠合并的程度。類似的情況也發(fā)生在了用戶空間的影子堆棧(user-space shadow-stack)patch set 上,在經(jīng)歷多次修訂后,這些 patch 最近被 Rick Edgecombe 接手了。
2021年年底,Peter Zijlstra 決定創(chuàng)建一個獨立的英特爾 IBT 實現(xiàn)來保護內(nèi)核本身;第一個版是在去年 11 月發(fā)布的,Zijlstra 顯然是 "在周五晚上/周六早上趕工出來的"。這項工作發(fā)展得很快,3月初發(fā)布的第四個修訂版就是為 5.18 合并的版本了(鏈接見參考文檔CET-IBT patches)
這就是目前為止的情況了。從 2020 年底上市的 Tiger Lake 一代開始,英特爾處理器就支持 IBT 了,只支持了內(nèi)核代碼。這并不是一個完美的工具,但它將提高攻擊者攻擊這類系統(tǒng)的門檻。同時,目前還不清楚用戶空間的支持何時(或是否)會進入 mainline 內(nèi)核;到目前為止發(fā)布的 30 個修訂版中,有許多根本沒有收到任何 review 意見。該部分已經(jīng)被Rick Edgecombe接手并發(fā)布了v1版本,后續(xù)我們拭目以待,希望能在6.2中會合入全部的CET代碼。
審核編輯:劉清
-
操作系統(tǒng)
+關注
關注
37文章
6684瀏覽量
123140 -
狀態(tài)機
+關注
關注
2文章
491瀏覽量
27456 -
JOP
+關注
關注
0文章
2瀏覽量
8382
原文標題:Intel CET 安全防御機制深度解析
文章出處:【微信號:LinuxDev,微信公眾號:Linux閱碼場】歡迎添加關注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關推薦
評論