电子说
内存标签扩展(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体系结构添加了三类指令:
为了在后续产品种加入MTE,ARM将开发新版本的CHI协议,以支持MTE的传输和一致性要求。
为了支持MTE,还需要对软件进行部署。ARM正在进行相关的工作。
MTE无需更改程序源代码。然而,MTE必然会导致开销,因为标签必须从内存系统中提取并存储到内存系统中。这种开销与内存分配的大小和生命周期以及标记和数据是一起操作还是单独操作有关。开销可以通过以下方式最小化:
全部0条评论
快来发表一下你的评论吧 !