TEE踩坏浮点寄存器引起SF NE

来源:互联网 发布:oracle linux 编辑:程序博客网 时间:2024/06/05 22:42

问题背景

reboot测试,surfaceflinger 出现NE

高概率复现!M1.MP3版本

分析过程

用GAT解开db,并结合对应的symbols文件(symbols目录里的文件必须和db一致),利用工具E-Consulter分析,分析报告如下:

== 异常报告v1.7(仅供参考) ==
报告解读: MediaTek On-Line> Quick Start> E-Consulter之NE/KE分析报告解读> NE分析报告
详细描述: 从错误的地址(0x0000000000000009)读数据, 请结合崩溃线程调用栈检查相关代码
版本 : alps-mp-m1.mp3/userdebug build
发生时间: Tue Sep 27 01:48:47 CST 2016
命令行 : /system/bin/surfaceflinger
进程标识符(pid): 287, 父进程标识符(ppid): 1 (/init)
进程状态: 正在运行
优先级 : 112 (0~99: 实时进程, 100~139: 普通进程)

== 线程信息(共5个线程) ==
当前线程信息:
线程名: /system/bin/surfaceflinger, 暂停, 线程标识符(tid): 287 (主线程)
errno: 2
本地调用栈:
linker64 SymbolName::gnu_hash() <bionic/linker/linker.cpp:696>
linker64 soinfo::gnu_lookup(this=0x0000007FB592D1F8, symbol_name=0, vi=0, symbol_index=0x0000007FE75472EC) + 36 <bionic/linker/linker.cpp:546>
linker64 soinfo::find_symbol_by_name(vi=0, symbol=0x0000007FE7547380) + 32 <bionic/linker/linker.cpp:508>
linker64 operator()(global_si=0x0000007FB592D1F8) + 116 <bionic/linker/linker.cpp:744>
linker64 visit<soinfo_do_lookup(soinfo*, char const*, const version_info*, soinfo**, const soinfo_list_t&, const soinfo_list_t&, const Elf64_Sym**)::<lambda(soinfo*)> >() + 132 <bionic/linker/linked_list.h:113>
linker64 soinfo_do_lookup(si_from=0x0000007FB59109B8, name=0x0000007FB250D22D, vi=0, si_found_in=0x0000007FE7547460, symbol=0x0000007FE7547458) + 500 <bionic/linker/linker.cpp:755>
linker64 soinfo::relocate() + 1104 <bionic/linker/linker.cpp:1903>
linker64 soinfo::link_image(this=0x0000007FB59109B8, global_group=0x0000007FE7547640, local_group=0x0000007FE7547650, extinfo=0) + 724 <bionic/linker/linker.cpp:3011>
linker64 operator()(si=0x0000007FB59109B8) + 40 <bionic/linker/linker.cpp:1557>
linker64 visit<find_libraries(soinfo*, char const* const*, size_t, soinfo**, std::__1::vector<soinfo*>*, size_t, int, const android_dlextinfo*)::<lambda(soinfo*)> >(this=0x0000007FE7547650) + 40 <bionic/linker/linked_list.h:113>
linker64 find_libraries(start_with=0, library_names=0x0000007FE7547890, library_names_count=1, soinfos=0x0000007FE7547898) + 2356 <bionic/linker/linker.cpp:1564>
linker64 find_library(name=0x0000007FB41E70D8) + 28 <bionic/linker/linker.cpp:1582>
linker64 do_dlopen(name=0x0000007FB41E70D8, flags=2, extinfo=0) + 116 <bionic/linker/linker.cpp:1725>
linker64 dlopen_ext(flags=-413894424, filename=0x0000007FB41E70D8) + 32 <bionic/linker/dlfcn.cpp:72>
linker64 dlopen(filename=0x0000007FB41E70D8, flags=2) + 44 <bionic/linker/dlfcn.cpp:85>
libEGL.so android::Loader::load_driver(this=0x0000007FB41D0018, cnx=android::gEGLImpl, mask=7) + 80 <frameworks/native/opengl/libs/EGL/Loader.cpp:431>
libEGL.so android::Loader::open(this=0x0000007FB41D0018, cnx=android::gEGLImpl) + 44 <frameworks/native/opengl/libs/EGL/Loader.cpp:180>
libEGL.so egl_init_drivers_locked() + 188 <frameworks/native/opengl/libs/EGL/egl.cpp:355>
libEGL.so android::egl_init_drivers() + 216 <frameworks/native/opengl/libs/EGL/egl.cpp:366>
libEGL.so eglGetDisplay(display=0) + 24 <frameworks/native/opengl/libs/EGL/eglApi.cpp:269>
libsurfaceflinger.so android::SurfaceFlinger::init(参数1=0x0000007FB41ED000) + 92 <frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp:514>
surfaceflinger main(参数1=1, 参数2=0x0000007FE7547BE8, 参数3=0x0000007FE7547BF8) + 164 <frameworks/native/services/surfaceflinger/main_surfaceflinger.cpp:46>
libc.so __libc_init(raw_args=0x0000007FE7547BE0, onexit=0, slingshot=main(), structors=0x0000007FE7547BC8) + 100 <bionic/libc/bionic/libc_init_dynamic.cpp:113>
surfaceflinger do_arm64_start() + 80
== 栈结束 ==
对应汇编指令:
行号 地址 指令 提示
bionic/linker/linker.cpp
696 : 0000007FB58DBD14: LDRB W0, [X1, #0x9] ; soinfo::gnu_lookup()参数 2可能有问题
当时的寄存器值:
X0: 0000007FB592D1F8, X1: 0000000000000000, X2: 0000000000000000, X3: 0000007FE75472EC
X4: 0000000040000041, X5: 0000000045956AE9, X6: 0000000000000000, X7: 0000000000000000
X8: 0000007FB5924298, X9: 0000000000000000, X10: 0000000000000000, X11: 0000000000000000
X12: 000000000000002B, X13: 0000000000004010, X14: 0000000000000001, X15: 0000000000000000
X16: 0000000000002A18, X17: 0000007FB24198C8, X18: 00000000000150C0, X19: 0000007FB592D1F8
X20: 0000007FB592D1F8, X21: 0000007FB591FA30, X22: 0000007FB592D1F8, X23: 0000007FB250D22D
X24: 0000000000000000, X25: 0000007FE7547460, X26: 0000007FB5901378, X27: 0000007FB5900DB0
X28: 0000007FB5910B61, X29: 0000007FE7547230, X30: 0000007FB58DC28C, SP: 0000007FE7547230
PC: 0000007FB58DBD14

问题出在linker64,先查看对应的代码:

uint32_t SymbolName::gnu_hash() {
if (!has_gnu_hash_) { /* 这里发生了NE */
......
}
return gnu_hash_;
}

对应的汇编代码看到X1=0,导致了NE,这里X1就是this指针,而LDRB W0, [X1, #0x9]就是取this->has_gnu_hash_的值。

我们需要追查X1从哪里赋值过来,在trace32界面点击up按钮,可以看到前一个函数帧:
这是当前崩溃的样子:

对应的函数就是SymbolName::gnu_hash和soinfo::gnu_lookup(这里虽然显示__dl_$x,但实际的函数是soinfo::gnu_lookup),这2个函数没有修改到X1,结合代码可以看到:

bool soinfo::gnu_lookup(SymbolName& symbol_name,
const version_info* vi,
uint32_t* symbol_index) const {
uint32_t hash = symbol_name.gnu_hash();
uint32_t h2 = hash >> gnu_shift2_;
......
}

X1就是symbol_name了,由于没有修改到X1,因此需要看前一个函数帧,按下up按钮之后:

这个函数是soinfo::find_symbol_by_name,这里也没有看到X1被修改,结合代码看到:

bool soinfo::find_symbol_by_name(SymbolName& symbol_name, const version_info* vi, const ElfW(Sym)** symbol) const {
uint32_t symbol_index;
bool success = is_gnu_hash() ?
gnu_lookup(symbol_name, vi, &symbol_index) :
elf_lookup(symbol_name, vi, &symbol_index);
......
}

继续点击up:

对应的函数是soinfo_do_lookup,这里看到X1的值是从D9这个浮点寄存器赋值而来。结合代码看到:

bool soinfo_do_lookup(soinfo* si_from, const char* name, const version_info* vi, soinfo** si_found_in, const soinfo::soinfo_list_t& global_group,
const soinfo::soinfo_list_t& local_group, const ElfW(Sym)** symbol) {
SymbolName symbol_name(name);
......
if (s == nullptr) {
bool error = false;
global_group.visit([&](soinfo* global_si) {
DEBUG("%s: looking up %s in %s (from global group)",
si_from->get_realpath(), name, global_si->get_realpath());
if (!global_si->find_symbol_by_name(symbol_name, vi, &s)) {
error = true;
return false;
}
......
}

symbol_name来自name,对应的汇编代码是参数name的值X1赋值给D9做临时保存用,然后在调用soinfo::find_symbol_by_name函数时,将D9还原回X1。我们看下参数name的值是否也是0:

参数name的值正常。这个就奇怪了,X1(值为0x0000007FB250D22D)赋值给D9(从_exp_detail.txt看到值V9也是为0),然后D9赋值给X1(值为0)。

后面有复现几次这样的问题,我们一一分析了NE db,看到也是类似的问题。因此怀疑浮点寄存器被意外清空,谁会清空浮点寄存器呢?kernel肯定是不会的了,因为kernel有完整的浮点支持,且kernel本身是不用浮点的。
那么除了kernel,还有atf和tee os。

  • 检查atf的代码,context switch是不会备份浮点寄存器,只备份通用寄存器和系统寄存器,而且atf和kernel一样,本身不会用浮点寄存器,因此atf也可以排除。
  • 问题很明显了,出在tee os,而且指纹识别会用到浮点运算。

我们做对比试验,出一个移除tee os的版本对比测试,发现这个版本就不会出问题。因此下一步需要第3方追查浮点寄存器被踩坏的原因。

根本原因:

tee os在用浮点运算时,没有做好备份,导致影响到了app。

解决方法:

需要第3方修复。

结语:

熟练各种trace32技巧,对不同层次的系统的上下文切换有深入了解。

0 0