Android AddressSanitizier

Asan是一个快速的内存错误检测器,它可以检测C、C++代码中的例如野指针和内存溢出错误,具体可以分为以下几类:

  • Out-of-bounds accesses to heap, stack and globals
  • Use-after-free
  • Use-after-return (to some extent)
  • Double-free, invalid free
  • Memory leaks (experimental)

有了这样的利器,对于Android Native和系统层开发者来说真是一大福音,目前Asan是集成在LLVM这个工程当中的,使用clang来编译你的C C++代码的时候可以添加-fsanitize=address 就 能 打 开Asan支持,如果你想在出错的时候打印函数调用栈,那么可以再加上 -fno-omit-frame-pointer-O1选项,这会帮助你更加快速的定位问题。

Asan on Android

这么好的工具,Android 自然会吸收进来,在Android的官网上面就有介绍这个工具的使用,但是比较坑的是当我们按照他们的文档实际验证的时候遇到了很多问题,例如编译不过,例如编译通过,但是Asan不起作用,再或者机器直接起不来等诸多问题,猜想导致这么多问题的原因可能有以下几个:

  • Android版本升级了,但是对应的文档并没有升级
  • 芯片厂家对clang等编译器部分有自己的定制
  • 终端制造商对系统的定制差异导致不兼容

总之被各种奇奇怪怪的问题折腾了几遍之后,结合芯片厂家的文档终于还是搞定了怎么去把asan添加到Android的有关模块当中,之所以说有关模块而不是所有模块,是因为有几种模块是无法添加asan支持的,主要有以下几类:

  • 非开源库 ,因为给我们的就是二进制文件,没有源代码,所以我们无法通过编译给它插入错误检测指令,对于Android来说主要是vendor目录下的一些模块
  • Java库,asan不支持java的检测
  • Kernel,Kernel有专门的Kasan

除了上面这些模块,理论上来说其他可执行文件和so动态库我们都可以通过如下的方式来添加asan支持:

Android.mk文件:

LOCAL_CLANG := true  //必选
LOCAL_SANITIZE := address //必选
LOCAL_MULTILIB := both //可选,分别编译32和64位文件
LOCAL_MODULE_RELATIVE_PATH := asan //可选,so库会被安装到/system/lib/asan或者/system/lib64/asan

Android.bp文件:

cflags: [
 "-fno-omit-frame-pointer",
 "-O0",
 "-Wno-frame-larger-than="
 ],
 clang: true,
 sanitize: {
 address: true,
 },
注意:Android.bp文件里面编译的支持asan的so文件默认是安装到/data/asan/system/lib目录的

这里要说明的是如果一个可执行文件没有添加asan支持的话,那么它是无法加载已经添加了asan支持的动态库文件的,所以针对一些公共库,例如libgui.so,它可能同时会被mediaserver、system_server、surfaceflinger等进程使用,如果只有surfaceflinger开了asan支持,而mediaserver和system_server没有开asan支持的话,那么我们需要在固件里面编译两份libgui.so,一份放在/system/lib64等常规目录下,另一份放在/system/lib64/asan目录下面,然后使用LD_LIBRARY_PATH的方式来让不同的进程加载不同目录下的libgui.so文件,然而在使用LD_LIBRARY_PATH的时候,按照Android的文档来操作又遇到了坑…….,按照Google的做法,我们只要在相应的rc文件里面添加 setenv LD_LIBRARY_PATH …….就可以了,但是实际操作起来,例如在surfaceflinger.rc文件里面添加了之后,系统都无法起来了,利用一些其他技巧(例如下面app_process的方式)给surfaeflinger添加了LD_LIBRARY_PATH环境变量之后,还是无法加载到想要的目录下的文件,这种情况下,目前只有想到在linker的相关代码里面去添加类似白名单的做法,虽然方法有点low,但是目前唯一可以走通的方法,更好的方法还在研究中.

zygote系进程添加asan支持

虽然asan无法支持Java代码中的异常,但是我们可以在app_process、libart、libhwui、jni库等可执行文件和动态库文件中添加asan支持,动态库添加支持的方式与上面无异,app_process倒有一种更简单的方式,只要执行external/compiler-rt/lib/asan/scripts/asan_device_setup这个脚本就可以了,这个脚本会把设备上面的app_process(32/64)重命名为app_process(32/64).real,同时添加/system/bin/app_process(32/64)这两个shell文件,他们的内容如下所示:

app_process32文件内容:

#!/system/bin/sh-from-zygote
ASAN_OPTIONS=start_deactivated=1,alloc_dealloc_mismatch=0,malloc_context_size=0,allow_user_segv_handler=1 \
ASAN_ACTIVATION_OPTIONS=include_if_exists=/data/local/tmp/asan.options.%b \
LD_PRELOAD=$LD_PRELOAD:libclang_rt.asan-arm-android.so \
exec /system/bin/app_process32.real $@

app_process64文件内容:

#!/system/bin/sh-from-zygote
ASAN_OPTIONS=start_deactivated=1,alloc_dealloc_mismatch=0,malloc_context_size=0,allow_user_segv_handler=1 \
ASAN_ACTIVATION_OPTIONS=include_if_exists=/data/local/tmp/asan.options.%b \
LD_PRELOAD=$LD_PRELOAD:libclang_rt.asan-aarch64-android.so \
exec /system/bin/app_process64.real $@

这样zygote系的进程都可以添加asan支,是不是很方便~~

asan原理

先借用MTK的一张图,觉得这是我目前看到的最好理解asan工作原理的一张图了:

《Android AddressSanitizier》 image.png

说白一点就是用在分配内存的时候,除了分配实际所需内存外,还在它的两端添加相应的redzone,分配的内存和redzone都有对应的影子内存,影子内存的bit位代表了相应内存是否可以访问,然后在访问内存的时候相应的添加检测影子内存的指令,这样就达到了监控的目的,这种方式虽然会带来内存和运行速度的影响,但是相比于那些莫名其妙的内存问题,我们完全可以在开发阶段打开asan支持或者在特殊的固件当中打开asan支持.

常见QA

Q1. Android N didn't compile libclang_rt.asan-arm-android.so default. How to build "
libclang_rt.asan-arm-android.so"?
A1.
Solution:
Modify file "./external/compiler-rt/lib/asan/Android.mk" as following
178 #ifeq (true,$(FORCE_BUILD_SANITIZER_SHARED_OBJECTS))
179 #ifdef 2ND_ADDRESS_SANITIZER_RUNTIME_LIBRARY
180 $(eval $(call build-asan-rt-shared-library,$(ADDRESS_SANITIZER_RUNTIME_LIBRARY)
,64))
181 $(eval $(call build-asan-rt-shared-library,$(
2ND_ADDRESS_SANITIZER_RUNTIME_LIBRARY),32))
182 #else
183 # $(eval $(call build-asan-rt-shared-library,$(ADDRESS_SANITIZER_RUNTIME_LIBRARY),32))
184 #endif
185 #endif
And then build comiler-rt
/external/compiler-rt/$ mm


Q2. How to solve build error "error: 'out/target/product/xxxx/system/bin/linker_asan64'"?
A2.
Logs:
ninja: error: 'out/target/product/xxxx/system/bin/linker_asan64', needed by 'out/target/product/
xxxx/system/bin/asan_test', missing and no known rule to make it
make: *** [ninja_wrapper] Error 1
make: Leaving directory `/mnt/android/Builds/xxxx'
Solution:
copy linker to linker_asan(32 bit & 64 bit)
cp out/target/product/xxx/system/bin/linker64 out/target/product/xxx/system/bin/linker_asan64
cp out/target/product/xxx/system/bin/linker out/target/product/xxx/system/bin/linker_asan


Q3. How to solve build error "art/runtime/class_linker.cc:351:19: error: stack frame size of
3040 bytes "?
A3.
Logs:
art/runtime/class_linker.cc:351:19: error: stack frame size of 3040 bytes in function 'art::
ClassLinker::InitWithoutImage' [ -Werror,-Wframe-larger-than= ]
bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>>
boot_class_path,
^
art/runtime/class_linker.cc:1559:19: error: stack frame size of 1824 bytes in function 'art::
ClassLinker::AddImageSpace' [-Werror,-Wframe-larger-than=]
bool ClassLinker::AddImageSpace(
Solution:
Add LOCAL_CFLAGS "-Werror" and "-Wno-frame-larger-than=" in Android.mk.
[Example patch]
=====================================================================
diff --git a/runtime/Android.mk b/runtime/Android.mk
index aa12c83..e2e3075 100644--- a/runtime/Android.mk
+++ b/runtime/Android.mk
@@ -523,6 +523,13 @@ endif
LOCAL_MULTILIB := both
endif
+ LOCAL_CLANG := true
+ LOCAL_SANITIZE := address
+ LOCAL_MULTILIB := both
+
+ LOCAL_CFLAGS += -Werror
+ LOCAL_CFLAGS += -Wno-frame-larger-than=
+
LOCAL_C_INCLUDES += $$(ART_C_INCLUDES)
LOCAL_C_INCLUDES += art/cmdline
LOCAL_C_INCLUDES += art/sigchainlib
=====================================================================


Q4. How to solve "Shadow memory range interleaves with an existing memory mapping.
ASan cannot proceed correctly. ABORTING." issue?
A4: Please merge below kernel patch. Rebuild and reflash boot.img.
Logs:
03-28 01:59:00.239 1912 1912 I : ==1912==Shadow memory range interleaves with an
existing memory mapping. ASan cannot proceed correctly. ABORTING.
03-28 01:59:00.239 1912 1912 I :
03-28 01:59:00.239 1912 1912 I : ==1912==ASan shadow was supposed to be located in the
[0x00000000-0x1fffffff] range.
03-28 01:59:00.239 1912 1912 I :
03-28 01:59:00.249 1912 1912 I : ==1912==Process memory map follows:
03-28 01:59:00.249 1912 1912 I :
03-28 01:59:00.249 1912 1912 I : 0x0ed56000-0x0ed5d000 /system/bin/app_process32
03-28 01:59:00.249 1912 1912 I :
03-28 01:59:00.249 1912 1912 I : 0x0ed5d000-0x0ed5e000 /system/bin/app_process32
Patch:
=====================================================================
Change-Id: Iceaba90a3745323288be01f73aa51f4f4dbbda16
---
arch/arm64/include/asm/elf.h | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h
index b983322..a383c28 100644
--- a/arch/arm64/include/asm/elf.h
+++ b/arch/arm64/include/asm/elf.h
@@ -114,11 +114,12 @@
#define ELF_EXEC_PAGESIZE PAGE_SIZE
/*
- * This is the base location for PIE (ET_DYN with INTERP) loads. On
- * 64-bit, this is raised to 4GB to leave the entire 32-bit address
- * space open for things that want to use the area for 32-bit pointers.
+ * This is the location that an ET_DYN program is loaded if exec'ed. Typical
+ * use of this is to invoke "./ld.so someprog" to test out a new version of
+ * the loader. We need to make sure that it is out of the way of the program
+ * that it will "exec", and that there is sufficient room for the brk.
*/
-#define ELF_ET_DYN_BASE 0x100000000UL
+#define ELF_ET_DYN_BASE (2 * TASK_SIZE_64 / 3)
#ifndef __ASSEMBLY__
@@ -169,8 +170,7 @@ extern int arch_setup_additional_pages(struct linux_binprm *bprm,
#ifdef CONFIG_COMPAT
-/* PIE load location for compat arm. Must match ARM ELF_ET_DYN_BASE. */
-#define COMPAT_ELF_ET_DYN_BASE 0x000400000UL
+#define COMPAT_ELF_ET_DYN_BASE (2 * TASK_SIZE_32 / 3)
/* AArch32 registers. */
#define COMPAT_ELF_NGREG 18

asan示例解读

  • Use after free
// RUN: clang -O -g -fsanitize=address %t && ./a.out
int main(int argc, char **argv) {
  int *array = new int[100];
  delete [] array;
  return array[argc];  // BOOM
}

=================================================================
==6254== ERROR: AddressSanitizer: heap-use-after-free on address 0x603e0001fc64 at pc 0x417f6a bp 0x7fff626b3250 sp 0x7fff626b3248
READ of size 4 at 0x603e0001fc64 thread T0
    #0 0x417f69 in main example_UseAfterFree.cc:5
    #1 0x7fae62b5076c (/lib/x86_64-linux-gnu/libc.so.6+0x2176c)
    #2 0x417e54 (a.out+0x417e54)
0x603e0001fc64 is located 4 bytes inside of 400-byte region [0x603e0001fc60,0x603e0001fdf0)
freed by thread T0 here:
    #0 0x40d4d2 in operator delete[](void*) /home/kcc/llvm/projects/compiler-rt/lib/asan/asan_new_delete.cc:61
    #1 0x417f2e in main example_UseAfterFree.cc:4
previously allocated by thread T0 here:
    #0 0x40d312 in operator new[](unsigned long) /home/kcc/llvm/projects/compiler-rt/lib/asan/asan_new_delete.cc:46
    #1 0x417f1e in main example_UseAfterFree.cc:3
Shadow bytes around the buggy address:
  0x1c07c0003f30: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x1c07c0003f40: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x1c07c0003f50: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x1c07c0003f60: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x1c07c0003f70: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x1c07c0003f80: fa fa fa fa fa fa fa fa fa fa fa fa[fd]fd fd fd
  0x1c07c0003f90: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x1c07c0003fa0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x1c07c0003fb0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fa fa
  0x1c07c0003fc0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x1c07c0003fd0: 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
  Heap righ redzone:     fb
  Freed Heap region:     fd
  Stack left redzone:    f1
  Stack mid redzone:     f2
  Stack right redzone:   f3
  Stack partial redzone: f4
  Stack after return:    f5
  Stack use after scope: f8
  Global redzone:        f9
  Global init order:     f6
  Poisoned by user:      f7
  ASan internal:         fe
==6254== ABORTING

  • Heap buffer overflow
// RUN: clang -O -g -fsanitize=address %t && ./a.out
int main(int argc, char **argv) {
  int *array = new int[100];
  array[0] = 0;
  int res = array[argc + 100];  // BOOM
  delete [] array;
  return res;
}

=================================================================
==6226== ERROR: AddressSanitizer: heap-buffer-overflow on address 0x603e0001fdf4 at pc 0x417f8c bp 0x7fff64c0c010 sp 0x7fff64c0c008
READ of size 4 at 0x603e0001fdf4 thread T0
    #0 0x417f8b in main example_HeapOutOfBounds.cc:5
    #1 0x7fa97c09376c (/lib/x86_64-linux-gnu/libc.so.6+0x2176c)
    #2 0x417e54 (a.out+0x417e54)
0x603e0001fdf4 is located 4 bytes to the right of 400-byte region [0x603e0001fc60,0x603e0001fdf0)
allocated by thread T0 here:
    #0 0x40d312 in operator new[](unsigned long) /home/kcc/llvm/projects/compiler-rt/lib/asan/asan_new_delete.cc:46
    #1 0x417f1c in main example_HeapOutOfBounds.cc:3
Shadow bytes around the buggy address:
  0x1c07c0003f60: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x1c07c0003f70: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x1c07c0003f80: fa fa fa fa fa fa fa fa fa fa fa fa 00 00 00 00
  0x1c07c0003f90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x1c07c0003fa0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x1c07c0003fb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00[fa]fa
  0x1c07c0003fc0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x1c07c0003fd0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x1c07c0003fe0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x1c07c0003ff0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x1c07c0004000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
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
  Heap righ redzone:     fb
  Freed Heap region:     fd
  Stack left redzone:    f1
  Stack mid redzone:     f2
  Stack right redzone:   f3
  Stack partial redzone: f4
  Stack after return:    f5
  Stack use after scope: f8
  Global redzone:        f9
  Global init order:     f6
  Poisoned by user:      f7
  ASan internal:         fe
==6226== ABORTING

  • Stack buffer overflow
// RUN: clang -O -g -fsanitize=address %t && ./a.out
int main(int argc, char **argv) {
  int stack_array[100];
  stack_array[1] = 0;
  return stack_array[argc + 100];  // BOOM
}

=================================================================
==6240== ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7fff8098b2b4 at pc 0x417fe1 bp 0x7fff8098b0f0 sp 0x7fff8098b0e8
READ of size 4 at 0x7fff8098b2b4 thread T0
    #0 0x417fe0 in main example_StackOutOfBounds.cc:5
    #1 0x7fa3667c976c (/lib/x86_64-linux-gnu/libc.so.6+0x2176c)
    #2 0x417e54 (a.out+0x417e54)
Address 0x7fff8098b2b4 is located at offset 436 in frame <main> of T0's stack:
  This frame has 1 object(s):
    [32, 432) 'stack_array'
HINT: this may be a false positive if your program uses some custom stack unwind mechanism or swapcontext
      (longjmp and C++ exceptions *are* supported)
Shadow bytes around the buggy address:
  0x1ffff0131600: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x1ffff0131610: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x1ffff0131620: f1 f1 f1 f1 00 00 00 00 00 00 00 00 00 00 00 00
  0x1ffff0131630: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x1ffff0131640: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x1ffff0131650: 00 00 00 00 00 00[f4]f4 f3 f3 f3 f3 00 00 00 00
  0x1ffff0131660: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x1ffff0131670: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x1ffff0131680: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x1ffff0131690: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x1ffff01316a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
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
  Heap righ redzone:     fb
  Freed Heap region:     fd
  Stack left redzone:    f1
  Stack mid redzone:     f2
  Stack right redzone:   f3
  Stack partial redzone: f4
  Stack after return:    f5
  Stack use after scope: f8
  Global redzone:        f9
  Global init order:     f6
  Poisoned by user:      f7
  ASan internal:         fe
==6240== ABORTING
  • Global Buffer Overflow
// RUN: clang -O -g -fsanitize=address %t && ./a.out
int global_array[100] = {-1};
int main(int argc, char **argv) {
  return global_array[argc + 100];  // BOOM
}


=================================================================
==6211== ERROR: AddressSanitizer: global-buffer-overflow on address 0x000000622314 at pc 0x417fee bp 0x7fff2e146300 sp 0x7fff2e1462f8
READ of size 4 at 0x000000622314 thread T0
    #0 0x417fed in main example_GlobalOutOfBounds.cc:4
    #1 0x7f1c10d2a76c (/lib/x86_64-linux-gnu/libc.so.6+0x2176c)
    #2 0x417ef4 (a.out+0x417ef4)
0x000000622314 is located 4 bytes to the right of global variable 'global_array (example_GlobalOutOfBounds.cc)' (0x622180) of size 400
Shadow bytes around the buggy address:
  0x1000000c4410: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x1000000c4420: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x1000000c4430: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x1000000c4440: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x1000000c4450: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x1000000c4460: 00 00[f9]f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9
  0x1000000c4470: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x1000000c4480: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x1000000c4490: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x1000000c44a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x1000000c44b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
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
  Heap righ redzone:     fb
  Freed Heap region:     fd
  Stack left redzone:    f1
  Stack mid redzone:     f2
  Stack right redzone:   f3
  Stack partial redzone: f4
  Stack after return:    f5
  Stack use after scope: f8
  Global redzone:        f9
  Global init order:     f6
  Poisoned by user:      f7
  ASan internal:         fe
==6211== ABORTING

  • User After Return
// RUN: clang -O -g -fsanitize=address %t && ./a.out
// By default, AddressSanitizer does not try to detect
// stack-use-after-return bugs.
// It may still find such bugs occasionally
// and report them as a hard-to-explain stack-buffer-overflow.

// You need to run the test with ASAN_OPTIONS=detect_stack_use_after_return=1

int *ptr;
__attribute__((noinline))
void FunctionThatEscapesLocalObject() {
  int local[100];
  ptr = &local[0];
}

int main(int argc, char **argv) {
  FunctionThatEscapesLocalObject();
  return ptr[argc];
}


=================================================================
==6268== ERROR: AddressSanitizer: stack-use-after-return on address 0x7fa19a8fc024 at pc 0x4180d5 bp 0x7fff73c3fc50 sp 0x7fff73c3fc48
READ of size 4 at 0x7fa19a8fc024 thread T0
    #0 0x4180d4 in main example_UseAfterReturn.cc:17
    #1 0x7fa19b11d76c (/lib/x86_64-linux-gnu/libc.so.6+0x2176c)
    #2 0x417f34 (a.out+0x417f34)
Address 0x7fa19a8fc024 is located at offset 36 in frame <_Z30FunctionThatEscapesLocalObjectv> of T0's stack:
  This frame has 1 object(s):
    [32, 432) 'local'
HINT: this may be a false positive if your program uses some custom stack unwind mechanism or swapcontext
      (longjmp and C++ exceptions *are* supported)
Shadow bytes around the buggy address:
  0x1ff43351f7b0: fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe
  0x1ff43351f7c0: fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe
  0x1ff43351f7d0: fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe
  0x1ff43351f7e0: fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe
  0x1ff43351f7f0: fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe
=>0x1ff43351f800: f5 f5 f5 f5[f5]f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
  0x1ff43351f810: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
  0x1ff43351f820: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
  0x1ff43351f830: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 00 00 00 00
  0x1ff43351f840: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x1ff43351f850: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
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
  Heap righ redzone:     fb
  Freed Heap region:     fd
  Stack left redzone:    f1
  Stack mid redzone:     f2
  Stack right redzone:   f3
  Stack partial redzone: f4
  Stack after return:    f5
  Stack use after scope: f8
  Global redzone:        f9
  Global init order:     f6
  Poisoned by user:      f7
  ASan internal:         fe
==6268== ABORTING

  • Use After Scope
// RUN: clang -O -g -fsanitize=address -fsanitize-address-use-after-scope \
//    use-after-scope.cpp -o /tmp/use-after-scope
// RUN: /tmp/use-after-scope

// Check can be disabled in run-time:
// RUN: ASAN_OPTIONS=detect_stack_use_after_scope=0 /tmp/use-after-scope

volatile int *p = 0;

int main() {
  {
    int x = 0;
    p = &x;
  }
  *p = 5;
  return 0;
}
=================================================================
==58237==ERROR: AddressSanitizer: stack-use-after-scope on address 0x7ffc4d830880 at pc 0x0000005097ed bp 0x7ffc4d830850 sp 0x7ffc4d830848
WRITE of size 4 at 0x7ffc4d830880 thread T0
    #0 0x5097ec  (/tmp/use-after-scope+0x5097ec)
    #1 0x7ff85fa6bf44  (/lib/x86_64-linux-gnu/libc.so.6+0x21f44)
    #2 0x41a005  (/tmp/use-after-scope+0x41a005)

Address 0x7ffc4d830880 is located in stack of thread T0 at offset 32 in frame
    #0 0x5096ef  (/tmp/use-after-scope+0x5096ef)

  This frame has 1 object(s):
    [32, 36) 'x' <== Memory access at offset 32 is inside this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism or swapcontext
      (longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-use-after-scope (/tmp/use-after-scope+0x5097ec) 
Shadow bytes around the buggy address:
  0x100009afe0c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100009afe0d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100009afe0e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100009afe0f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100009afe100: 00 00 00 00 00 00 00 00 00 00 00 00 f1 f1 f1 f1
=>0x100009afe110:[f8]f3 f3 f3 00 00 00 00 00 00 00 00 00 00 00 00
  0x100009afe120: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100009afe130: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100009afe140: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100009afe150: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100009afe160: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
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
  Heap right redzone:      fb
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack partial redzone:   f4
  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
==58237==ABORTING

AddressSanitizerFlags

不知道在读Use After Return这个示例的时候,有没有注意观察到这么一句话 ,You need to run the test with ASAN_OPTIONS=detect_stack_use_after_return=1,大意就是说你可以设置ASAN_OPTIONS这个环境变量的值为detect_stack_use_after_return=1 才可以开启use after return这种检测,其实关于ASAN_OPTIONS的用法在上面介绍system_server的脚本的时候就有:

 app_process64文件内容:
#!/system/bin/sh-from-zygote
ASAN_OPTIONS=start_deactivated=1,alloc_dealloc_mismatch=0,malloc_context_size=0,allow_user_segv_handler=1 \
ASAN_ACTIVATION_OPTIONS=include_if_exists=/data/local/tmp/asan.options.%b \
LD_PRELOAD=$LD_PRELOAD:libclang_rt.asan-aarch64-android.so \
exec /system/bin/app_process64.real $@

ASAN _OPTION这个环境变量我们可以称为AddressSanitizerFlags,AddressSanitizerFlags又分为Compiler flags 和 Run-time flags,利用这些flag,我们就可以控制asan的编译时和运行时行为,更多详细的介绍,可以参考wiki上面的介绍.

    原文作者:HuangTao_Zoey
    原文地址: https://www.jianshu.com/p/173f74ea2b47
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞