摘要——1988年的互聯(lián)網(wǎng)蠕蟲病毒奪走了雛形網(wǎng)絡(luò)的十分之一,并嚴(yán)重地減慢了剩余網(wǎng)絡(luò)的速度[1]。30多年過去了,用類C語言編寫的代碼中最重要的兩類安全漏洞仍然是對(duì)內(nèi)存安全的侵犯。
根據(jù)2019年的BlueHat演示文稿,微軟產(chǎn)品中解決的所有安全問題中,有70%是由違反內(nèi)存安全造成的[2]。Google也報(bào)告了Android的類似數(shù)據(jù),超過75%的漏洞是違反內(nèi)存安全的【3】。雖然這些違規(guī)中的許多在較新的語言中是不可能的,但用C和C++編寫的在用代碼的基礎(chǔ)是龐大的。僅Debian Linux就包含了超過5億行。
本文介紹了Armv8.5-A內(nèi)存標(biāo)記擴(kuò)展(MTE)。MTE的目標(biāo)是提高用不安全語言編寫的代碼的內(nèi)存安全性,而不需要更改源代碼,在某些情況下,也不需要重新編譯。對(duì)內(nèi)存安全違規(guī)的可輕松部署的檢測和緩解措施可以防止一大類安全漏洞被利用。
簡介
內(nèi)存安全的破壞分為兩大類:空間安全和時(shí)間安全。
可利用的違規(guī)行為是攻擊的第一階段,旨在傳送惡意負(fù)載或與其他類型的漏洞鏈接,以獲得系統(tǒng)控制權(quán)或泄漏特權(quán)信息。
當(dāng)訪問對(duì)象超出其真實(shí)邊界時(shí),空間安全就會(huì)受到侵犯。例如,當(dāng)棧上的緩沖區(qū)溢出時(shí)。這可能會(huì)被利用來覆蓋函數(shù)的返回地址,這可能會(huì)成為幾種類型攻擊的基礎(chǔ)。
當(dāng)對(duì)對(duì)象的引用超出范圍使用時(shí),通常是在對(duì)象的內(nèi)存被重新分配之后,就違反了時(shí)間安全性。例如,當(dāng)包含某種類型的函數(shù)指針的類型被惡意數(shù)據(jù)覆蓋時(shí),惡意數(shù)據(jù)也可以構(gòu)成多種攻擊的基礎(chǔ)。
MTE提供了一種機(jī)制來檢測兩類主要的內(nèi)存安全違規(guī)。MTE通過提高測試和Fuzzing的有效性來幫助在部署之前檢測潛在的漏洞。MTE還可以在部署后幫助大規(guī)模檢測漏洞。
Fuzzing是一種軟件測試技術(shù),也稱為模糊測試。它通過向軟件系統(tǒng)輸入大量隨機(jī)、無效或異常的數(shù)據(jù),來檢測系統(tǒng)在處理這些數(shù)據(jù)時(shí)是否會(huì)出現(xiàn)異?;虮罎ⅰuzzing可以幫助發(fā)現(xiàn)軟件系統(tǒng)中的漏洞和安全問題,從而提高軟件系統(tǒng)的穩(wěn)定性和安全性。
通過仔細(xì)的軟件設(shè)計(jì),可以始終檢測到在真正邊界之前或之后立即訪問內(nèi)存的順序安全違規(guī)。可以概率地檢測到地址空間中任意位置的“野生”違規(guī)。
在部署之前定位和修復(fù)漏洞,減少了部署代碼的攻擊面。在部署后大規(guī)模檢測漏洞,支持在漏洞被廣泛利用之前被動(dòng)地修復(fù)漏洞。對(duì)網(wǎng)絡(luò)犯罪經(jīng)濟(jì)學(xué)的研究【5】表明它對(duì)規(guī)模非常敏感。及時(shí)的檢測和被動(dòng)的修補(bǔ)可能在大規(guī)模打擊網(wǎng)絡(luò)犯罪方面非常有效。
威脅模型
MTE旨在提供魯棒性,以抵御試圖破壞代碼處理攻擊者提供的惡意數(shù)據(jù)的攻擊。它不解決算法漏洞或惡意軟件。
MTE旨在檢測內(nèi)存安全違規(guī),并提高針對(duì)違規(guī)所導(dǎo)致的攻擊的魯棒性。在動(dòng)態(tài)鏈接系統(tǒng)中,遺留代碼受益于MTE的堆分配,而無需重新編譯。
將MTE應(yīng)用到堆棧需要重新編譯。MTE架構(gòu)設(shè)計(jì)時(shí),假設(shè)堆棧指針是可信的。因此,在為堆棧分配部署MTE時(shí),將MTE與其他功能(例如分支目標(biāo)識(shí)別(BTI)和指針驗(yàn)證碼(PAC))結(jié)合使用非常重要,以降低存在允許攻擊者控制的小工具的可能性的堆棧指針。
MTE的內(nèi)存安全
Arm內(nèi)存標(biāo)記擴(kuò)展實(shí)現(xiàn)了對(duì)內(nèi)存的鎖定和鍵訪問??梢栽趦?nèi)存上設(shè)置鎖,在內(nèi)存訪問時(shí)提供鍵。如果密鑰與鎖匹配,則允許訪問。如果不匹配,則會(huì)報(bào)錯(cuò)。
通過在物理內(nèi)存的每16字節(jié)中添加4位元數(shù)據(jù)來標(biāo)記內(nèi)存位置。這就是標(biāo)簽顆粒。標(biāo)記內(nèi)存實(shí)現(xiàn)了鎖。
指針和虛擬地址都被修改為包含鍵。
為了在不需要更大指針的情況下實(shí)現(xiàn)密鑰位,MTE使用了Armv8-A架構(gòu)的Top Byte Ignore (TBI)特性。當(dāng)啟用TBI時(shí),當(dāng)將虛擬地址的最高字節(jié)用作地址轉(zhuǎn)換的輸入時(shí),將忽略它。這允許頂部字節(jié)存儲(chǔ)元數(shù)據(jù)。在MTE中,最高字節(jié)的4位用于提供密鑰。
MTE依賴于鎖和密鑰的不同來檢測內(nèi)存安全違規(guī)。
由于可用的標(biāo)記位數(shù)有限,因此不能保證兩次內(nèi)存分配對(duì)于任何特定的執(zhí)行都具有不同的標(biāo)記。但是,內(nèi)存分配器可以確保順序分配的標(biāo)記總是不同的,從而確保總是檢測到最常見的安全違規(guī)類型。
更普遍的是,MTE支持隨機(jī)標(biāo)簽生成和基于種子的偽隨機(jī)標(biāo)簽生成。在一個(gè)程序的執(zhí)行次數(shù)足夠多的情況下,其中至少一個(gè)程序檢測到違規(guī)的概率趨于100%。
架構(gòu)細(xì)節(jié)
MTE在Arm架構(gòu)中增加了一種新的內(nèi)存類型,即Normal Tagged Memory。
除了一些例外,如果可以靜態(tài)地確定訪問的安全性,加載和存儲(chǔ)到這個(gè)新的存儲(chǔ)器類型執(zhí)行訪問,其中地址寄存器頂部字節(jié)中的標(biāo)記與存儲(chǔ)在存儲(chǔ)器中的標(biāo)記進(jìn)行比較。
當(dāng)不匹配配置為異步上報(bào)時(shí),詳細(xì)信息將累積在系統(tǒng)寄存器中。提供了一個(gè)控制,以確保在進(jìn)入以更高的異常級(jí)別運(yùn)行的軟件時(shí)更新此寄存器。這使得操作系統(tǒng)內(nèi)核能夠?qū)⒉黄ヅ涞那闆r隔離到特定的執(zhí)行線程,并基于這些信息做出決策。
同步異常的精確性在于,可以精確地確定是哪個(gè)加載或存儲(chǔ)指令導(dǎo)致了標(biāo)記不匹配。相反,異步報(bào)告是不精確的,因?yàn)樗荒軐⒉黄ヅ涓綦x到特定的執(zhí)行線程。
MTE為Armv8-A架構(gòu)添加了以下概述的說明,并將其分為三個(gè)不同的類別【6】:
適用于棧和堆標(biāo)記的標(biāo)記操作說明。
?IRG 為了使MTE的統(tǒng)計(jì)基礎(chǔ)有效,需要一個(gè)隨機(jī)標(biāo)簽的來源。IRG被定義為在硬件中提供此標(biāo)記,并將這樣的標(biāo)記插入到寄存器中,以供其他指令使用。?GMI 此指令用于操作排除的標(biāo)記集,以便與IRG指令一起使用。這適用于軟件為特殊目的使用特定標(biāo)記值,同時(shí)為正常分配保留隨機(jī)標(biāo)記行為的情況。?LDG、STG、STZG 這些指令允許在內(nèi)存中獲取或設(shè)置標(biāo)記。它們的目的是在不修改數(shù)據(jù)或?qū)?shù)據(jù)歸零的情況下更改內(nèi)存中的標(biāo)記。?ST2G和STZ2G 這些是STG和STZG的更密集的替代方案,它們?cè)诜峙浯笮≡试S的情況下在兩個(gè)內(nèi)存顆粒上運(yùn)行。?STGP 該指令將標(biāo)記和數(shù)據(jù)都存儲(chǔ)到內(nèi)存中。
用于指針?biāo)阈g(shù)和堆棧標(biāo)記的指令:
?ADDG和SUBG 這些是ADD和SUB指令的變體,旨在對(duì)地址進(jìn)行算術(shù)運(yùn)算。它們?cè)试S標(biāo)記和地址都被一個(gè)立即值單獨(dú)修改。這些指令用于創(chuàng)建堆棧上對(duì)象的地址。?SUBP(S) 此指令提供了一個(gè)56位減法,帶有可選的標(biāo)志設(shè)置,這是指針運(yùn)算所必需的,忽略頂部字節(jié)中的標(biāo)記。
系統(tǒng)使用說明:
?LDGM、STGM和STZGM 這些是在EL0處未定義的批量標(biāo)簽操作指令。它們旨在供系統(tǒng)軟件為了初始化和序列化的目的來操作標(biāo)記。例如,它們可以用于實(shí)現(xiàn)將標(biāo)記的內(nèi)存交換到不識(shí)別標(biāo)記的介質(zhì)。清零形式可以用于高效的內(nèi)存初始化。此外,MTE還提供了一組設(shè)計(jì)用于標(biāo)簽的緩存維護(hù)操作。這些提供了在整個(gè)緩存行上運(yùn)行的高效機(jī)制。
MTE規(guī)模部署
Arm預(yù)計(jì),在產(chǎn)品開發(fā)和部署的不同階段,MTE將部署在不同的配置中。
精確的檢查旨在提供有關(guān)故障位置的最多信息。不精確的檢查旨在實(shí)現(xiàn)更高的性能。
操作系統(tǒng)內(nèi)核可以選擇是否終止由于標(biāo)記不匹配而導(dǎo)致異常的進(jìn)程,或者記錄該異常的發(fā)生并允許進(jìn)程繼續(xù)進(jìn)行。
在啟用MTE的情況下測試產(chǎn)品可以發(fā)現(xiàn)它的許多潛在問題。在這個(gè)階段,檢測和記錄盡可能多的問題的信息是合適的。
不需要保護(hù)系統(tǒng)免受攻擊者的攻擊??赡苄枰獙⑾到y(tǒng)配置為:
?進(jìn)行精準(zhǔn)檢查。?累積標(biāo)記不匹配的數(shù)據(jù),而不是終止進(jìn)程。這種配置允許收集最多信息,以支持通過定向測試和Fuzzing找到最大數(shù)量的缺陷。
發(fā)布產(chǎn)品后,可能需要將MTE配置為:
?執(zhí)行不精確的檢查。?在標(biāo)記不匹配時(shí)終止進(jìn)程。
此配置在性能和檢測可能啟動(dòng)針對(duì)軟件的漏洞的內(nèi)存安全違規(guī)之間提供了一種平衡。
在發(fā)布后,配置對(duì)黑客具有高價(jià)值的進(jìn)程(例如加密密鑰存儲(chǔ))可能是合適的,以執(zhí)行精確的檢查,以便有關(guān)檢查失敗位置的準(zhǔn)確信息可以通過錯(cuò)誤報(bào)告和遙測系統(tǒng)傳回其開發(fā)人員。
系統(tǒng)自適應(yīng)地改變其MTE配置也可能是合適的。
例如,如果使用不精確檢查運(yùn)行的進(jìn)程因?yàn)闃?biāo)記檢查失敗而終止,那么下次啟動(dòng)該進(jìn)程時(shí),它可能會(huì)從啟用精確檢查開始,以便為其開發(fā)人員收集更好的診斷信息。這種部署模型融合了不精確檢查的性能優(yōu)勢和精確檢查的優(yōu)勢,以提供更好的質(zhì)量反饋。
MTE硬件部署
為了支持實(shí)現(xiàn)MTE的未來Arm產(chǎn)品,正在開發(fā)一個(gè)新版本的AMBA 5相干集線器接口(CHI)規(guī)范,該規(guī)范支持MTE的傳輸和相干性要求【7】。
堆標(biāo)記
在動(dòng)態(tài)鏈接系統(tǒng)中,可以在不改變現(xiàn)有二進(jìn)制文件的情況下部署標(biāo)記堆。只需要修改操作系統(tǒng)內(nèi)核和C庫代碼。
Arm通過添加對(duì)Linux內(nèi)核的支持,對(duì)MTE進(jìn)行原型化。需要修改的區(qū)域如下:
?能夠在使用用戶空間指針時(shí)將標(biāo)記從它們中刪除用于地址空間管理。?使虛擬內(nèi)存系統(tǒng)中的clear_page和copy_page函數(shù)感知標(biāo)簽。?增加標(biāo)簽不匹配導(dǎo)致的故障處理。類似于SIGSEGV處理翻譯故障的方式。?轉(zhuǎn)換可能暴露給用戶空間的內(nèi)存映射進(jìn)程來使用普通標(biāo)記內(nèi)存。?增加擴(kuò)展檢測和系統(tǒng)寄存器配置以啟用擴(kuò)展。
Arm正在向上游貢獻(xiàn)Linux內(nèi)核支持。
在C庫中,Arm修改了這些與內(nèi)存相關(guān)的函數(shù):
?malloc?free?calloc?realloc
此外,還修改了內(nèi)存拷貝和字符串相關(guān)函數(shù),以防止它們過度讀取源緩沖區(qū)。
堆棧標(biāo)記
在運(yùn)行時(shí)堆棧上分配的內(nèi)存需要編譯器支持和內(nèi)核支持。二進(jìn)制文件必須重新編譯??梢允褂迷S多不同的堆棧標(biāo)記策略。
我們的合作伙伴利用IRG設(shè)計(jì)了一個(gè)隨機(jī)選擇標(biāo)簽的策略指令,在函數(shù)進(jìn)入期間,分配一個(gè)新的棧幀。然后,編譯器使用ADDG和SUBG指令為函數(shù)內(nèi)的每個(gè)棧槽創(chuàng)建標(biāo)記地址,其中標(biāo)記從初始隨機(jī)標(biāo)記偏移。堆棧分配可以使用適當(dāng)?shù)臉?biāo)記存儲(chǔ)指令進(jìn)行批量初始化,但編譯器不需要在函數(shù)體代碼使用之前初始化任何插槽。
此策略確保MTE的統(tǒng)計(jì)屬性對(duì)于每個(gè)函數(shù)調(diào)用都有效,并確保堆棧上相鄰的對(duì)象具有不同的標(biāo)記,從而導(dǎo)致順序上溢和下溢。
保護(hù)堆棧上的相鄰對(duì)象需要增加這些對(duì)象與標(biāo)記顆粒的對(duì)齊,即16字節(jié)。在某些程序中,MTE會(huì)因?yàn)檫@個(gè)效應(yīng)而導(dǎo)致堆棧使用率增加。我們的基準(zhǔn)分析表明,漲幅通常不大。
為了提高性能,在MTE下取消檢查使用堆棧指針尋址模式的立即偏移量的內(nèi)存訪問。這是因?yàn)榫幾g器可以靜態(tài)地證明它們是正確的,或者在編譯時(shí)發(fā)出診斷。
MTE優(yōu)化
MTE的設(shè)計(jì)使得它不需要修改源代碼就可以糾正代碼。但是,MTE必然會(huì)帶來開銷,因?yàn)闃?biāo)記必須從內(nèi)存系統(tǒng)中獲取并存儲(chǔ)到內(nèi)存系統(tǒng)中。這種開銷與內(nèi)存分配的大小和生存期以及標(biāo)記和數(shù)據(jù)是一起操作還是分開操作有關(guān)??梢酝ㄟ^以下方式最大限度地減少開銷:
?同時(shí)寫標(biāo)簽和初始化內(nèi)存。在許多情況下,內(nèi)存必須初始化為零,并設(shè)置標(biāo)記。例如,在將頁面交給用戶空間之前,清除操作系統(tǒng)內(nèi)核中的頁面。Arm基于Linux的原型機(jī)為此使用了STZGM指令。?避免過度分配從未向其寫入數(shù)據(jù)的地址空間。在某些情況下,軟件分配的地址空間遠(yuǎn)比它所需的多,并且在解除分配之前只接觸其中的一小部分。使用MTE,這更昂貴,因?yàn)榧词箶?shù)據(jù)永遠(yuǎn)不會(huì)寫入內(nèi)存,標(biāo)記也可能需要。?避免過度的去分配和再分配。避免過多的去分配和再分配通常是一個(gè)好的實(shí)踐,無論是否部署了MTE。但是,由于使用MTE分配和解除分配的固定成本會(huì)增加,現(xiàn)有的性能問題可能會(huì)被放大。?避免在堆棧上進(jìn)行大的固定大小分配。堆棧上的大的、固定大小的分配往往會(huì)被使用不足,例如,PATH_MAX等固定大小的緩沖區(qū)通常包含相對(duì)較短的字符串。避免這樣的分配,通過減少必須寫入的未使用的內(nèi)存標(biāo)記的數(shù)量,減少了保護(hù)堆棧的開銷。
參考文獻(xiàn)
?[1] F. B. I. [Online]。 Available: https://www.fbi.gov/news/stories/morris worm-30- years-since-first-major-attack-on-internet-110218
?[2] M. Miller, “Bluehat Abstracts,” [Online]。 Available: https://msrnd-cdn-stor. azureedge.net/bluehat/bluehatil/2019/assets/doc/Trends%2C%20 Challenges%2C%20and%20Strategic%20Shifts%20in%20the%20Software%20 Vulnerability%20Mitigation%20Landscape.pdf
?[3] “Google Queue Hardening,” [Online]。 Available: https://security.googleblog. com/2019/05/queue-hardening-enhancements.html
?[4] Debian, “Stretch Statistics,” [Online]。 Available: https://sources.debian.org/stats/ stretch
?[5] “ACM,” [Online]。 Available: https://dl.acm.org/citation.cfm?id=2654847
?[6] “AArch64 Instructions,” [Online]。 Available: https://developer.arm.com/docs/ ddi0596/latest/base-instructions-alphabetic-order
?[7] “Architecture Reference Manual,” [Online]。 Available: https://developer.arm.com/ docs/ddi0487/lates
編輯:黃飛
評(píng)論