先理解一下題目:VoltJockey: Breaching TrustZone by Software-Controlled Voltage Manipulation over Multi-core Frequencies,這個漏洞打破了ARM下的TrustZone(可信執行環境),通過使用軟件控制的電壓來影響多核上的頻率來達到目的,這個軟件實際上就是DVFS(dynamic voltage and frequency scaling),后面會講到。作者利用“騎士”漏洞從TrustZone中獲取到AES的key,並且繞過了基於RSA的TrustZone驗證機制。
1.背景知識
1.1 TrustZone
TEE(Trusted Execution Environment)可信執行環境,是CPU上的一塊區域(SoC 芯片級系統),該區域能為代碼和數據提供一個隔離的、安全的執行環境。TrustZone是ARM設計的可信執行環境,相應地,Intel也推出了對應功能,叫SGX(Software Guard eXtensions)
目前,針對TrustZone的攻擊主要是利用軟件接口存在的漏洞,比如安全監控調用 (SMC),中斷請求 (IRQ),快速終端請求 (FIQ),共享內存訪問,和可信的特定程序調用。
修正不安全的函數調用能有效阻止這些攻擊。
針對硬件,使用邊信道、硬件錯誤注入(VoltJockey屬於硬件錯誤注入攻擊)等攻擊方法也有成功的案例,如CLKscrew(VoltJockey受此啟發),該攻擊能被硬件頻率鎖阻止。
在TrustZone中,一個物理處理器會被虛擬化為兩個虛擬處理器(一個用於一般環境,一個用於安全執行環境),並通過時間片切換的方式,分別執行兩種環境中的程序。受信任的程序只要能夠通過TrustZone的驗證機制(基於RSA),就能從一般環境加載進安全執行環境中被執行。
1.2 DVFS(Dynamic Voltage and Frequency Scaling)
能耗是瞬時動態功率隨時間變化的積分,可以表示如下:P = αCV2F,其中,P表示能耗,C表示電容,V表示電壓,F表示頻率,α為常數。
DVFS就是一個用來提高能源效率的東西,它能根據實時的計算負載,動態調整處理器核心的電壓和頻率。
廠商規定的電壓、頻率操作性能點將電壓和頻率關聯起來,根據運行需要的頻率,產生特定的電壓,從而保證處理器正確運行並且能源效率最高。系統管理員可以使用驅動命令手動設置cpu頻率,但是不能直接改變cpu的電壓。
Krait架構中的電源管理(Krait是用於本文實驗的處理器)
通常,芯片級系統(SoC)會整合多種外設,這些設備可能需要不同的電壓。SoC如何為這么多外設提供電壓呢,如果為所有外設提供一個固定的電壓,很明顯是不現實的,所以就提出了電源管理集成電路(PMIC)的概念,這個電路集成了多個硬件管理器,從而能夠為不同外設提供不同電壓。
圖:Krait下的電壓管理機制

在安卓設備中,有兩個重要的驅動能夠改變電壓:
- 高通支持一個供應商特定的管理驅動,該去東能夠控制PMIC的輸出並封裝電壓相關操作;
- 通用DVFS會根據節能和性能兩個標准更新處理器核心的頻率,這會間接導致電壓變化。問題就出現在這里,所有處理器核心共享一個硬件管理器,該管理器提供的某一電壓,能在同一時刻為不同核心提供不同的頻率。本論文將會利用到這一點。
1.3 基於電壓的硬件錯誤注入
電壓是確保電路實現正確功能的關鍵因素,不恰當的電壓會違反時序約束並且使數字電路產生錯誤輸出。本文就是通過控制電壓產生硬件錯誤,從而實現攻擊。為了進一步理解攻擊的原理,我們需要先了解什么是時序約束以及如何通過電壓產生錯誤輸出。
1.3.1 時序約束
數字電路包含多個電子元器件,對於某個電子元器件,給定一個輸入數據,需要一個特定的時間來產生穩定的、明確的輸出結果。這個時候,就需要適當地滿足時間約束,從而保證數字電路中的信息被有效處理。
下面用一個例子解釋什么是時序約束:

在這個例子中,電路的開始和結束分別是一個序列電子元件(本例中是flip-flop觸發器),中間的邏輯單元將第一個flip-flop觸發器的輸出結果傳輸給最后一個flip-flop觸發器。
flip-flop(觸發器): 能夠存儲一位二進制數字信號的基本單元電路叫做觸發器。
假設兩個flip-flop觸發器是由時鍾脈沖上升沿觸發的,表示如上圖,對其解釋如下:
- Tclk表示同步時鍾脈沖的時鍾周期,反映了電路的時鍾頻率(1秒內多少個周期就是頻率);
- 最后一個flip-flop觸發器的輸入信號(Idst)需要在下一次時鍾脈沖的上升沿到來之前的Tsetup時間內維持不變,這個Tsetup時間相當於一個緩沖間隔,用來確保時鍾脈沖上升沿到來之時,得到的數據是正確的。
- Tsrc表示在接收到時鍾脈沖上升沿信號后,第一個序列單元(Esrc)給出穩定輸出所需要的時間。
- Ttransfer表示從第一個序列單元(Esrc)輸出的數據傳輸到最后一個序列單元(Edst)所需要的時間,也就是中間邏輯單元的執行時間。
如果要形成穩定的頻率,周期(Tclk)必須是一個常數,同時,對於給定的Edst,其Tsetup實固定不變的。為了使得Edst的輸出結果(Odst)符合預期,Tsrc、Ttransfer需要滿足以下關系:
Tsrc + Ttransfer ⩽ Tclk - Tsetup - Tϵ
其中,Tϵ是非常小的一個常數。等式表達的意思是,在開始Tsetup時間前再預留一點時間,確保所有數據都已經正確傳輸過來。
1.3.2 通過不恰當的電壓產生硬件錯誤
如果提供的電壓比期望值低,Tsrc和Ttransfer將會增加,這將會使得等式 Tsrc + Ttransfer ⩽ Tclk - Tsetup - Tϵ 不成立,從而違反時間約束。

Tsrc和Ttransfer增加后,因為在下一個時鍾上升沿到來之時,Idst還沒有准備好(還沒有從1變為0),所以Odst將不會發生變化,這種情況將會導致硬件錯誤,從而造成比特位翻轉(例如:本來應該輸出0,結果輸出1),同樣的道理,如果施加一個低於期望值的電壓,也會導致硬件錯誤。
2.攻擊方法
通過上面內容,已經知道了如何通過電壓產生硬件錯誤,但是,如何在多核CPU上面通過電壓使其產生硬件錯誤呢?
如果一個處理器核心的電壓和頻率與其它內核相互獨立,那么攻擊者可以找到受害者的處理器核心,固定其頻率並選擇一個低於預期的得電壓,從而產生硬件錯誤。但是,現在的大部分包含DVFS的CPU中,多個處理器核心是共享同一個硬件電壓管理器,換話說,所有處理器核心是使用同樣的電壓,如果改變某處理器核心的電壓,則其它核心的電壓也會同步改變。
一個處理器核心的頻率是由底層電路的延遲決定的,高電壓導致低的電路延遲,從而產生高頻率。DVFS需要管理多個不同的頻率,不同頻率需要的電壓之間存在的差值是產生問題的關鍵。
2.1 VoltJockey思路
攻擊者的進程運行在一個低頻率的處理器核心,受害者的進程運行在一個高頻率的處理器核心上,攻擊者進程提供一個短時間的故障電壓,控制好電壓的大小,使得這個電壓對攻擊者進程所在處理器核心沒有影響,但是能使受害者進程所在處理器核心產生硬件錯誤,從而影響受害者進程。
舉兩個例子:
- 為了攻擊被TrustZone保護的AES函數,攻擊者可以調用AES並且將錯誤引入中間狀態矩陣,從而竊取AES的加密密鑰。
- 為了將不受信任的應用程序加載進TrustZone,攻擊者可以改變RSA解密函數的公共模數,從而改變該函數的最終輸出,欺騙(繞過)RSA身份驗證機制。
下圖對"VoltJockey"的思路進行了展示:

- 為能夠通過電壓干擾程序運行的環境作准備;
- 攻擊者程序等待受害者程序被調用;
- 攻擊者程序等待目標代碼被執行;
- 攻擊者程序改變處理器核心的電壓,使得受害者程序所在處理器核心產生硬件錯誤;
- 恢復到之前的正常電壓。
從上圖可以看到,實際上,就是在受害者程序執行到攻擊者想要攻擊的代碼時,改變處理器核心的電壓,使受害者程序所在的處理器核心產生硬件錯誤,從而使被攻擊代碼不能正確執行,最后恢復正常電壓。(受害者程序錯誤執行后,需要正確執行后面的代碼)
下面是每個步驟的具體細節:
- 准備一個適當的能夠發生電壓故障的環境,做三件事:(1)將受害者程序運行的處理器核心配置成高頻率,其它處理器核心配置成低頻率;(2)攻擊者程序用一個固定、安全的電壓初始化處理器;(3)清楚目標設備的剩余狀態,包括Cache布局、分支預測表、中斷向量表和狀態寄存器等。
- 通常情況下,能夠被VoltJockey注入錯誤的函數在受害者程序中只占很小的一部分,我們並不能確定其具體的執行時間,因此,攻擊者程序需要在受害者程序產生錯誤之前對其中間執行過程進行監控,等待能夠用來注入錯誤的函數被執行。
- 硬件注入攻擊的目標是改目標函數的一小部分指令和數據,而且,這部分被影響的代碼應該盡可能小。因此,錯誤注入點應該能被精確控制。到能夠產生錯誤注入之前需要的時間,稱為“預延遲”。
- 故障電壓的大小和持續時間,是使產生的硬件錯誤能夠被控制的兩個因素。找到恰當的電壓和持續時間,使得數據按照預期被改變,從而影響原有的程序流程,是非常重要的。
- 攻擊的最終目的是獲取受害者程序的敏感數據,或者篡改受害者進程的函數,而不是使受害者程序所在內核崩潰,因此,需要錯誤注入完成后,盡快恢復處理器核心電壓為修改之前的正常值,確保受害者程序繼續執行。
2.2 面臨的挑戰
-
並行執行:在VoltJockey中,攻擊者程序和受害者程序使並行執行的。
應對:系統庫函數提供來了將某個線程和處理器核心綁定的函數,此外,操作系統也允許用戶設置某個任務在特定的處理器核心上運行。
-
剩余狀態:受害者程序被執行之前的系統剩余狀態會影響受害者程序的指令執行時間,反映再三個方面:1)當訪問數據時,緩存命中比緩存未命中需要的時間更少;2)分支預測會導致指令執行的時間改變;3)未完成的任務和中斷可能強制處理器核心運行受害者程序。
應對:首先,清除緩存中的所有舊數據,然后,通過多次運行受害者程序的方法填充緩存數據,並且設置和受害者程序數據有關的處理器狀態寄存器。此外,還關閉了在操作電壓過程中針對受害者程序所在處理器核心的IRO和FIQ中斷。
-
有效的執行電壓:在android系統中,OPPs定義在一個驅動相關的系統文件dtsi中,里面規定了可用的頻率相應的安全電壓。
應對:VoltJockey需要突破OPPs規定的限制,從而控制電壓。作者分析了Nexus 6的DVFS中軟件棧的內核代碼,發現頂層驅動負責頻率表的建立和頻率的選擇。此外,供應商特定的頻率-電壓調節驅動會使用頂層軟件修改處理器核心的頻率和電壓,無論想要修改的值是否在頻率表中。這使得電壓管理機制規定的有效頻率和電壓輕易被打破。
-
電壓閾值:高通公司為krait架構植入了低壓差線性穩壓器(LDO)模式,該模式可為內核提供穩定且可控的電壓(電壓閾值),從而避免處理器出現故障。
也就是說如果請求的電壓小於閾值,則廠商特定的電壓調節器就把處理器電壓模式轉換為LDO,從而為處理器提供穩定的閾值電壓,而不是這個較小的電壓(原本請求的電壓)。
同理,如果使用高電壓閾值,理論上能達到和上面一樣的效果,但在實驗中發現,如果設置為高電壓閾值,系統就會立即重啟,因此不可用。
應對:這個閾值定義在“管理器屬性描述文件”中,使用電壓管理器中的功率指針讀取。本實驗中,通過修改功率指針函數修改這個電壓閾值,這比直接修改“管理器屬性描述文件”的影響更小。
-
電壓下調限制:為了保證處於高頻的內核在調整電壓的時候能夠正確運行,電壓管理器驅動器僅選擇 請求電壓 和 處於高頻內核對應的電壓 兩者中的最大值作為調整后的值。換句話說,除非降低頻率,否則調節器不接受任何向下調調節電壓的操作。
應對:在本研究中,通過修改調節器驅動程序來取消此類限制。
-
VoltJockey 內核:我們可以通過更改管理器驅動的方式繞過上面提到的限制,此外,我們在驅動中加入了一個限制機制,確保電壓被更改后不會被其他程序再次更改。用戶態程序沒有權限執行電壓管理器暴露出來的與電壓有關的操作。但是,本文作者希望攻擊程序能夠運行在用戶態,因為這樣會更穩定,並且易執行。
應對:為了達到這個目標,開發了一個用於電壓操作的內核模塊(VoltJockey kernel)來調用管理器驅動並且向用戶程序提供接口。為了保證操作電壓時的時序穩定以增加注入精度,內核模塊實現了前面提到的5個攻擊步驟。
-
監測受害者進程:錯誤注入進程要在受害者函數被執行之后馬上執行,攻擊者還需要檢測數據是否按被更改為預期值。這要求在實驗中,受害者進程的數據能夠被攻擊者看到。但是,在操作系統中攻擊者進程所在不能直接讀取受害者進程的數據,因為他們屬於兩個不同的進程。
應對:在本文中,使用側信道攻擊的方式來預測受害者程序中的數據。常見的側信道攻擊有:prime+probe, flush+reload, evict+reload, and flush+flush,本文使用prime+probe方法。
-
之前提到的延遲和故障電壓持續時間都是時間相關的因素,但是,在實際操作中,為了達成恰當的錯誤注入,通常需要幾個時鍾周期。操作系統提供的計時功能無法滿足對實驗對時間精度的要求。
應對:在VoltJockey內核中,使用只有NOP操作的特定循環來計算執行周期,NOP操作只花費一個時鍾周期而不會執行任何操作,這能保證計時精度。將時間計算指令放在需要的位置來估計函數從調用到返回消耗的時間。
-
電壓操作:發生硬件故障時,異常的電壓可能會使系統重啟。 此外,某些操作也可能失敗。
應對:為了避免重啟和提高攻擊的效率和可靠性,使用以下方法:
1)使和攻擊無關的內核處於“忙”狀態,下圖展示了在Nexus 6處理器中,無關內核(除攻擊者程序和受害者程序所在內核)分別處於不同的狀態(關閉、正常、忙),施加不同電壓時,為了實現硬件錯誤注入攻擊,該電壓需要持續的最短時間。可以看出,無關內核(黑線)關閉時,最小需要持續的時間最長,這是因為此時的處理器電壓充足,受害者程序所在內核運行很穩定,要使其發生錯誤,故障電壓則需要持續更長時間。為了不使錯誤影響到無關內核,實驗中,它們使用和攻擊者相同的低頻率。
2)從上圖可以看出,電壓越低,攻擊越容易(故障電壓持續時間更短),但是,突然的大幅度電壓下降會導致系統重啟和中斷。實驗發現,從基線電壓到故障電壓之間的差值越小,效果越好。因此,將處理器基線電壓設置成適合所有處理器核心的最低電壓。
3)適當的溫度對VoltJockey攻擊的實現也相當重要,我們發現,較高的溫度對注入攻擊的成功有幫助。實驗中,通過一個計算任務,使CPU得溫度在攻擊實施之前達到35◦C到40◦C之間。
從頻率表中選出頻率,並找到對應頻率下,使得系統穩定的邊界電壓。此外,還要獲得受害者進程所在處理器核心處於“忙”狀態時的安全電壓邊界。結果如下圖:
從圖中可以看到,不通頻率對應的電壓區別是很明顯的,處理器核心空閑時候的邊界電壓比忙的時候要高,特別是在高頻率的時候更明顯,可能因為忙的時候需要消耗更多能量。
-
攻擊程序的安全性:將兩個程序放在不同的處理器核心,可以在受害者程序因為硬件錯誤而崩潰時不至於影響到攻擊者程序,但是,故障電壓也可能導致攻擊者程序所在核心出現故障,特別是攻擊者程序核心的頻率不低於受害者程序核心時。從上圖可以看到,一個處理器核心的最小可接受電壓和頻率成正相關,可以找到一個頻率,使得其對低頻率是安全的,但是對高頻率時有害的。
應對:幸運的是,不同處理器核心的頻率是獨立的,攻擊之前,我們設置攻擊者程序所在核心為低頻率,受害者程序所在處理器核心在高頻率,然后選擇一個電壓,使得受害者程序需哦在和信出現硬件故障,但是攻擊者程序所在核心是安全的。
-
預備延遲:預備延遲控制着錯誤注入現場,主要由下面四個因素影響:1)受害者函數代碼,2)受害者核心頻率,3)攻擊者核心頻率,4)電壓。
應對:對於一個固定函數,特別是加密函數,它的實現通常是公開的,這很方便分析受害者函數的執行過程並提前找到合適的注入點。本研究中,實現了基於S-box的AES加密函數和基於安卓加密庫的RSA函數,我們使用不同的受害者核心頻率,相同的電壓,獲得了從AES開始到第七輪的MixColumn操作的NOP循環周期。此外,還計算了從RSA開始到將大尾數公共模轉換為小尾數模的指令所需的時間。 下圖顯示了預備延遲與AES和RSA受害者核心頻率之間的關系:
-
故障電壓和持續時間組合:雖然硬件錯誤的根源是電壓,但是惡意的操作是由電壓和持續時間決定的。我們的目標是將可控的硬件故障注入到第八輪AES的輸入狀態矩陣和RSA的公共模數中。觀察由不同的電壓和持續時間組合引起的數據修改可以幫助我們選擇適當的攻擊參數。
應對:我們固定處理器核心頻率,然后施加不同的核心電壓,並保持這個電壓持續不同時間。接下來,在第八輪AES和RSA的公共模數之前獲取狀態矩陣中引起的字節錯誤數。 對於每個電壓和持續時間組合,進行五次測試,並將平均修改后的位數繪制為如下所示的變色點/正方形。
3.后記
論文后面介紹了兩種利用“騎士”漏洞的具體攻擊實施過程,一種是攻擊TrustZone的AES加密算法,破解私鑰,另一種是攻擊基於RSA的TrustZone驗證機制,繞過驗證並在其中運行任意程序。