1.meltdown的補丁:KPTI(X86和AARCH64)
meltdown產(chǎn)生的主要原因是CPU的投機執(zhí)行(speculative execution)。本質(zhì)上是硬件的漏洞,那么我們?nèi)绾螐能浖用孢M行修復呢?
1.meltdown修復的出發(fā)點
在x86中,每個進程都有一張頁表,此頁表覆蓋內(nèi)核空間+用戶空間地址,在用戶態(tài)執(zhí)行時,頁表中也有內(nèi)核空間的地址映射,所以才使得用戶空間非法訪問內(nèi)核空間地址的代碼被投機執(zhí)行(之后才收到page fault)。那么,修復漏洞最簡單有效的軟件手段就是讓CPU運行在用戶態(tài)的時候,頁表不覆蓋內(nèi)核空間地址。
所以,為了修復漏洞,添加一張頁表,使用戶態(tài)一張頁表,內(nèi)核態(tài)一張頁表,每次從用戶態(tài)切換到內(nèi)核態(tài)時也切換頁表。但在用戶態(tài)運行時完全不覆蓋內(nèi)核地址也不可行,因為發(fā)生中斷、系統(tǒng)調(diào)用和異常時,需要切入和換出內(nèi)核空間,切入和換出接口的地址是內(nèi)核空間的。所以,用戶態(tài)的頁表覆蓋修改為用戶態(tài)+內(nèi)核態(tài)跳轉(zhuǎn)(trampoline),一旦系統(tǒng)調(diào)用發(fā)生,接口代碼負責立即將頁表切換成完整的覆蓋用戶態(tài)+內(nèi)核態(tài)的頁表;從系統(tǒng)調(diào)用中出來時,再切換回覆蓋用戶態(tài)+內(nèi)核態(tài)跳轉(zhuǎn)的頁表。如下圖所示:

可以看出,修復meldown后,如果應用中系統(tǒng)調(diào)用很多,運行時不斷的發(fā)生中斷,每次用戶態(tài)與內(nèi)核態(tài)切換時就要完成頁表的切換,開銷會很大,性能也會下降。
在AARCH64中,本來就是兩張頁表,硬件上存在TTBR0,TTBR1兩個寄存器,TTBR0中填的頁表只覆蓋用戶空間,TTBR1中填的頁表只覆蓋內(nèi)核空間。但AARCH64仍然存在meltdown的漏洞,因為TTBR1仍然是覆蓋整個內(nèi)核空間的,在用戶態(tài)切換到內(nèi)核空間時仍然可以投機訪問到內(nèi)核空間的所有地址。
所以在AARCH64中修復meltdown漏洞,采取類似x86的方法,讓TTBR1中填的頁表不覆蓋全部的內(nèi)核地址空間,引入第三張頁表(trampoline),也被TTBR1指向,但此頁表只指向中斷、系統(tǒng)調(diào)用、異常切入和換出內(nèi)核的代碼,在切換用戶態(tài)/內(nèi)核態(tài)時修改TTBR1的指向即可。如下圖所示:保證在user模式(EL0)運行時,沒有一張頁表可以覆蓋整個內(nèi)核空間的地址。

2.內(nèi)核與用戶交界點的安全性問題

i.為什么要檢查地址范圍?access_ok?
應用程序有無數(shù)種方法可以偽造一個指向內(nèi)核態(tài)的指針,所以內(nèi)核在訪問用戶數(shù)據(jù)時存在一系列安全問題。
kernel space在訪問user space時,必須判斷user space地址的合法性:
2.為什么要做access_ok
比如,將kernel space的一個數(shù)據(jù)a存放到user space的地址b(*b =a;),但如果不做access_ok的檢查,是不能確保地址b一定是user space的,這樣就可以通過用一個kernel space的地址偽裝成user space地址的方式,將kernel space地址的內(nèi)容修改掉(*k = a)。這樣就有無數(shù)種方法將Linux Kernel攻陷,如修改代碼邏輯突破root權(quán)限等。
有很多漏洞都是誕生在kernel和user的交界點上,所以在交界點上一定要確保地址的合法性及使用copy_from/to_user。
更多安全漏洞參考:
CVE Details
https://www.cvedetails.com/product/47/Linux-Linux-Kernel
CVE-2017-5123漏洞
https://github.com/nongiach/CVE/tree/master/CVE-2017-5123
ii.copy_from/to_user等API

3.為什么要u_k copy
比如,kernel不能直接操作user space的數(shù)據(jù),而是操作copy_from_user后的kernel space的副本。如果直接操作user space數(shù)據(jù),而user space的程序是多線程的,某個線程就可以在操作user space數(shù)據(jù)過程中修改這塊數(shù)據(jù),來實現(xiàn)對內(nèi)核的攻擊。
i.阻止內(nèi)核訪問用戶的PAN和SMAP
最保險的方法是讓userspace完全不能訪問kernel space,但這是不可行的。次安全的方法,比如硬件上提供一個開關,每次在kernel space中訪問user space時打開,訪問后關閉,即可把kernel space對user space的訪問限制在copy_from/to_user這樣的API中。ARM中的PAN及x86中的SMAP即為實現(xiàn)此功能的機制。

3.內(nèi)存碎片避免
什么是碎片?
Internal fragmentation:申請32個字節(jié),但是buddy要給1頁-> slab。
External fragmentation : 申請2n連續(xù)頁,但是系統(tǒng)盡管空閑內(nèi)存很多,由于非連續(xù),也無法滿足。
內(nèi)存連續(xù)的好處:一方面可服務需要連續(xù)內(nèi)存的申請(如CMA本身就需要連續(xù)內(nèi)存);另一方面,利用MMU支持巨頁的技術,提高TLB命中率,內(nèi)存訪問遍歷Page table的開銷被減小。
早期的buddy算法不區(qū)分申請內(nèi)存的類型,如下圖紅色頁面被不可移動的頁申請走,如內(nèi)核中kmalloc申請內(nèi)存。但周圍很多頁都是空閑的,并且紅色的頁面一直不釋放,導致紅色頁面和空閑白色頁面無法合并到一起。所以,Linux后期采用將不可移動的頁面與可移動的頁面分開,將空閑的內(nèi)存分為可移動(一般為用戶程序的內(nèi)存),可回收(一般為文件系統(tǒng)的緩存),不可移動(一般為kernel的內(nèi)存)。這樣避免了不可移動的與可移動的頁面混合在一起,從而使可移動的頁面能夠merge在一起,提供出更大的連續(xù)內(nèi)存。

4.分migration type的意義

如上圖所示,在每個ZONE的空閑內(nèi)存free list中,分成UNMOVABLE、MOVABLE、RECLAIMABLE類型,分別管理,注意此三種類型的內(nèi)存一直在動態(tài)的變化。比如,Linux剛剛啟動時,默認情況下內(nèi)存都是可移動的,此時有內(nèi)核模塊調(diào)用kmalloc申請一頁不可移動內(nèi)存,Linux內(nèi)核不會只從可移動內(nèi)存中申請一頁作為不可移動的,而是一次性申請出較大一塊內(nèi)存作為不可移動的使用(如210個頁面),所以可移動的則不再會被不可移動的所污染。如果210個頁面不夠用,則再次申請出一塊作為不可移動內(nèi)存使用。同時,不可移動的內(nèi)存不再使用時也會被釋放,釋放掉后仍然可再次作為可移動的內(nèi)存(fallback)。

如上圖紅色行所示,比如申請不可移動內(nèi)存,但此時沒有,則會先從可回收中去找,可回收中還是找不到則從可移動中去找。
CMA比較特殊,如下圖代碼所示,可移動的如果申請不到則會從CMA中去找,如果CMA中也申請不到,則會從fallback表中尋找內(nèi)存(上圖中綠色行所示)。
(對應第一次課:CMA內(nèi)存在不使用時,會服務于可移動頁面的內(nèi)存申請。)

Linux內(nèi)核中“內(nèi)存緊湊技術”,類似于磁盤碎片整理。當申請比較大的連續(xù)內(nèi)存時或申請巨頁時,內(nèi)核啟用Memory compaction機制,如下圖所示:紅色部分為被申請掉的內(nèi)存,白色的部分為空閑內(nèi)存。Memory compaction將前面的紅色部分移動到后面的白色部分,使空閑內(nèi)存變連續(xù)。

如下圖所示,在echo 1 > compact_memory后可以看出低階的空閑內(nèi)存變少,而高階的空閑內(nèi)存變多。

總結(jié)
migrate type是anti-fragmentation:申請內(nèi)存時歸類,把可移動與不可移動的分開,屬于一種預防技術。
compaction是de-fragmentation:已經(jīng)發(fā)生碎片,做整理。
-
cpu
+關注
關注
68文章
11226瀏覽量
223189 -
Linux
+關注
關注
88文章
11637瀏覽量
218171 -
內(nèi)存管理
+關注
關注
0文章
169瀏覽量
14824
原文標題:郝健: Linux內(nèi)存管理學習筆記-第6節(jié)課
文章出處:【微信號:LinuxDev,微信公眾號:Linux閱碼場】歡迎添加關注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
LED為什么會產(chǎn)生熱量?LED發(fā)熱的幾個主要原因是什么?
產(chǎn)生Congestion的主要原因
錫膏焊接后PCBA焊點產(chǎn)生空洞的原因是什么?
放大電路中產(chǎn)生零點漂移的主要原因是什么
焊接質(zhì)量缺陷產(chǎn)生的主要原因

meltdown產(chǎn)生的主要原因是CPU的投機執(zhí)行
評論