1 : // Copyright 2012 Google Inc.
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 : #include <windows.h>
15 :
16 : #include "base/logging.h"
17 : #include "base/memory/scoped_ptr.h"
18 : #include "syzygy/agent/asan/asan_heap.h"
19 : #include "syzygy/agent/asan/asan_shadow.h"
20 :
21 : extern "C" {
22 :
23 : using agent::asan::HeapProxy;
24 :
25 E : static HANDLE process_heap = GetProcessHeap();
26 :
27 : HANDLE WINAPI asan_HeapCreate(DWORD options,
28 : SIZE_T initial_size,
29 E : SIZE_T maximum_size) {
30 E : scoped_ptr<HeapProxy> proxy(new HeapProxy());
31 E : if (!proxy->Create(options, initial_size, maximum_size))
32 i : proxy.reset();
33 :
34 E : return HeapProxy::ToHandle(proxy.release());
35 E : }
36 :
37 E : BOOL WINAPI asan_HeapDestroy(HANDLE heap) {
38 E : if (heap == process_heap)
39 i : return ::HeapDestroy(heap);
40 :
41 E : HeapProxy* proxy = HeapProxy::FromHandle(heap);
42 E : if (!proxy)
43 i : return FALSE;
44 :
45 E : if (proxy->Destroy()) {
46 E : delete proxy;
47 E : return TRUE;
48 : }
49 :
50 i : return FALSE;
51 E : }
52 :
53 : LPVOID WINAPI asan_HeapAlloc(HANDLE heap,
54 : DWORD flags,
55 E : SIZE_T bytes) {
56 E : if (heap == process_heap)
57 i : return ::HeapAlloc(heap, flags, bytes);
58 :
59 E : HeapProxy* proxy = HeapProxy::FromHandle(heap);
60 E : if (!proxy)
61 i : return NULL;
62 :
63 E : return proxy->Alloc(flags, bytes);
64 E : }
65 :
66 : LPVOID WINAPI asan_HeapReAlloc(HANDLE heap,
67 : DWORD flags,
68 : LPVOID mem,
69 E : SIZE_T bytes) {
70 E : if (heap == process_heap)
71 i : return ::HeapReAlloc(heap, flags, mem, bytes);
72 :
73 E : HeapProxy* proxy = HeapProxy::FromHandle(heap);
74 E : if (!proxy)
75 i : return NULL;
76 :
77 E : return proxy->ReAlloc(flags, mem, bytes);
78 E : }
79 :
80 : BOOL WINAPI asan_HeapFree(HANDLE heap,
81 : DWORD flags,
82 E : LPVOID mem) {
83 E : if (heap == process_heap)
84 i : return ::HeapFree(heap, flags, mem);
85 :
86 E : HeapProxy* proxy = HeapProxy::FromHandle(heap);
87 E : if (!proxy)
88 i : return FALSE;
89 :
90 E : return proxy->Free(flags, mem);
91 E : }
92 :
93 : SIZE_T WINAPI asan_HeapSize(HANDLE heap,
94 : DWORD flags,
95 E : LPCVOID mem) {
96 E : if (heap == process_heap)
97 i : return ::HeapSize(heap, flags, mem);
98 :
99 E : HeapProxy* proxy = HeapProxy::FromHandle(heap);
100 E : if (!proxy)
101 i : return -1;
102 :
103 E : return proxy->Size(flags, mem);
104 E : }
105 :
106 : BOOL WINAPI asan_HeapValidate(HANDLE heap,
107 : DWORD flags,
108 E : LPCVOID mem) {
109 E : if (heap == process_heap)
110 i : return ::HeapValidate(heap, flags, mem);
111 :
112 E : HeapProxy* proxy = HeapProxy::FromHandle(heap);
113 E : if (!proxy)
114 i : return FALSE;
115 :
116 E : return proxy->Validate(flags, mem);
117 E : }
118 :
119 : SIZE_T WINAPI asan_HeapCompact(HANDLE heap,
120 E : DWORD flags) {
121 E : if (heap == process_heap)
122 i : return ::HeapCompact(heap, flags);
123 :
124 E : HeapProxy* proxy = HeapProxy::FromHandle(heap);
125 E : if (!proxy)
126 i : return 0;
127 :
128 E : return proxy->Compact(flags);
129 E : }
130 :
131 E : BOOL WINAPI asan_HeapLock(HANDLE heap) {
132 E : if (heap == process_heap)
133 i : return ::HeapLock(heap);
134 :
135 E : HeapProxy* proxy = HeapProxy::FromHandle(heap);
136 E : if (!proxy)
137 i : return FALSE;
138 :
139 E : return proxy->Lock();
140 E : }
141 :
142 E : BOOL WINAPI asan_HeapUnlock(HANDLE heap) {
143 E : if (heap == process_heap)
144 i : return ::HeapUnlock(heap);
145 :
146 E : HeapProxy* proxy = HeapProxy::FromHandle(heap);
147 E : if (!proxy)
148 i : return FALSE;
149 :
150 E : return proxy->Unlock();
151 E : }
152 :
153 : BOOL WINAPI asan_HeapWalk(HANDLE heap,
154 E : LPPROCESS_HEAP_ENTRY entry) {
155 E : if (heap == process_heap)
156 i : return ::HeapWalk(heap, entry);
157 :
158 E : HeapProxy* proxy = HeapProxy::FromHandle(heap);
159 E : if (!proxy)
160 i : return FALSE;
161 :
162 E : return proxy->Walk(entry);
163 E : }
164 :
165 : BOOL WINAPI asan_HeapSetInformation(
166 : HANDLE heap, HEAP_INFORMATION_CLASS info_class,
167 E : PVOID info, SIZE_T info_length) {
168 E : if (heap == process_heap)
169 i : return ::HeapSetInformation(heap, info_class, info, info_length);
170 :
171 E : HeapProxy* proxy = HeapProxy::FromHandle(heap);
172 E : if (!proxy)
173 i : return FALSE;
174 :
175 E : return proxy->SetInformation(info_class, info, info_length);
176 E : }
177 :
178 : BOOL WINAPI asan_HeapQueryInformation(
179 : HANDLE heap, HEAP_INFORMATION_CLASS info_class,
180 E : PVOID info, SIZE_T info_length, PSIZE_T return_length) {
181 E : if (heap == process_heap) {
182 : return ::HeapQueryInformation(heap,
183 : info_class,
184 : info,
185 : info_length,
186 i : return_length);
187 : }
188 :
189 E : HeapProxy* proxy = HeapProxy::FromHandle(heap);
190 E : if (!proxy)
191 i : return FALSE;
192 :
193 : bool ret = proxy->QueryInformation(info_class,
194 : info,
195 : info_length,
196 E : return_length);
197 E : return ret == true;
198 E : }
199 :
200 : } // extern "C"
201 :
202 : namespace agent {
203 : namespace asan {
204 :
205 E : void __cdecl CheckAccessSlow(const uint8* location) {
206 E : if (!Shadow::IsAccessible(location)) {
207 i : LOG(FATAL) << "Invalid write access to location "
208 : << reinterpret_cast<const void*>(location);
209 : }
210 E : }
211 :
212 : } // namespace asan
213 : } // namespace agent
214 :
215 : // On entry, eax is the byte to check, e.g. the last byte accessed.
216 : // On stack above the return address we have the saved values of eax.
217 E : extern "C" __declspec(naked) void asan_check_access() {
218 : __asm {
219 : // Save the flags and save eax for the slow case.
220 E : pushfd
221 E : push eax
222 :
223 : // Check for zero shadow - fast case.
224 E : shr eax, 3
225 E : mov al, byte ptr[eax + agent::asan::Shadow::shadow_]
226 E : test al, 0xFF
227 :
228 : // Uh-oh - non-zero shadow byte means we go to the slow case.
229 E : jne non_zero_shadow
230 :
231 : // Drop the slow path's copy of the address.
232 E : add esp, 4
233 : // Restore flags and original eax.
234 E : popfd
235 E : mov eax, DWORD PTR[esp + 4]
236 E : ret 4
237 :
238 : non_zero_shadow:
239 : // Save ecx/edx, they're caller-save.
240 E : push edx
241 E : push ecx
242 : // Push the address to check.
243 E : push dword ptr[esp + 8]
244 E : call agent::asan::CheckAccessSlow
245 E : add esp, 4
246 :
247 : // Restore everything.
248 E : pop ecx
249 E : pop edx
250 E : add esp, 4
251 E : popfd
252 E : mov eax, DWORD PTR[esp + 4]
253 E : ret 4
254 : }
255 : }
|