进行native内存安全测试时,一旦发生内存错误,通常都会导致应用崩溃。这会打断测试进程,带来测试效率的降低:
- 发生错误后程序即崩溃,必须解决后才能继续测试发现问题,降低了测试效率,测试过程较长
- 崩溃点如果在开源/三方so,它们难以修改;在不修改崩溃点情况下,无法运行到自有代码,也就无法识别自有代码的内存错误
针对上述问题,AOSP和APP层面目前可能的对策是:
- AOSP:在14中引入“permissive"模式,此模式下,MTE触发内存错误后,可以关闭当前线程的MTE检测,不导致进程崩溃。其问题也显而易见,MTE的关闭导致本线程无法继续检测问题,内存安全测试相当于关闭了。
- APP:捕获系统信号,自行处理后,不转发给系统处理,从而避免系统信号处理函数将应用崩溃。这种方法需要修改自定义信号处理方法,另外还旁路了系统信号处理,相应的处理也被跳过(比如tombstone文件不会生成)
- 发生MTE识别的SIGSEGV时,立即关闭MTE,一段时间后重新打开MTE,继续检测
- 崩溃堆栈包含指定so时,跳过此次崩溃,无tombstone生成
- 崩溃堆栈与上一次崩溃堆栈一致时,跳过此次崩溃,无tombstone生成
- 拦截发送给AMS的信号,避免AMS杀进程
- 旁路APP自定义崩溃处理流程,避免处理流程中杀死进程,APP无需修改自身崩溃SDK的行为
前置条件:
1. 支持MTE的设备
2. 通过OTA升级了支持专注模式的系统版本
专注模式通过属性开关控制,各开关功能如下:
属性名称 | 默认值 | 属性值 | 意义 | 生效时机 | 持续周期 |
---|---|---|---|---|---|
debug.mte.failover | false | true | 进入failover模式 | 立刻 | 本次开机,重启失效 |
false | 关闭failover模式 | 立刻 | 本次开机,重启失效 | ||
debug.mte.sigsegv.no.userhandler | false | true | 让进程设置signal handler操作不生效,发生SIGSEGV时,进程自定义的崩溃处理程序不会执行,避免有些崩溃处理程序的自杀行为。 | 重启应用 | 本次开机,重启失效 |
false | 恢复系统默认行为,进程设置signal handler操作生效 | 重启应用 | 本次开机,重启失效 | ||
debug.mte.failover.delayseconds | 1 | n | 设置mte延迟开启等待n秒,默认值为1秒。仅debug.mte.failover=true时才生效。 一般情况下无需设置 | 立刻 | 本次开机,重启失效 |
debug.mte.notcrash.sigsegv | false | true | 开启MTE时,系统不让app在SIGSEGV上崩溃。一般情况下无需设置,因为这会让非MTE检测出的SIGSEGV信号也被系统忽略 | 立刻 | 本次开机,重启失效 |
false | 非MTE检测出的SIGSEGV信号不被系统忽略,按系统原生逻辑处理,可能导致应用崩溃 | 立刻 | 本次开机,重启失效 | ||
debug.mte.notcrash.any | false | true | 开启MTE时,系统不让app在任何类型信号上崩溃。一般情况下无需设置,因为这会让SIGSEGV外的任何信号都被系统忽略 | 立刻 | 本次开机,重启失效 |
false | SIGSEGV外的任何信号不被系统忽略,按系统原生逻辑处理,可能导致应用崩溃 | 立刻 | 本次开机,重启失效 | ||
debug.mte.sigsegv.ignoreframe | - | 白名单 | 设置白名单,","分隔,当发生内存错误时的堆栈包含白名单中任意值时,忽略此次错误,无tombstone生成。**适应于忽略三方库产生的任何错误。**最多设置10个,每个长度最多30B | 立刻 | 本次开机,重启失效 |
debug.mte.sigsegv.ignoreframe.process.{processname} | - | 白名单 | 针对某个进程{processname}生效,将覆盖debug.mte.sigsegv.ignoreframe的值最多设置10个,每个长度最多30B | 立刻 | 本次开机,重启失效 |
debug.mte.sigsegv.checkframes | - | n | 设置发生内存错误时,比较与上一次发生错误时的堆栈前n个帧,如果都相同,则说明在相同的位置发生内存错误,忽略本次错误,不生成tombstone文件,保存本次堆栈。n的最大值为256 | 立刻 | 本次开机,重启失效 |
debug.mte.sigsegv.checkframes.process.{processname} | - | n | 针对某个进程{processname}生效,将覆盖debug.mte.sigsegv.checkframes的值 | 立刻 | 本次开机,重启失效 |