Linux中國

KPTI:內核頁表隔離的當前的發展

在十月底的時候,KAISER 補丁集被披露了;它做了一項工作,將內核空間與用戶空間使用的 頁表 page tables 進行了隔離,以解決 x86 處理器上向攻擊者透露內核布局的安全漏洞。這些補丁是自它們被公布以來,這一星期中最值關注的事情,但是,它們似乎正在接近最終的狀態。這應該是再次審視它們的合適機會。

這項工作被重命名為 「 內核頁表隔離 kernel page-table isolation 」 (KPTI),但是目的是一樣的:分割頁表,將現在被用戶空間和內核空間共享使用的這張表分成兩套,內核空間和用戶空間各自使用一個。這對內核的內存管理產生了根本性的變化,並且,這是本來人們期望先爭論多年再做決定的,尤其是考慮到它的性能影響的時候。不過,KPTI 仍然處於快速發展的軌道上。一組預備補丁 已被被合併到 4.15 - rc4 之後的主版本線上了 — 一般情況下僅重要的修復才被允許這樣做 — 並且其餘的似乎被確定進入 4.16 版的合併窗口中。許多內核開發者都在這項工作上投入了大量的時間,並且 Linus Torvalds 要求 將這項工作 回遷 backport 到長期穩定內核中。

也就是說,KPTI 已經在最後期限的壓力下安全補丁的所有標記都已經就緒了。對於任何基於 ARM 的讀者,在這裡值的注意的是,在這項工作中有一個 為 arm64 的等效補丁集

51 個補丁乃至更多

在這篇文章中,x86 補丁系列正處在 163 版本。它包含 51 個補丁,因此,我們應該感謝那些沒有公開的版本。最初的補丁集,由 Dave Hansen 發布,由 Thomas Gleixner、Peter Zijlstra、Andy Lutomirski、和 Hugh Dickins 根據許多其它人的建議,做了大量的修訂。任何還存在的缺陷都不是由於沒有足夠多的有經驗的開發人員過目所導致的。

在現代系統中,頁表是以一個樹形結構進行組織的,這樣可以高效地存儲稀疏內存映射和支持巨頁特性;可以查看這篇 2005 年的文章 了解更多細節以及它是怎麼工作的示意圖。在一個有四級頁面表的系統上(目前的大多數大型系統都是這樣),頂級是頁面全局目錄(PGD)。緊接著是頁面上層目錄(PUD)、頁面中層目錄(PMD)和頁面表條目(PTE)。有五級頁面表的系統是在 PGD 下面插入了一層(稱為 P4D)。

頁面故障解析通常遍歷整個樹去查找所需的 PTE,但是,巨頁可以被更高層級的特定條目所表示。例如,一個 2MB 的內存 chunk 既可以由 PMD 層級的一個單個的巨頁條目表示,也可以由一個單頁 PTE 條目的完整頁面表示。

在當前的內核中,每個處理器有一個單個的 PGD;在 KPTI 系列補丁中所採取的第一步的其中一個措施是,去創建一個第二個 PGD。當內核運行時,原來的仍然在使用;它映射所有的地址空間。當處理器運行在用戶空間時,(在打完該系列補丁之後)第二個被激活。它指向屬於該進程的頁面的相同目錄層次,但是,描述內核空間(位於虛擬地址空間的頂端)的部分通常都不在這裡。

頁表條目包含許可權描述位,它們記錄了內存該如何被訪問;不用說都知道,這些位是用來設置阻止用戶空間訪問內核頁面的,即便是通過那些被映射到該地址空間的頁面訪問。不幸的是,一些硬體級的錯誤允許用戶空間的攻擊者去確定一個給定的內核空間地址是否被映射,而不管那個頁面上映射的地址是否被允許訪問。而那個信息可以被用於擊敗內核地址空間布局隨機化,可以使一個本地的攻擊者更易於得逞。在 KPTI 背後的核心思想是,切換到一個沒有內核空間映射的 PGD,將會使基於這個漏洞的攻擊失效,而到現在為止,我們還沒有看到這些攻擊。

細節

這個想法很簡單,但是,就像經常發生的那樣,有各種各樣麻煩的細節使得這個簡單的想法變成了一個由 51 個部分構成的補丁集。其中最初的一個是,如果處理器在用戶模式運行時響應一個硬體中斷,處理中斷需要的內核代碼將在地址空間中不存在。因此,必須有足夠的內核代碼映射在用戶模式中,以能夠切換回到內核 PGD,使剩餘的代碼也可用。對於 traps、非屏蔽中斷、和系統調用,也存在一個相似的情況。這個代碼很小而且可以與其它部分隔離,但是,在處理安全且有效地切換時,涉及到一些很複雜的細節。

另一個難題來自 x86 本地描述符表(LDT)的構成,它可以被用於去改變用戶空間的內存布局。它可以使用鮮為人知的 modify_ldt() 系統調用來做微調。例如,在 Linux 上早期的 POSIX 線程實現,使用了 LDT 去創建一個本地線程存儲區域。在現在的 Linux 系統上,LDT 幾乎不再使用了,但是,一些應用程序(比如,Wine)仍然需要它。當它被使用時,LDT 必須能夠被用戶空間和內核空間都可以訪問到,但是,它必須一直處於內核空間中。KPTI 補丁集打亂內核附近的內存,在 PGD 級別上為 LDT 保留一個完全的條目;因此,vmalloc() 調用的可用空間收縮到僅有 12,800TB。那是一個非常巨大的 LDT 空間數,可以滿足有很多 CPU 系統的需要。這種變化的其中一個結果是,LDT 的位置將是固定的,並且已知道用戶空間 ——因此這將是個潛在的問題,由於覆寫 LDT 的能力很容易被用來破壞整個系統。在這個系列的最終的補丁是映射為只讀 LDT,以阻止此類攻擊。

另一個潛在的安全缺陷是,如果內核可以一直被操縱直至返回用戶空間,以至於不切換回經過過濾的 PGD。因為內核空間 PGD 也映射用戶空間內存,這種疏忽可能在一段時間內不會被察覺到。對此問題的應對方法是將虛擬內存空間中用戶空間的部分以非可執行的方式映射到內核的 PGD。只要用戶空間(的程序)開始從一個錯誤的頁面表開始執行,它將會立即崩潰。

最後,雖然所有已存在的 x86 處理器似乎都會受到這個信息泄露的漏洞影響,但是,以後的處理器可能不會受此影響。KPTI 有一個可測量的運行時成本,估計在 5%。有些用戶也許不願意為這些成本埋單,尤其是他們拿到了不存在這個問題的新處理器之後。為此將會有一個 nopti (內核)命令行選項來在啟動的時候禁用這個機制。這個補丁系列也增加了一個新的「特性」標識(X86_BUG_CPU_INSECURE)去標識有漏洞的 CPU;它被設置在現在所有的 x86 CPU 上(LCTT 譯註:AMD 表示不背這鍋),但是在以後的硬體上可能沒有。如果沒有該特性標識,頁面隔離將自動被關閉。

在 4.16 版的合併窗口打開之前剩下將近一個月。在這期間,針對一些新發現而不可避免的小毛病,KPTI 補丁集毫無疑問的將迎來一系列的小修訂。一旦所有的事情都敲定了,看起來這些代碼將會被合併同時以相對快的速度遷回到穩定版本的內核。顯而易見的是,我們將會收到一個更慢,但是更安全的內核作為一個新年禮物。

via: https://lwn.net/SubscriberLink/741878/eb6c9d3913d7cb2b/

作者:Jonathan Corbet 譯者:qhwdw 校對:wxy

本文由 LCTT 原創編譯,Linux中國 榮譽推出


本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive

對這篇文章感覺如何?

太棒了
0
不錯
0
愛死了
0
不太好
0
感覺很糟
0
雨落清風。心向陽

    You may also like

    Leave a reply

    您的電子郵箱地址不會被公開。 必填項已用 * 標註

    此站點使用Akismet來減少垃圾評論。了解我們如何處理您的評論數據

    More in:Linux中國