From 03a5f45c5c680c2e3505847806e18f4f877d3be2 Mon Sep 17 00:00:00 2001 From: Vyacheslav Cherkashin Date: Mon, 22 Jul 2019 13:40:47 +0300 Subject: [PATCH] [Tizen] Implement ASan wrapper for Linux ARM32 This commit implements wrappers that allow interception transitions from managed to external unmanaged code (jit -> native) and back (native -> jit). This allows enable/disable ASan during transitions. Due to this, we sanitize only external code, which allows us to achieve acceptable performance. Change-Id: I53ecdc14d28f7210cd9e7f5bd4db0c8ef5ed81fc Signed-off-by: Vyacheslav Cherkashin --- src/vm/CMakeLists.txt | 11 ++++ src/vm/arm/stubs.cpp | 10 ++++ src/vm/arm/tizenasanenv.S | 61 +++++++++++++++++++++ src/vm/dllimport.cpp | 12 +++++ src/vm/tizenasanenv.cpp | 134 ++++++++++++++++++++++++++++++++++++++++++++++ src/vm/tizenasanenv.h | 15 ++++++ 6 files changed, 243 insertions(+) create mode 100644 src/vm/arm/tizenasanenv.S create mode 100644 src/vm/tizenasanenv.cpp create mode 100644 src/vm/tizenasanenv.h diff --git a/src/vm/CMakeLists.txt b/src/vm/CMakeLists.txt index 62acecf..e391e1d 100644 --- a/src/vm/CMakeLists.txt +++ b/src/vm/CMakeLists.txt @@ -736,6 +736,17 @@ else(WIN32) ${ARCH_SOURCES_DIR}/patchedcode.S ${ARCH_SOURCES_DIR}/pinvokestubs.S ) + if (TIZEN_ASAN_ENVIRONMENT) + list(APPEND VM_SOURCES_WKS + tizenasanenv.cpp + ) + list(APPEND VM_HEADERS_WKS + tizenasanenv.h + ) + list(APPEND VM_SOURCES_WKS_ARCH_ASM + ${ARCH_SOURCES_DIR}/tizenasanenv.S + ) + endif() elseif(CLR_CMAKE_TARGET_ARCH_ARM64) set(VM_SOURCES_WKS_ARCH_ASM ${ARCH_SOURCES_DIR}/asmhelpers.S diff --git a/src/vm/arm/stubs.cpp b/src/vm/arm/stubs.cpp index 7e7435c..b86732c 100644 --- a/src/vm/arm/stubs.cpp +++ b/src/vm/arm/stubs.cpp @@ -26,6 +26,10 @@ #include "ecall.h" #include "threadsuspend.h" +#if defined(TIZEN_ASAN_ENVIRONMENT) && !defined(CROSS_COMPILE) && !defined(DACCESS_COMPILE) +#include +#endif + // target write barriers EXTERN_C void JIT_WriteBarrier(Object **dst, Object *ref); EXTERN_C void JIT_WriteBarrier_End(); @@ -2477,6 +2481,12 @@ class UMEntryThunk * UMEntryThunk::Decode(void *pCallback) void UMEntryThunkCode::Encode(BYTE* pTargetCode, void* pvSecretParam) { +#if defined(TIZEN_ASAN_ENVIRONMENT) && !defined(CROSS_COMPILE) && !defined(DACCESS_COMPILE) + pTargetCode = (BYTE *)TizenASanEnv::CreateWrapper((LPVOID)pTargetCode, + TizenASanEnv::PushAndDisableASan, + TizenASanEnv::PopAndEnableASan); +#endif + // ldr r12, [pc + 8] m_code[0] = 0xf8df; m_code[1] = 0xc008; diff --git a/src/vm/arm/tizenasanenv.S b/src/vm/arm/tizenasanenv.S new file mode 100644 index 0000000..6a8adb9 --- /dev/null +++ b/src/vm/arm/tizenasanenv.S @@ -0,0 +1,61 @@ +.macro PUSH_REGS + push {r0-r12} + vpush.64 {d0-d7} +.endm + +.macro POP_REGS + vpop.64 {d0-d7} + pop {r0-r12} +.endm + + +// Export symbols +.global tizenASanWrapper +.global tizenASanWrapperSize +.global tizenASanWrapperEntryOffset + +.text +.arm + +tizenASanWrapper: +// !!! ATTENTION !!! +// Don't move this labels (target, pushAddr, popAddr) +// because they mapped to AuxiliaryCalls struct from src/vm/tizenasanenv.cpp +target: .word 0xdeadc0de +pushAddr: .word 0xdeadc0de @ void pushAddr(LPVOID addr) +popAddr: .word 0xdeadc0de @ LPVOID popAddr() + +entryPointer: + // Save context + PUSH_REGS + + // Save the return address and call 'pre handler' + mov r0, lr + ldr r1, pushAddr + blx r1 + + // Restore context + POP_REGS + + // Change the return address + adr lr, postLabel + + // Call original function + ldr pc, target +postLabel: + // Save context + PUSH_REGS + + // Get the return address and call 'post handler' + ldr r0, popAddr + blx r0 + + // Restore the return address + mov lr, r0 + + // Restore context + POP_REGS + bx lr + +tizenASanWrapperSize: .word . - tizenASanWrapper +tizenASanWrapperEntryOffset: .word entryPointer - tizenASanWrapper diff --git a/src/vm/dllimport.cpp b/src/vm/dllimport.cpp index 18e77d8..ce6e6cc 100644 --- a/src/vm/dllimport.cpp +++ b/src/vm/dllimport.cpp @@ -47,6 +47,10 @@ #include "compile.h" #endif // FEATURE_PREJIT +#ifdef TIZEN_ASAN_ENVIRONMENT +#include +#endif // TIZEN_ASAN_ENVIRONMENT + #include "eventtrace.h" #include "clr/fs/path.h" using namespace clr::fs; @@ -6903,6 +6907,14 @@ VOID NDirect::NDirectLink(NDirectMethodDesc *pMD) LPVOID pvTarget = NDirectGetEntryPoint(pMD, hmod); if (pvTarget) { +#ifdef TIZEN_ASAN_ENVIRONMENT + if (PAL_IsSanitizedModule(hmod)) + { + pvTarget = TizenASanEnv::CreateWrapper(pvTarget, + TizenASanEnv::PushAndEnableASan, + TizenASanEnv::PopAndDisableASan); + } +#endif // TIZEN_ASAN_ENVIRONMENT #ifdef MDA_SUPPORTED MdaInvalidOverlappedToPinvoke *pOverlapCheck = MDA_GET_ASSISTANT(InvalidOverlappedToPinvoke); diff --git a/src/vm/tizenasanenv.cpp b/src/vm/tizenasanenv.cpp new file mode 100644 index 0000000..067aa3d --- /dev/null +++ b/src/vm/tizenasanenv.cpp @@ -0,0 +1,134 @@ +#include +#include "common.h" +#include "tizenasanenv.h" + + +template +class StaticStack { + // We don't create constructor because + // this class is used in a zeroed memory area +public: + void push(Type addr) + { + _ASSERTE(m_pos < STACK_SIZE); + + m_data[m_pos++] = addr; + } + + void pop() + { + _ASSERTE(m_pos > 0); + --m_pos; + } + + Type top() + { + _ASSERTE(m_pos > 0); + + return m_data[m_pos - 1]; + } + + bool empty() + { + return m_pos == 0; + } + +private: + int m_pos; + Type m_data[STACK_SIZE]; +}; + +#include +struct AuxiliaryCalls { + LPVOID target; + void (*pushAddr)(LPVOID addr); + LPVOID (*popAddr)(); +}; + +extern "C" void __sanitizer_disable_interceptors(); +extern "C" void __sanitizer_enable_interceptors(); + +extern LPVOID tizenASanWrapper; +extern UINT32 tizenASanWrapperSize; +extern UINT32 tizenASanWrapperEntryOffset; + +static __thread StaticStack s_retaddrStack; +static __thread int s_enableCounter; + + +static void TryEnable() +{ + if (s_enableCounter == 0) + __sanitizer_enable_interceptors(); + ++s_enableCounter; +} + +static void TryDisable() +{ + if (s_enableCounter == 1) + __sanitizer_disable_interceptors(); + --s_enableCounter; +} + + +namespace TizenASanEnv { + +void PushAndDisableASan(LPVOID addr) +{ + TryDisable(); + s_retaddrStack.push(addr); +} + +LPVOID PopAndEnableASan() +{ + LPVOID addr = s_retaddrStack.top(); + s_retaddrStack.pop(); + + TryEnable(); + + return addr; +} + +void PushAndEnableASan(LPVOID addr) +{ + s_retaddrStack.push(addr); + TryEnable(); +} + +LPVOID PopAndDisableASan() +{ + TryDisable(); + + LPVOID addr = s_retaddrStack.top(); + s_retaddrStack.pop(); + + return addr; +} + +LPVOID CreateWrapper(LPVOID target, void (*pushAddr)(LPVOID addr), LPVOID (*popAddr)()) +{ + _ASSERTE(tizenASanWrapperEntryOffset == sizeof(AuxiliaryCalls)); + + LPVOID wrapperSpace = (LPVOID)SystemDomain::GetGlobalLoaderAllocator()->GetExecutableHeap()->AllocMem(S_SIZE_T(tizenASanWrapperSize)); + + AuxiliaryCalls calls = { + .target = target, + .pushAddr = pushAddr, + .popAddr = popAddr, + }; + + // copy auxiliary calls + memcpy(wrapperSpace, &calls, sizeof(calls)); + + LPVOID entryPointer = (LPVOID)((UINT_PTR)wrapperSpace + tizenASanWrapperEntryOffset); + LPVOID wrapperEntryPointer = (LPVOID)((UINT_PTR)&tizenASanWrapper + tizenASanWrapperEntryOffset); + UINT32 wrapperCodeSize = tizenASanWrapperSize - tizenASanWrapperEntryOffset; + + // copy executable code wrapper + memcpy(entryPointer, wrapperEntryPointer, wrapperCodeSize); + + FlushInstructionCache(GetCurrentProcess(), wrapperSpace, tizenASanWrapperSize); + + return entryPointer; +} +} // namespace TizenASanEnv diff --git a/src/vm/tizenasanenv.h b/src/vm/tizenasanenv.h new file mode 100644 index 0000000..7200936 --- /dev/null +++ b/src/vm/tizenasanenv.h @@ -0,0 +1,15 @@ +#ifndef TIZENASANENV_H_ +#define TIZENASANENV_H_ + +namespace TizenASanEnv { + +void PushAndDisableASan(LPVOID addr); +LPVOID PopAndEnableASan(); +void PushAndEnableASan(LPVOID addr); +LPVOID PopAndDisableASan(); + +LPVOID CreateWrapper(LPVOID target, void (*pushAddr)(LPVOID addr), LPVOID (*popAddr)()); + +} // namespace TizenASanEnv + +#endif // TIZENASANENV_H_ -- 2.7.4