1. ASan和HWAsan比较
ASan |
HWASan |
|
全称 |
Address Sanitizer |
Hardware-assisted AddressSanitizer |
版本 |
可以在32位和64位的x86、x86-64上。 从API 27(Android O MR 1)开始,Android NDK 可支持ASAN。 在Android 11 之后的AOSP master中,弃用了arm64 上的平台开发ASan,改为使用HWASan。 |
只在Android 10 及以上版本有效,且只使用于AArch64硬件平台。 |
检测bugs |
Stack and heap buffer overflow/underflow Heap use after free Stack use outside scope Double free/wild free |
Stack and heap buffer overflow/underflow Heap use after free Stack use outside scope Double free/wild free stack use after return |
要求 |
CPU 开销(~ 2倍) 代码大小开销(50% ~ 2倍) 内存开销(~ 2倍) |
CPU 开销(~ 2倍) 代码大小开销(40% ~ 50%) 内存开销(10% ~ 35%) |
原理 |
使用shadow memory(内存的一个区域)内存状态进行标记,如free掉的内存在shadow中标记为0xfd,已经申请的内存,前后存在安全区标记为0xfa |
AArch64是64位的架构,一个64bit的指针值,其中真正用于寻址的只有低48位。 AArch64拥有地址标记(Address tagging, or top-byte-ignore)的特性,它表示允许软件使用64bit指针值的高8位开发特定功能。HWASAN用这8bit来存储一块内存区域的标签(tag)。 |
缺点 |
1)ASAN的运行是需要消耗memory和CPU资源的,此外它也会增加代码大小。它的性能相比于之前的工具确实有了质的提升,但仍然无法适用于某些压力测试场景,尤其是需要全局打开的时候。这一点在Android上尤为明显,每当我们想要全局打开ASAN调试某些奇葩问题时,系统总会因为负载过重而跑不起来; 2)对于 free 的内存标记存在隔离时间,即 free 的区域一段时间后重新分配其他所有者,此时原持有者访问不会报错; 3)对应flow的安全区总归有大小,如果踩踏过了安全区,同样不会报错; |
1)可移植性差,只用于64位平台; 2)需要对Linux Kernel做一些改动以支持工具 3)对于所有错误的检测将有一定概率false negative(漏掉一些真实的错误),概率为1/256。原因是tag的生成只能从256(2的8次方)个数中选一个,因此不同地址的tag将有可能相同 |
优点 |
比较ASan: 1)不再需要安全区来检测buffer overflow,既极大地降低了工具对于内存的消耗,也不会出现ASAN中某些overflow检测不到的情况; 2)不再需要隔离区来检测UseAfterFree,因此不会出现ASAN中某些UseAfterFree检测不到的情况 |
2. ASan 编译
2.1 整体编译
m -j16
SANITIZE_TARGET=address m -j16
注意,这里需要两次编译。第一次是为了在 /system/lib 中编译常规库,第二次编译是为了在 /system/lib/asan 中进行 ASan 插桩。
需要刷新system、vendor、system分区,因为上述第 2 步编译ASAN库在/data/asan目录下。
2.2 单独编译
Android.mk
LOCAL_SANITIZE := address
Android.bp
sanitize: { address: true }
2.2.1 编译共享库
LOCAL_SANITIZE:=address
LOCAL_MODULE_RELATIVE_PATH := asan
这样一来,系统会将库放到 /system/lib/asan 中而非 /system/lib 中。但是需要指定库的路径方便链接:
LD_LIBRARY_PATH=/system/lib/asan
或
setenv LD_LIBRARY_PATH /system/lib/asan
通过 /proc/PID/maps 验证使用的库是否来自 /system/lib/asan(如果此库存在),如果不是,可能需要停用 selinux:
adb root
adb shell setenforce 0
# restart the process with adb shell kill $PID
# if it is a system service, or may be adb shell stop; adb shell start.
2.3 无法使用ASan构建
有些目标无法使用ASan 构建:
- 静态关联的可执行文件
- LOCA_CLANG:=false 目标
- 不会针对 SANITIZE_TARGET=address进行ASan 操作的LOCAL_SANITIZE:=false 的目标
在 SANITIZE_TARGET build 中,系统会跳过此类可执行文件,且会将第一个make 调用中构建的版本留在 /system/bin 中。
3. HWASan 编译
3.1 整体编译
export SANITIZE_TARGET=hwaddress
m -j16
与ASan 不同,HWASan 无需构建两次,只需增量构建,没有特殊的刷写指令,不需要擦除,支持静态可执行文件,并且可以跳过除 libc 之外的任何库的排错。
通过环境变量 SANITIZE_TARGET 指定排错(sanitizer)。
3.2 单独编译bin/lib
在编译脚本中增加如下参数即可
Android.mk
LOCAL_SANITIZE:= hwaddress
Android.bp
sanitize: { hwaddress: true }
如果需要在整体构建中,去除某模块HWASAN的编译
Android.mk
LOCAL_NOSANITIZE := hwaddress
Android.bp
sanitize: { hwaddress: false}
4. 解析
由于版本默认库或者bin是stripped过的,因此无法解析,如
==4415==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x003a861bb057 at pc 0x00775f3c664c bp 0x007fd0f434b0 sp 0x007fd0f42c90
READ of size 8 at 0x003a861bb057 thread T0
#0 0x775f3c6648 (/system/lib64/libclang_rt.asan-aarch64-android.so+0x72648)
#1 0x775f3c6ff8 (/system/lib64/libclang_rt.asan-aarch64-android.so+0x72ff8)
#2 0x59861bf0a8 (/vendor/bin/qrtr-lookup+0x20a8)
#3 0x775f72488c (/apex/com.android.runtime/lib64/bionic/libc.so+0x4988c)
0x003a861bb057 is located 0 bytes to the right of 7-byte region [0x003a861bb050,0x003a861bb057)
allocated by thread T0 here:
#0 0x775f3f6088 (/system/lib64/libclang_rt.asan-aarch64-android.so+0xa2088)
#1 0x59861bf094 (/vendor/bin/qrtr-lookup+0x2094)
#2 0x775f72488c (/apex/com.android.runtime/lib64/bionic/libc.so+0x4988c)
#3 0x59861bf044 (/vendor/bin/qrtr-lookup+0x2044)
#4 0x7760b9fbb4 (/vendor/bin/qrtr-lookup+0x4cbb4)
SUMMARY: AddressSanitizer: heap-buffer-overflow (/system/lib64/libclang_rt.asan-aarch64-android.so+0x72648)
Shadow bytes around the buggy address:
0x001750c375b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x001750c375c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x001750c375d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x001750c375e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x001750c375f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x001750c37600: fa fa 00 fa fa fa 00 fa fa fa[07]fa fa fa fa fa
0x001750c37610: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x001750c37620: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x001750c37630: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x001750c37640: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x001750c37650: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
Shadow gap: cc
==4415==ABORTING
4.1 直接解析
- push llvm-symbolizer到 system/bin下
- 如 push到其他目录,需要保证该目录在PATH下或者设置环境变量export ASAN_SYMBOLIZER_PATH=/system/bin/llvm-symbolizer
- llvm-symbolizer路径:android\vendor\qcom\proprietary\llvm-arm-toolchain-ship\10.0\aarch64-linux-android\bin\llvm-symbolizer
- push 对应模块带有symbols的库或者bin到对应目录,源文件位于android\out\target\product\shift\symbols
上述工作完成后,当ASAN / HWASan 检查到错误后,相关结果会自动解析到logcat 或screen 上,包括具体的函数,行号等等
==================================================================
==6646==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x003c452d8057 at pc 0x00749d4d364c bp 0x007fd09ac530 sp 0x007fd09abd10
READ of size 8 at 0x003c452d8057 thread T0
#0 0x749d4d3648 in printf_common(void*, char const*, std::__va_list) /out/llvm-project/compiler-rt/lib/asan/../sanitizer_common/sanitizer_common_interceptors_format.inc:547:9
#1 0x749d4d3ff8 in __interceptor_vprintf /out/llvm-project/compiler-rt/lib/asan/../sanitizer_common/sanitizer_common_interceptors.inc:1645:1
#2 0x749d4d3ff8 in printf /out/llvm-project/compiler-rt/lib/asan/../sanitizer_common/sanitizer_common_interceptors.inc:1703:1
#3 0x5b452dc1a8 in main vendor/qcom/proprietary/qmi-framework/qrtr/src/lookup.c:143:5
#4 0x749d3a888c in __libc_init (/apex/com.android.runtime/lib64/bionic/libc.so+0x4988c)
0x003c452d8057 is located 0 bytes to the right of 7-byte region [0x003c452d8050,0x003c452d8057)
allocated by thread T0 here:
#0 0x749d503088 in malloc /out/llvm-project/compiler-rt/lib/asan/asan_malloc_linux.cpp:145:3
#1 0x5b452dc194 in main vendor/qcom/proprietary/qmi-framework/qrtr/src/lookup.c:142:21
#2 0x749d3a888c in __libc_init (/apex/com.android.runtime/lib64/bionic/libc.so+0x4988c)
#3 0x5b452dc044 in _start_main bionic/libc/arch-common/bionic/crtbegin.c:45:3
#4 0x749eb2dbb4 (/vendor/bin/qrtr-lookup+0x4cbb4)
SUMMARY: AddressSanitizer: heap-buffer-overflow /out/llvm-project/compiler-rt/lib/asan/../sanitizer_common/sanitizer_common_interceptors_format.inc:547:9 in printf_common(void*, char const*, std::__va_list)
Shadow bytes around the buggy address:
0x001788a5afb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x001788a5afc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x001788a5afd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x001788a5afe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x001788a5aff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x001788a5b000: fa fa 00 fa fa fa 00 fa fa fa[07]fa fa fa fa fa
0x001788a5b010: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x001788a5b020: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x001788a5b030: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x001788a5b040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x001788a5b050: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
Shadow gap: cc
==6646==ABORTING
Aborted
4.2 编译带symbols 的lib/bin(单独模块进行排错)
- ASAN/HWASan,push 额外libc++_shared.so
- 命令 adb push android\prebuilts\ndk\r21\sources\cxx-stl\llvm-libc++\libs\arm64-v8a\libc++_shared.so /system/lib64
- HWASan 需要额外push libclang_rt.hwasan-aarch64-android.so库
- 命令 adb push android\vendor\qcom\proprietary\llvm-arm-toolchain-ship\10.0\lib\clang\10.0.7\lib\linux\libclang_rt.hwasan-aarch64-android.so /system/lib64
- push llvm-symbolizer到system/bin下
- 模块的编译脚本携带如下参数
Android.mk
LOCAL_STRIP_MODULE :=false
Android.bp
strip :{keep_symbols: true,},
可得到如下信息,得到具体的函数
==10804==ERROR: HWAddressSanitizer: invalid-free on address 0x0038f7647040 at pc 0x0072ed942bb8
tags: 1a/96 (ptr/mem)
#0 0x72ed942bb4 in __sanitizer_free /out/llvm-project/compiler-rt/lib/hwasan/hwasan_interceptors.cpp:108:3
#1 0x57f764b0b8 in main (/vendor/bin/qrtr-lookup+0x20b8)
#2 0x72ed831174 in __libc_init (/apex/com.android.runtime/lib64/bionic/libc.so+0x4e174)
#3 0x57f764b044 in _start_main (/vendor/bin/qrtr-lookup+0x2044)
#4 0x72eefd3bb4 (/vendor/bin/qrtr-lookup+0x4cbb4)
[0x0038f7647040,0x0038f7647060) is a small unallocated heap chunk; size: 32 offset: 0
0x0038f7647040 is located 0 bytes inside of 7-byte region [0x0038f7647040,0x0038f7647047)
freed by thread T0 here:
#0 0x72ed942bb4 in __sanitizer_free /out/llvm-project/compiler-rt/lib/hwasan/hwasan_interceptors.cpp:108:3
#1 0x57f764b0b0 in main (/vendor/bin/qrtr-lookup+0x20b0)
#2 0x72ed831174 in __libc_init (/apex/com.android.runtime/lib64/bionic/libc.so+0x4e174)
#3 0x57f764b044 in _start_main (/vendor/bin/qrtr-lookup+0x2044)
#4 0x72eefd3bb4 (/vendor/bin/qrtr-lookup+0x4cbb4)
previously allocated here:
#0 0x72ed943084 in __sanitizer_malloc /out/llvm-project/compiler-rt/lib/hwasan/hwasan_interceptors.cpp:169:3
#1 0x72ed826bdc in malloc (/apex/com.android.runtime/lib64/bionic/libc.so+0x43bdc)
#2 0x57f764b094 in main (/vendor/bin/qrtr-lookup+0x2094)
#3 0x72ed831174 in __libc_init (/apex/com.android.runtime/lib64/bionic/libc.so+0x4e174)
#4 0x57f764b044 in _start_main (/vendor/bin/qrtr-lookup+0x2044)
#5 0x72eefd3bb4 (/vendor/bin/qrtr-lookup+0x4cbb4)
hwasan_dev_note_heap_rb_distance: 1 1023
Thread: T0 0x006900002000 stack: [0x007fd2fc0000,0x007fd37c0000) sz: 8388608 tls: [0x000000000000,0x000000000000)
Memory tags around the buggy address (one tag corresponds to 16 bytes):
0x006d8f764680: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x006d8f764690: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x006d8f7646a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x006d8f7646b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x006d8f7646c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x006d8f7646d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x006d8f7646e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x006d8f7646f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x006d8f764700: 08 00 08 00 [96] 00 00 00 00 00 00 00 00 00 00 00
0x006d8f764710: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x006d8f764720: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x006d8f764730: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x006d8f764740: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x006d8f764750: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x006d8f764760: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x006d8f764770: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x006d8f764780: 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):
0x006d8f7646f0: .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. ..
=>0x006d8f764700: e2 .. 7a .. [..] .. .. .. .. .. .. .. .. .. .. ..
0x006d8f764710: .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. ..
See https://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html#short-granules for a description of short granule tags
SUMMARY: HWAddressSanitizer: invalid-free /out/llvm-project/compiler-rt/lib/hwasan/hwasan_interceptors.cpp:108:3 in __sanitizer_free
4.3 host 解析
将dump信息copy进入文件dumpinfo,按照如下格式(===开头)
=================================================================
==24786==ERROR: AddressSanitizer: SEGV on unknown address 0x180001a46bc1c34 (pc 0x00761175f308 bp 0x007fc5f519b0 sp 0x007fc5f51970 T0)
==24786==The signal is caused by a READ memory access.
#0 0x761175f308 (/system/system_ext/lib64/libimsmedia_jni.so+0x3308)
#1 0x761175f1b8 in JNI_OnLoad (/system/system_ext/lib64/libimsmedia_jni.so+0x31b8)
#2 0x7681c104d8 in art::JavaVMExt::LoadNativeLibrary(_JNIEnv*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, _jobject*, _jclass*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*) (/apex/com.android.art/lib64/libart.so+0x5be4d8)
#3 0x7678bf2128 in JVM_NativeLoad (/apex/com.android.art/lib64/libopenjdkjvm.so+0x8128)
#4 0x6fba7a24 (/apex/com.android.art/javalib/arm64/boot.oat+0x80a24)
然后执行(asan_symbolize路径,android\external\compiler-rt\lib\asan\scripts)
asan_symbolize -s "$OUT/symbols"/ < ./external/compiler-rt/lib/asan/scripts/dumpinfo
#0 0x7332a21308 in _Z18load_ims_media_libPKc vendor/qcom/proprietary/commonsys/telephony-apps/ims/jni/media/ims_media_jni.cpp:477:56
#1 0x7332a211b8 in _Z18load_ims_media_libPKc vendor/qcom/proprietary/commonsys/telephony-apps/ims/jni/media/ims_media_jni.cpp:0:0
#2 0x73a24dc168 in _ZN3art9JavaVMExt17LoadNativeLibraryEP7_JNIEnvRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEP8_jobjectP7_jclassPS9_ art/runtime/jni/java_vm_ext.cc:1080:19
#3 0x7399a1b16c in JVM_NativeLoad art/openjdkjvm/OpenjdkJvm.cc:333:24
5. FAQ
5.1 system 编译失败
由于当前为非动态分区,且system分区大小为1.5G,开启ASAN/HWASAN后,编译的system.img超过了1.5G,因此需要按照如下修改(后续改成动态分区则不需要修改了)
partion
vi device/jxx/shift/BoardConfig.mk
ifneq ($(strip $(BOARD_DYNAMIC_PARTITION_ENABLE)),true)
#BOARD_BUILD_SYSTEM_ROOT_IMAGE := true
BOARD_VENDORIMAGE_PARTITION_SIZE := 1043333120 #1073741824
ifeq ($(strip $(WITH_GMS)),true)
BOARD_SYSTEMIMAGE_PARTITION_SIZE := 3093299200 #3221225472
else
BOARD_SYSTEMIMAGE_PARTITION_SIZE := 3093299200 #1610612736
endif
BOARD_PRODUCTIMAGE_PARTITION_SIZE := 838860800
ifeq ($(ENABLE_AB), true)
AB_OTA_PARTITIONS ?= system
endif
else
5.2 Not enough space to resize partition
烧录system时,提示无足够空间,因为当前ROM是4G,而system.img超过了1.5G,烧录system时,除了system.img,还剩余空间少于1.5G,因此失败,此时需要将system和vendor打包为super.img烧录文章来源:https://www.toymoban.com/news/detail-618276.html
- super打包命令
lpmake --metadata-size 65536 --super-name super --metadata-slots 3 --virtual-ab --device super:4294967296 \
--group qti_dynamic_partitions_a:4290772992 --group qti_dynamic_partitions_b:4290772992 \
--partition system_a:readonly:$(get_build_var BOARD_SYSTEMIMAGE_PARTITION_SIZE):qti_dynamic_partitions_a --image system_a=$OUT/system.img \
--partition system_b:readonly:0:qti_dynamic_partitions_b \
--partition system_ext_a:readonly:0:qti_dynamic_partitions_a \
--partition system_ext_b:readonly:0:qti_dynamic_partitions_b \
--partition product_a:readonly:0:qti_dynamic_partitions_a \
--partition product_b:readonly:0:qti_dynamic_partitions_b \
--partition vendor_a:readonly:$(get_build_var BOARD_VENDORIMAGE_PARTITION_SIZE):qti_dynamic_partitions_a --image vendor_a=$OUT/vendor.img \
--partition vendor_b:readonly:0:qti_dynamic_partitions_b \
--sparse --output $OUT/super.img
- super烧录命令
fastboot flash super super.img
5.3 userdata 烧录
由于文件系统的不同,烧录userdata会导致系统无法启动,因此在烧录特殊版本的ASAN时,不烧录userdata.img,待system、vendor烧录启动后,push $OUT/data/asan到板卡的data目录下即可文章来源地址https://www.toymoban.com/news/detail-618276.html
到了这里,关于ASan和HWAsan在Android中使用的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!