1. 程式人生 > >Spectre/Meltdown演義-專業篇(3)

Spectre/Meltdown演義-專業篇(3)

微信公眾號 mindshare思享


前面幾篇文章已經講過來Speculation和cache side channel attack. 有了這些知識,終於到了講Google Project Zero (GPZ)的Spectre和Meltdown的時候了。

 


Spectre和Meltdown的共性就是都是利用了CPU的Speculation和cache side channel attack. 但也有不同點:

Meltdown是直接跨過了CPU硬體定義的特權級許可權,讓更低特權的軟體有機會獲取到高特權級的資料。

Spectre本身沒有跨過CPU硬體定義的特權級許可權,但是軟體可以利用一些特定程式碼實現獲取高特權或同等特權級的資料。


Spectre/Meltdown總覽

目前為止共有四個spectre/Meltdown的問題被揭露。

最近的是今年5月披露的Spectre variant4. 相信隨著對各CPU廠商的微構架的更多發掘,也許還會有更多的問題被發現。


本文先講Spectre Variant1.

Spectre Variant1: 跨過軟體邊界檢查

原理概述

對應特權軟體(比如OS)說,通常它會檢查不可信任的軟體(比如application)傳進來用來作為訪問(特權/信任軟體的訪問)一個數組或是結構體的offset. 很多常見的攻擊方式都會通過訪問指標越界來實施,比如Linux kernel很多User interface的檢查,Java對陣列的邊界檢查等。

軟體一般可以這樣寫,


在現代的CPU裡,為了高效能,就像在之前文章裡所說的,它可以在邊界檢查if(untrusted_offset_from_user < arr->length還沒有確認是否越界的情況下 specualatively去做value=arr->data[untrusted_offset_from_user]的訪問。

當CPU在可信任的軟體裡執行以上程式碼時,不可信任軟體可以傳入任意untrusted_offset_from_user值,都有可能被bypass邊界檢查而使arr->data[untrusted_offset_from_user]被speculatively訪問。

正如前文所述,如果真正在architecture執行的時候發現(untrusted_offset_from_user< arr->length條件不滿足,“value =arr->data[untrusted_offset_from_user]”中的value不會真的設定為arr->data[untrusted_offset_from_user].但是” arr->data[untrusted_offset_from_user]”這個值會因為speculation進入到cache裡面。

接下來我們需要利用這個speculative的值去檢索一個untrusted buf: arr2.

比如我們想知道value (arr->data[untrusted_offset_from_user]bit0的值是0還是1的話,可以做如上操作。如果是0的話,arr2->data[0x200]被speculative訪問,進入cache;如果是1的話,arr2->data[0x300]被speculative訪問,進入cache.

Untrusted軟體現在需要利用cache side channel attack的辦法,訪問arr2->data[0x200]和arr2->data[0x300]並測量訪問時間,就知道arr->data[untrusted_offset_from_user]的bit[0]是0還是1.

 

在現代的CPU裡,speculation甚至可以多次跨過邊界檢查,比如以下程式碼,speculation可以跨過第二次的邊界檢查,

 

因為untrusted_offset_from_user可以是任意地址,所以理論上可以將所有的敏感資料洩露。

為加強攻擊效果,有的時候攻擊軟體可能會通過訓練分支預測,然speculation更容易發生。可以這樣做:

在傳入攻擊untrusted_offset_from_user之前,多次傳入正常不會越界的untrusted_offset_from_user,訓練分支預測硬體,以使其預測if (untrusted_offset_from_user < arr1->length)條件成立。

然後突施殺招,傳入攻擊用的非正常untrusted_offset_from_user,由於之前的訓練,CPU硬體比較容易speculatively訪問value =arr1->data[untrusted_offset_from_user];

基於這個原理,所有這種攻擊可以發生在:

1.JIT引擎, Javascript,kernel空間的eBPF bytecode直譯器。使JIT的一個應用可以獲取到另一應用的資訊,比如一個browser的密碼外掛的資訊。

2.一個虛擬機器VM獲取到另一個虛擬機器VM的資訊。

3.VM獲取到hypervisor的資訊

4. Application可能獲取到OS的資訊

利用這個問題來攻擊需要找到這樣的程式碼序列,並且需要一個可以probe的buff,並且由於在guest OS切換到App, 或是Hypervisor切換到guest OS的過程中有很多的軟體save/restore的過程,在現實世界裡,這個攻擊是比較難實施的。

比較現實的攻擊是對JIT,JavaScript code, 比如JavaScript code執行在一個沙盒裡,JavaScript引擎可以解釋執行或是JIT編譯執行,但是Java引擎或是JIT編譯器會保證:

1.在這個沙盒裡不允許訪問不能訪問的記憶體

2.沒有指標,陣列訪問都會做邊界檢查

但是由於這個Spectre問題,會導致邊界檢查時speculative bypass, 出現沙盒的資訊洩露。


軟體Mitigation(緩解辦法)

由上所述,Spectrevaraint1的是speculation導致的,但是現代的CPU Speculation的特性是Natural的(有生具有的),就是說Speculation是沒法簡單去掉的。如在上文通俗篇所述,簡單去掉speculation會在比較大的程度上影響到效能,而且絕大多數的時候,Speculation有益無害。

那麼只能想一些緩解的辦法。

題外話,英文裡的Mitigation是指緩解,不是完全修復。

這個辦法就是定義一個新型別的barrier指令,這個指令的作用就是告訴PCU硬體在這個地方不要做speculation.軟體工程師在認為可能出現Spectre variant1安全問題的地方插入(當然需要軟體工程師手動加,不要指望Compiler幫忙)這個新的barrier指令。

 

arm新加一條CSDB 有條件speculation barrier指令,這個指令的作用是,

在這個barrier完成之前

1)在CSDB程式順序之後,和條件選擇指令/或非直接跳轉指令有地址依賴關係的,任何讀寫和預取指令,

2)這些指令在條件選擇指令/或非直接跳轉指令條件明確之前,不會影響到cache allocation。

 

舉個例子,同樣對於下面的程式碼,

它可以生成如下指令

 

我們可以在if (untrusted_offset < limit)之後插入新的barrier指令,

Intel的情況類似,Intel推薦使用LFENCE 指令,它阻止老的指令retire之前新的指令被speculative執行。

這個問題mitigation的困難之處在於,需要讓無辜的軟體工程師編寫程式碼時思考是否為spectrevariant1的情況加barrier。還記得理解和使用mb, smp_mb, wmb等其他barrier的痛苦嗎?

對於arm來說,可用的mitigation已經包括,

·      在compiler toolchain里加入對新的barrier的支援。

·      在Linux kernel的eBPF中 

·      https://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git/tag/?h=security_fixes_20180118

         Variant 1 – genericebpf fix from list arm32and arm64 support being reworked for new Dan Williams proposal


Spectre Variant1 結語

因為Spectre variant1是效能和安全的魚和熊掌不能兼得的問題,雖然各CPU廠商提出來緩解的方法,但是挑戰和困難之處在於需要軟體工程師找到合適的地方實施這些緩解方法。



待續

相關閱讀

Spectre/Meltdown演義-- 通俗篇

Spectre/Meltdown演義--專業篇(1)

Spectre/Meltdown演義-專業篇(2)

Spectre/Meltdown演義-專業篇(3)