Arm64 Linux Kernel KPTI (Meltdown防御)方案解釋

ZenonXiu修志龍

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? MindShare思享? ? ? ? ? ? ? ? ? ? ? 1月17日

原創(chuàng)聲明:未經(jīng)作者許可,不許轉(zhuǎn)載。本文純屬個(gè)人觀點(diǎn)

Meltdown概述

Meltdown破壞了位于用戶和操作系統(tǒng)之間的基本隔離,允許惡意代碼訪問內(nèi)核內(nèi)存,從而竊取其他應(yīng)用程序以及OS數(shù)據(jù)。這個(gè)漏洞“熔化”了由硬件來實(shí)現(xiàn)的安全邊界。低權(quán)限用戶級別的應(yīng)用程序能利用它“越界”間接獲取內(nèi)存數(shù)據(jù)。

Meltdown 允許能夠在存

在漏洞的處理器上運(yùn)行代碼,

獲得整個(gè)內(nèi)核的數(shù)據(jù)。 Meltdown 的根本

原因是推測性和亂序執(zhí)行造成的。?

有關(guān)Meltdown的介紹文章已經(jīng)有很多,在本文中不再贅述.

本文主要說明arm64 Linux kernel是如何通過KPTI(Kernel Page Table Isolation 技術(shù)來解決Meltdown的問題。

需要說明的是,在Meltdown和Spectre問題爆發(fā)之前,Arm已經(jīng)有計(jì)劃利用KPTI (Kaiser)技術(shù)實(shí)現(xiàn)KASLR(Kernel Address Space Layout Randomization). ?Kaiser?防御機(jī)制具有阻

止 Meltdown攻擊的作用.

Meltdown on Arm processor

Arm

Cortex-A processors 中只有Cortex-A75受到Meltdown(Variant3) 的影響,Cortex-A75

DynamIQ處理器是目前Arm公布的最高性能的處理器(所以out of order最多). 在Arm的security

whitepaper里Meltdown對應(yīng)的是Variant 3 和 3a. KPTI是針對variant 3. 因?yàn)?a

只能讀到部分更高EL的system registers(不能改寫), 到目前為止,還沒有能利用這個(gè)實(shí)現(xiàn)攻擊的辦法.?

并且Cortex-A75也不受3a影響。

White paper 可以從這里下到?https://developer.arm.com/support/security-update/download-the-whitepaper?

問題描述:

Cortex-A75在更低的EL(比如user

application in EL0)時(shí),可以speculatively去訪問更高EL(比如kernel in

EL1)才有訪問權(quán)限的數(shù)據(jù),雖然最終application代碼不能通過load/store指令得到kernel的data(最終如果這個(gè)load被architectually執(zhí)行會(huì)觸發(fā)MMU訪問權(quán)限fault,

導(dǎo)致segment fault), 但是speculation已經(jīng)將某些數(shù)據(jù)帶到cache里,通過精心設(shè)計(jì)的cache

FLUSH+RELOAD 側(cè)邊道攻擊,可以通過間接手段得到kernel的數(shù)據(jù)。

所以這個(gè)問題的發(fā)生由 (在低特權(quán)級的ELspeculative access 更高EL數(shù)據(jù))+(精心設(shè)計(jì)的低特權(quán)級代碼)+(Cache FLUSH+RELOAD side channel attack)來觸發(fā)的。

參考white paper 提供的代碼

在EL0,有下面代碼

1 ?LDR X1, [X2] ; 精心設(shè)計(jì)這個(gè)load產(chǎn)生cache miss, 以便CPU會(huì)speculative做 4和7的訪問

2 ?CBZ X1, over ; 這個(gè)跳轉(zhuǎn)按代碼邏輯會(huì)跳

3 ? ? ? ? ? ? ? ; 但是CPU預(yù)測不跳

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對應(yīng)的數(shù)據(jù)都從cache 趕出去。

2. 制作條件(讓上面1對應(yīng)的load miss in cache)

3. 執(zhí)行以上代碼

3. 因?yàn)镾peculation, CPU會(huì)speculatively load 以上代碼的4和7,因?yàn)槭莝peculation, 指令不會(huì)retire和回寫到X3和X5. 但是數(shù)據(jù)可以帶進(jìn)cache.

? 比如如果kernel數(shù)據(jù)是1的話,在probe buffer 里offset 為0x1000對應(yīng)的數(shù)據(jù)會(huì)進(jìn)cache

? 如果kernel數(shù)據(jù)是0的話,在probe buffer 里offset 為0x0000對應(yīng)的數(shù)據(jù)會(huì)進(jìn)cache

4. 如果最終architectually 執(zhí)行?

4 ?LDR X3, [X4]

會(huì)導(dǎo)致訪問權(quán)限segment fault.

5. 攻擊者可以以cache line size 為stirde遍歷訪問probe buffer的數(shù)據(jù), 并測量每個(gè)訪問時(shí)間,如果那個(gè)訪問時(shí)間短,說明其數(shù)據(jù)已經(jīng)在cache 里面。再利用step3,可以反推出kernel data是 0還是1.

比如如果對probe buffer offset 為0x000的數(shù)據(jù)訪問時(shí)間短,那么可推出kernel data是0

比如如果對probe buffer offset 為0x000的數(shù)據(jù)訪問時(shí)間短,那么可推出kernel data是1

理解上面的內(nèi)容需要對CPU設(shè)計(jì)有比較好的理解,因?yàn)楸救艘恢敝С諥rm 構(gòu)架和CPU, 所以理解并不費(fèi)事。

為了幫助理解,貼一個(gè)我認(rèn)為最接近的比喻,

我們把CPU比做學(xué)校食堂,把黑客比作兩個(gè)男生A,B,用戶則是女神。

這天,男生A,B總要想辦法獲得女神的一點(diǎn)私密信息——比如,女神今天午飯吃的啥~

中午,女神來到食堂打飯,點(diǎn)了一份小籠包。

男生A在女神后面跟食堂大娘說:我也來一份,跟她一樣的~

然而這會(huì)食堂大娘表示,你等會(huì),你前面還有人哦。

好吧,雖然說是這么說,但是后面的廚房師傅已經(jīng)聽到了對話,已經(jīng)提前開始準(zhǔn)備好了另一份小籠包.....

后來女神點(diǎn)好走了,輪到男生A點(diǎn),他表示,我要一個(gè)跟她一樣的...

然而這會(huì),

食堂大娘表示,人家是人家,你是你,我們不能透露女神隱私喔,你可以走了,下一個(gè)! (這就是目前CPU的內(nèi)置的安全防線)

然而!

當(dāng)下一個(gè)男生B走到食堂大娘面前,直接說:隨便,哪道菜最快給我上哪道...

于是乎,既然之前廚房師傅已經(jīng)提前多準(zhǔn)備好了一份小籠包,就干脆直接把小籠包給了男生B....

這下男生知道了,女神中午吃了小籠包......

關(guān)鍵信息,就這么被泄露了,

雖然以上比喻中有很多不貼切

并沒有關(guān)鍵的用kernel data作為 probe buffer index部分。。。

男生和女生的包子應(yīng)該是隔離的

Meltdown 防御 on Arm64 Linux

接下來的內(nèi)容假設(shè)大家對Arm Linux 比較熟悉。

通過以上分析,我們知道了這個(gè)問題最關(guān)鍵的地方是,

在EL0運(yùn)行application時(shí),application

speculatively訪問kernel address時(shí), MMU可以做這個(gè)地址轉(zhuǎn)換,MMU

hardware并不檢查訪問權(quán)限,只做VA到PA的地址轉(zhuǎn)換. 得到PA后可以做memory access到cache中。

有人會(huì)問,為什么MMU不做訪問權(quán)限檢查,地址轉(zhuǎn)換同時(shí)做訪問權(quán)限檢查不是隨便可以做的事情嗎?對software

engineer來說好像工作并不多,但是對CPU的設(shè)計(jì)者來說,在RTL關(guān)鍵路徑(critical

path)上作一些看似不多的工作會(huì)帶來后端綜合的timing收斂的問題,影響到CPU可以跑到的最高頻率。

并且現(xiàn)代CPU的設(shè)計(jì)也不能禁止 speculation, out of order,我們不能因噎廢食,否則性能可能一夜回到解放前。

解決方案是什么呢? 方法就是,

在運(yùn)行user

application 的時(shí)候,將kernel mapping 減少到最少,只保留必須的user到kernel的exception entry

mapping. 其他的kernel mapping 在運(yùn)行user application時(shí)都去掉,變成無效mapping,

這樣的話,如果user訪問kernel data, 在MMU地址轉(zhuǎn)換的時(shí)候就會(huì)被擋掉(因?yàn)闊o效mapping).

設(shè)計(jì)方面就是設(shè)計(jì)一個(gè)trampoline 的kernel PGD給運(yùn)行user時(shí)用。

Trampoline kernel mapping PGD只包含exception entry必需的mapping.

當(dāng)user

通過系統(tǒng)調(diào)用,或是timer或其他異常進(jìn)入kernel是首先用trampoline的mapping,

接下來tramponline的vector處理會(huì)將kernel mapping 換成正常的kernel mapping

(SWAPPER_PGD_DIR), 并直接跳轉(zhuǎn)到kernel原來的vector entry, 繼續(xù)正常處理。

我們把上述過程稱之為map kernel mapping.

當(dāng)從kernel返回到user時(shí),正常的kernel_exit會(huì)調(diào)用trampoline的exit,tramp_exit會(huì)重新將kernel mapping 換成是trampoline. 這個(gè)過程叫unmap kernel mapping.

相關(guān)代碼請看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工作原理比較熟悉的話,可能會(huì)進(jìn)一步想到一個(gè)問題。User和kernel的translation是共享同一TLB 硬件的。

大家知道MMU會(huì)現(xiàn)在TLB里lookup,

我們需要避免user application發(fā)出的kernel address可以在TLB

hit,因?yàn)門LB中可能已經(jīng)有了用過的SWAPPER_PGD_DIR mapping的entry.

在KPTI之前kernel的mapping都是global(不匹配ASID). User application發(fā)出的kernel

address translation可以直接在TLB hit。這樣的話KPTI的translation table隔離機(jī)制就不work了。

這個(gè)問題可以用在kernel和user切換時(shí)對整個(gè)TLB invalidate,但是代價(jià)很高,我們要避免。

怎么處理呢?KPTI會(huì)

1. 給kernel space 也分配ASID,kernel mapping也變成和userspace一樣的non global mapping.

2. kernel分配ASID的時(shí)候,分出一個(gè)奇偶ASID對,kernel用偶的,user用奇的,從2開始分。比如kernel ASID 2, user ASID3 或kernel ASID 4, user ASID 5.

這樣的話因?yàn)檫\(yùn)行在user時(shí)的ASID和kernel時(shí)的ASID不一樣,user發(fā)出的地址沒法hit到kernel的TLB entry。

這個(gè)問題會(huì)在后面的圖示里表達(dá)比較清楚。

代碼請參照 ?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是個(gè)聰明的辦法,但是KPTI的開發(fā)還在演化中,以后可能會(huì)有變化。

Arm64 KPTI 圖示

代碼可以大家去看,但是看懂代碼需要對Arm 構(gòu)架和Linux kernel要比較了解。

為了幫助大家理解,我連夜畫了幾個(gè)圖。

圖1 沒有KTPI時(shí)運(yùn)行在user application的地址轉(zhuǎn)換和訪問

圖2 沒有KTPI時(shí)運(yùn)行在kernel的地址轉(zhuǎn)換和訪問

圖3 有KTPI時(shí)運(yùn)行在user application的地址轉(zhuǎn)換和訪問

圖4 ?有KTPI時(shí)運(yùn)行在kernel的地址轉(zhuǎn)換和訪問

圖5 Trampoline工作流程

總結(jié)

Arm64 Linux KPTI巧妙地通過trampoline以最小kernel改動(dòng)實(shí)現(xiàn)了Meltdown的防御。

KPTI可以通過enable一下kernel configuration來開關(guān)。

UNMAP_KERNEL_AT_EL0

Kernel patch set可以在這里找到,

https://patchwork.kernel.org/project/linux-arm-kernel/list/?submitter=will+deacon

Meltdown(variant 3) 只對Cortex-A75有影響。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 虛擬化(Virtualization)這種起源于上世紀(jì)60年代IBM大型機(jī)系統(tǒng)的技術(shù)在處理器性能大幅度提升的當(dāng)下,...
    古斟布衣閱讀 4,802評論 0 7
  • qemu中uboot用tftp加載內(nèi)核并用NFS作為根文件系統(tǒng)作者 codercjg 在 20 八月 2015, ...
    codercjg閱讀 1,498評論 0 2
  • 今天跟媽媽回奶奶家了,現(xiàn)在真是冰天雪地??!我要在自己在奶奶家呆好些天!我會(huì)想媽媽的!
  • 老婆是個(gè)非常愛說話的人。只要她在家,不管你聽不聽,她都喜歡不停的和你說話,似乎永遠(yuǎn)不會(huì)感到疲勞。久而久之,我也就習(xí)...
    東方忞閱讀 352評論 2 4

友情鏈接更多精彩內(nèi)容