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