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

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

微信公眾號 mindshare思享


上文Spectre/Meltdown演義-專業篇(1)講過了CPU可以怎麼做speculativeaccess. 這篇文章再說一個主題Cache side channel timing attack.


先從cache的原理開始說起,大家都知道cache是很靠近CPUcore的memory,所以有很快的訪問速度,如果一個數據進入到cache,可以在以後被多次使用的話,就可以避免每次記憶體訪問都要去外部的Flash,RAM, DRAM, ROM裡取指令或資料,提高系統的memory訪問效率。現在的一般程式的cache命中率可以達到95%以上(本人經常看一些benchmark,應用的效能問題,基本上如果cache命中率在90%一下就可能就會導致效能問題).

通常cache會分成多級cache,比如L1,L2, L3 cache,越是現代的CPU cache level會更多。比如armCortex-A 處理器的發展(內容均來在arm官方網站或公開網路資訊)

Cortex-A9, A5只有L1 cache,但是可以外接一個PL310的L2cache.


到了A15, A7, A17乃至後來的一些v8-a的處理器A57,A53, A35, A72, A73等,將L2 cache移進了Processor的Cluster裡面,每個CPU有自己單獨的L1指令和資料cache,但是一個Cluster裡面的所有CPU共享L2 cache.



最近的Cortex-A75, A55, A76的DynamIQprocessor已經在一個DSU的Cluster裡整合L3  cache. 每個CPU有自己私有的L1,L2 cache, 但是共享L3 cache.


 Cache基礎

如果你對cache基本知識很熟悉,可以跳過這一章節。

Cache不想一般的memory是直接將訪問地址decode然後直接訪問。因為cache是要在整個地址空間共享的,所以它的訪問方式有些不一樣,

Cache訪問時,cache會把一個地址分成3大部分,Tag,Set 和offset.其中Set是用來檢索cache的cachelines的.現代的cache都是set/wayassociative的,也就是cache會被分成多個way (你也可以理解成是多個bank的cache).

Cache包含幾個部分,用來緩衝從外部memory來的內容的很多cacheline的資料部分組成了cachedata ram, 用來每個cache line對應的部分地址(Tag)的組成了cacheTag ram. 除此之外,還有表示cache line是不是有效的Validbit, 和cache line是不是dirty的dirty bits.

 

基本上cache的工作方式是,

1.    如果訪問一個cacheable 的地址,CPU會在cache裡面找是不是要的內容在cache裡。

2.    Cache首先用地址的set部分去索引indexcache lines, 比如如果set部分是0就找第0個cacheline. 對於set/wayassociative的cache來說,這個檢索同時在多個way裡面進行(選通)

3.    接下來, cache 比較選通的cacheline對應的Tag是不是和訪問地址的tag部分相等,這個比較也是同時在多個way裡同時進行的。

4.    如果其中一個cache line對應的tag是和訪問地址的tag是一樣的,這就是cachehit, 說明資料在這個cacheline,  cache將資料直接交給cpu.

如果沒有任何一個cacheline對應的tag和訪問的地址是一致的話,這就是cachemiss, 說明資料不在cache裡面。

 

5.    如果cache miss, CPU 要從下一層memory(比如L2cache, 或是外部記憶體)取一個cacheline 的資料到cache中。這個行為(cacheline fill)對於讀來說是這樣的,對於寫來說不一定,取決於是write-back還是write-through(限於篇幅,不展開講)。

6.    取到的資料是放在那個way(way0?way1)對應的index為訪問地址set的cacheline 取決於cachereplace policy, 可以是隨機的,LRU等等。

如果選擇的cacheline裡面有有效資料,而且是dirty的,表示被替換的cacheline裡還沒有寫回到下一級記憶體的資料。這個時候cache需要先將原來cacheline的資料回寫到下級記憶體,然後才能將新的資料放到這個cache line, 這個過程叫cacheeviction.

將新的資料帶到選擇的cache line, 然後更新這個cache line對應的 Tag為訪問地址的Tag.


Cache timing side channel attack

Cache side channel timing attack的基本思路是利用這樣一個事實,

1.    如果一個數據已經在cache 裡面,對這個資料的訪問時間很短。

2.    如果一個數據不再cache 裡面,需要從下一級記憶體比如外部的RAM做cacheline fill, 這個資料的訪問時間會比較長。

3.    如果可以測量對資料訪問的時間(timing)長短,就可以知道一個數據是不是原來就在cache裡面。

大家一想,好像知道一個數據在不在cache裡面也沒關係啊,只要不知道這個資料的值也沒什麼安全問題。

但是有聰明人就可以利用這個線索像‘聞香識女人“中的中校一樣得到資料的值。

 

其實cache side channel attack早在2005年前就被人發現被利用來破解AES演算法密碼,後面更多的cacheside channel攻擊手段比如FLUSH+PROBE, PRIME+PROBE被髮明. 直到2017年GoogleProject Zero團隊將CPU speculation和cache side channel attack結合起來才發現了著名的CPUSpectre/Meltdown漏洞。

 

那它是怎麼工作的呢?

比如FLUSH+PROBE攻擊,

右邊是攻擊者attacker,左邊是受害者victim,他們共享cache.假設這次的攻擊目標是attacker獲取只有victim才能訪問的Message.Message的值是0b1010.

這次攻擊需要藉助一個attacker和victim都可以訪問的probe buff。

 

Step1:

Victim將cache 裡對應probebuff的cacheline全部flush出cache.鋪平沙坑,就等victim來踏了。

Step2

無辜的victim執行,

   for ( i=0; i<4,i++)

       if (message[i])    

          access(probe_buff[i*cache_line_size])

因為只是用message的bit作為probe buffer的檢索。Victim以為沒事,message本身沒洩露。殊不知已經掉進了圈套。

因為message的bit的腳印已經印到cache裡面了。

如果某bit是1,那麼對應的probe buff進入cache 裡面。

如果某bit是0,那麼對應的probe buff不會訪問,不進入cache裡面。

 

其實更實際的攻擊是  access(probe_buff[i*page_size]),其原因後表。


Step3:

魚上鉤了,該收網了。

Attacker挨個訪問probe buff,並測量每個訪問花的時間。如果時間短說明probe buff的資料原來就在cache中,attacker已經知道其對應的message bit是1. 如果訪問時間長,說明probe buff的資料還不在cache裡面,所以其對應的message bit 為0.

比如訪問probe buff[1]時間短,所以message bit [1]為1.

訪問probe buff[0]時間長,所以message bit[0]為0.



一個實際的例子

一個實際的例子可以在這裡找到:https://github.com/crozone/SpectrePoC/blob/master/spectre.c

 

Step1:

Flush cache:

 

Step2:

Victim受害


 

Step3:

收網,分析結果


本篇完


相關閱讀

Spectre/Meltdown演義-引子

Spectre/Meltdown演義-通俗篇

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