[Tizen] Implement ASan wrapper for Linux ARM32
[platform/upstream/dotnet/runtime.git] / src / coreclr / vm / tizenasanenv.cpp
1 #include <string.h>
2 #include "common.h"
3 #include "tizenasanenv.h"
4
5
6 template <typename Type, int STACK_SIZE>
7 class StaticStack {
8     // We don't create constructor because
9     // this class is used in a zeroed memory area
10 public:
11     void push(Type addr)
12     {
13         _ASSERTE(m_pos < STACK_SIZE);
14
15         m_data[m_pos++] = addr;
16     }
17
18     void pop()
19     {
20         _ASSERTE(m_pos > 0);
21         --m_pos;
22     }
23
24     Type top()
25     {
26         _ASSERTE(m_pos > 0);
27
28         return m_data[m_pos - 1];
29     }
30
31     bool empty()
32     {
33         return m_pos == 0;
34     }
35
36 private:
37     int m_pos;
38     Type m_data[STACK_SIZE];
39 };
40
41 #include <pshpack1.h>
42 struct AuxiliaryCalls {
43     LPVOID target;
44     void (*pushAddr)(LPVOID addr);
45     LPVOID (*popAddr)();
46 };
47
48 struct ReturnInfo {
49     LPVOID addr;
50     bool isSanitized;
51 };
52
53 extern "C" void __sanitizer_disable_interceptors();
54 extern "C" void __sanitizer_enable_interceptors();
55 extern "C" bool __sanitizer_interceptors_are_enabled();
56
57 extern LPVOID tizenASanWrapper;
58 extern UINT32 tizenASanWrapperSize;
59 extern UINT32 tizenASanWrapperEntryOffset;
60
61 // The maximum nesting of transitions between managed and unmanaged code that we support.
62 // This number is estimated from the common sense. We think this is enough to check any
63 // sane code (if it is not recursive) and it won't bloat TLS.  We do not use dynamic
64 // allocation because it complicates the process of memory management in TLS variables.
65 // It is used only for firmware with ASan and will not affect the release version.
66 #define MAX_STACK_DEPTH 128
67 static __thread StaticStack<ReturnInfo, MAX_STACK_DEPTH> s_retInfoStack;
68
69
70 static void DoEnable()
71 {
72     _ASSERTE(__sanitizer_interceptors_are_enabled() == false);
73     __sanitizer_enable_interceptors();
74 }
75
76 static void DoDisable()
77 {
78     _ASSERTE(__sanitizer_interceptors_are_enabled() == true);
79     __sanitizer_disable_interceptors();
80 }
81
82 static void PushAndEnableASan(LPVOID addr)
83 {
84     _ASSERTE(__sanitizer_interceptors_are_enabled() == false);
85
86     ReturnInfo retInfo = {
87         .addr = addr,
88         .isSanitized = false,
89     };
90
91     s_retInfoStack.push(retInfo);
92     DoEnable();
93 }
94
95 static LPVOID PopAndDisableASan()
96 {
97     _ASSERTE(__sanitizer_interceptors_are_enabled() == true);
98
99     ReturnInfo retInfo = s_retInfoStack.top();
100     s_retInfoStack.pop();
101
102     _ASSERTE(retInfo.isSanitized == false);
103     DoDisable();
104
105     return retInfo.addr;
106 }
107
108 static void PushAndMayBeDisableASan(LPVOID addr)
109 {
110     ReturnInfo retInfo = {
111         .addr = addr,
112         .isSanitized = __sanitizer_interceptors_are_enabled(),
113     };
114
115     if (retInfo.isSanitized)
116         DoDisable();
117
118     s_retInfoStack.push(retInfo);
119 }
120
121 static LPVOID PopAndMayBeEnableASan()
122 {
123     _ASSERTE(__sanitizer_interceptors_are_enabled() == false);
124
125     ReturnInfo retInfo = s_retInfoStack.top();
126     s_retInfoStack.pop();
127
128     if (retInfo.isSanitized)
129         DoEnable();
130
131     return retInfo.addr;
132 }
133
134 static LPVOID CreateWrapper(LPVOID target, void (*pushAddr)(LPVOID addr), LPVOID (*popAddr)())
135 {
136     _ASSERTE(tizenASanWrapperEntryOffset == sizeof(AuxiliaryCalls));
137
138     LPVOID wrapperSpace = (LPVOID)SystemDomain::GetGlobalLoaderAllocator()->GetExecutableHeap()->AllocMem(S_SIZE_T(tizenASanWrapperSize));
139
140     AuxiliaryCalls calls = {
141         .target = target,
142         .pushAddr = pushAddr,
143         .popAddr = popAddr,
144     };
145
146     // copy auxiliary calls
147     memcpy(wrapperSpace, &calls, sizeof(calls));
148
149     LPVOID entryPointer = (LPVOID)((UINT_PTR)wrapperSpace + tizenASanWrapperEntryOffset);
150     LPVOID wrapperEntryPointer = (LPVOID)((UINT_PTR)&tizenASanWrapper + tizenASanWrapperEntryOffset);
151     UINT32 wrapperCodeSize = tizenASanWrapperSize - tizenASanWrapperEntryOffset;
152
153     // copy executable code wrapper
154     memcpy(entryPointer, wrapperEntryPointer, wrapperCodeSize);
155
156     FlushInstructionCache(GetCurrentProcess(), wrapperSpace, tizenASanWrapperSize);
157
158     return entryPointer;
159 }
160
161
162 namespace TizenASanEnv {
163
164 LPVOID CreateWrapperSanitizedEntryPoint(LPVOID target)
165 {
166     return CreateWrapper(target, PushAndEnableASan, PopAndDisableASan);
167 }
168
169 LPVOID CreateWrapperILCode(LPVOID target)
170 {
171     return CreateWrapper(target, PushAndMayBeDisableASan, PopAndMayBeEnableASan);
172 }
173
174 } // namespace TizenASanEnv