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