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

ZenonXiu修志龍

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

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

Meltdown概述

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

Meltdown 允許能夠在存

在漏洞的處理器上運行代碼,

獲得整個內(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)有計劃利用KPTI (Kaiser)技術(shù)實現(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對應(yīng)的是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)才有訪問權(quán)限的數(shù)據(jù),雖然最終application代碼不能通過load/store指令得到kernel的data(最終如果這個load被architectually執(zhí)行會觸發(fā)MMU訪問權(quán)限fault,

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

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

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

參考white paper 提供的代碼

在EL0,有下面代碼

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

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

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. 因為Speculation, CPU會speculatively load 以上代碼的4和7,因為是speculation, 指令不會retire和回寫到X3和X5. 但是數(shù)據(jù)可以帶進cache.

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

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

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

4 ?LDR X3, [X4]

會導(dǎo)致訪問權(quán)限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設(shè)計有比較好的理解,因為本人一直支持Arm 構(gòu)架和CPU, 所以理解并不費事。

為了幫助理解,貼一個我認為最接近的比喻,

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

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

中午,女神來到食堂打飯,點了一份小籠包。

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

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

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

后來女神點好走了,輪到男生A點,他表示,我要一個跟她一樣的...

然而這會,

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

然而!

當(dāng)下一個男生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 比較熟悉。

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

在EL0運行application時,application

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

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

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

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

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

并且現(xiàn)代CPU的設(shè)計也不能禁止 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).

設(shè)計方面就是設(shè)計一個trampoline 的kernel PGD給運行user時用。

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

當(dāng)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.

當(dāng)從kernel返回到user時,正常的kernel_exit會調(diào)用trampoline的exit,tramp_exit會重新將kernel mapping 換成是trampoline. 這個過程叫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工作原理比較熟悉的話,可能會進一步想到一個問題。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 構(gòu)架和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來開關(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輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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

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

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