內(nèi)存標(biāo)簽擴(kuò)展(Memory Tagging Extension,MTE)是Armv8.5-A中添加的新功能。
目前對(duì)計(jì)算機(jī)系統(tǒng)的攻擊,大部分是對(duì)內(nèi)存的攻擊。內(nèi)存安全問(wèn)題又可以分為兩類(lèi):空間安全(spatial safety)和時(shí)間安全(temporal safety)。
當(dāng)試圖訪問(wèn)安全區(qū)域以外的數(shù)據(jù),即違反了空間安全性,比如緩沖區(qū)溢出(Buffer Overflow)攻擊。緩沖區(qū)溢出是指在存在緩存溢出安全漏洞的計(jì)算機(jī)中,攻擊者可以用超出常規(guī)長(zhǎng)度的字符數(shù)來(lái)填滿(mǎn)一個(gè)域,通常是內(nèi)存區(qū)地址。
緩存區(qū)溢出存在于各種電腦程序中,特別是廣泛存在于用C、C++等這些本身不提供內(nèi)存越界檢測(cè)功能的語(yǔ)言編寫(xiě)的程序中,例如Debian中就存在5億行C/C++代碼。
當(dāng)試圖訪問(wèn)已超出正常時(shí)間范圍的內(nèi)存資源時(shí),即違反了時(shí)間安全性,比如釋放后再使用(Use After Free)攻擊。顧名思義,就是當(dāng)一個(gè)內(nèi)存塊被釋放之后再次被訪問(wèn)。
攻擊程序可以先申請(qǐng)一塊內(nèi)存,然后釋放內(nèi)存,但是不清空該內(nèi)存指針,等待一段時(shí)間后再次通過(guò)指針對(duì)內(nèi)存進(jìn)行訪問(wèn)。如果恰好在訪問(wèn)操作之前這塊內(nèi)存被分配給了其它的程序,那么攻擊程序可以通過(guò)內(nèi)存對(duì)此程序發(fā)起攻擊。
內(nèi)存攻擊不只以上提到的兩種。我不是安全專(zhuān)家,就不在這里啰嗦了。
可以通過(guò)軟件機(jī)制來(lái)檢測(cè)內(nèi)存訪問(wèn)違例,但代價(jià)是運(yùn)行效率低。
MTE提供一種硬件機(jī)制來(lái)檢測(cè)這兩類(lèi)內(nèi)存違例的情況,這種機(jī)制類(lèi)似于鎖和鑰匙的關(guān)系。在分配內(nèi)存的時(shí)候加上一把鎖,訪問(wèn)的時(shí)候需要提供一把鑰匙,如果鑰匙和鎖不匹配,即阻止訪問(wèn),并報(bào)告錯(cuò)誤。
具體來(lái)說(shuō),通過(guò)向物理內(nèi)存的每個(gè)16字節(jié)添加四-bit元數(shù)據(jù)(Metadata)來(lái)做內(nèi)存標(biāo)記;指針和虛擬地址被修改為包含鑰匙。16字節(jié)被定義為一個(gè)“標(biāo)簽顆粒(Tag Granule)”。為了在不需要較大指針的情況下實(shí)現(xiàn)鑰匙,Armv8-A架構(gòu)中使用“頂部字節(jié)忽略(Top Byte Ignore,TBI)”功能。
啟用TBI后,在做地址轉(zhuǎn)換時(shí),虛擬地址的頂部字節(jié)會(huì)被忽略。這樣就可以使用頂部字節(jié)來(lái)存儲(chǔ)元數(shù)據(jù),實(shí)現(xiàn)內(nèi)存標(biāo)簽的鑰匙。當(dāng)前,僅使用頂部字節(jié)的4-bit。
來(lái)看一個(gè)例子,下圖上半部分,顯示的是緩沖區(qū)溢出情況。通過(guò)new()函數(shù)分配一個(gè)16-byte的內(nèi)存給ptr指針。當(dāng)程序通過(guò)ptr指針來(lái)訪問(wèn)隨后的地址空間,會(huì)產(chǎn)生內(nèi)存違例,這是因?yàn)楹竺娴膬?nèi)存的鎖與ptr的鑰匙不相符。下圖下半部分,顯示的是UAF情況。當(dāng)內(nèi)存被再次分配時(shí),產(chǎn)生了一個(gè)新鎖,如果攻擊程序用舊的指針去訪問(wèn),鑰匙和鎖不相符。
MTE支持標(biāo)簽的隨機(jī)產(chǎn)生,或基于種子的偽隨機(jī)產(chǎn)生。如果一個(gè)程序的執(zhí)行次數(shù)足夠,則至少其中一個(gè)程序檢測(cè)到違規(guī)的概率趨于100%。
或許你已經(jīng)注意到了一個(gè)細(xì)節(jié),那就是4-bit的元數(shù)據(jù)最多只能標(biāo)記16種不同的鎖。也就是說(shuō)還有1/16的可能性,錯(cuò)誤的鑰匙適配到了鎖。為了避免這類(lèi)錯(cuò)誤,需要軟件通過(guò)其它方式增加標(biāo)簽的不同可能性。
MTE增加了一種新的內(nèi)存類(lèi)型,普通標(biāo)簽內(nèi)存(Normal Tagged Memory)。
地址中的標(biāo)簽和內(nèi)存中的標(biāo)簽之間的不匹配可以配置為導(dǎo)致同步異常(synchronous exception)或異步報(bào)告(asynchronous report)。
同步異常是精確的,因?yàn)榭梢跃_地確定哪個(gè)加載或存儲(chǔ)指令導(dǎo)致了標(biāo)記不匹配。相反,異步報(bào)告是不精確的,因?yàn)樗荒軐⒉黄ヅ涓綦x到特定的執(zhí)行線程。
MTE為Armv8-A體系結(jié)構(gòu)添加了三類(lèi)指令:
- 適用于堆棧(stack)和堆(heap)標(biāo)記的標(biāo)簽操作指令
- IRG(insert random tag),此指令在第一個(gè)源寄存器的地址中插入一個(gè)隨機(jī)邏輯地址標(biāo)記,并將結(jié)果寫(xiě)入目標(biāo)寄存器。IRG在硬件層面支持為一個(gè)寄存器中的地址插入隨機(jī)tag,這個(gè)tag隨后可以為其它指令使用。
- GMI(tag mask insert),將第一源寄存器中的標(biāo)記插入第二源寄存器中指定的排除集,將新的排除集寫(xiě)入目標(biāo)寄存器。此指令用于操作與IRG指令一起使用的排除標(biāo)記集,適用于軟件為特殊目的使用特定標(biāo)記值,同時(shí)為正常分配保留隨機(jī)標(biāo)記行為的情況。
- LDG(load allocation tag),此指令從內(nèi)存地址加載分配標(biāo)記(allocation tag),從分配標(biāo)記生成邏輯地址標(biāo)記,并將其合并到目標(biāo)寄存器中。
- STG(store allocation tag),此指令存儲(chǔ)分配標(biāo)記到內(nèi)存
- STZG(store allocation tag, zeroing),此指令將分配標(biāo)記存儲(chǔ)到內(nèi)存,將相關(guān)數(shù)據(jù)位置歸零
- ST2G,此指令將分配標(biāo)記存儲(chǔ)到內(nèi)存的兩個(gè)標(biāo)記顆粒
- STZ2G,此指令將分配標(biāo)記存儲(chǔ)到內(nèi)存的兩個(gè)標(biāo)記顆粒,將相關(guān)數(shù)據(jù)位置歸零
- STGP(store allocation tag and pair of registers),此指令從兩個(gè)寄存器向內(nèi)存存儲(chǔ)一個(gè)分配標(biāo)記和兩個(gè)64位雙字
- 用于指針運(yùn)算和堆棧標(biāo)記的指令
- ADDG(add with tag),此指令將由標(biāo)記顆??s放的立即數(shù)加到源寄存器中的地址,使用立即值修改地址的邏輯地址標(biāo)記,并將結(jié)果寫(xiě)入目標(biāo)寄存器。
- SUBG(subtract with tag),此指令從源寄存器中的地址減去由標(biāo)記顆??s放的立即數(shù),使用立即數(shù)修改地址的邏輯地址標(biāo)記,并將結(jié)果寫(xiě)入目標(biāo)寄存器。
- SUBP(subtract pointer),此指令從第一源寄存器中保存的56位地址減去第二源寄存器中保留的56位的地址,符號(hào)擴(kuò)展結(jié)果到64位,并將結(jié)果寫(xiě)入目標(biāo)寄存器。
- 用于系統(tǒng)的指令
- LDGM(load tag multiple),此指令讀取N個(gè)分配標(biāo)記的自然對(duì)齊塊
- STGM(store tag multiple),此指令存儲(chǔ)N個(gè)分配標(biāo)記的自然對(duì)齊塊
- STZGM(store tag and zero multiple),此指令存儲(chǔ)N個(gè)分配標(biāo)記的自然對(duì)齊塊,并將零存儲(chǔ)到相關(guān)數(shù)據(jù)位置
為了在后續(xù)產(chǎn)品種加入MTE,ARM將開(kāi)發(fā)新版本的CHI協(xié)議,以支持MTE的傳輸和一致性要求。
為了支持MTE,還需要對(duì)軟件進(jìn)行部署。ARM正在進(jìn)行相關(guān)的工作。
MTE無(wú)需更改程序源代碼。然而,MTE必然會(huì)導(dǎo)致開(kāi)銷(xiāo),因?yàn)闃?biāo)簽必須從內(nèi)存系統(tǒng)中提取并存儲(chǔ)到內(nèi)存系統(tǒng)中。這種開(kāi)銷(xiāo)與內(nèi)存分配的大小和生命周期以及標(biāo)記和數(shù)據(jù)是一起操作還是單獨(dú)操作有關(guān)。開(kāi)銷(xiāo)可以通過(guò)以下方式最小化:
- 同時(shí)寫(xiě)入標(biāo)簽和初始化內(nèi)存
- 避免過(guò)度分配從未寫(xiě)入數(shù)據(jù)的地址空間
- 避免過(guò)度的釋放和重新分配
- 避免在堆棧上分配大塊固定大小內(nèi)存
-
計(jì)算機(jī)
+關(guān)注
關(guān)注
19文章
7500瀏覽量
88033 -
C++
+關(guān)注
關(guān)注
22文章
2109瀏覽量
73678 -
ARMv8
+關(guān)注
關(guān)注
1文章
35瀏覽量
14159
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論