ART Runtime上的暴露崩溃

时间:2016-02-01 09:27:38

标签: android art-runtime

我在ART上测试Dexposed,它在art :: ReferenceMapVisitor :: VisitQuickFrame()中随机崩溃。 我认为dexposed可能会错误地处理堆栈帧:

     .extern artQuickDexposedInvokeHandler
ENTRY art_quick_dexposed_invoke_handler
    SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
    str     r0, [sp, #0]           @ place proxy method at bottom of frame
    mov     r2, r9                 @ pass Thread::Current
    mov     r3, sp                 @ pass SP
    blx     artQuickDexposedInvokeHandler  @ (Method* proxy method, receiver, Thread*, SP)
    ldr     r2, [r9, #THREAD_EXCEPTION_OFFSET]  @ load Thread::Current()->exception_
    add     sp, #16                @ skip r1-r3, 4 bytes padding.
    .cfi_adjust_cfa_offset -16
    cbnz    r2, 1f                 @ success if no exception is pending
    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
    bx      lr                     @ return on success
1:
    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
    DELIVER_PENDING_EXCEPTION
END art_quick_dexposed_invoke_handler

用于hookMethodNative:

static void com_taobao_android_dexposed_DexposedBridge_hookMethodNative(JNIEnv *env, jclass, jobject java_method......) {
    ArtMethod *art_method = ArtMethod::FromReflectedMethod(soa, java_method);
    ......
    art_method->SetEntryPointFromQuickCompiledCode((void *) art_quick_dexposed_invoke_handler);
    art_method->SetAccessFlags((art_method->GetAccessFlags() & ~kAccNative));
}

函数VisitQuickFrame在art/runtime/thread.cc中,在访问从map.data_[1]

中检索到的map.RegWidth()中的ArtMethod::GetEntryPointFromQuickCompiledCode时崩溃了
private:
void VisitQuickFrame() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
  StackReference<mirror::ArtMethod>* cur_quick_frame = GetCurrentQuickFrame();
  mirror::ArtMethod* m = cur_quick_frame->AsMirrorPtr();
  mirror::ArtMethod* old_method = m;
  visitor_(reinterpret_cast<mirror::Object**>(&m), 0 /*ignored*/, this);
  if (m != old_method) {
    cur_quick_frame->Assign(m);
  }

  // Process register map (which native and runtime methods don't have)
  if (!m->IsNative() && !m->IsRuntimeMethod() && !m->IsProxyMethod()) {
    const uint8_t* native_gc_map = m->GetNativeGcMap(sizeof(void*));
    CHECK(native_gc_map != nullptr) << PrettyMethod(m);
    const DexFile::CodeItem* code_item = m->GetCodeItem();
    DCHECK(code_item != nullptr) << PrettyMethod(m);  // Can't be nullptr or how would we compile its instructions?
    NativePcOffsetToReferenceMap map(native_gc_map);
    size_t num_regs = std::min(map.RegWidth() * 8,
                               static_cast<size_t>(code_item->registers_size_));
    if (num_regs > 0) {
  ......

上面的汇编代码是从art/runtime/arch/arm/quick_entrypoints_arm.S

复制的
    /*
     * Called by managed code that is attempting to call a method on a proxy class. On entry
     * r0 holds the proxy method and r1 holds the receiver; r2 and r3 may contain arguments. The
     * frame size of the invoked proxy method agrees with a ref and args callee save frame.
     */
     .extern artQuickProxyInvokeHandler
ENTRY art_quick_proxy_invoke_handler
    SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
    str     r0, [sp, #0]           @ place proxy method at bottom of frame
    mov     r2, r9                 @ pass Thread::Current
    mov     r3, sp                 @ pass SP
    blx     artQuickProxyInvokeHandler  @ (Method* proxy method, receiver, Thread*, SP)
    ldr     r2, [r9, #THREAD_EXCEPTION_OFFSET]  @ load Thread::Current()->exception_
    add     sp, #16                @ skip r1-r3, 4 bytes padding.
    .cfi_adjust_cfa_offset -16
    cbnz    r2, 1f                 @ success if no exception is pending
    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
    bx      lr                     @ return on success
1:
    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
    DELIVER_PENDING_EXCEPTION
END art_quick_proxy_invoke_handler

是否正确保存/恢复堆栈帧?

崩溃回溯:

*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
Build fingerprint: 'google/hammerhead/hammerhead:5.1.1/LMY48I/2074855:user/release-keys'
Revision: '11'
ABI: 'arm'
pid: 16711, tid: 16727, name: Binder_1  >>> joker.li.dexposeltest <<<
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0xd101755d
    r0 b487a600  r1 71db5d14  r2 71db5d14  r3 711e23a8
    r4 b3749ba8  r5 d101755c  r6 b47faa70  r7 001c1448
    r8 b3749a00  r9 c52d968f  sl b47f83e8  fp b4623ad1
    ip fffffaa8  sp b37499b8  lr 0000fff8  pc b4732696  cpsr a0070030
    d0  0000000000000000  d1  0000000000000000
    d2  0000000000000000  d3  0000000000000000
    d4  b4a23400b4a24800  d5  b4a25800b4a24c00
    d6  b4a27400aec3b400  d7  b4a2a800b4a28800
    d8  0000000000001a50  d9  0000000000000000
    d10 0000000000000000  d11 0000000000000000
    d12 0000000000000000  d13 0000000000000000
    d14 0000000000000000  d15 0000000000000000
    d16 be9b62b000000000  d17 0000000000004000
    d18 0000000000004000  d19 0000000000000000
    d20 00000000c8baf094  d21 00000000003d3dcb
    d22 70f7634070f76340  d23 0000000004352858
    d24 0000000000014d1e  d25 000000000000039d
    d26 00000000000150bb  d27 00000000000d0e49
    d28 00000000044236a1  d29 0000000000004000
    d30 0000000000000001  d31 0000000000000000
    scr 80000011

backtrace:
    #00 pc 0023d696  /system/lib/libart.so (art::ReferenceMapVisitor<art::RootCallbackVisitor>::VisitQuickFrame()+333)
    #01 pc 0023dcb9  /system/lib/libart.so (art::ReferenceMapVisitor<art::RootCallbackVisitor>::VisitFrame()+224)
    #02 pc 00231959  /system/lib/libart.so (art::StackVisitor::WalkStack(bool)+276)
    #03 pc 002336b3  /system/lib/libart.so (art::Thread::VisitRoots(void (*)(art::mirror::Object**, void*, art::RootInfo const&), void*)+994)
    #04 pc 0012db67  /system/lib/libart.so (art::gc::collector::CheckpointMarkThreadRoots::Run(art::Thread*)+126)
    #05 pc 00240455  /system/lib/libart.so (art::ThreadList::RunCheckpoint(art::Closure*)+296)
    #06 pc 0012c7b1  /system/lib/libart.so (art::gc::collector::MarkSweep::MarkRootsCheckpoint(art::Thread*, bool)+96)
    #07 pc 0013021d  /system/lib/libart.so (art::gc::collector::MarkSweep::PreCleanCards()+172)
    #08 pc 00130393  /system/lib/libart.so (art::gc::collector::MarkSweep::MarkingPhase()+126)
    #09 pc 00130479  /system/lib/libart.so (art::gc::collector::MarkSweep::RunPhases()+176)
    #10 pc 00127067  /system/lib/libart.so (art::gc::collector::GarbageCollector::Run(art::gc::GcCause, bool)+246)
    #11 pc 001460af  /system/lib/libart.so (art::gc::Heap::CollectGarbageInternal(art::gc::collector::GcType, art::gc::GcCause, bool)+1406)
    #12 pc 00201357  /system/lib/libart.so (art::VMDebug_countInstancesOfClass(_JNIEnv*, _jclass*, _jclass*, unsigned char)+294)
    #13 pc 0001a3ed  /data/dalvik-cache/arm/system@framework@boot.oat

1 个答案:

答案 0 :(得分:0)

1,Art hook打破了艺术的堆栈布局:

class ArtMethod{

  ...

  // Total size in bytes of the frame

  size_t frame_size_in_bytes_;

  ...

}

“frame_size_in_bytes是与Quick帧对应的帧的一部分。也就是说,它是从ArtMethod *存储到下一个Quick帧的帧的大小。在内部,JNI帧在该地址注册,并且框架尺寸用于堆叠行走。“ --- https://code.google.com/p/android/issues/detail?id=79204

因此,运行时在堆栈中获取错误的ArtMethod指针。

2,StackVisitor :: WalkStack()检查编译的代码是否在dex中具有相应的操作码。

Art hook应修复这些或避免调用WalkStack()。