Intel 設計缺陷背後的原因是什麼? | Linux 中國
實用的原文連結請訪問文末的“ 原文連結”獲得可點選的文內連結、全尺寸原圖和相關文章。 致謝 編譯自 | https://arstechnica.com/gadgets/2018/01/whats-behind-the-intel-design-flaw-forcing-numerous-patches/
作者 | Peter Bright
譯者 | qhwdw ? ? ?
?
? 共計翻譯:80 篇 貢獻時間:119 天
我們知道有問題。可是並不知道問題的具體情況。
(本文發表於 1 月份)近期 Windows 和 Linux 都發送了重大安全更新。為防範這個尚未全然公開的問題。在最壞的情況下。它可能會導致效能下降多達一半。
在過去的幾周。Linux 核心陸續打了幾個補丁。Microsoft 自 11 月份開始也內部測試了 Windows 更新[1],而且它估計在下週二的例行補丁中將這個改進推送到主流 Windows 構建版中。
Microsoft 的 Azure 也在下週的維護窗體中做好了安排,而 Amazon 的 AWS 也安排在週五對相關的設施進行維護。
自從 Linux 第一個補丁 (參見 KPTI:核心頁表隔離的當前的發展
保持地址跟蹤
在一個系統中的每一個記憶體位元組都是隱性編碼的,這些編碼數字是每一個位元組的地址。早期的作業系統使用實體記憶體地址,可是,實體記憶體地址由於各種原因,它並不非常合適。比如,在地址中常常會有空隙,而且(尤其是 32 位的系統上)實體地址非常難操作,須要 36 位數字,甚至很多其他。
因此。如今作業系統全然依賴一個叫虛擬記憶體的概念。虛擬記憶體系統同意程式和核心一起在一個簡單、清晰、統一的環境中各自去操作。而不是使用空隙和其他奇怪的東西的實體記憶體,每一個程式和核心自身都使用虛擬地址去訪問記憶體。這些虛擬地址是連續的 —— 不用操心有空隙 —— 而且合適的大小也更便於操作。
32 位的程式僅能夠看到 32 位的地址。而不用管實體地址是 36 位還是很多其他位。
儘管虛擬地址對每一個軟體差點兒是透明的,可是,處理器終於還是須要知道虛擬地址引用的實體地址是哪個。因此,有一個虛擬地址到實體地址的對映,它儲存在一個被稱為頁面表的資料結構中。作業系統構建頁面表,使用一個由處理器決定的佈局。而且處理器和作業系統在虛擬地址和實體地址之間進行轉換時就須要用到頁面表。
這個對映過程是非常重要的,它也是現代作業系統和處理器的重要基礎,處理器有專用的快取 — Translation Lookaside Buffer(簡稱 TLB)—— 它儲存了一定數量的虛擬地址到實體地址的對映,這樣就不須要每次都使用全部頁面。
虛擬記憶體的使用為我們提供了非常多除了簡單定址之外的實用的特性。當中最基本的是,每一個程式都有了自己獨立的一組虛擬地址,有了它自己的一組虛擬地址到實體地址的對映。這就是用於提供“記憶體保護”的關鍵技術。一個程式不能破壞或者篡改其他程式使用的記憶體,由於其他程式的記憶體並不在它的地址對映範圍之內。
由於每一個程序使用一個單獨的對映,因此每一個程式也就有了一個額外的頁面表,這就使得 TLB 快取非常擁擠。TLB 並不大 —— 普通情況下總共能夠容納幾百個對映 —— 而系統使用的頁面表越多,TLB 能夠包括的不論什麼特定的虛擬地址到實體地址的對映就越少。
一半一半
為了更好地使用 TLB,每一個主流的作業系統都將虛擬地址範圍一分為二。一半用於程式;還有一半用於核心。
當程序切換時,僅有一半的頁面表條目發生變化 —— 僅屬於程式的那一半。核心的那一半是每一個程式公用的(由於僅僅有一個核心)而且因此它能夠為每一個程序使用同樣的頁面表對映。
這對 TLB 的幫助非常大。儘管它仍然會丟棄屬於程序的那一半記憶體地址對映;可是它還保持著還有一半屬於核心的對映。
這樣的設計並非一成不變的。在 Linux 上做了一項工作,使它能夠為一個 32 位的程序提供整個地址範圍,而不用在核心頁面表和每一個程序之間共享。
儘管這樣為程式提供了很多其他的地址空間。但這是以犧牲效能為代價的,由於每次核心程式碼須要執行時,TLB 又一次載入核心的頁面表條目。因此。這樣的方法並沒有廣泛應用到 x86 的系統上。
在核心和每一個程式之間切割虛擬地址的這樣的做法的一個負面影響是,記憶體保護被削弱了。
假設核心有它自己的一組頁面表和虛擬地址,它將在不同的程式之間提供同樣的保護;核心記憶體將是簡單的不可見。可是使用地址切割之後。使用者程式和核心使用了同樣的地址範圍,而且從原理上來說,一個使用者程式有可能去讀寫核心記憶體。
為避免這樣的明顯不好的情況,處理器和虛擬地址系統有一個 “Ring” 或者 “模式”的概念。
x86 處理器有很多 Ring。可是對於這個問題。僅有兩個是相關的:“user” (Ring 3)和 “supervisor”(ring 0)。當執行普通的使用者程式時,處理器將置為使用者模式 (Ring 3)。當執行核心程式碼時,處理器將處於 Ring 0 —— supervisor 模式,也稱為核心模式。
這些 Ring 也用於從使用者程式中保護核心記憶體。頁面表並不僅僅有虛擬地址到實體地址的對映;它也包括關於這些地址的元資料。包括哪個 Ring 可能訪問哪個地址的資訊。核心頁面表條目被標記為僅有 Ring 0 能夠訪問。程式的條目被標記為不論什麼 Ring 都能夠訪問。
假設一個處於 Ring 3 中的程序去嘗試訪問標記為 Ring 0 的記憶體,處理器將阻止這個訪問並生成一個意外錯誤資訊。執行在 Ring 3 中的使用者程式不能得到核心以及執行在 Ring 0 記憶體中的不論什麼東西。
至少理論上是這樣的。大量的補丁和更新表明,這個地方已經被突破了。這就是最大的謎團所在。
Ring 間遷移
這就是我們所知道的。
每一個現代處理器都執行一定數量的猜測執行。比如。給一些指令。讓兩個數加起來,然後將結果儲存在記憶體中,在查明記憶體中的目標是否可訪問和可寫入之前。一個處理器可能已經猜測性地做了加法。在一些常見案例中,在地址可寫入的地方。處理器節省了一些時間,由於它以並行方式計算出記憶體中的目標是什麼。假設它發現目標位置不可寫入 —— 比如。一個程式嘗試去寫入到一個沒有對映的地址或壓根就不存在的物理位置 —— 然後它將產生一個意外錯誤,而猜測執行就白做了。
Intel 處理器,尤其是(儘管不是 AMD 的[4])同意對 Ring 3 程式碼進行猜測執行並寫入到 Ring 0 記憶體中的處理器上。處理器並不全然阻止這樣的寫入,可是猜測執行輕微擾亂了處理器狀態。由於。為了查明目標位置是否可寫入。某些資料已經被載入到快取和 TLB 中。這又意味著一些操作可能快幾個週期,或者慢幾個週期。這取決於它們所須要的資料是否仍然在快取中。除此之外,Intel 的處理器還有一些特殊的功能,比方,在 Skylake 處理器上引入的軟體保護擴充套件(SGX)指令,它改變了一點點訪問記憶體的方式。
同樣的,處理器仍然是保護 Ring 0 的記憶體不被來自 Ring 3 的程式所訪問,可是同樣的,它的快取和其他內部狀態已經發生了變化,產生了可測量的差異。
我們至今仍然並不知道具體的情況。究竟有多少核心的記憶體資訊洩露給了使用者程式,或者資訊洩露的情況有多easy發生。
以及有哪些 Intel 處理器會受到影響?也或者並不全然清晰。可是,有跡象表明每一個 Intel 晶片都使用了猜測執行(是自 1995 年 Pentium Pro 以來的全部主流處理器嗎?),它們都可能會因此而洩露資訊。
這個問題第一次被披露是由來自 奧地利的 Graz Technical University[5] 的研究者。他們披露的資訊表明這個問題已經足夠破壞核心模式地址空間佈局隨機化(核心 ASLR,或稱 KASLR)。ASLR 是防範 緩衝區溢位[6] 漏洞利用的最後一道防線。啟用 ASLR 之後。程式和它們的資料被置於隨機的記憶體地址中。它將使一些安全漏洞利用更加困難。KASLR 將這樣的隨機化應用到核心中。這樣就使核心的資料(包括頁面表)和程式碼也隨機化分佈。
Graz 的研究者開發了 KAISER[7],一組防範這個問題的 Linux 核心補丁。
假設這個問題正好使 ASLR 的隨機化被破壞了,這也許將成為一個巨大的災難。
ASLR 是一個非常強大的保護措施,可是它並非完美的。這意味著對於黑客來說將是一個非常大的障礙。一個無法逾越的障礙。整個行業對此的反應是 —— Windows 和 Linux 都有一個非常重要的變化,祕密開發 —— 這表明不僅是 ASLR 被破壞了。而且從核心洩露出資訊的更普遍的技術被開發出來了。
確實是這樣的,研究者已經 在 Twitter 上公佈資訊[8],他們已經能夠任意洩露和讀取核心資料了。還有一種可能是。漏洞可能被用於從虛擬機器中“越獄”,並可能會危及 hypervisor。
Windows 和 Linux 選擇的解決方式是非常類似的,將 KAISER 分為兩個區域:核心頁面表的條目不再是由每一個程序共享。在 Linux 中,這被稱為核心頁面表隔離(KPTI)。
應用補丁後,記憶體地址仍然被一分為二:這樣使核心的那一半差點兒是空的。當然它並非非常的空。由於一些核心片斷須要永久對映,不論程序是執行在 Ring 3 還是 Ring 0 中,它都差點兒是空的。這意味著假設惡意使用者程式嘗試去探測核心記憶體以及洩露資訊。它將會失敗 —— 由於那裡差點兒沒有資訊。而真正的核心頁面中僅僅有當核心自身執行的時刻它才幹被用到。
這樣做就破壞了最初將地址空間切割的理由。如今,每次切換到使用者程式時,TLB 須要實時去清除與核心頁面表相關的全部條目,這樣就失去了啟用切割帶來的效能提升。
影響的具體大小取決於工作負載。每當一個程式被調入到核心 —— 從磁碟讀入、傳送資料到網路、開啟一個檔案等等 —— 這樣的呼叫的成本可能會新增一點點,由於它強制 TLB 清除了快取並實時載入核心頁面表。不使用核心的程式可能會觀測到 2 - 3 個百分點的效能影響 —— 這裡仍然有一些開銷,由於核心仍然是偶爾會執行去處理一些事情。比方多工等等。
可是大量呼叫進入到核心的工作負載將觀測到非常大的效能損失。在一個基準測試中,一個除了調入到核心之外什麼都不做的程式,觀察到 它的效能下降大約為 50%[9];換句話說就是,打補丁後每次對核心的呼叫的時間要比不打補丁呼叫核心的時間新增一倍。基準測試使用的 Linux 的網路迴環(loopback)也觀測到一個非常大的影響。比方,在 Postgres 的基準測試中大約是 17%[10]。真實的資料庫負載使用了實時網路可能觀測到的影響要低一些,由於使用實時網路時,核心呼叫的開銷基本是使用真實網路的開銷。
儘管對 Intel 系統的影響是眾所周知的。可是它們可能並非唯一受影響的。其他的一些平臺,比方 SPARC 和 IBM 的 S390,是不受這個問題影響的,由於它們的處理器的記憶體管理並不須要切割地址空間和共享核心頁面表;在這些平臺上的作業系統一直就是將它們的核心頁面表從使用者模式中隔離出來的。可是其他的,比方 ARM。可能就沒有這麼幸運了。適用於 ARM Linux 的類似補丁[11] 正在開發中。
PETER BRIGHT[12] 是 Ars 的一位技術編輯。他涉及微軟、程式設計及軟體開發、Web 技術和瀏覽器、以及安全方面。
它居住在紐約的布魯克林。
via: https://arstechnica.com/gadgets/2018/01/whats-behind-the-intel-design-flaw-forcing-numerous-patches/
作者:PETER BRIGHT[14] 譯者:qhwdw 校對:wxy
本文由 LCTT 原創編譯。Linux中國 榮譽推出