ARM MTE简介

一、MTE 介绍(Memory_Tagging_Extension

MTE 是ARM新架构(ARM V8.5 引入)的一个特性,它通过给分配的内存打标记(tag),追踪最常见的非法内存操作。如果密钥的值和锁的值一样,表示访问成功,否则会报告一个错误。

通常内存安全相关的bug,特别是在Android codebase 的native 代码层是常见的异常类型。按照google 的异常统计,超过50%的安全漏洞是内存引起的(如下图所示):

3c86b50cfd6e9cdba5a46970596a8340.png

为了解决和发现内存bug,Android 引入了ASan/HWASan, KASAN, GWP-ASan,KFENCE和MTE内存检测工具,其中MTE是Android 12开始加入支持。

MTE 原理和HWASan类似,下面对比分析下:

1、检测部分HWASan通过编译方式,在内存访问前插入检测代码;tag(key)生成通过软件随机方式生成;tag(lock)存储在shadow memory中(shadow 内存通常提前设定);

2、MTE 检测和tag生成存储有了硬件层面的支持,MTE通过指令生成tag(key);检测也是通过指令完成;tag (lock)存储的部分存放在物理内存特定区域(无需软件参与显示分配或者设置);

重点差异对比表

895a40f3b1d2af806e3fa7f90ccec728.png

以下是三个工具的开销对比,可以直观感受到MTE的提升。

64c8f8a2e8c60d0d31a202876b71f58e.png

二、MTE 原理 

MTE 在实现时就利用的Armv8-A 的TBI(Top Byte Ignore)特性,使用指针的高 4 bits 存储 tag(即 key),使用专用的内存(tagging memory)存储 tag(即 lock)。下图是MTE 工作的原理图

6ccfd8113af1c11aacaea8de24ee4eba.png

MTE 引入的新指令操作标记内存:

e9d5f3ee23dd158860c5bf0b5f3f3a45.png

大部分指令完成带tag的加减等数据操作,核心指令IRG,STG ,LDG完成关键的tag生成,存储和读取。

   打开MTE时,正确的内存访问需要指针的 key 值与该内存的 lock 值保持一致。当 lock 和 key 不匹配时,可选择触发一个同步或异步异常。下面来介绍这两种模式差别:

1、同步模式(Sync

Sync 模式是精确的错误检测工具,对性能有一定损耗,在内存访问(ldr/str)时,同步检测tag是否匹配,如果不匹配异常触发,进程会收到SIGSEGV (code SEGV_MTESERR)信号同时立即结束;

其中:siginfo.si_code = SEGV_MTESERR(SERR中的S表示synchronous),siginfo.si_addr = <fault-address>)

当工作在sync 模式时,android 分配器还会记录分配释放的stack trace,出现问题时还能提供更详细的memory异常分类,如 user-after-free,buffer-overflow 等;

 2、异步模式(ASync

更轻量级的内存检测,Android用来发现内存踩踏bug;在内存访问时,异步检测tag是否匹配,如果不匹配则更新TFSR_EL1寄存器中的TF0 bit。当下一次用户/内核切换时,系统会去检测TFSR_EL1寄存器,然后产生SIGSEGV信号(code = SEGV_MTEAERR);此时的 siginfo.si_code = SEGV_MTEAERR (AERR中的A表示asynchronous),siginfo.si_addr = 0 ,表明系统并不知道是哪一条具体的指令导致的问题。

三、MTE Android S平台使用方法

MTE 检测分为上层native 和kernel 部分,先来看上层native 使能部分

1、使能所有的native code,通过环境变量控制

0f8f932402f4babeca951b5261c54e17.png

2、增加指定路径的project  (BoardConfig.mk中)

PRODUCT_MEMTAG_HEAP_SYNC_INCLUDE_PATHSPRODUCT_MEMTAG_HEAP_ASYNC_INCLUDE_PATHS

3、通过Android bp setting打开

78d7d6bceb30fab64dc59b2d7296e97b.png

4、在版本中还可以通过属性控制:

arm64.memtag.process. <basename>= off| async | sync

比如使能system_server进程mte: arm64.memtag.process.system_server

5、NDK API 控制使能方法

mallopt (NONE or TBI or ASYNC or SYNC)

6、注意默认版本中MTE是关闭的,需要检查对应的rc文件确保MTE打开

[device/XXX/init.target.rc]

on early-init

# export MEMTAG_OPTIONS off

修改成sync 或者async

kernel 侧MTE 使能

1、确认平台本身MTE 已经支持

2、MTE kernel 相关配置

CONFIG_ARM64_MTE       //  using MTE in the userspace

CONFIG_KASAN and CONFIG_KASAN_HW_TAGS  //using MTE in the kernel

3、通过cmdline 控kasan 开关:

e64eb8cb20a02abd694108e4b0fb1a96.png

四、MTEKERNEL Android S中的实现

1.MTE打开方法
 
 

SCTLR_EL1寄存器用来打开关闭MTE,在TCF0设置MTE模式

227da393b8875c7988859b994d9434d4.png

033828432ae27bb91b67e7649422978a.png

Android 中MTE 打开的流程

f7e7d269ce34315d4b36a10903bbe52a.png

上层scudo malloc分配时流程

7775cef906aba2ad4e31d7ff0d5d2696.png

 
 

2.MTE工作流程

Tag 检测异常触发流程,data abort时,arm 通过ESR_EL1(Exception SyndromeRegister) 寄存

器ISS部分(低22位)来记录:

162f4fbdd1c6da8c0cd0bb1d086d8371.png

DFSC, bits[5:0]

Data Fault Status Code.

0b010001 WhenFEAT_MTE2 is implemented Synchronous TagCheck Fault.

DFSC为17时表示触发了MTE tag 检查不匹配;

SYNC模式工作流程

5bdd5c767a45a24aa700b8e02ce6defd.png

ASYNC模式工作流程

dcb8c3a70f4e921507fa0a3893618a0c.png

从sync 和async 实现部分看,sync 在触发异常时立刻发送SEGV_MTESERR给进程,

而async在进程系统调用或其他user/kernel切换时,主动检查mte 标记位然后发送

SEGV_MTEAERR。

 
 

3. MTE检测框图

MTE在tag mismatch时触发异常,消息回传用户程序后,抓取当前调用栈和访问内存及

附近的tag,通过指针tag和内存tag来判断是哪种内存异常。

e0d564ff198aad39233d51490dd90139.png

73b9f2774e71a4455cefb60fe79bbc28.png

MTE Kernel 中的实现如下,关键宏定义:



上面的定义可以明显看到MTE Tag size为 4 ,标记16个字节,tag存放在指针偏移56位;
当前kernel中TAG的值范围0xF0~0xFD, 0xFE用来标记未分配或已经释放的内存。



上图是kernel 触发tag mismatch的原理图,需要注意的是MTE 的tag lock储存读取也是硬

件实现的。

五、MTE 检测案例

1.userspace踩踏例子

Example1:underflow

std::unique_ptr<int[]> p =std::make_unique<int[]>(4);

 volatile int oob = p[-1];

(void)oob;

执行代码后触发tomstone

6d2354eca2402851ea07dae1d28e4560.png

8f2bc3aabff4724c469f7a9d14bebf20.png

Example2: overflow

std::unique_ptr<int[]> p =std::make_unique<int[]>(4);

 volatile int oob = p[5];

 (void)oob;

执行代码后触发tomstone

606df6c2447cd9c6cb5088cb58f97906.png

b3354e0dad2ad19ada4c107d7aeb0cd9.png

Example3: useafter free

int * p = new int[16];

delete[] p;

p[3] = 9;

b9e0c2cd588e6d67f5867c0c2e1f759f.png

cf6d3167bf2dca5130ffad6b444b7ed1.png

上面的例子中可以看到MTE 能准确的检测到常见的uaf, unferflow, overflow 异常;

整体异常

2. Kernel hwkasan例子

Example : kmalloc overflow

0f250b77eea281b7a4e0cc134918627a.png

582e8bac92c3303a18e6949d4bd2614a.png

00b0324daafc48ae420d260a79c58dfc.png

测试代码sample:

ptr = kmalloc(234, GFP_KERNEL);

ptr[256] = 0;

 从上面的log看kernel mte 检测过程:

分配的指针:fdffff8878a8f500

越界的地方:fdffff8878a8f601    

Pointer tag : [fd],  memory tag: [f4].

ptr指针为0xfdffff8878a8f500,标记的可访问内存是0xffffff8878a8f500 ~ 0xffffff8878a8f5EA, mte是

标记是16字节对齐的,所以实际是标记连续234/16 =14.6= 15个(向上取整)。Ptr

指针只能访问tag为fd标记的区域,实际ptr 访问到了tag为f4标记的内存区域,通过

tag计算我们也能推导出内存访问越界点;

1ec1869f990d3985bc3f36ca3296bb97.png

Under flow 流程类似overflow,tag 打印会在ptr能访问内存的前面;

User after free 的话mem的tag会变成fe(用来表示已经释放或无法访问的内存);

六、总结

当前MTE 在android中需要绑定scudo 分配器使用,相信随着更多平台支撑mte后,传统的

分配器也会引入mte。

MTE 通过4 bit Tag Size 来做key lock 匹配,存在连续两个内存分配相同的tag key情况,

也就是1/16 概率出现无法检测的情况(kernel 中实际只有14个tag可用,实际概率更高)

;如果能保证相邻内存tag 不同的话,miss的概率会大大降低。

MTE 无法检测 16 byte内的内存越界访问;分配大小非16字节对齐,向后踩踏<16字节

对齐的踩踏无法被MTE检测到,比如:

ptr = kmalloc(12, GFP_KERNEL);

ptr[12] = 0;

….

ptr[15] = 0;

ptr[16] = 0; //这里才能触发检测

MTE不依赖编译,低性能损耗,可以考虑将MTE在用户/试用用户侧选择性的打开,发

现内部难以发现的内存类问题。

参考:

https://www.kernel.org/doc/html/latest/arm64/memory-tagging-exte

nsion.html

https://community.arm.com/arm-community-blogs/b/architectures-an

d-processors-blog/posts/enhanced-security-through-mte?_ga=2.4176

8226.1458341132.1636618591-1030760285.1629468403
https://juejin.cn/post/7013595058125406238

https://www.reexpound.com/2021/05/21/%E6%B7%B1%E5%85%A5%E7%90%86

%E8%A7%A3arm%E5%86%85%E5%AD%98%EF%BC%9A%E4%B8%80-memory-tagging-

extension-mte/

https://aijishu.com/a/1060000000006711

https://developer.arm.com/-/media/Arm%20Developer%20Community/PD

F/Arm_Memory_Tagging_Extension_Whitepaper.pdf

74a886a5bcbf2a7271f5ac245854d86e.gif

长按关注

内核工匠微信

Linux 内核黑科技 | 技术文章 | 精选教程

  • 6
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

内核工匠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值