FLUSH+RELOAD技術


FLUSH+RELOAD技術是PRIME+PROBE技術的變體,攻擊間諜進程和目標進程的共享頁。在共享頁中,間諜進程可以確保一個特定的內存的映射從整個cache的層級中剔除。間諜進程就是使用這一點去監控所有的內存映射。這個攻擊的方式是Gullasch 等人提出技術為基礎的,增加了對虛擬化和多核條件下的適應。

一個攻擊輪由三個階段。在第一階段中,被監控的內存的映射從cache中被剔除,在第三階段之前,間諜進程允許目標訪問內存。在第三階段,間諜進程重新載入內存行,測量重新載入的時間。如果在等待的階段,目標進程訪問了指定的內存空間,那么這個內存的空間就在cache中有記錄,重載就只需要很短的時間。另一方面,如果目標沒有訪問指定的內存空間,則這個空間就需要從內存中提取,重載話費更長的時間。圖3(a)和(b)分別顯示了無目標進程訪問和有目標進程訪問的時間線。

如圖3(c)所示,目標進程訪問可能和間諜的重載階段重疊,在這種情況下,目標進程訪問不會觸發緩存的填充。相反,目標進程會使用重載階段的緩存數據。因此,間諜進程就錯過了訪問機會。類似的,也發生在部分覆蓋的情況。就像圖3(D),重載發生在目標進程訪問數據時。由於目標進程和間諜進程代碼執行是無關的,因此增加等待的時間可以減少由於重疊而丟失訪問的概率。另一方面,增加等待的時間也削弱了攻擊的粒度。

提高攻擊分辨率而不增加錯誤率的方法的就是提高針對指定區域提高訪問速率,例如使用循環體。攻擊無法區分不同訪問,但是,如圖3(e),丟失的幾率很小。

由於目標進程的處理器的內存入口隨機化,多處理器優化可能出現錯誤。這些優化包括數據的預提取以開辟空間和亂序執行。在分析攻擊結果的時候,攻擊着必須意識到優化和發展,並過濾他們的影響。我們的攻擊代碼如下,這個代碼測量在內存地址讀取數據的時間,然后剔除cache中的內存的映射。這個測量使用內嵌匯編指令的方式執行。

int probe(char *adrs) {                  
  volatile unsigned long time;           
                                        
  asm __volatile__ (                     
    " mfence \n"                             
" lfence \n"                             
    " rdtsc \n"                              
" lfence \n"                             
    " movl %%eax, %%esi \n"                  
" movl (%1), %%eax \n"                   
    " lfence \n"                             
" rdtsc \n"                              
    " subl %%esi, %%eax \n"                  
" clflush 0(%1) \n"                      
    : "=a" (time)                            
: "c" (adrs)                             
    : "%esi", "%edx");                      
return time < threshold;                 
}                                        

  

匯編代碼需要一個輸入,地址,儲存在%ecx中(16行)。變量time是返回值,他是讀取%eax寄存器中地址儲存值的時間(15行)。第10行讀取%ecx中地址指向4個bytes,地址由adrs變量指向。

為了測量此次讀取所需要的時間,我們使用處理器的時間戳計數器。在第7行rdtsc指令讀取64位計數器,低32bits在%eax中,%edx中儲存高32bits。由於我們測量的時間很短,所以我們只是用低位,忽略%edx中的高位。第9行將計數器復制到%ESI。讀取內存之后,再次調用,時間戳計數器(12行)。第13行,減去計數器的值,把結果放在寄存器%eax中。這個技術的關鍵是在cache中剔除指定的內存映射的能力。這個功能使用在14行中clflush這個指令。clflush指令可以從所有的cache層次中剔除指定的內存映射,包括所有核心的L1層和L2層。剔除所核心的映射,確保下次目標進程被映射到L3層上。

mfence和ifence指令的作用是使指令連續化。處理器可能在執行指令的時候是並行化或者不按順序的。如果沒有連續化,指令可能被分割執行。lfence指令可以使指令部分連續。他確保這個指令后面的指令不會在它之前執行。mfence指令作用於儲存操作。然而,他不針對其他指令,無法有效的分割。英特爾推薦使用cpuid進行指令串行化,然而,在虛擬化環境中,虛擬機管理器中cpuid仿真耗時過長(1000個周期以上),無法提供攻擊所需的粒度。18行比較兩個rdtsc指令與預定閾值之間的時間差。應為之前已經被清除了映射關系,如果返回的時間差小於閾值,則表明另一個進程訪問了內存行,超過的話,則沒有訪問。

攻擊中閾值的選擇是依賴於系統,為了找到測試系統的閾值,我們使用代碼測試內存和L1緩存的加載時間(為了測量L1的時間,我們移除14行的clflush指令)。在centos6.5系統,HP Elite 8300電腦的測試,如圖5,電腦使用i5-3470處理器。

來自L1cache緩存的數據經歷了44個周期(注意,這里包括了rdtsc和fence指令的執行時間,因此比單一指令時間更長)。從內存加載數據的時間,超過百分之98的時間在270到290個周期之間。其余分布在880個周期,大約200個在1140到1175個周期。內存訪問,沒有小於200個時鍾周期。

這個時間取決於硬件和軟件環境,戴爾PowerEdge T420,從L1載入需要33到43個,而內存需要230個周期,在相同的硬件條件下,使用KVM虛擬化,有百分之0.02從內存載入需要6000個周期。

基於測量結果和英特爾文檔,我們將閾值設置為120個周期。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM