在Android中实际使用AddressSanitizer的一些经验

作者 by adtxl / 2022-05-11 / 暂无评论 / 434 个足迹

之前写了一篇文章,是关于asan的使用:AddressSanitizer & UndefinedBehaviorSanitizer & BoundSanitizer在Android中的使用 实际这篇文章就是对aosp文档的翻译,在实际使用过程中,发现google的文档写的比较简单。

另外,可能是版本的原因,有些配置并不适合最新的Android系统,本文使用的Android版本为11和12,因此本文所述的内容大概适用于这两个版本,随着不断的版本升级,以后这篇文章大概也会过时吧

关于asan的介绍可以先看下上面的文章,本文主要总结一些经验

1.如何更方便的使用asan?

作为一个系统开发者,最简单的使用方式就是使用asan整编所有code,然后烧写所有image.方式如下:

source build/envsetup.sh
lunch xxx
make –jxx 
SANITIZE_TARGET=address make –jxx

在实际使用过程中,asan对内存和CPU的影响开销还是比较大的,内存比较小的话,如1.5G内存,是无法亮屏的。
或者,有些模块开发者也不需要检查所有服务,只是关注于自己的服务,因此,我更推荐下面你的使用方式。

2. 整编于部分编译的结合,实际使用的方式?

请注意,使用asan编译的so不再生成到system或vendor下面,而是生成到userdata分区,因此,实际开发中,下面这种方式更方便:

  1. 正常编译一遍:source, lunch, make
  2. 使用asan完整编译一次:SANITIZE_TARGET=address  make –jxx [可选,Android12遇到abi build error使用SKIP_ABI_CHECKS=true]
  3. 使用fastboot单独烧写userdata.img
  4. 修改指定bin文件的Android.bp或Android.mk
  5. 完成第4步后,正常编译
  6. 再单独烧写bin文件所在的分区,如vendor.img
  7. 如想检查其它的native bin,重复4-6步即可

这样做的优点,可以针对性调试特定 Native bin,而且不用关心需要打开哪些 lib 的 asan

3. 如何检查所有app?

ASan 无法检查 Java 代码,但可以检测 JNI 库中的错误。为此,您需要使用 ASan 构建可执行文件(在此情况下是 /system/bin/app_process(32|64))。这将在设备上的所有应用中同时启用 ASan,因而负载非常大,但 2 GB RAM 的设备应该能够从容应对。

image.png

4. 如何单独检查一个app?

这里发现使用aosp中文档的方法不太适用,实际像下面这样操作是可以的。

步骤1:使用asan编译app_process,并生成到system/bin/asan/app_process
command:按下面修改完成后,直接编译Android,make -jxx

imaged97d8a16d14e6872.png

步骤2:将asan下面的app_process push到开发板
command:使用adb sync或adb push,将asan编译的app_process,生成到system/bin/asan/app_process

注意:不要直接烧写system.img

image714c66bb3ea29ad2.png

步骤3:获取app的native lib path

Command:adb shell pm dump PACKAGE_NAME

imagea8febc1b21dc7575.png

对于 32 位程序需要在上面那个 path 后面加上一级 arm 目录,上面例子就是/product/app/xxxLauncherLite/lib/arm/这个目录

步骤4:添加wrap.sh脚本,并添加可执行权限

Command: mkdir&adb push

![](https://adtxl.com/usr/uploads/2022/05/108565465.png)#!/system/bin/sh

shift
set -- "/system/bin/asan/app_process $@"
exec $@

最终状态如下:

imaged07df98e72beb78c.png

步骤5:关闭selinux,kill掉相关进程,结果验证

Command: setenforce 0

imagec5a86c370863b7ff.png

5. 不检查app,只想检查native bin

这个称为 asan lite 功能,因为 App 有虚拟机,如果打开 asan,内存需求明显,那么可以只打开 Native asan

1.正常编译一次:make –jxx
2.使用asan lite完整编译一遍:
SANITIZE_LITE=true SANITIZE_TARGET=address make -jxx
3.烧写所有image

6. 如何确定进程是否使用了asan编译的so?

可以通过读取/proc/$PID/maps,验证是否使用了asan编译的so

image7f86443c3655cfcd.png

如果不是,可以尝试关闭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.

另一种方法,通过linker判断

linker 中会检查 bin 程序的 interpreter 是否如框内容,如果是的话,就使用 asan 的 namespace,从而会优先引用 /data/asan/ 下面的 lib.

image48b807b9f15571f4.png

imagecd95bf685ddd22ba.png

程序的 interpreter 可以通过 readelf -e BIN_NAME 查看,类似下图

image2c58a13d68e7b217.png

独特见解