CPU漏洞詳解
1. 導(dǎo)言
性能測(cè)試對(duì)于 Linux 發(fā)行版來(lái)說(shuō)至關(guān)重要,Alibaba Cloud Linux 2 也是如此。(Alibaba Cloud Linux 2 是阿里巴巴操作系統(tǒng)團(tuán)隊(duì)推出的一款開(kāi)源且免費(fèi)的 Linux 操作系統(tǒng)發(fā)行版,其深度集成與優(yōu)化阿里云基礎(chǔ)設(shè)施,旨在為阿里云 ECS 客戶提供豐富功能、高性能且穩(wěn)定的操作系統(tǒng)服務(wù),歡迎大家使用。)然而在測(cè)試過(guò)程中發(fā)現(xiàn)很多子系統(tǒng)例如網(wǎng)絡(luò)子系統(tǒng)的性能與 CPU 調(diào)度性能密切相關(guān)。系統(tǒng)的調(diào)度性能固然與內(nèi)核中的調(diào)度算法相關(guān),然而過(guò)去一段時(shí)間內(nèi)現(xiàn)代 CPU 架構(gòu)下不斷發(fā)現(xiàn)的硬件漏洞及其修復(fù)嚴(yán)重影響了系統(tǒng)的調(diào)度性能。因而了解這些 CPU 漏洞的原理及修復(fù),對(duì)于系統(tǒng)性能測(cè)試具有重要意義。本文嘗試對(duì)當(dāng)前版本內(nèi)核中存在的 CPU 漏洞及修復(fù)作一個(gè)簡(jiǎn)單的介紹,本文亦可作為一個(gè)知識(shí)庫(kù),在需要的時(shí)候快速索引瀏覽。由于作者水平以及文章篇幅所限,文中若存在錯(cuò)誤,請(qǐng)大家共同交流學(xué)習(xí) ^^ 。2. 背景介紹
2018年一月,Google Project Zero 爆出現(xiàn)代處理器存在安全漏洞 Spectre 與 Meltdown。其實(shí)早在 2017 年Google Project Zero 就已經(jīng)發(fā)現(xiàn)了這些漏洞,而與此同時(shí) Moritz Lipp、Paul Kocher 等安全研究人員也對(duì)此進(jìn)行了研究。攻擊者可以使用這些漏洞竊取高特權(quán)級(jí)的數(shù)據(jù),因而對(duì)系統(tǒng)安全存在嚴(yán)重威脅。同時(shí)這兩組漏洞幾乎涉及當(dāng)今大部分主流的處理器(包括 Intel、AMD、ARM 等多種架構(gòu)),因而一公開(kāi)便引起了廣泛的討論。包括 Linux 在內(nèi)的主流操作系統(tǒng)隨后都對(duì)漏洞進(jìn)行了相應(yīng)的修復(fù)。由于這些漏洞利用處理器硬件的投機(jī)執(zhí)行(speculative execution)以及亂序執(zhí)行(out-of-order execution)特性,而這些特性對(duì)于現(xiàn)代處理器的性能提升具有不可或缺的作用,因而其中的一些修復(fù)會(huì)帶來(lái)較大的性能回退。由于這些漏洞源自現(xiàn)代處理器硬件的架構(gòu)設(shè)計(jì),軟件方面的修復(fù)通常只能緩解而不能根治問(wèn)題,同時(shí)自 2018年一月 Spectre 與 Meltdown 漏洞首次公布以來(lái),新變種以及新類(lèi)型的漏洞不斷出現(xiàn),因而可以預(yù)見(jiàn)這些漏洞的存在在未來(lái)相當(dāng)一段時(shí)間內(nèi)會(huì)成為常態(tài)。本文描述了當(dāng)前 CPU 架構(gòu)下存在的漏洞,對(duì)于各個(gè)漏洞現(xiàn)有的修復(fù)方案以及開(kāi)啟方式。/sys/devices/system/cpu/vulnerabilities/
目錄下存在以下文件,分別描述對(duì)應(yīng)的 CPU 漏洞:- meltdown
- spectre_v1
- spectre_v2
- spec_store_bypass
- l1tf
- mds
- “Not affected” 表示當(dāng)前 CPU 不存在該漏洞
- ?”Vulnerable” 表示當(dāng)前 CPU 存在該漏洞,同時(shí)沒(méi)有采取任何緩解措施
- “Mitigation: $M” 表示當(dāng)前 CPU 存在該漏洞,同時(shí)采取了相應(yīng)緩解措施
3. 漏洞詳解
3.1 Spectre Variant 1
本節(jié)描述的 spectre variant 1 特指 Bounds check bypass,SWAPGS 見(jiàn)下一節(jié)。
/sys/devices/system/cpu/vulnerabilities/spectre_v1
?描述 Spectre variant 1 的修復(fù)情況。早期版本中 Spectre Variant 1 只存在對(duì)于?array bounds check bypass?的修復(fù),且這種修復(fù)無(wú)法關(guān)閉,此時(shí)?spectre_v1
?文件的輸出只有一種顯示,即:- “Mitigation: __user pointer sanitization”
spectre_v1
?增加了對(duì)?swapgs?的修復(fù),詳情見(jiàn)下一節(jié)。3.1.1 Array bounds check bypass
Spectre variant 1 (CVE-2017-5753, Bounds check bypass) 的原理是利用處理器在執(zhí)行條件分支(conditional branch)時(shí)的投機(jī)執(zhí)行(speculative execution),使得處理器在投機(jī)執(zhí)行 false 分支的時(shí)候泄露相關(guān)的旁路信息,使得攻擊者通過(guò)旁路攻擊竊取數(shù)據(jù)。Spectre variant 1 的攻擊方式多見(jiàn)于 array bounds / user pointer check bypass。內(nèi)核對(duì)于該攻擊方式已經(jīng)存在相應(yīng)修復(fù):對(duì)于前者,在使用 array index 訪問(wèn)內(nèi)存之前,將 array index 執(zhí)行 mask 操作,從而確保 index 落在 [0, array_size] 的有效范圍內(nèi);而對(duì)于后者,在對(duì) user pointer 執(zhí)行有效性檢查的時(shí)候,添加一條 lfence 指令,以防止檢查完成前投機(jī)執(zhí)行之后的指令。以上這些修復(fù)的指令開(kāi)銷(xiāo)很小,同時(shí)只有在 1) 執(zhí)行數(shù)組訪問(wèn),同時(shí) array index 是用戶傳入的值,例如系統(tǒng)調(diào)用,或 2) 執(zhí)行 copy-from-user 的時(shí)候顯式調(diào)用對(duì)應(yīng)的修復(fù),而不是全局開(kāi)啟,因而開(kāi)銷(xiāo)較??;這些修復(fù)在 Upstreamv4.16-rc2
?版本合入。3.1.2 開(kāi)關(guān)
對(duì)于 array bounds check bypass 的修復(fù)目前無(wú)法關(guān)閉。3.2?SWAPGS
SWAPGS 是 spectre variant 1 的另一個(gè)變種,此時(shí)?/sys/devices/system/cpu/vulnerabilities/spectre_v1
?文件的輸出有:- “Vulnerable: __user pointer sanitization and usercopy barriers only; no swapgs barriers”
- “Mitigation: usercopy/swapgs barriers and __user pointer sanitization”
3.2.1 SWAPGS
Spectre variant 1 的原理是利用處理器執(zhí)行條件分支(conditional branch)時(shí)的投機(jī)執(zhí)行,因而其攻擊方式不局限于?array bounds / user pointer check bypass,另一種攻擊方式是在中斷或異常發(fā)生時(shí),攻擊者可以訓(xùn)練 branch predictor,使其錯(cuò)誤地跳過(guò)或執(zhí)行 swapgs 指令,從而為旁路攻擊制造條件,這種攻擊方式也就被稱(chēng)為?swapgs。例如當(dāng)由用戶態(tài)進(jìn)入中斷或異常時(shí),以下代碼中在條件分支判斷結(jié)束前,CPU 就可能會(huì)跳過(guò) swapgs 而執(zhí)行之后的代碼,此時(shí)執(zhí)行 GS 寄存器的訪問(wèn)操作時(shí),由于跳過(guò)了 swapgs 操作,因而此時(shí)實(shí)際訪問(wèn)的仍是用戶態(tài) GS 寄存器,此時(shí)攻擊者可以精心設(shè)計(jì)用戶態(tài) GS 寄存器的值,以獲取特定內(nèi)存地址處內(nèi)存的值。if (coming from user space)
swapgs
mov %gs:<percpu_offset>, %reg1
對(duì)于該攻擊方式的修復(fù)也是在中斷或異常的入口,在條件分支之后添加 lfence 指令,該修復(fù)在 Upstream?v5.3-rc4
? 合入主線。3.2.2 開(kāi)關(guān)
可以通過(guò)?nospectre_v1=off
?或?mitigations=off
?啟動(dòng)參數(shù)關(guān)閉對(duì)?swapgs?的修復(fù),注意這兩個(gè)參數(shù)均不能關(guān)閉之前對(duì)?array bounds check bypass?的修復(fù)。3.3 Spectre Variant 2
/sys/devices/system/cpu/vulnerabilities/spectre_v2
?描述 Spectre Variant 2 的修復(fù)情況,其輸出有如下情形:- “Vulnerable”,表示未開(kāi)啟任何修復(fù)
- “Mitigation: Full generic retpoline”,表示當(dāng)前開(kāi)啟?retpoline?修復(fù)
- “Mitigation: Full AMD retpoline”,表示當(dāng)前開(kāi)啟 AMD 處理器專(zhuān)用的?retpoline?修復(fù),只有 AMD 處理器可以開(kāi)啟該修復(fù)
- “Mitigation: Enhanced IBRS”,表示當(dāng)前開(kāi)啟?IBRS?修復(fù)
3.3.1 原理
Spectre variant 2 (CVE-2017-5715, Branch target injection) 實(shí)際是利用了處理器執(zhí)行間接跳轉(zhuǎn)指令時(shí)的投機(jī)執(zhí)行行為。間接跳轉(zhuǎn)指令執(zhí)行過(guò)程中,當(dāng)需要跳轉(zhuǎn)的絕對(duì)地址不在緩存中、而需要從內(nèi)存讀取時(shí),就會(huì)執(zhí)行分支預(yù)測(cè)功能。處理器硬件內(nèi)部使用 BTB (Branch Target Buffer) 來(lái)緩存 (間接跳轉(zhuǎn)指令的原地址, 跳轉(zhuǎn)指令的目標(biāo)地址) 這一對(duì)數(shù)據(jù),處理器硬件的分支預(yù)測(cè)即使用 BTB 來(lái)預(yù)測(cè)當(dāng)前執(zhí)行的間接跳轉(zhuǎn)指令對(duì)應(yīng)的目標(biāo)跳轉(zhuǎn)地址。然而該機(jī)制存在的一個(gè)問(wèn)題是,同一個(gè)處理器上的不同應(yīng)用程序會(huì)共用同一個(gè) BTB,因而 spectre variant 2 的原理即是攻擊者通過(guò)用戶態(tài)程序執(zhí)行特定的間接跳轉(zhuǎn)指令來(lái)訓(xùn)練當(dāng)前處理器的 BTB,從而使同一處理器上運(yùn)行的 Linux 內(nèi)核運(yùn)行間接跳轉(zhuǎn)指令時(shí),分支預(yù)測(cè)功能就會(huì)被誤導(dǎo)跳轉(zhuǎn)到攻擊者設(shè)計(jì)的一個(gè)特定地址上,從而運(yùn)行攻擊者設(shè)計(jì)的程序。3.3.2 retpoline 修復(fù)
spectre variant 2 漏洞主要攻擊間接跳轉(zhuǎn)指令,Google 提出的一種軟件解決方案稱(chēng)為?retpoline,其原理是使用 ret 指令來(lái)實(shí)現(xiàn)地址跳轉(zhuǎn)。由于 ret 指令使用的 RSB (Return Stack Buffer) 預(yù)測(cè)機(jī)制更為明確,因而不會(huì)受到攻擊者的惡意訓(xùn)練。該修復(fù)在 Upstreamv4.15-rc8
?版本合入。3.3.3 IBRS 修復(fù)
retpoline?的原理是使用 RSB ,從而規(guī)避用戶態(tài)程序?qū)?BTB 的惡意訓(xùn)練。然而對(duì)于 Skylake 及之后的機(jī)型,retpoline?并不能完全解決 Spectre variant 2。這是因?yàn)?Skylake 及之后的機(jī)型在調(diào)用深度較大而導(dǎo)致 RSB 用盡時(shí),會(huì)“回退”使用 BTB,從而又重新遭受 Spectre 威脅。Intel 提出的一種稱(chēng)為?IBRS?(Indirect Branch Restricted Speculation) 的解決方案,其原理是運(yùn)行于高特權(quán)級(jí)(privilege level) 的程序,不能復(fù)用低特權(quán)級(jí)程序緩存的 BTB,即內(nèi)核在使用 BTB 進(jìn)行分支預(yù)測(cè)時(shí),不能使用用戶態(tài)程序訓(xùn)練的 BTB 項(xiàng)。該解決方案需要處理器的 microcode 更新支持。該修復(fù)方案中處理器每次由低特權(quán)級(jí)切換到高特權(quán)級(jí)時(shí),都需要軟件配置一次相應(yīng)的寄存器,以 flush 掉之前低特權(quán)級(jí)程序訓(xùn)練的 BTB,因而實(shí)際存在一定的性能損耗。IBRS 修復(fù)方案實(shí)際沒(méi)有合入 Upstream,因而也不存在與 Cloud Kernel。3.3.4 EIBRS 修復(fù)
之前描述的 IBRS 修復(fù)需要處理器每次由低特權(quán)級(jí)切換到高特權(quán)級(jí)時(shí),軟件都需要配置一次相應(yīng)的寄存器,這給軟件設(shè)計(jì)帶來(lái)不便,同時(shí)存在一定的性能損耗。EIBRS (Enhanced IBRS) 是一種改進(jìn)的 IBRS,其原理與 IBRS 相同,唯一的區(qū)別是只需要在系統(tǒng)初始化時(shí)對(duì)寄存器進(jìn)行一次設(shè)置,之后處理器由低特權(quán)級(jí)切換到高特權(quán)級(jí)時(shí),處理器硬件都會(huì)自動(dòng)地 flush 掉之前低特權(quán)級(jí)程序訓(xùn)練的 BTB。該修復(fù)方案需要處理器硬件支持,目前只支持 “future CPUs”,在 Upstreamv4.19-rc1
?合入。3.3.5 開(kāi)關(guān)
可以使用?spectre_v2
?啟動(dòng)參數(shù)可以設(shè)置是否開(kāi)啟 Spectre variant 2 修復(fù),以及選擇哪一種修復(fù)方案,其格式為:spectre_v2=[off|on|retpoline|retpoline,amd|retpoline,generic|auto]
- “off”, 表示關(guān)閉 Spectre variant 2 修復(fù);
- “retpoline,generic”, 表示開(kāi)啟?retpoline?修復(fù);
- “retpoline,amd”, 表示開(kāi)啟 AMD 處理器特定的?retpoline?修復(fù);
- “retpoline”,表示開(kāi)啟?retpoline?修復(fù),但是會(huì)根據(jù)當(dāng)前處理器的型號(hào),自定選擇 “retpoline,generic” 或是 “retpoline,amd”;
- “on”?與?“auto”?具有相同的效果,表示開(kāi)啟 Spectre variant 2 修復(fù),并自動(dòng)選擇修復(fù)方案:若處理器支持?EIBRS?,則開(kāi)啟?EIBRS?修復(fù),否則開(kāi)啟?retpoline?修復(fù)。
spectre_v2
?啟動(dòng)參數(shù)時(shí),默認(rèn)為?spectre_v2=auto
,即自動(dòng)選擇 Spectre variant 2 的修復(fù)方案。需要關(guān)閉 Spectre variant 2 修復(fù)時(shí),可以通過(guò)?nospectre_v2
?或?spectre_v2=off
?啟動(dòng)參數(shù)關(guān)閉從 Upstream LTS?v4.19.43
? 版本起,也可以使用?mitigations=off
?啟動(dòng)參數(shù)關(guān)閉包含 Spectre Variant 2 修復(fù)在內(nèi)的所有修復(fù)。3.4 Spectre Variant 4 (Speculative Store Bypass)
/sys/devices/system/cpu/vulnerabilities/spec_store_bypass
?描述 Speculative Store Bypass 的修復(fù)情況,其輸出有如下情形:- “Vulnerable”,表示不開(kāi)啟任何?Speculative Store Bypass 修復(fù)
- “Mitigation: Speculative Store Bypass disabled”,表示在處理器硬件層面全局關(guān)閉 store buffer bypass 特性,這會(huì)較大程度地影響處理器性能
- “Mitigation: Speculative Store Bypass disabled via prctl”,表示用戶態(tài)程序可以通過(guò)?prctl 系統(tǒng)調(diào)用修復(fù)?Speculative Store Bypass
- “Mitigation: Speculative Store Bypass disabled via prctl and seccomp”,表示用戶態(tài)程序可以通過(guò) seccom 框架修復(fù)?Speculative Store Bypass
3.4.1 原理
Spectre variant 4 (CVE-2018-3639, Speculative Store Bypass) 利用?store buffer bypass?時(shí)泄漏的旁路信息。現(xiàn)代處理器在對(duì)內(nèi)存進(jìn)行讀寫(xiě)時(shí),通常在處理器與內(nèi)存之間維護(hù)一個(gè)高速緩存,稱(chēng)為 load buffer 與 store buffer。當(dāng)處理器對(duì)某個(gè)內(nèi)存地址進(jìn)行讀操作時(shí),除了查詢 load buffer,還需要查詢 store buffer,以獲取處理器之前對(duì)該內(nèi)存地址寫(xiě)入的值。盡管 store buffer 相對(duì)于內(nèi)存屬于高速緩存,然而其訪問(wèn)速度相對(duì)于 CPU 來(lái)說(shuō)仍然較慢。因而為了提升性能,在這種情況下現(xiàn)代處理器通常采用 Speculative Store Bypass 的優(yōu)化方式,即假設(shè) store buffer 中不存在當(dāng)前內(nèi)存地址的更新值,就開(kāi)始投機(jī)執(zhí)行之后的指令,若之后發(fā)現(xiàn) store buffer 中存在更新的值,就丟棄之前投機(jī)之行的結(jié)果。然而在該投機(jī)執(zhí)行的過(guò)程中,已經(jīng)泄露了相關(guān)的旁路信息。3.4.2?Speculative Store Bypass Disable (SSBD) 修復(fù)
可以通過(guò)設(shè)置處理器的相關(guān)寄存器,全局關(guān)閉處理器的 Speculative Store Bypass 優(yōu)化。該修復(fù)方案需要 microcode 更新支持,Upstreamv4.17-rc7
?合入。3.4.3 prctl 修復(fù)
Speculative Store Bypass 攻擊只能發(fā)生在相同特權(quán)級(jí)下,即用戶態(tài)無(wú)法攻擊內(nèi)核態(tài),因而 Spectre variant 4 常見(jiàn)的一種攻擊場(chǎng)景是 sandbox。這種場(chǎng)景下同一個(gè)進(jìn)程分別運(yùn)行 sandbox 主體程序、以及運(yùn)行在 sandbox 內(nèi)部的 untrusted 程序這兩種程序,通過(guò) Spectre variant 4 運(yùn)行在 sandbox 內(nèi)部的程序有可能竊取 sandbox 主體程序的數(shù)據(jù)。同時(shí)之前所述全局關(guān)閉 Speculative Store Bypass 的方式代價(jià)過(guò)大,內(nèi)核提供了一種 prctl 的修復(fù)方案。這種修復(fù)方案實(shí)際是以 per-thread 粒度關(guān)閉 Speculative Store Bypass 優(yōu)化。用戶態(tài)進(jìn)程可以調(diào)用 prctl 系統(tǒng)調(diào)用(with PR_SET_SPECULATION_CTRL - PR_SPEC_DISABLE 參數(shù)),使得處理器只有在調(diào)度執(zhí)行當(dāng)前進(jìn)程的過(guò)程中,關(guān)閉 Speculative Store Bypass 優(yōu)化。該修復(fù)方案在 Upstreamv4.17-rc7
?合入。3.4.4 seccomp 修復(fù)
與 prctl 修復(fù)方案類(lèi)似,seccomp 修復(fù)也是以 per-thread 粒度關(guān)閉 Speculative Store Bypass 優(yōu)化,只是采用 seccomp 框架的進(jìn)程會(huì)自動(dòng)關(guān)閉該優(yōu)化,而不需要進(jìn)程顯式調(diào)用 prctl 系統(tǒng)調(diào)用。該修復(fù)方案在 Upstreamv4.17-rc7
?合入。3.4.5 開(kāi)關(guān)
spec_store_bypass_disable
?啟動(dòng)參數(shù)用于設(shè)置是否開(kāi)啟 Speculative Store Bypass 修復(fù),以及采用何種修復(fù)方案,其格式為:spec_store_bypass_disable=[off|on|auto|prctl|seccomp]
- “off”,表示不開(kāi)啟任何修復(fù)
- “on”,表示全局關(guān)閉處理器的?Speculative Store Bypass 優(yōu)化
- “prctl”,表示采用 prctl 修復(fù)方式
- “seccomp”,表示采用 seccomp 修復(fù)方式
- “auto”,表示自動(dòng)選擇修復(fù)方式,若系統(tǒng)支持 seccomp 框架,則默認(rèn)采用 seccomp 修復(fù)方式,否則采用 prctl 修復(fù)方式
spec_store_bypass_disable
?啟動(dòng)參數(shù)時(shí),若處理器支持 Speculative Store Bypass Disable,則默認(rèn)采用spec_store_bypass_disable=auto
,否則默認(rèn)不開(kāi)啟所有 Speculative Store Bypass 修復(fù)。可以通過(guò)?spec_store_bypass_disable=off
?或?nospec_store_bypass_disable
?啟動(dòng)參數(shù)關(guān)閉該修復(fù)。以上修復(fù)以及啟動(dòng)參數(shù)都在 Upstream v4.17-rc7
?版本合入。從 Upstream LTS?v4.19.43
? 版本起,也可以使用?mitigations=off
?啟動(dòng)參數(shù)關(guān)閉包含 Speculative Store Bypass 修復(fù)在內(nèi)的所有修復(fù)。3.5 Meltdown
/sys/devices/system/cpu/vulnerabilities/meltdown
? 描述 Meltdown 的修復(fù)情況,其輸出- “Vulnerable”,表示未開(kāi)啟任何修復(fù)
- “Mitigation: PTI”,表示采用 PTI 修復(fù)
3.5.1 原理
現(xiàn)代操作系統(tǒng)通常將內(nèi)核態(tài)與用戶態(tài)的地址空間相分隔,用戶態(tài)程序沒(méi)有權(quán)限訪問(wèn)內(nèi)核態(tài)的地址空間,這一特性是系統(tǒng)安全的重要基石。Meltdown (CVE-2017-5754) 攻擊則利用現(xiàn)代處理器的亂序執(zhí)行(out-of-order execution)特性,打破了用戶態(tài)、內(nèi)核態(tài)地址空間之間的隔離,通過(guò)旁路攻擊,使得用戶態(tài)程序可以獲取內(nèi)核態(tài)地址空間處內(nèi)存的值。movzx (%rcx), %rax
shl $12, %rax
movq (%rbx, %rax), %rbi
考慮以上示例代碼,假設(shè) rcx 寄存器保存內(nèi)核地址空間內(nèi)需要探測(cè)的某一內(nèi)存地址,指令 1 即 movzx 指令表示讀取該內(nèi)存地址處內(nèi)存的值,并保存到 rax 寄存器中。在該指令執(zhí)行過(guò)程中檢測(cè)到進(jìn)程不具備該內(nèi)存地址的訪問(wèn)權(quán)限,因而會(huì)觸發(fā)異常,而導(dǎo)致 rax 寄存器中的值被丟棄。以上過(guò)程都符合處理器的設(shè)計(jì),然而實(shí)際上處理器硬件自身存在指令亂序執(zhí)行的優(yōu)化,在執(zhí)行 movzx 指令尚未結(jié)束的情況下,之后的指令 2、3 實(shí)際已經(jīng)開(kāi)始運(yùn)行。在指令 1 (權(quán)限檢查)結(jié)束之前,指令 2、3 已經(jīng)可以訪問(wèn) rax 寄存器的值。雖然之后指令 1 結(jié)束時(shí),指令 2、3 之行過(guò)程中寄存器的狀態(tài)都被丟棄,但是 cache 的狀態(tài)變化得以保留。攻擊程序通過(guò) cache 旁路攻擊就可以獲取泄露的內(nèi)核地址空間中內(nèi)存的值。3.5.2 PTI 修復(fù)
以上 Meltdown 攻擊實(shí)現(xiàn)的另外一個(gè)重要條件是,Linux 內(nèi)核在實(shí)現(xiàn)時(shí)出于性能考慮,用戶態(tài)進(jìn)程使用的 page table 實(shí)際包含內(nèi)核態(tài)地址空間的映射,因而在以上攻擊方式中,攻擊者可以在用戶態(tài)進(jìn)程中獲取內(nèi)核態(tài)地址空間的內(nèi)存數(shù)據(jù)。KPTI (Kernel Page Table Isolation) 則恰好可以縮減用戶態(tài)進(jìn)程使用的 page table 中內(nèi)核地址空間的映射,其原理是進(jìn)程運(yùn)行在用戶態(tài)時(shí),將內(nèi)核映射中除 exception entry 之外的其他映射都設(shè)置為無(wú)效,這樣再發(fā)生 meltdown 攻擊時(shí),由于對(duì)應(yīng)的映射無(wú)效,因而攻擊者已經(jīng)無(wú)法再讀取對(duì)應(yīng)內(nèi)核地址空間中的數(shù)據(jù)。當(dāng)進(jìn)程通過(guò)系統(tǒng)調(diào)用或異常由用戶態(tài)進(jìn)入內(nèi)核態(tài)時(shí),會(huì)將用戶進(jìn)程的 page table 中的內(nèi)核映射切換為有效的映射;當(dāng)調(diào)用結(jié)束進(jìn)程從內(nèi)核態(tài)回到用戶態(tài)時(shí),再次切換進(jìn)程的內(nèi)核映射,使其變?yōu)闊o(wú)效。KPTI 其實(shí)早在 Meltdown 漏洞爆發(fā)之前就已經(jīng)出現(xiàn),因?yàn)榍『每梢跃徑?Meltdown 攻擊而被廣泛使用,其于 Upstream?v4.15
?合入。KPTI 修復(fù)對(duì)于系統(tǒng)性能存在較大影響,可以參考 Brendan Gregg 的分析。3.5.3 開(kāi)關(guān)
pti
?啟動(dòng)參數(shù)(Upstream?v4.15-rc6
?合入)用于設(shè)置是否開(kāi)啟 KPTI 修復(fù),其格式為pti=[off|on|auto]
- “off”,表示不開(kāi)啟 KPTI 修復(fù)
- “on”,表示開(kāi)啟 KPTI 修復(fù)
- “auto”,表示只有當(dāng)前處理器存在 Meltdown 漏洞時(shí)才開(kāi)啟 KPTI 修復(fù)
pti=off
?或?nopti
?(Upstream v4.15-rc6 合入)啟動(dòng)參數(shù)關(guān)閉 KPTI 修復(fù)。從 Upstream LTS?v4.19.43
? 版本起,也可以使用?mitigations=off
?啟動(dòng)參數(shù)關(guān)閉包含 KPTI 修復(fù)在內(nèi)的所有修復(fù)。3.6 L1TF
/sys/devices/system/cpu/vulnerabilities/l1tf
?描述 L1TF 的修復(fù)情況,其輸出有如下格式:
Mitigation: PTE Inversion;[VMX: ][, SMT: ]
- “Mitigation: PTE Inversion”,表示使用 PTE inversion 修復(fù)
- VMX?字段描述是否開(kāi)啟?L1D flush 修復(fù)
- “vulnerable”,表示不開(kāi)啟?L1D flush 修復(fù)
- “conditional cache flushes”,表示開(kāi)啟 conditional L1D flush 修復(fù)
- “cache flushes”,表示開(kāi)啟 unconditional L1D flush 修復(fù),
- SMT?字段描述是否開(kāi)啟 SMT
- “vulnerable”,表示開(kāi)啟 SMT
- “disabled”,表示關(guān)閉 SMT
3.6.1 原理
L1TF (CVE-2018-3615, ?L1 data Terminal Fault) 同樣是利用處理器的投機(jī)執(zhí)行來(lái)獲取一個(gè) physical page 的內(nèi)容。Linux 中使用 page table entry (PTE) 來(lái)實(shí)現(xiàn)虛擬地址到物理地址之間的轉(zhuǎn)換,x86 PTE 的格式如上圖所示,其中 PFN (Page Frame Number) 字段描述對(duì)應(yīng) page frame 的物理地址,P (Present) 字段描述當(dāng)前虛擬地址是否存在對(duì)應(yīng)的物理地址,即是否為該虛擬地址分配了對(duì)應(yīng)的 physical page frame。進(jìn)程在使用虛擬地址訪問(wèn)內(nèi)存時(shí),會(huì)首先找到該虛擬地址對(duì)應(yīng)的 PTE,若 P 字段為 0,則會(huì)發(fā)生 page fault;若 P 字段為 1,根據(jù) PFN 字段的值在 L1 data cache 中尋找是否存在緩存。Intel 處理器在判斷 P 標(biāo)志位是否為 1 的時(shí)候,在判斷尚未結(jié)束之前會(huì)投機(jī)之行之后的代碼,即根據(jù) PFN 字段的值在 L1 data cache 中尋找是否存在緩存。若緩存命中,那么通過(guò) cache 旁路攻擊,攻擊者就可以獲取某一物理地址處的內(nèi)存數(shù)據(jù)。3.6.2?PTE inversion 修復(fù)
當(dāng)不涉及虛擬化時(shí),L1TF 的危害其實(shí)相對(duì)有限,因?yàn)楣粽卟惶菀讟?gòu)造 PFN 字段具有特定值的 PTE,這樣攻擊者就不能通過(guò) L1TF 獲取特定物理地址處的內(nèi)存值。即使攻擊方式不太容易實(shí)現(xiàn),數(shù)據(jù)泄露的風(fēng)險(xiǎn)是確實(shí)存在的。同時(shí)考慮到以上攻擊方式成功的重要條件是 PFN 構(gòu)成的物理地址在 L1 cache 中緩存命中,因而 PTE inversion 可以用于修復(fù)。其原理是當(dāng)開(kāi)啟 PTE inversion 時(shí),逆序存儲(chǔ) non-Present 的 PTE 中的所有 bit,這樣以上攻擊方式中,使用 PFN 字段逆序之后的值在 L1 cache 中就會(huì)發(fā)生 cache miss。PTE inversion 總是開(kāi)啟。3.6.3 L1D flush 修復(fù)
注意:該修復(fù)只適用于 host kernelL1TF 攻擊也可以發(fā)生在 guest VM 中,此時(shí)若攻擊者可以自由更換 guest kernel,那么攻擊者就可以自由地構(gòu)造 PTE 使得 non-Present PTE 的 PFN 字段具有特定值,從而讀取任意物理地址處的內(nèi)存值,使得 guest VM 獲取 host kernel 甚至其他 guest VM 的數(shù)據(jù)。guest kernel 使用 PTE inversion 只能防止用戶態(tài)進(jìn)程竊取 guest kernel 的數(shù)據(jù),而為了防止 guest VM 獲取 host 乃至其他 guest VM 的數(shù)據(jù),host kernel 可以采用 L1D flush 的修復(fù)方式。其原理是,考慮到 L1TF 攻擊方式的重要條件是對(duì)應(yīng)的物理地址在 L1 data cache 中存在緩存,那么 host kernel 每次在進(jìn)入 guest 之前,都執(zhí)行 flush L1 data cache 操作。當(dāng) VMEXIT/VMENTER 的頻率較大時(shí),該修復(fù)方式會(huì)對(duì)系統(tǒng)帶來(lái)較大的性能回退。因而 L1D flush 實(shí)際提供兩種工作模式:- conditional flush
- unconditional flush
conditional flush 是指當(dāng) VMEXIT 與 VMENTER 之間執(zhí)行的都是不重要的代碼路徑時(shí),就不執(zhí)行 flush L1 data cache 操作,這減小了性能開(kāi)銷(xiāo),但是會(huì)泄露 hypervisor 的內(nèi)存布局。
3.6.3 SMT Disabling 修復(fù)
注意:該修復(fù)只適用于 host kernel以上 L1D flush 修復(fù)可以防止 guest VM 對(duì) host kernel 的 L1TF 攻擊,但是在開(kāi)啟 SMT (Symmetric Multi-Threading, or Hyperthreads) 的情況下,一個(gè) logical CPU 執(zhí)行 L1D flush 操作后,同一個(gè) Core 上的另一個(gè) logical CPU 實(shí)際可以重新生成 L1D cache。因而為了讓 L1D flush 修復(fù)真正生效,有時(shí)還需要配合關(guān)閉 SMT 特性。3.6.4 開(kāi)關(guān)
l1tf 啟動(dòng)參數(shù)用于設(shè)置是否開(kāi)啟 L1TF 修復(fù),以及采用何種修復(fù)方案,其格式為:l1tf=[off|flush,nowarn|flush|flush,nosmt|full|full,force]
- “off”,表示不開(kāi)啟任何 L1TF 修復(fù)
- “flush”,表示開(kāi)啟 conditional L1D flush 修復(fù),關(guān)閉SMT Disabling 修復(fù)
- “flush,nowarn”,與 “flush” 一樣,開(kāi)啟L1D flush 修復(fù),關(guān)閉SMT Disabling 修復(fù),只是 “flush” 在第一臺(tái) VM 啟動(dòng)時(shí)會(huì)發(fā)出 warning 警告(因?yàn)?SMT Disabling 修復(fù)沒(méi)有開(kāi)啟而可能存在潛在的威脅),而?”flush,nowarn” 則不會(huì)
- “flush,nosmt”,表示開(kāi)啟 conditional L1D flush 修復(fù),開(kāi)啟 SMT Disabling 修復(fù)
- “full”,表示開(kāi)啟 unconditional L1D flush 修復(fù),開(kāi)啟 SMT Disabling 修復(fù)
- “full,force”,與 “full” 一樣,只是?”full” 配置下還可以通過(guò) sysfs 接口在運(yùn)行時(shí)動(dòng)態(tài)開(kāi)啟或關(guān)閉 L1D flush 修復(fù)或 SMT Disabling 修復(fù),而?”full,force” 配置下則不行
l1tf=off
?(?v4.19-rc1
?合入)關(guān)閉 L1TF 修復(fù)。從 Upstream LTS?v4.19.43
?版本起,也可以使用?mitigations=off
?啟動(dòng)參數(shù)關(guān)閉包含 L1TF 修復(fù)在內(nèi)的所有修復(fù)。3.7 MDS
/sys/devices/system/cpu/vulnerabilities/mds
? (?v4.19.43
?合入)描述 MDS 的修復(fù)情況- “Vulnerable”,表示不開(kāi)啟 MDS 修復(fù)
- “Vulnerable: Clear CPU buffers attempted, no microcode”,表示開(kāi)啟?CPU buffer clear 修復(fù),但是當(dāng)前處理器沒(méi)有 microcode 支持,因而當(dāng)前修復(fù)基于?best effort 原則
- “Mitigation: Clear CPU buffers”,表示開(kāi)啟 CPU buffer clear 修復(fù)
3.7.1 原理
MDS (Microarchitectural Data Sampling) 是利用處理器的投機(jī)執(zhí)行,通過(guò)旁路攻擊獲取 store buffer、fill buffer、load port 中數(shù)據(jù)的攻擊方式。通過(guò) MDS 攻擊,低特權(quán)級(jí)程序可以獲取高特權(quán)級(jí)的數(shù)據(jù),即用戶態(tài)程序可以獲取內(nèi)核數(shù)據(jù),guest kernel 可以獲取 host 數(shù)據(jù),但是由于攻擊程序無(wú)法構(gòu)造特定的內(nèi)存地址以獲取特定地址處的內(nèi)存數(shù)據(jù),因而只能通過(guò)“采樣”的方式獲取某一內(nèi)存地址處對(duì)應(yīng)的數(shù)據(jù),同時(shí)由于這些緩存單次泄漏的數(shù)據(jù)量相對(duì)較小,攻擊者需要收集大量數(shù)據(jù)才有可能推測(cè)敏感數(shù)據(jù),因而其危害相對(duì)有限。針對(duì) MDS 的修復(fù)主要是由內(nèi)核態(tài)切換到用戶態(tài),或由 hypervisor 切換到 guest 時(shí),對(duì) store buffer、fill buffer、load port 等緩存執(zhí)行 flush 操作,該修復(fù)需要 microcode 更新支持。當(dāng)處理器支持 SMT 時(shí),該修復(fù)還需要配合關(guān)閉 SMT,以防止同一個(gè) physical core 上的另一個(gè) logical CPU 重新填充這些緩存。3.7.2 開(kāi)關(guān)
可以通過(guò)?mds=[off|full|full,nosmt]
?(v4.19.43 合入) 啟動(dòng)參數(shù)控制知否開(kāi)啟 MDS 修復(fù)- “off”,表示不開(kāi)啟 MDS 修復(fù)
- “full”,表示開(kāi)啟?CPU buffer clear 修復(fù),但是不會(huì)關(guān)閉 SMT
- “full,nosmt”,表示開(kāi)啟 CPU buffer clear 修復(fù),同時(shí)關(guān)閉 SMT
mds=off
?(v4.19.43 合入) 啟動(dòng)參數(shù)關(guān)閉 MDS 修復(fù)。從 Upstream LTS?v4.19.43
? 版本起,也可以使用?mitigations=off
?啟動(dòng)參數(shù)關(guān)閉包含 MDS 修復(fù)在內(nèi)的所有修復(fù)。4. 外部鏈接
Spectre Attacks: Exploiting Speculative ExecutionMeltdown: Reading Kernel Memory from User Space
Spectre Side Channels
Deep Dive: Indirect Branch Restricted Speculation
Speculative-Execution-Side-Channel-Mitigations
Retpoline: A Branch Target Injection Mitigation
Speculative Store Bypass
Speculative Store Bypass explained: what it is, how it works?
Meltdown strikes back: the L1 terminal fault vulnerability
L1TF - L1 Terminal Fault
Meltdown strikes back: the L1 terminal fault vulnerability
MDS - Microarchitectural Data Sampling
Deep Dive: Intel Analysis of Microarchitectural Data Sampling