summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorVyacheslav Cherkashin <v.cherkashin@samsung.com>2019-07-22 13:40:47 +0300
committerGleb Balykov <g.balykov@samsung.com>2020-03-25 15:29:41 +0300
commitdda4d81c0e07b7462a849e12a819ad3e0084a42d (patch)
treeee682237ad30768977cff9e14c11ebf65693563b /src
parente191c349605f44747b01f00331ca34eca923b953 (diff)
downloadcoreclr-dda4d81c0e07b7462a849e12a819ad3e0084a42d.tar.gz
coreclr-dda4d81c0e07b7462a849e12a819ad3e0084a42d.tar.bz2
coreclr-dda4d81c0e07b7462a849e12a819ad3e0084a42d.zip
[Tizen] Implement ASan wrapper for Linux ARM32
This commit implements wrappers that allow interception transitions from managed to external unmanaged code (CIL -> native) and back (native -> CIL). 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 <v.cherkashin@samsung.com>
Diffstat (limited to 'src')
-rw-r--r--src/vm/CMakeLists.txt13
-rw-r--r--src/vm/arm/stubs.cpp8
-rw-r--r--src/vm/arm/tizenasanenv.S61
-rw-r--r--src/vm/dllimport.cpp11
-rw-r--r--src/vm/tizenasanenv.cpp174
-rw-r--r--src/vm/tizenasanenv.h11
6 files changed, 278 insertions, 0 deletions
diff --git a/src/vm/CMakeLists.txt b/src/vm/CMakeLists.txt
index 3a556aff2f..3f37720742 100644
--- a/src/vm/CMakeLists.txt
+++ b/src/vm/CMakeLists.txt
@@ -714,6 +714,14 @@ elseif(CLR_CMAKE_TARGET_ARCH_ARM64)
endif()
else(WIN32)
+ if (TIZEN_ASAN_ENVIRONMENT)
+ list(APPEND VM_SOURCES_WKS
+ tizenasanenv.cpp
+ )
+ list(APPEND VM_HEADERS_WKS
+ tizenasanenv.h
+ )
+ endif()
if(CLR_CMAKE_TARGET_ARCH_AMD64)
set(VM_SOURCES_WKS_ARCH_ASM
@@ -750,6 +758,11 @@ else(WIN32)
${ARCH_SOURCES_DIR}/patchedcode.S
${ARCH_SOURCES_DIR}/pinvokestubs.S
)
+ if (TIZEN_ASAN_ENVIRONMENT)
+ 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 6da58b5326..078a16cb8f 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 <tizenasanenv.h>
+#endif
+
// target write barriers
EXTERN_C void JIT_WriteBarrier(Object **dst, Object *ref);
EXTERN_C void JIT_WriteBarrier_End();
@@ -2490,6 +2494,10 @@ 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::CreateWrapperILCode((LPVOID)pTargetCode);
+#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 0000000000..6a8adb94fe
--- /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 685ea03309..d3c4874af5 100644
--- a/src/vm/dllimport.cpp
+++ b/src/vm/dllimport.cpp
@@ -46,6 +46,10 @@
#include "compile.h"
#endif // FEATURE_PREJIT
+#ifdef TIZEN_ASAN_ENVIRONMENT
+#include <tizenasanenv.h>
+#endif // TIZEN_ASAN_ENVIRONMENT
+
#include "eventtrace.h"
#include "clr/fs/path.h"
using namespace clr::fs;
@@ -6696,6 +6700,13 @@ VOID NDirect::NDirectLink(NDirectMethodDesc *pMD)
LPVOID pvTarget = NDirectGetEntryPoint(pMD, hmod);
if (pvTarget)
{
+#ifdef TIZEN_ASAN_ENVIRONMENT
+ if (PAL_IsSanitizedLibraryDirect(hmod))
+ {
+ pvTarget = TizenASanEnv::CreateWrapperSanitizedEntryPoint(pvTarget);
+ }
+#endif // TIZEN_ASAN_ENVIRONMENT
+
pMD->SetNDirectTarget(pvTarget);
fSuccess = TRUE;
}
diff --git a/src/vm/tizenasanenv.cpp b/src/vm/tizenasanenv.cpp
new file mode 100644
index 0000000000..8ffeefad8b
--- /dev/null
+++ b/src/vm/tizenasanenv.cpp
@@ -0,0 +1,174 @@
+#include <string.h>
+#include "common.h"
+#include "tizenasanenv.h"
+
+
+template <typename Type, int STACK_SIZE>
+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 <pshpack1.h>
+struct AuxiliaryCalls {
+ LPVOID target;
+ void (*pushAddr)(LPVOID addr);
+ LPVOID (*popAddr)();
+};
+
+struct ReturnInfo {
+ LPVOID addr;
+ bool isSanitized;
+};
+
+extern "C" void __sanitizer_disable_interceptors();
+extern "C" void __sanitizer_enable_interceptors();
+extern "C" bool __sanitizer_interceptors_are_enabled();
+
+extern LPVOID tizenASanWrapper;
+extern UINT32 tizenASanWrapperSize;
+extern UINT32 tizenASanWrapperEntryOffset;
+
+// The maximum nesting of transitions between managed and unmanaged code that we support.
+// This number is estimated from the common sense. We think this is enough to check any
+// sane code (if it is not recursive) and it won't bloat TLS. We do not use dynamic
+// allocation because it complicates the process of memory management in TLS variables.
+// It is used only for firmware with ASan and will not affect the release version.
+#define MAX_STACK_DEPTH 128
+static __thread StaticStack<ReturnInfo, MAX_STACK_DEPTH> s_retInfoStack;
+
+
+static void DoEnable()
+{
+ _ASSERTE(__sanitizer_interceptors_are_enabled() == false);
+ __sanitizer_enable_interceptors();
+}
+
+static void DoDisable()
+{
+ _ASSERTE(__sanitizer_interceptors_are_enabled() == true);
+ __sanitizer_disable_interceptors();
+}
+
+static void PushAndEnableASan(LPVOID addr)
+{
+ _ASSERTE(__sanitizer_interceptors_are_enabled() == false);
+
+ ReturnInfo retInfo = {
+ .addr = addr,
+ .isSanitized = false,
+ };
+
+ s_retInfoStack.push(retInfo);
+ DoEnable();
+}
+
+static LPVOID PopAndDisableASan()
+{
+ _ASSERTE(__sanitizer_interceptors_are_enabled() == true);
+
+ ReturnInfo retInfo = s_retInfoStack.top();
+ s_retInfoStack.pop();
+
+ _ASSERTE(retInfo.isSanitized == false);
+ DoDisable();
+
+ return retInfo.addr;
+}
+
+static void PushAndMayBeDisableASan(LPVOID addr)
+{
+ ReturnInfo retInfo = {
+ .addr = addr,
+ .isSanitized = __sanitizer_interceptors_are_enabled(),
+ };
+
+ if (retInfo.isSanitized)
+ DoDisable();
+
+ s_retInfoStack.push(retInfo);
+}
+
+static LPVOID PopAndMayBeEnableASan()
+{
+ _ASSERTE(__sanitizer_interceptors_are_enabled() == false);
+
+ ReturnInfo retInfo = s_retInfoStack.top();
+ s_retInfoStack.pop();
+
+ if (retInfo.isSanitized)
+ DoEnable();
+
+ return retInfo.addr;
+}
+
+static 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 {
+
+LPVOID CreateWrapperSanitizedEntryPoint(LPVOID target)
+{
+ return CreateWrapper(target, PushAndEnableASan, PopAndDisableASan);
+}
+
+LPVOID CreateWrapperILCode(LPVOID target)
+{
+ return CreateWrapper(target, PushAndMayBeDisableASan, PopAndMayBeEnableASan);
+}
+
+} // namespace TizenASanEnv
diff --git a/src/vm/tizenasanenv.h b/src/vm/tizenasanenv.h
new file mode 100644
index 0000000000..df74d91a3b
--- /dev/null
+++ b/src/vm/tizenasanenv.h
@@ -0,0 +1,11 @@
+#ifndef TIZENASANENV_H_
+#define TIZENASANENV_H_
+
+namespace TizenASanEnv {
+
+LPVOID CreateWrapperSanitizedEntryPoint(LPVOID target);
+LPVOID CreateWrapperILCode(LPVOID target);
+
+} // namespace TizenASanEnv
+
+#endif // TIZENASANENV_H_