1 : // Copyright 2012 Google Inc. All Rights Reserved.
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 :
15 : #include "syzygy/agent/asan/asan_rtl_impl.h"
16 :
17 : #include "base/bind.h"
18 : #include "base/logging.h"
19 : #include "base/debug/alias.h"
20 : #include "syzygy/agent/asan/asan_heap.h"
21 : #include "syzygy/agent/asan/asan_runtime.h"
22 : #include "syzygy/agent/asan/asan_shadow.h"
23 :
24 : namespace {
25 :
26 : using agent::asan::AsanErrorInfo;
27 : using agent::asan::AsanRuntime;
28 : using agent::asan::HeapProxy;
29 :
30 : HANDLE process_heap = NULL;
31 :
32 : // The asan runtime manager.
33 : AsanRuntime* asan_runtime = NULL;
34 :
35 : } // namespace
36 :
37 : namespace agent {
38 : namespace asan {
39 :
40 E : void SetUpRtl(AsanRuntime* runtime) {
41 E : DCHECK(runtime != NULL);
42 E : asan_runtime = runtime;
43 E : process_heap = GetProcessHeap();
44 E : }
45 :
46 E : void TearDownRtl() {
47 E : process_heap = NULL;
48 E : }
49 :
50 : } // namespace asan
51 : } // namespace agent
52 :
53 : extern "C" {
54 :
55 : HANDLE WINAPI asan_HeapCreate(DWORD options,
56 : SIZE_T initial_size,
57 E : SIZE_T maximum_size) {
58 E : DCHECK(asan_runtime != NULL);
59 : scoped_ptr<HeapProxy> proxy(new HeapProxy(asan_runtime->stack_cache(),
60 E : asan_runtime->logger()));
61 E : if (!proxy->Create(options, initial_size, maximum_size))
62 E : return NULL;
63 :
64 E : asan_runtime->AddHeap(proxy.get());
65 :
66 E : return HeapProxy::ToHandle(proxy.release());
67 E : }
68 :
69 E : BOOL WINAPI asan_HeapDestroy(HANDLE heap) {
70 E : DCHECK(process_heap != NULL);
71 E : if (heap == process_heap)
72 i : return ::HeapDestroy(heap);
73 :
74 E : HeapProxy* proxy = HeapProxy::FromHandle(heap);
75 E : if (!proxy)
76 i : return FALSE;
77 :
78 E : asan_runtime->RemoveHeap(proxy);
79 :
80 E : if (proxy->Destroy()) {
81 E : delete proxy;
82 E : return TRUE;
83 : }
84 :
85 i : return FALSE;
86 E : }
87 :
88 : LPVOID WINAPI asan_HeapAlloc(HANDLE heap,
89 : DWORD flags,
90 E : SIZE_T bytes) {
91 E : DCHECK(process_heap != NULL);
92 E : if (heap == process_heap)
93 i : return ::HeapAlloc(heap, flags, bytes);
94 :
95 E : HeapProxy* proxy = HeapProxy::FromHandle(heap);
96 E : if (!proxy)
97 i : return NULL;
98 :
99 E : return proxy->Alloc(flags, bytes);
100 E : }
101 :
102 : LPVOID WINAPI asan_HeapReAlloc(HANDLE heap,
103 : DWORD flags,
104 : LPVOID mem,
105 E : SIZE_T bytes) {
106 E : DCHECK(process_heap != NULL);
107 E : if (heap == process_heap)
108 i : return ::HeapReAlloc(heap, flags, mem, bytes);
109 :
110 E : HeapProxy* proxy = HeapProxy::FromHandle(heap);
111 E : if (!proxy)
112 i : return NULL;
113 :
114 E : return proxy->ReAlloc(flags, mem, bytes);
115 E : }
116 :
117 : BOOL WINAPI asan_HeapFree(HANDLE heap,
118 : DWORD flags,
119 E : LPVOID mem) {
120 E : DCHECK(process_heap != NULL);
121 E : if (heap == process_heap)
122 i : return ::HeapFree(heap, flags, mem);
123 :
124 E : HeapProxy* proxy = HeapProxy::FromHandle(heap);
125 E : if (!proxy)
126 i : return FALSE;
127 :
128 E : if (!proxy->Free(flags, mem)) {
129 : CONTEXT context;
130 E : ::RtlCaptureContext(&context);
131 E : AsanErrorInfo error_info = {};
132 E : error_info.error_type = HeapProxy::UNKNOWN_BAD_ACCESS;
133 E : asan_runtime->OnError(&context, &error_info);
134 E : return false;
135 : }
136 :
137 E : return true;
138 E : }
139 :
140 : SIZE_T WINAPI asan_HeapSize(HANDLE heap,
141 : DWORD flags,
142 E : LPCVOID mem) {
143 E : DCHECK(process_heap != NULL);
144 E : if (heap == process_heap)
145 i : return ::HeapSize(heap, flags, mem);
146 :
147 E : HeapProxy* proxy = HeapProxy::FromHandle(heap);
148 E : if (!proxy)
149 i : return -1;
150 :
151 E : return proxy->Size(flags, mem);
152 E : }
153 :
154 : BOOL WINAPI asan_HeapValidate(HANDLE heap,
155 : DWORD flags,
156 E : LPCVOID mem) {
157 E : DCHECK(process_heap != NULL);
158 E : if (heap == process_heap)
159 i : return ::HeapValidate(heap, flags, mem);
160 :
161 E : HeapProxy* proxy = HeapProxy::FromHandle(heap);
162 E : if (!proxy)
163 i : return FALSE;
164 :
165 E : return proxy->Validate(flags, mem);
166 E : }
167 :
168 : SIZE_T WINAPI asan_HeapCompact(HANDLE heap,
169 E : DWORD flags) {
170 E : DCHECK(process_heap != NULL);
171 E : if (heap == process_heap)
172 i : return ::HeapCompact(heap, flags);
173 :
174 E : HeapProxy* proxy = HeapProxy::FromHandle(heap);
175 E : if (!proxy)
176 i : return 0;
177 :
178 E : return proxy->Compact(flags);
179 E : }
180 :
181 E : BOOL WINAPI asan_HeapLock(HANDLE heap) {
182 E : DCHECK(process_heap != NULL);
183 E : if (heap == process_heap)
184 i : return ::HeapLock(heap);
185 :
186 E : HeapProxy* proxy = HeapProxy::FromHandle(heap);
187 E : if (!proxy)
188 i : return FALSE;
189 :
190 E : return proxy->Lock();
191 E : }
192 :
193 E : BOOL WINAPI asan_HeapUnlock(HANDLE heap) {
194 E : DCHECK(process_heap != NULL);
195 E : if (heap == process_heap)
196 i : return ::HeapUnlock(heap);
197 :
198 E : HeapProxy* proxy = HeapProxy::FromHandle(heap);
199 E : if (!proxy)
200 i : return FALSE;
201 :
202 E : return proxy->Unlock();
203 E : }
204 :
205 : BOOL WINAPI asan_HeapWalk(HANDLE heap,
206 E : LPPROCESS_HEAP_ENTRY entry) {
207 E : DCHECK(process_heap != NULL);
208 E : if (heap == process_heap)
209 i : return ::HeapWalk(heap, entry);
210 :
211 E : HeapProxy* proxy = HeapProxy::FromHandle(heap);
212 E : if (!proxy)
213 i : return FALSE;
214 :
215 E : return proxy->Walk(entry);
216 E : }
217 :
218 : BOOL WINAPI asan_HeapSetInformation(
219 : HANDLE heap, HEAP_INFORMATION_CLASS info_class,
220 E : PVOID info, SIZE_T info_length) {
221 E : DCHECK(process_heap != NULL);
222 E : if (heap == NULL || heap == process_heap)
223 E : return ::HeapSetInformation(heap, info_class, info, info_length);
224 :
225 E : HeapProxy* proxy = HeapProxy::FromHandle(heap);
226 E : if (!proxy)
227 i : return FALSE;
228 :
229 E : return proxy->SetInformation(info_class, info, info_length);
230 E : }
231 :
232 : BOOL WINAPI asan_HeapQueryInformation(
233 : HANDLE heap, HEAP_INFORMATION_CLASS info_class,
234 E : PVOID info, SIZE_T info_length, PSIZE_T return_length) {
235 E : DCHECK(process_heap != NULL);
236 E : if (heap == NULL || heap == process_heap) {
237 : return ::HeapQueryInformation(heap,
238 : info_class,
239 : info,
240 : info_length,
241 i : return_length);
242 : }
243 :
244 E : HeapProxy* proxy = HeapProxy::FromHandle(heap);
245 E : if (!proxy)
246 i : return FALSE;
247 :
248 : bool ret = proxy->QueryInformation(info_class,
249 : info,
250 : info_length,
251 E : return_length);
252 E : return ret == true;
253 E : }
254 :
255 E : void WINAPI asan_SetCallBack(AsanErrorCallBack callback) {
256 E : DCHECK(asan_runtime != NULL);
257 E : asan_runtime->SetErrorCallBack(base::Bind(callback));
258 E : }
259 :
260 : } // extern "C"
261 :
262 : namespace agent {
263 : namespace asan {
264 :
265 : // Contents of the registers before calling the ASAN memory check function.
266 : #pragma pack(push, 1)
267 : struct AsanContext {
268 : DWORD original_edi;
269 : DWORD original_esi;
270 : DWORD original_ebp;
271 : DWORD original_esp;
272 : DWORD original_ebx;
273 : DWORD original_edx;
274 : DWORD original_ecx;
275 : DWORD original_eax;
276 : DWORD original_eflags;
277 : DWORD original_eip;
278 : };
279 : #pragma pack(pop)
280 :
281 : // Report a bad access to the memory.
282 : // @param location The memory address of the access.
283 : // @param access_mode The mode of the access.
284 : // @param access_size The size of the access.
285 : // @param asan_context The context of the access.
286 : void ReportBadMemoryAccess(void* location,
287 : HeapProxy::AccessMode access_mode,
288 : size_t access_size,
289 E : struct AsanContext* asan_context) {
290 : // Capture the context and restore the value of the register as before calling
291 : // the asan hook.
292 :
293 : // Capture the current context.
294 E : CONTEXT context = {};
295 :
296 : // We need to call ::RtlCaptureContext if we want SegSS and SegCS to be
297 : // properly set.
298 E : ::RtlCaptureContext(&context);
299 E : context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
300 :
301 : // Restore the original value of the registers.
302 E : context.Eip = asan_context->original_eip;
303 E : context.Eax = asan_context->original_eax;
304 E : context.Ecx = asan_context->original_ecx;
305 E : context.Edx = asan_context->original_edx;
306 E : context.Ebx = asan_context->original_ebx;
307 E : context.Ebp = asan_context->original_ebp;
308 E : context.Esp = asan_context->original_esp;
309 E : context.Esi = asan_context->original_esi;
310 E : context.Edi = asan_context->original_edi;
311 E : context.EFlags = asan_context->original_eflags;
312 :
313 E : StackCapture stack;
314 E : stack.InitFromStack();
315 : // We need to compute a relative stack id so that for the same stack trace
316 : // we'll get the same value every time even if the modules are loaded at a
317 : // different base address.
318 E : stack.set_stack_id(stack.ComputeRelativeStackId());
319 :
320 : // Check if we can ignore this error.
321 E : if (asan_runtime->ShouldIgnoreError(stack.stack_id()))
322 i : return;
323 :
324 : // We keep a structure with all the useful information about this bad access
325 : // on the stack.
326 E : AsanErrorInfo bad_access_info = {};
327 E : bad_access_info.access_mode = access_mode;
328 E : bad_access_info.access_size = access_size;
329 E : bad_access_info.alloc_stack_size = 0U;
330 E : bad_access_info.alloc_tid = 0U;
331 E : bad_access_info.error_type = HeapProxy::UNKNOWN_BAD_ACCESS;
332 E : bad_access_info.free_stack_size = 0U;
333 E : bad_access_info.free_tid = 0U;
334 E : bad_access_info.microseconds_since_free = 0U;
335 :
336 : // Make sure this structure is not optimized out.
337 E : base::debug::Alias(&bad_access_info);
338 :
339 : asan_runtime->ReportAsanErrorDetails(location,
340 : context,
341 : stack,
342 : access_mode,
343 : access_size,
344 E : &bad_access_info);
345 :
346 : // Call the callback to handle this error.
347 E : asan_runtime->OnError(&context, &bad_access_info);
348 E : }
349 :
350 : // Check if the memory location is accessible and report an error on bad memory
351 : // accesses.
352 : // @param location The memory address of the access.
353 : // @param access_mode The mode of the access.
354 : // @param access_size The size of the access.
355 : // @param context The registers context of the access.
356 : void CheckMemoryAccess(void* location,
357 : HeapProxy::AccessMode access_mode,
358 : size_t access_size,
359 E : AsanContext* context) {
360 E : if (!agent::asan::Shadow::IsAccessible(location))
361 E : ReportBadMemoryAccess(location, access_mode, access_size, context);
362 E : }
363 :
364 : // Check if the memory accesses done by a string instructions are valid.
365 : // @param dst The destination memory address of the access.
366 : // @param dst_access_mode The destination mode of the access.
367 : // @param src The source memory address of the access.
368 : // @param src_access_mode The source mode of the access.
369 : // @param length The number of memory accesses.
370 : // @param access_size The size of each the access in byte.
371 : // @param increment The increment to move dst/src after each access.
372 : // @param compare Flag to activate shortcut of the execution on difference.
373 : // @param context The registers context of the access.
374 : void CheckStringsMemoryAccesses(
375 : uint8* dst, HeapProxy::AccessMode dst_access_mode,
376 : uint8* src, HeapProxy::AccessMode src_access_mode,
377 : uint32 length, size_t access_size, int32 increment, bool compare,
378 E : AsanContext* context) {
379 E : int32 offset = 0;
380 :
381 E : for (uint32 i = 0; i < length; ++i) {
382 : // Check next memory location at src[offset].
383 E : if (src_access_mode != HeapProxy::ASAN_UNKNOWN_ACCESS)
384 E : CheckMemoryAccess(&src[offset], src_access_mode, access_size, context);
385 :
386 : // Check next memory location at dst[offset].
387 E : if (dst_access_mode != HeapProxy::ASAN_UNKNOWN_ACCESS)
388 E : CheckMemoryAccess(&dst[offset], dst_access_mode, access_size, context);
389 :
390 : // For CMPS instructions, we shortcut the execution of prefix REPZ when
391 : // memory contents differ.
392 E : if (compare) {
393 E : uint32 src_content = 0;
394 E : uint32 dst_content = 0;
395 E : switch (access_size) {
396 : case 4:
397 E : src_content = *reinterpret_cast<uint32*>(&src[offset]);
398 E : dst_content = *reinterpret_cast<uint32*>(&dst[offset]);
399 E : break;
400 : case 2:
401 E : src_content = *reinterpret_cast<uint16*>(&src[offset]);
402 E : dst_content = *reinterpret_cast<uint16*>(&dst[offset]);
403 E : break;
404 : case 1:
405 E : src_content = *reinterpret_cast<uint8*>(&src[offset]);
406 E : dst_content = *reinterpret_cast<uint8*>(&dst[offset]);
407 E : break;
408 : default:
409 i : NOTREACHED() << "Unexpected access_size.";
410 : break;
411 : }
412 :
413 E : if (src_content != dst_content)
414 E : return;
415 : }
416 :
417 : // Increments offset of dst/src to the next memory location.
418 E : offset += increment;
419 E : }
420 E : }
421 :
422 : } // namespace asan
423 : } // namespace agent
424 :
425 : // This is a trick for efficient saving/restoring part of the flags register.
426 : // see http://blog.freearrow.com/archives/396
427 : // Flags (bits 16-31) probably need a pipeline flush on update (POPFD). Thus,
428 : // using LAHF/SAHF instead gives better performance.
429 : // PUSHFD/POPFD: 23.314684 ticks
430 : // LAHF/SAHF: 8.838665 ticks
431 :
432 : // This macro starts by saving EAX onto the stack and then loads the value of
433 : // the flags into it.
434 : #define ASAN_SAVE_EFLAGS \
435 : __asm push eax \
436 : __asm lahf \
437 : __asm seto al
438 :
439 : // This macro restores the flags, their previous value is assumed to be in EAX
440 : // and we expect to have the previous value of EAX on the top of the stack.
441 : // AL is set to 1 if the overflow flag was set before the call to our hook, 0
442 : // otherwise. We add 0x7f to it so it'll restore the flag. Then we restore the
443 : // low bytes of the flags and EAX.
444 : #define ASAN_RESTORE_EFLAGS \
445 : __asm add al, 0x7f \
446 : __asm sahf \
447 : __asm pop eax
448 :
449 : // This is the common part of the fast path shared between the different
450 : // implementations of the hooks, this does the following:
451 : // - Saves the memory location in EDX for the slow path.
452 : // - Checks if the address we're trying to access is signed, if so this mean
453 : // that this is an access to the upper region of the memory (over the
454 : // 2GB limit) and we should report this as an invalid wild access.
455 : // - Checks for zero shadow for this memory location. We use the cmp
456 : // instruction so it'll set the sign flag if the upper bit of the shadow
457 : // value of this memory location is set to 1.
458 : // - If the shadow byte is not equal to zero then it jumps to the slow path.
459 : // - Otherwise it removes the memory location from the top of the stack.
460 : #define ASAN_FAST_PATH \
461 : __asm push edx \
462 : __asm sar edx, 3 \
463 : __asm js report_failure \
464 : __asm movzx edx, BYTE PTR[edx + agent::asan::Shadow::shadow_] \
465 : __asm cmp dl, 0 \
466 : __asm jnz check_access_slow \
467 : __asm add esp, 4
468 :
469 : // This is the common part of the slow path shared between the different
470 : // implementations of the hooks. The memory location is expected to be on top of
471 : // the stack and the shadow value for it is assumed to be in DL at this point.
472 : // This also relies on the fact that the shadow non accessible byte mask has its
473 : // upper bit set to 1 and that we jump to this macro after doing a
474 : // "cmp shadow_byte, 0", so the sign flag would be set to 1 if the value isn't
475 : // accessible.
476 : // We inline the Shadow::IsAccessible function for performance reasons.
477 : // This function does the following:
478 : // - Checks if this byte is accessible and jump to the error path if it's
479 : // not.
480 : // - Removes the memory location from the top of the stack.
481 : #define ASAN_SLOW_PATH \
482 : __asm js report_failure \
483 : __asm mov dh, BYTE PTR[esp] \
484 : __asm and dh, 7 \
485 : __asm cmp dh, dl \
486 : __asm jae report_failure \
487 : __asm add esp, 4
488 :
489 : // This is the error path. It expects to have the previous value of EDX at
490 : // [ESP + 4] and the address of the faulty instruction at [ESP].
491 : // This macro take cares of saving and restoring the flags.
492 : #define ASAN_ERROR_PATH(access_size, access_mode_value) \
493 : /* Restore original value of EDX, and put memory location on stack. */ \
494 : __asm xchg edx, DWORD PTR[esp + 4] \
495 : /* Create an ASAN registers context on the stack. */ \
496 : __asm pushfd \
497 : __asm pushad \
498 : /* Fix the original value of ESP in the ASAN registers context. */ \
499 : /* Removing 12 bytes (e.g. EFLAGS / EIP / Original EDX). */ \
500 : __asm add DWORD PTR[esp + 12], 12 \
501 : /* Push ARG4: the address of ASAN context on stack. */ \
502 : __asm push esp \
503 : /* Push ARG3: the access size. */ \
504 : __asm push access_size \
505 : /* Push ARG2: the access type. */ \
506 : __asm push access_mode_value \
507 : /* Push ARG1: the memory location. */ \
508 : __asm push DWORD PTR[esp + 52] \
509 : __asm call agent::asan::ReportBadMemoryAccess \
510 : /* Remove 4 x ARG on stack. */ \
511 : __asm add esp, 16 \
512 : /* Restore original registers. */ \
513 : __asm popad \
514 : __asm popfd \
515 : /* Return and remove memory location on stack. */ \
516 : __asm ret 4
517 :
518 : // Generates the asan check access functions. The name of the generated method
519 : // will be asan_check_(@p access_size)_byte_(@p access_mode_str)().
520 : // @param access_size The size of the access (in byte).
521 : // @param access_mode_str The string representing the access mode (read_access
522 : // or write_access).
523 : // @param access_mode_value The internal value representing this kind of access.
524 : // @note Calling this function doesn't alter any register.
525 : #define ASAN_CHECK_FUNCTION(access_size, access_mode_str, access_mode_value) \
526 : extern "C" __declspec(naked) \
527 : void asan_check_ ## access_size ## _byte_ ## access_mode_str ## () { \
528 : __asm { \
529 : /* Save the EFLAGS. */ \
530 : ASAN_SAVE_EFLAGS \
531 : ASAN_FAST_PATH \
532 : /* Restore original EDX. */ \
533 : __asm mov edx, DWORD PTR[esp + 8] \
534 : /* Restore the EFLAGS. */ \
535 : ASAN_RESTORE_EFLAGS \
536 : __asm ret 4 \
537 : __asm check_access_slow: \
538 : ASAN_SLOW_PATH \
539 : /* Restore original EDX. */ \
540 : __asm mov edx, DWORD PTR[esp + 8] \
541 : /* Restore the EFLAGS. */ \
542 : ASAN_RESTORE_EFLAGS \
543 : __asm ret 4 \
544 : __asm report_failure: \
545 : /* Restore memory location in EDX. */ \
546 : __asm pop edx \
547 : /* Restore the EFLAGS. */ \
548 : ASAN_RESTORE_EFLAGS \
549 : ASAN_ERROR_PATH(access_size, access_mode_value) \
550 : } \
551 : }
552 :
553 : // Generates a variant of the asan check access functions that don't save the
554 : // flags. The name of the generated method will be
555 : // asan_check_(@p access_size)_byte_(@p access_mode_str)_no_flags().
556 : // @param access_size The size of the access (in byte).
557 : // @param access_mode_str The string representing the access mode (read_access
558 : // or write_access).
559 : // @param access_mode_value The internal value representing this kind of access.
560 : // @note Calling this function may alter the EFLAGS register only.
561 : #define ASAN_CHECK_FUNCTION_NO_FLAGS(access_size, \
562 : access_mode_str, \
563 : access_mode_value) \
564 : extern "C" __declspec(naked) \
565 : void asan_check_ ## access_size ## _byte_ ## access_mode_str ## \
566 : _no_flags() { \
567 : __asm { \
568 : ASAN_FAST_PATH \
569 : /* Restore original EDX. */ \
570 : __asm mov edx, DWORD PTR[esp + 4] \
571 : __asm ret 4 \
572 : __asm check_access_slow: \
573 : ASAN_SLOW_PATH \
574 : /* Restore original EDX. */ \
575 : __asm mov edx, DWORD PTR[esp + 4] \
576 : __asm ret 4 \
577 : __asm report_failure: \
578 : /* Restore memory location in EDX. */ \
579 : __asm pop edx \
580 : ASAN_ERROR_PATH(access_size, access_mode_value) \
581 : } \
582 : }
583 :
584 : // Redefine some enums to make them accessible in the inlined assembly.
585 : // @{
586 : enum AccessMode {
587 : AsanReadAccess = HeapProxy::ASAN_READ_ACCESS,
588 : AsanWriteAccess = HeapProxy::ASAN_WRITE_ACCESS,
589 : AsanUnknownAccess = HeapProxy::ASAN_UNKNOWN_ACCESS,
590 : };
591 : // @}
592 :
593 : // The slow path rely on the fact that the shadow memory non accessible byte
594 : // mask have its upper bit set to 1..
595 : COMPILE_ASSERT(
596 : (agent::asan::Shadow::kHeapNonAccessibleByteMask & (1 << 7)) != 0,
597 : asan_shadow_mask_upper_bit_is_0);
598 :
599 i : ASAN_CHECK_FUNCTION(1, read_access, AsanReadAccess)
600 i : ASAN_CHECK_FUNCTION(2, read_access, AsanReadAccess)
601 i : ASAN_CHECK_FUNCTION(4, read_access, AsanReadAccess)
602 i : ASAN_CHECK_FUNCTION(8, read_access, AsanReadAccess)
603 i : ASAN_CHECK_FUNCTION(10, read_access, AsanReadAccess)
604 i : ASAN_CHECK_FUNCTION(16, read_access, AsanReadAccess)
605 i : ASAN_CHECK_FUNCTION(32, read_access, AsanReadAccess)
606 i : ASAN_CHECK_FUNCTION(1, write_access, AsanWriteAccess)
607 i : ASAN_CHECK_FUNCTION(2, write_access, AsanWriteAccess)
608 i : ASAN_CHECK_FUNCTION(4, write_access, AsanWriteAccess)
609 i : ASAN_CHECK_FUNCTION(8, write_access, AsanWriteAccess)
610 i : ASAN_CHECK_FUNCTION(10, write_access, AsanWriteAccess)
611 i : ASAN_CHECK_FUNCTION(16, write_access, AsanWriteAccess)
612 i : ASAN_CHECK_FUNCTION(32, write_access, AsanWriteAccess)
613 :
614 : #undef ASAN_CHECK_FUNCTION
615 :
616 i : ASAN_CHECK_FUNCTION_NO_FLAGS(1, read_access, AsanReadAccess)
617 i : ASAN_CHECK_FUNCTION_NO_FLAGS(2, read_access, AsanReadAccess)
618 i : ASAN_CHECK_FUNCTION_NO_FLAGS(4, read_access, AsanReadAccess)
619 i : ASAN_CHECK_FUNCTION_NO_FLAGS(8, read_access, AsanReadAccess)
620 i : ASAN_CHECK_FUNCTION_NO_FLAGS(10, read_access, AsanReadAccess)
621 i : ASAN_CHECK_FUNCTION_NO_FLAGS(16, read_access, AsanReadAccess)
622 i : ASAN_CHECK_FUNCTION_NO_FLAGS(32, read_access, AsanReadAccess)
623 i : ASAN_CHECK_FUNCTION_NO_FLAGS(1, write_access, AsanWriteAccess)
624 i : ASAN_CHECK_FUNCTION_NO_FLAGS(2, write_access, AsanWriteAccess)
625 i : ASAN_CHECK_FUNCTION_NO_FLAGS(4, write_access, AsanWriteAccess)
626 i : ASAN_CHECK_FUNCTION_NO_FLAGS(8, write_access, AsanWriteAccess)
627 i : ASAN_CHECK_FUNCTION_NO_FLAGS(10, write_access, AsanWriteAccess)
628 i : ASAN_CHECK_FUNCTION_NO_FLAGS(16, write_access, AsanWriteAccess)
629 i : ASAN_CHECK_FUNCTION_NO_FLAGS(32, write_access, AsanWriteAccess)
630 :
631 : #undef ASAN_CHECK_FUNCTION_NO_FLAGS
632 : #undef ASAN_SAVE_EFLAGS
633 : #undef ASAN_RESTORE_EFLAGS
634 : #undef ASAN_FAST_PATH
635 : #undef ASAN_SLOW_PATH
636 : #undef ASAN_ERROR_PATH
637 :
638 : // Generates the asan check access functions for a string instruction.
639 : // The name of the generated method will be
640 : // asan_check_(@p prefix)(@p access_size)_byte_(@p inst)_access().
641 : // @param inst The instruction mnemonic.
642 : // @param prefix The prefix of the instruction (repz or nothing).
643 : // @param counter The number of times the instruction must be executed (ECX). It
644 : // may be a register or a constant.
645 : // @param dst_mode The memory access mode for destination (EDI).
646 : // @param src_mode The memory access mode for destination (ESI).
647 : // @param access_size The size of the access (in byte).
648 : // @param compare A flag to enable shortcut execution by comparing memory
649 : // contents.
650 : #define ASAN_CHECK_STRINGS(func, prefix, counter, dst_mode, src_mode, \
651 : access_size, compare) \
652 : extern "C" __declspec(naked) \
653 : void asan_check ## prefix ## access_size ## _byte_ ## func ## _access() { \
654 : __asm { \
655 : /* Prologue, save context. */ \
656 : __asm pushfd \
657 : __asm pushad \
658 : /* Fix the original value of ESP in the ASAN registers context. */ \
659 : /* Removing 8 bytes (e.g.EFLAGS / EIP was on stack). */ \
660 : __asm add DWORD PTR[esp + 12], 8 \
661 : /* Setup increment in EBX (depends on direction flag in EFLAGS). */ \
662 : __asm mov ebx, access_size \
663 : __asm pushfd \
664 : __asm pop eax \
665 : __asm test eax, 0x400 \
666 : __asm jz skip_neg_direction \
667 : __asm neg ebx \
668 : __asm skip_neg_direction: \
669 : /* By standard calling convention, direction flag must be forward. */ \
670 : __asm cld \
671 : /* Push ARG(context), the ASAN registers context. */ \
672 : __asm push esp \
673 : /* Push ARG(compare), shortcut when memory contents differ. */ \
674 : __asm push compare \
675 : /* Push ARG(increment), increment for EDI/EDI. */ \
676 : __asm push ebx \
677 : /* Push ARG(access_size), the access size. */ \
678 : __asm push access_size \
679 : /* Push ARG(length), the number of memory accesses. */ \
680 : __asm push counter \
681 : /* Push ARG(src_access_mode), source access type. */ \
682 : __asm push src_mode \
683 : /* Push ARG(src), the source pointer. */ \
684 : __asm push esi \
685 : /* Push ARG(dst_access_mode), destination access type. */ \
686 : __asm push dst_mode \
687 : /* Push ARG(dst), the destination pointer. */ \
688 : __asm push edi \
689 : /* Call the generic check strings function. */ \
690 : __asm call agent::asan::CheckStringsMemoryAccesses \
691 : __asm add esp, 36 \
692 : /* Epilogue, restore context. */ \
693 : __asm popad \
694 : __asm popfd \
695 : __asm ret \
696 : } \
697 : }
698 :
699 i : ASAN_CHECK_STRINGS(cmps, _repz_, ecx, AsanReadAccess, AsanReadAccess, 4, 1)
700 i : ASAN_CHECK_STRINGS(cmps, _repz_, ecx, AsanReadAccess, AsanReadAccess, 2, 1)
701 i : ASAN_CHECK_STRINGS(cmps, _repz_, ecx, AsanReadAccess, AsanReadAccess, 1, 1)
702 i : ASAN_CHECK_STRINGS(cmps, _, 1, AsanReadAccess, AsanReadAccess, 4, 1)
703 i : ASAN_CHECK_STRINGS(cmps, _, 1, AsanReadAccess, AsanReadAccess, 2, 1)
704 i : ASAN_CHECK_STRINGS(cmps, _, 1, AsanReadAccess, AsanReadAccess, 1, 1)
705 :
706 i : ASAN_CHECK_STRINGS(movs, _repz_, ecx, AsanWriteAccess, AsanReadAccess, 4, 0)
707 i : ASAN_CHECK_STRINGS(movs, _repz_, ecx, AsanWriteAccess, AsanReadAccess, 2, 0)
708 i : ASAN_CHECK_STRINGS(movs, _repz_, ecx, AsanWriteAccess, AsanReadAccess, 1, 0)
709 i : ASAN_CHECK_STRINGS(movs, _, 1, AsanWriteAccess, AsanReadAccess, 4, 0)
710 i : ASAN_CHECK_STRINGS(movs, _, 1, AsanWriteAccess, AsanReadAccess, 2, 0)
711 i : ASAN_CHECK_STRINGS(movs, _, 1, AsanWriteAccess, AsanReadAccess, 1, 0)
712 :
713 i : ASAN_CHECK_STRINGS(stos, _repz_, ecx, AsanWriteAccess, AsanUnknownAccess, 4, 0)
714 i : ASAN_CHECK_STRINGS(stos, _repz_, ecx, AsanWriteAccess, AsanUnknownAccess, 2, 0)
715 i : ASAN_CHECK_STRINGS(stos, _repz_, ecx, AsanWriteAccess, AsanUnknownAccess, 1, 0)
716 i : ASAN_CHECK_STRINGS(stos, _, 1, AsanWriteAccess, AsanUnknownAccess, 4, 0)
717 i : ASAN_CHECK_STRINGS(stos, _, 1, AsanWriteAccess, AsanUnknownAccess, 2, 0)
718 i : ASAN_CHECK_STRINGS(stos, _, 1, AsanWriteAccess, AsanUnknownAccess, 1, 0)
719 :
720 : #undef ASAN_CHECK_STRINGS
|