欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 健康 > 养生 > Android HWASAN使用与实现原理

Android HWASAN使用与实现原理

2024/10/23 16:44:14 来源:https://blog.csdn.net/youthcowboy/article/details/140134843  浏览:    关键词:Android HWASAN使用与实现原理

一、背景

为了提前检测出Android User Sapce的app或native进程的内存错误问题,帮助研发定位与分析这些问题,基于Android 14版本上对HWASAN做了调研分析。

二、ASAN介绍

HWASAN是在ASAN的基础上做了拓展,因此在介绍HWASAN之前先了解下ASAN.

ASAN(AddressSanitizer)和HWASAN(Hardware-assisted AddressSanitizer)都是内存错误检测工具,用于帮助开发者发现和修复内存相关的bug,如heap-buffer-overflow、Heap-use-after-free、stack-buffer-overflow、global-buffer-overflow、double-free、Use-after-return、Alloc-dealloc-mismatch、use-after-poision等内存错误问题。它们的主要区别在于实现方式和性能开销。

2.1 shadow memory

shadow memory区域来记录实际内存的状态信息,malloc申请的内存或其它方式申请的内存一般8字节对齐,8字节的正常内存对应1个字节的shadow memory,8个字节中可划分为可寻址(访问)与不可寻址区域。如,前4个字节可寻址,后4个字节不可寻址,shadow memory记录的数据为5,即0000 0100.

normal mem与shadow mem对应关系:

shadow memory address = (normal memory address >> 3) + 0x1000000000

8字节组成的normal memory region共有3种状态:

1)1~7个字节可寻址,即shadow memory的值为1~7。

2)8个字节都可寻址,即shadow memory的值为0。

3)0个字节可寻址,shadow memory的值为负数。

0个字节可寻址其实可以分为多种情况,如:

这块区域是heap redzones、stack redzones、global redzones、freed memory,不同错误类型对应的shadow memory值也不一样。

 Addressable:           00Partially addressable: 01 02 03 04 05 06 07 Heap left redzone:     fa (实际上Heap right redzone也是fa)Freed Heap region:     fdStack left redzone:    f1Stack mid redzone:     f2Stack right redzone:   f3Stack after return:    f5Stack use after scope: f8Global redzone:        f9Global init order:     f6Poisoned by user:      f7Container overflow:    fcArray cookie:          acIntra object redzone:  bbASan internal:         feLeft alloca redzone:   caRight alloca redzone:  cbShadow gap:            cc

每次访问normal memory地址时,都会去结合对应的shadow mem的值检测是否合法。

2.2 ASAN实现原理

ASAN实现原理:通过在内存分配时插入额外的代码来检查内存访问是否合法。使用一个影子内存(shadow memory)区域来记录实际内存的使用情况,当检测到非法内存访问时,ASAN会报告错误。

检测算法:

ShadowAddr = (Addr >> 3) + Offset;
k = *ShadowAddr;
if (k != 0 && ((Addr & 7) + AccessSize > k))ReportAndCrash(Addr);

k!=0,说明Normal memory region中的8个字节并不是都可以被寻址的。

Addr & 7,将得知此次内存访问是从memory region的第几个byte开始的。

AccessSize是此次内存访问需要访问的字节长度。

(Addr&7)+AccessSize > k,则说明此次内存访问将会访问到不可寻址的字节。

当此次内存访问可能会访问到不可寻址的字节时,ASAN会报错并结合shadow memory中具体的值明确错误类型。

下面以use-after-free、heap-buffer-overflow来分析具体的检测原理。

2.2.1 use-after-free检测

检测原理:

1)已经free的normal memory对应的shadow memory值为0xfd.

2)已经free的normal memory区域需要放入隔离区一段时间(过段时间才允许被重新分配),防止发生错误时该区域已经通过malloc重新分配给其他人使用。一旦分配给其他人使用,则可能漏掉UseAfterFree的错误。

3)如果再次访问该normal memory区域时,发现对应的shadow memory值为0xfd,则触发ASAN异常报错。

2.2.2 heap-buffer-overflow检测

检测原理:

1)分配内存时normal memory的前后需要插入一定长度的安全区(大小不定),且此安全区对应的shadow memory被标记为0xfa.

2)当访问越界时,刚好访问了normal memory的前后安全区,此安全区对应的shadow memory值为0xfa,则触发ASAN异常报错。

2.3 ASAN缺陷

2.3.1 存在漏检的风险

1)use-after-free检测依赖隔离区,一段时间后这块内存被其他模块重新分配后,该模块再去访问,则无法检测出use-after-ree的错误。


2)heap-buffer-overflow检测依赖安全区,安全区有大小限制。可能是8bytes,64bytes或者其他什么值,但不管怎么样终归是有限的。如果某次踩踏跨过了安全区,踩踏到另一片可寻址的内存区域,则无法检测出heap-buffer-overflow的错误。

2.3.2 性能开销大

有两个原因导致ASAN性能开销:

1)增加额外的内存消耗:8字节的normal memory对应1个字节的shadow memory,相当于额外多出1/8的内存用于记录正常内存的状态信息;内存分配时需要在前后插入安全区,用于检测越界访问。这两种情况都会导致内存增加。

2)效率降低:需要在每次内存访问时进行检查,降低了效率;被释放的内存,需被隔离一段时间,无法立即被重新分配,系统内存紧张时,可能存在较大的性能影响

因此,针对ASAN的存在漏检的风险和性能开销大的缺陷,google提出了HWASAN来改善这两大缺陷。HWASAN解决措施:

1)措施1:64位的机器,实际上ARMv8寻址只用到了低48位,因此malloc时,HWASAN利用高8位标记tag,对应的shadow memory的值也记做tag

由于HWASAN 16字节的normal memory对应1个字节的shadow memory(ASAN为8:1),降低额外内存的消耗;由于HWASAN use-after-free检测不依赖隔离区,解决use-after-free漏检的风险(详细参考3.1.1)。

2)措施2:去除ASAN安全区的内存机制

由于去除ASAN安全区的内存机制,被释放的内存可以被其他模块立即分配,从而提高了内存的利用效率;

同时可以解决heap-buffer-overflow漏检的风险(详细参考3.1.2)。

三、HWASAN介绍

HWASAN是ASAN的升级版,优化了ASAN性能开销和漏检风险的缺陷。

3.1 实现原理

实现原理:64位的机器,实际上ARMv8寻址只用到了低48位。HWASAN用这8bit来存储一块内存区域的标签(tag)。

堆内存通过malloc分配出来,HWASAN在它返回地址时会更改该有效地址的高8位,随机生成一个tag数值,并将该tag同步到内存对应的shadow memory,当内存释放时,更新shadow memory的tag,HWASAN中normal memory和shadow memory的映射关系是16:1,而ASAN中二者的映射关系是8:1。通过对比内存高8位的tag与shadow memory的tag是否一致,如果不一致,会触发HWASAN相关的内存错误。

下面以use-after-free、heap-buffer-overflow来分析具体的检测原理。

3.1.1 use-after-free检测

检测原理:

1)分配一块内存时,内存的高8位打上tag,对应的shadow memory的值也为该tag

2)内存释放时,更新对应的shadow memory的tag,使这块内存的高8位的tag与shadow memory的tag不一致

3)当再次访问这块内存时,发现内存的高8位的tag与shadow memory的tag不一致,触发HWASAN内存错误

如,char* p =new char[10],分配10个字节的内存,由于8个字节对齐,共占用16个字节,高8位随机生成tag1。

当内存释放时,对应的shadow memory的值由原来的tag1更新位tag2.再次访问p[0]时,检查高8位tag1与shadow memory中的值tag2不一致,触发HWASAN use-after-free.

char* p =new char[10];
delete [] p;
p[0] = "abc";

3.1.2 heap-buffer-overflow检测

检测原理:

1)相邻内存的shadow memory的tag不一致

2)当访问这块内存地址时,会去检测该地址高8位的tag与对应shadow memory的tag是否一直不一致。如果不一致,说明越界访问

如,char* p =new char[10],分配10个字节的内存,由于8个字节对齐,共占用16个字节,高8位随机生成tag2。当访问p[16]时,由于p+16所处地址对应的shadow memory的值为tag3与p地址对应的高8位tag2不一致,会触发HWASAN heap-buffer-overflow.

char* p =new char[10];
p[16] = "abc";

由于每次malloc,高8位的tag随机生成,因此存在相邻内存高8位的tag一致的概率(如tag2等于tag3),概率为1/256,在这种情况下即使越界访问,也无法检测出heap-buffer-overflow的问题。

3.2 HWASAN优缺点

优点:

解决了ASAN的缺陷

缺点:

1)由于采用了高8位的tag检测机制,因此只能适用于64位的机器

2)HWASAN中normal memory和shadow memory的映射关系是16:1,即会多消耗1/16的额外内存用于记录normal memory的状态(tag)信息

3)每次内存分配、释放、访问,都需要额外的检测工作,降低性能

4.1 系统全功能打开

1)编译带HWASAN的镜像和带hwasan的libc.so & libclang_rt.hwasan-aarch64-android.so

source build/envsetup.sh
lunch missi_auto_native_only64-userdebug
export SANITIZE_TARGET=hwaddress
make -j8 或make systemimage

libc.so路径:

out/target/product/missi/system/lib64/bootstrap/hwasan/libc.so

libclang_rt.hwasan-aarch64-android.so路径:out/target/product/missi/system/lib64/bootstrap/libclang_rt.hwasan-aarch64-android.so

2)刷机或push libc.so和libclang_rt.hwasan-aarch64-android.so到/system/lib64目录后重启设备

4.2 单个应用或进程打开

AndroidManifest.xml中 <application> 元素中配置了 android:debuggable="true"

<application android:debuggable="true"></application>

native进程开启HWASAN,需要在Android.bp中做配置:

sanitize: {hwaddress: true,
},

五、Debug案例

在设备验证HWASAN功能:

1)设置HWASAN环境变量,编译出带HWASAN的镜像或libc.so + libclang_rt.hwasan-aarch64-android.so

source build/envsetup.sh
lunch missi_auto_native_only64-userdebug
export SANITIZE_TARGET=hwaddress
make -j8 或make systemimage

带hwasan的libc.so路径:

out/target/product/missi/system/lib64/bootstrap/hwasan/libc.so

libclang_rt.hwasan-aarch64-android.so路径:out/target/product/missi/system/lib64/bootstrap/libclang_rt.hwasan-aarch64-android.so

(刷机方式效率较低,可以直接push so库到设备)

2)push libc.so和libclang_rt.hwasan-aarch64-android.so到/system/lib64目录后重启设备

3)自己编写一个Demo,push hw-asan-test-bin Demo到/system/bin目录并执行

检测double-free、use-after-free、invalid-free、heap-over-flow等场景,

分别执行./system/bin/hw-asan-test-bin double-free、./system/bin/hw-asan-test-bin use-after-free、./system/bin/hw-asan-test-bin heap-over-flow命令。

Demo的部分代码:

void doubleFree() {// 分配4个字节int *ptr = (int*)malloc(4);std::cout << "ptr = " << ptr << std::endl;free(ptr);free(ptr);
}void invalidFree() {int *ptr = (int*)malloc(4);std::cout << "ptr = " << ptr << std::endl;free(ptr+1);std::cout << "invalid-free ~" << std::endl;
}void useAfterFree() {char* ptr = new char[20];std::cout << "ptr = " << ptr << std::endl;delete[] ptr;ptr[0] = 'A';std::cout << "useAfterFree ~" << std::endl;
}void heapOverFlow() {char* ptr = new char[20];std::cout << "ptr = " << ptr << std::endl;ptr[32] = 'A';std::cout << "heapOverFlow ~" << std::endl;
}void memLeak() {for (int i = 0; i < 1000; i++) {char *buffer = (char *)malloc(100);}std::cout << "memLeak ~" << std::endl;
}

4)查询生成的tombstone文件

以下是hw-asan-test-bin Demo crash生成的HWASAN tombstone文件,如下:

Cmdline: ./system/bin/hw-asan-test-bin double-free
pid: 12968, tid: 12968, name: hw-asan-test-bi  >>> ./system/bin/hw-asan-test-bin <<<
uid: 0
tagged_addr_ctrl: 0000000000000001 (PR_TAGGED_ADDR_ENABLE)
pac_enabled_keys: 000000000000000f (PR_PAC_APIAKEY, PR_PAC_APIBKEY, PR_PAC_APDAKEY, PR_PAC_APDBKEY)
signal 6 (SIGABRT), code -1 (SI_QUEUE), fault addr --------
// 内存被释放后,0x003c95840020地址对应的内存被标记为6c
Abort message: '==12968==ERROR: HWAddressSanitizer: invalid-free on address 0x003c95840020 at pc 0x007d0dd81ba4 on thread T0
tags: 77/6c (ptr/mem)#0 0x7d0dd81ba4  (/system/lib64/libclang_rt.hwasan-aarch64-android.so+0x23ba4) (BuildId: 558b5c131872716737ddc0a62f3382dd3df70b9a)#1 0x5b9584c230  (/system/bin/hw-asan-test-bin+0x1230) (BuildId: b3d99e0748a4c4a2607c8c2b9b91815e)#2 0x5b9584c6a4  (/system/bin/hw-asan-test-bin+0x16a4) (BuildId: b3d99e0748a4c4a2607c8c2b9b91815e)#3 0x7d0aab6b60  (/apex/com.android.runtime/lib64/bionic/hwasan/libc.so+0xb0b60) (BuildId: 86a860a589207e712675d7d611b13147)#4 0x5b9584c054  (/system/bin/hw-asan-test-bin+0x1054) (BuildId: b3d99e0748a4c4a2607c8c2b9b91815e)[0x003c95840020,0x003c95840040) is a small unallocated heap chunk; size: 32 offset: 0Cause: use-after-free
// 分配的内存地址0x003c95840020至0x003c95840024,刚好是4个字节与Demo代码一致
0x003c95840020 is located 0 bytes inside a 4-byte region [0x003c95840020,0x003c95840024)
// HWASAN内存释放的堆栈信息
freed by thread T0 here:#0 0x7d0dd81ba4  (/system/lib64/libclang_rt.hwasan-aarch64-android.so+0x23ba4) (BuildId: 558b5c131872716737ddc0a62f3382dd3df70b9a)#1 0x5b9584c188  (/system/bin/hw-asan-test-bin+0x1188) (BuildId: b3d99e0748a4c4a2607c8c2b9b91815e)#2 0x5b9584c6a4  (/system/bin/hw-asan-test-bin+0x16a4) (BuildId: b3d99e0748a4c4a2607c8c2b9b91815e)#3 0x7d0aab6b60  (/apex/com.android.runtime/lib64/bionic/hwasan/libc.so+0xb0b60) (BuildId: 86a860a589207e712675d7d611b13147)#4 0x5b9584c054  (/system/bin/hw-asan-test-bin+0x1054) (BuildId: b3d99e0748a4c4a2607c8c2b9b91815e)
// HWASAN内存分配的堆栈信息
previously allocated here:#0 0x7d0dd82244  (/system/lib64/libclang_rt.hwasan-aarch64-android.so+0x24244) (BuildId: 558b5c131872716737ddc0a62f3382dd3df70b9a)#1 0x7d0aa671dc  (/apex/com.android.runtime/lib64/bionic/hwasan/libc.so+0x611dc) (BuildId: 86a860a589207e712675d7d611b13147)#2 0x5b9584c0d4  (/system/bin/hw-asan-test-bin+0x10d4) (BuildId: b3d99e0748a4c4a2607c8c2b9b91815e)#3 0x5b9584c6a4  (/system/bin/hw-asan-test-bin+0x16a4) (BuildId: b3d99e0748a4c4a2607c8c2b9b91815e)#4 0x7d0aab6b60  (/apex/com.android.runtime/lib64/bionic/hwasan/libc.so+0xb0b60) (BuildId: 86a860a589207e712675d7d611b13147)#5 0x5b9584c054  (/system/bin/hw-asan-test-bin+0x1054) (BuildId: b3d99e0748a4c4a2607c8c2b9b91815e)hwasan_dev_note_heap_rb_distance: 1 1023
hwasan_dev_note_num_matching_addrs: 0
hwasan_dev_note_num_matching_addrs_4b: 0
Thread: T0 0x007400002000 stack: [0x007fc95fb000,0x007fc9dfb000) sz: 8388608 tls: [0x007d0ea6efc0,0x007d0ea72000)
Memory tags around the buggy address (one tag corresponds to 16 bytes):0x003c9583f800: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00 0x003c9583f900: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00 0x003c9583fa00: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00 0x003c9583fb00: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00 0x003c9583fc00: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00 0x003c9583fd00: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00 0x003c9583fe00: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00 0x003c9583ff00: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00 
=>0x003c95840000: 08  00 [6c] 00  00  00  00  00  00  00  00  00  00  00  00  00 0x003c95840100: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00 0x003c95840200: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00 0x003c95840300: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00 0x003c95840400: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00 0x003c95840500: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00 0x003c95840600: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00 0x003c95840700: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00 0x003c95840800: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00 
Tags for short granules around the buggy address (one tag corresponds to 16 bytes):0x003c9583ff00: ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  .. 
=>0x003c95840000: 6e  .. [..] ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  .. 0x003c95840100: ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  .. ......backtrace:#00 pc 00000000000bab8c  /apex/com.android.runtime/lib64/bionic/hwasan/libc.so (abort+308) (BuildId: 86a860a589207e712675d7d611b13147)#01 pc 00000000000354b4  /system/lib64/libclang_rt.hwasan-aarch64-android.so (__sanitizer::Abort()+60) (BuildId: 558b5c131872716737ddc0a62f3382dd3df70b9a)#02 pc 0000000000033d3c  /system/lib64/libclang_rt.hwasan-aarch64-android.so (__sanitizer::Die()+204) (BuildId: 558b5c131872716737ddc0a62f3382dd3df70b9a)#03 pc 00000000000286c4  /system/lib64/libclang_rt.hwasan-aarch64-android.so (__hwasan::ScopedReport::~ScopedReport()+544) (BuildId: 558b5c131872716737ddc0a62f3382dd3df70b9a)#04 pc 0000000000027458  /system/lib64/libclang_rt.hwasan-aarch64-android.so (__hwasan::ReportInvalidFree(__sanitizer::StackTrace*, unsigned long)+560) (BuildId: 558b5c131872716737ddc0a62f3382dd3df70b9a)#05 pc 0000000000023c00  /system/lib64/libclang_rt.hwasan-aarch64-android.so (__sanitizer_free+264) (BuildId: 558b5c131872716737ddc0a62f3382dd3df70b9a)#06 pc 0000000000001230  /system/bin/hw-asan-test-bin (doubleFree()+472) (BuildId: b3d99e0748a4c4a2607c8c2b9b91815e)#07 pc 00000000000016a4  /system/bin/hw-asan-test-bin (main+648) (BuildId: b3d99e0748a4c4a2607c8c2b9b91815e)#08 pc 00000000000b0b60  /apex/com.android.runtime/lib64/bionic/hwasan/libc.so (__libc_init+148) (BuildId: 86a860a589207e712675d7d611b13147)......

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com