ZenonXiu修志龍
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? MindShare思享? ? ? ? ? ? ? ? ? ? ? 1月17日
原創(chuàng)聲明:未經(jīng)作者許可几睛,不許轉(zhuǎn)載蕉扮。本文純屬個人觀點
Meltdown概述
Meltdown破壞了位于用戶和操作系統(tǒng)之間的基本隔離迎罗,允許惡意代碼訪問內(nèi)核內(nèi)存捧灰,從而竊取其他應用程序以及OS數(shù)據(jù)钻注。這個漏洞“熔化”了由硬件來實現(xiàn)的安全邊界蚂且。低權限用戶級別的應用程序能利用它“越界”間接獲取內(nèi)存數(shù)據(jù)。
Meltdown 允許能夠在存
在漏洞的處理器上運行代碼幅恋,
獲得整個內(nèi)核的數(shù)據(jù)杏死。 Meltdown 的根本
原因是推測性和亂序執(zhí)行造成的。?
有關Meltdown的介紹文章已經(jīng)有很多,在本文中不再贅述.
本文主要說明arm64 Linux kernel是如何通過KPTI(Kernel Page Table Isolation 技術來解決Meltdown的問題淑翼。
需要說明的是腐巢,在Meltdown和Spectre問題爆發(fā)之前,Arm已經(jīng)有計劃利用KPTI (Kaiser)技術實現(xiàn)KASLR(Kernel Address Space Layout Randomization). ?Kaiser?防御機制具有阻
止 Meltdown攻擊的作用.
Meltdown on Arm processor
Arm
Cortex-A processors 中只有Cortex-A75受到Meltdown(Variant3) 的影響窒舟,Cortex-A75
DynamIQ處理器是目前Arm公布的最高性能的處理器(所以out of order最多). 在Arm的security
whitepaper里Meltdown對應的是Variant 3 和 3a. KPTI是針對variant 3. 因為3a
只能讀到部分更高EL的system registers(不能改寫), 到目前為止系忙,還沒有能利用這個實現(xiàn)攻擊的辦法.?
并且Cortex-A75也不受3a影響。
White paper 可以從這里下到?https://developer.arm.com/support/security-update/download-the-whitepaper?
問題描述:
Cortex-A75在更低的EL(比如user
application in EL0)時惠豺,可以speculatively去訪問更高EL(比如kernel in
EL1)才有訪問權限的數(shù)據(jù)银还,雖然最終application代碼不能通過load/store指令得到kernel的data(最終如果這個load被architectually執(zhí)行會觸發(fā)MMU訪問權限fault,
導致segment fault), 但是speculation已經(jīng)將某些數(shù)據(jù)帶到cache里,通過精心設計的cache
FLUSH+RELOAD 側(cè)邊道攻擊洁墙,可以通過間接手段得到kernel的數(shù)據(jù)蛹疯。
所以這個問題的發(fā)生由 (在低特權級的ELspeculative access 更高EL數(shù)據(jù))+(精心設計的低特權級代碼)+(Cache FLUSH+RELOAD side channel attack)來觸發(fā)的。
參考white paper 提供的代碼
在EL0热监,有下面代碼
1 ?LDR X1, [X2] ; 精心設計這個load產(chǎn)生cache miss, 以便CPU會speculative做 4和7的訪問
2 ?CBZ X1, over ; 這個跳轉(zhuǎn)按代碼邏輯會跳
3 ? ? ? ? ? ? ? ; 但是CPU預測不跳
4 ?LDR X3, [X4] ; X4指向只能kernel訪問的kernel space地址
5 ?LSL X3, X3, #imm
6 ?AND X3, X3, #0xFC0 ?捺弦;移位成 probe buffer的offset7 ?LDR X5, [X6,X3] ; X6 是user application可以訪問的地址,用來做cache side
;channel attack 的probe buffer8 over
1.首先 用Cache FLUSH+RELOAD的辦法講probe buffer對應的數(shù)據(jù)都從cache 趕出去孝扛。
2. 制作條件(讓上面1對應的load miss in cache)
3. 執(zhí)行以上代碼
3. 因為Speculation, CPU會speculatively load 以上代碼的4和7,因為是speculation, 指令不會retire和回寫到X3和X5. 但是數(shù)據(jù)可以帶進cache.
? 比如如果kernel數(shù)據(jù)是1的話列吼,在probe buffer 里offset 為0x1000對應的數(shù)據(jù)會進cache
? 如果kernel數(shù)據(jù)是0的話,在probe buffer 里offset 為0x0000對應的數(shù)據(jù)會進cache
4. 如果最終architectually 執(zhí)行?
4 ?LDR X3, [X4]
會導致訪問權限segment fault.
5. 攻擊者可以以cache line size 為stirde遍歷訪問probe buffer的數(shù)據(jù), 并測量每個訪問時間苦始,如果那個訪問時間短寞钥,說明其數(shù)據(jù)已經(jīng)在cache 里面。再利用step3陌选,可以反推出kernel data是 0還是1.
比如如果對probe buffer offset 為0x000的數(shù)據(jù)訪問時間短理郑,那么可推出kernel data是0
比如如果對probe buffer offset 為0x000的數(shù)據(jù)訪問時間短,那么可推出kernel data是1
理解上面的內(nèi)容需要對CPU設計有比較好的理解咨油,因為本人一直支持Arm 構架和CPU, 所以理解并不費事您炉。
為了幫助理解,貼一個我認為最接近的比喻役电,
我們把CPU比做學校食堂赚爵,把黑客比作兩個男生A,B法瑟,用戶則是女神囱晴。
這天,男生A瓢谢,B總要想辦法獲得女神的一點私密信息——比如,女神今天午飯吃的啥~
中午驮瞧,女神來到食堂打飯氓扛,點了一份小籠包。
男生A在女神后面跟食堂大娘說:我也來一份,跟她一樣的~
然而這會食堂大娘表示采郎,你等會千所,你前面還有人哦。
好吧蒜埋,雖然說是這么說淫痰,但是后面的廚房師傅已經(jīng)聽到了對話,已經(jīng)提前開始準備好了另一份小籠包.....
后來女神點好走了整份,輪到男生A點待错,他表示,我要一個跟她一樣的...
然而這會烈评,
食堂大娘表示火俄,人家是人家,你是你讲冠,我們不能透露女神隱私喔瓜客,你可以走了,下一個竿开! (這就是目前CPU的內(nèi)置的安全防線)
然而谱仪!
當下一個男生B走到食堂大娘面前,直接說:隨便否彩,哪道菜最快給我上哪道...
于是乎疯攒,既然之前廚房師傅已經(jīng)提前多準備好了一份小籠包,就干脆直接把小籠包給了男生B....
這下男生知道了胳搞,女神中午吃了小籠包......
關鍵信息卸例,就這么被泄露了,
雖然以上比喻中有很多不貼切
并沒有關鍵的用kernel data作為 probe buffer index部分肌毅。筷转。。
男生和女生的包子應該是隔離的
Meltdown 防御 on Arm64 Linux
接下來的內(nèi)容假設大家對Arm Linux 比較熟悉悬而。
通過以上分析呜舒,我們知道了這個問題最關鍵的地方是,
在EL0運行application時,application
speculatively訪問kernel address時, MMU可以做這個地址轉(zhuǎn)換笨奠,MMU
hardware并不檢查訪問權限袭蝗,只做VA到PA的地址轉(zhuǎn)換. 得到PA后可以做memory access到cache中。
有人會問般婆,為什么MMU不做訪問權限檢查到腥,地址轉(zhuǎn)換同時做訪問權限檢查不是隨便可以做的事情嗎?對software
engineer來說好像工作并不多蔚袍,但是對CPU的設計者來說乡范,在RTL關鍵路徑(critical
path)上作一些看似不多的工作會帶來后端綜合的timing收斂的問題配名,影響到CPU可以跑到的最高頻率。
并且現(xiàn)代CPU的設計也不能禁止 speculation晋辆, out of order,我們不能因噎廢食渠脉,否則性能可能一夜回到解放前。
解決方案是什么呢瓶佳? 方法就是芋膘,
在運行user
application 的時候,將kernel mapping 減少到最少霸饲,只保留必須的user到kernel的exception entry
mapping. 其他的kernel mapping 在運行user application時都去掉,變成無效mapping,
這樣的話为朋,如果user訪問kernel data, 在MMU地址轉(zhuǎn)換的時候就會被擋掉(因為無效mapping).
設計方面就是設計一個trampoline 的kernel PGD給運行user時用。
Trampoline kernel mapping PGD只包含exception entry必需的mapping.
當user
通過系統(tǒng)調(diào)用贴彼,或是timer或其他異常進入kernel是首先用trampoline的mapping,
接下來tramponline的vector處理會將kernel mapping 換成正常的kernel mapping
(SWAPPER_PGD_DIR), 并直接跳轉(zhuǎn)到kernel原來的vector entry, 繼續(xù)正常處理潜腻。
我們把上述過程稱之為map kernel mapping.
當從kernel返回到user時,正常的kernel_exit會調(diào)用trampoline的exit器仗,tramp_exit會重新將kernel mapping 換成是trampoline. 這個過程叫unmap kernel mapping.
相關代碼請看Will Deacon 的patch set
[v2,13/18] arm64: entry: Hook up entry trampoline to exception vectors- - -2017-11-30Will DeaconNew
[v2,12/18] arm64: entry: Explicitly pass exception level to kernel_ventry macro- - -2017-11-30Will DeaconNew
[v2,11/18] arm64: mm: Map entry trampoline into trampoline and kernel page tables- - -2017-11-30Will DeaconNew
[v2,10/18] arm64: entry: Add exception trampoline page for exceptions from EL0
https://patchwork.kernel.org/patch/10085275/
如果大家對Arm MMU, TLB工作原理比較熟悉的話融涣,可能會進一步想到一個問題。User和kernel的translation是共享同一TLB 硬件的精钮。
大家知道MMU會現(xiàn)在TLB里lookup,
我們需要避免user application發(fā)出的kernel address可以在TLB
hit威鹿,因為TLB中可能已經(jīng)有了用過的SWAPPER_PGD_DIR mapping的entry.
在KPTI之前kernel的mapping都是global(不匹配ASID). User application發(fā)出的kernel
address translation可以直接在TLB hit。這樣的話KPTI的translation table隔離機制就不work了轨香。
這個問題可以用在kernel和user切換時對整個TLB invalidate忽你,但是代價很高,我們要避免臂容。
怎么處理呢科雳?KPTI會
1. 給kernel space 也分配ASID,kernel mapping也變成和userspace一樣的non global mapping.
2. kernel分配ASID的時候脓杉,分出一個奇偶ASID對糟秘,kernel用偶的,user用奇的球散,從2開始分尿赚。比如kernel ASID 2, user ASID3 或kernel ASID 4, user ASID 5.
這樣的話因為運行在user時的ASID和kernel時的ASID不一樣,user發(fā)出的地址沒法hit到kernel的TLB entry蕉堰。
這個問題會在后面的圖示里表達比較清楚凌净。
代碼請參照 ?Will Deacon patch set
[03/18] arm64: mm: Move ASID from TTBR0 to TTBR1- - -2017-11-17Will DeaconNew
[02/18] arm64: mm: Temporarily disable ARM64_SW_TTBR0_PAN- - -2017-11-17Will DeaconNew
[01/18] arm64: mm: Use non-global mappings for kernel space
[07/18] arm64: mm: Allocate ASIDs in pairs- - -2017-11-17Will DeaconNew
[06/18] arm64: mm: Fix and re-enable ARM64_SW_TTBR0_PAN
需要說明的是,雖然trampoline是個聰明的辦法屋讶,但是KPTI的開發(fā)還在演化中冰寻,以后可能會有變化。
Arm64 KPTI 圖示
代碼可以大家去看皿渗,但是看懂代碼需要對Arm 構架和Linux kernel要比較了解性雄。
為了幫助大家理解没卸,我連夜畫了幾個圖。
圖1 沒有KTPI時運行在user application的地址轉(zhuǎn)換和訪問
圖2 沒有KTPI時運行在kernel的地址轉(zhuǎn)換和訪問
圖3 有KTPI時運行在user application的地址轉(zhuǎn)換和訪問
圖4 ?有KTPI時運行在kernel的地址轉(zhuǎn)換和訪問
圖5 Trampoline工作流程
總結(jié)
Arm64 Linux KPTI巧妙地通過trampoline以最小kernel改動實現(xiàn)了Meltdown的防御秒旋。
KPTI可以通過enable一下kernel configuration來開關。
UNMAP_KERNEL_AT_EL0
Kernel patch set可以在這里找到诀拭,
https://patchwork.kernel.org/project/linux-arm-kernel/list/?submitter=will+deacon
Meltdown(variant 3) 只對Cortex-A75有影響迁筛。