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 : #include <windows.h>
15 :
16 : #include "gtest/gtest.h"
17 : #include "syzygy/agent/asan/asan_heap.h"
18 : #include "syzygy/agent/asan/asan_runtime.h"
19 : #include "syzygy/agent/asan/asan_shadow.h"
20 : #include "syzygy/agent/asan/unittest_util.h"
21 : #include "syzygy/core/unittest_util.h"
22 :
23 : namespace agent {
24 : namespace asan {
25 :
26 : namespace {
27 :
28 : // The access check function invoked by the below.
29 : FARPROC check_access_fn = NULL;
30 : // A flag used in asan callback to ensure that a memory error has been detected.
31 : bool memory_error_detected = false;
32 : // A pointer to a context to ensure that we're able to restore the context when
33 : // an asan error is found.
34 : CONTEXT* context_before_hook = NULL;
35 : // This will be used in the asan callback to ensure that we detect the right
36 : // error.
37 : HeapProxy::BadAccessKind expected_error_type = HeapProxy::UNKNOWN_BAD_ACCESS;
38 : // A flag to override the direction flag on special instruction checker.
39 : bool direction_flag_forward = true;
40 : // An arbitrary size for the buffer we allocate in the different unittests.
41 : const size_t kAllocSize = 13;
42 :
43 : // Shorthand for discussing all the asan runtime functions.
44 : #define ASAN_RTL_FUNCTIONS(F) \
45 : F(HANDLE, HeapCreate, \
46 : (DWORD options, SIZE_T initial_size, SIZE_T maximum_size)) \
47 : F(BOOL, HeapDestroy, \
48 : (HANDLE heap)) \
49 : F(LPVOID, HeapAlloc, \
50 : (HANDLE heap, DWORD flags, SIZE_T bytes)) \
51 : F(LPVOID, HeapReAlloc, \
52 : (HANDLE heap, DWORD flags, LPVOID mem, SIZE_T bytes)) \
53 : F(BOOL, HeapFree, \
54 : (HANDLE heap, DWORD flags, LPVOID mem)) \
55 : F(SIZE_T, HeapSize, \
56 : (HANDLE heap, DWORD flags, LPCVOID mem)) \
57 : F(BOOL, HeapValidate, \
58 : (HANDLE heap, DWORD flags, LPCVOID mem)) \
59 : F(SIZE_T, HeapCompact, \
60 : (HANDLE heap, DWORD flags)) \
61 : F(BOOL, HeapLock, (HANDLE heap)) \
62 : F(BOOL, HeapUnlock, (HANDLE heap)) \
63 : F(BOOL, HeapWalk, \
64 : (HANDLE heap, LPPROCESS_HEAP_ENTRY entry)) \
65 : F(BOOL, HeapSetInformation, \
66 : (HANDLE heap, HEAP_INFORMATION_CLASS info_class, \
67 : PVOID info, SIZE_T info_length)) \
68 : F(BOOL, HeapQueryInformation, \
69 : (HANDLE heap, HEAP_INFORMATION_CLASS info_class, \
70 : PVOID info, SIZE_T info_length, PSIZE_T return_length)) \
71 : F(void, SetCallBack, \
72 : (void (*callback)(CONTEXT* context, AsanErrorInfo* error_info))) \
73 :
74 : #define DECLARE_ASAN_FUNCTION_PTR(ret, name, args) \
75 : typedef ret (WINAPI* name##FunctionPtr)args;
76 :
77 : ASAN_RTL_FUNCTIONS(DECLARE_ASAN_FUNCTION_PTR)
78 :
79 : #undef DECLARE_ASAN_FUNCTION_PTR
80 :
81 : class AsanRtlTest : public testing::TestWithAsanLogger {
82 : public:
83 : AsanRtlTest() : asan_rtl_(NULL), heap_(NULL),
84 : memory_src_(NULL), memory_dst_(NULL),
85 E : memory_length_(0), memory_size_(0) {
86 E : }
87 :
88 E : void SetUp() OVERRIDE {
89 E : testing::TestWithAsanLogger::SetUp();
90 :
91 : // Load the ASAN runtime library.
92 E : base::FilePath asan_rtl_path = testing::GetExeRelativePath(L"asan_rtl.dll");
93 E : asan_rtl_ = ::LoadLibrary(asan_rtl_path.value().c_str());
94 E : ASSERT_TRUE(asan_rtl_ != NULL);
95 :
96 : // Load all the functions and assert that we find them.
97 : #define LOAD_ASAN_FUNCTION(ret, name, args) \
98 : name##Function = reinterpret_cast<name##FunctionPtr>( \
99 : ::GetProcAddress(asan_rtl_, "asan_" #name)); \
100 : ASSERT_TRUE(name##Function != NULL);
101 :
102 E : ASAN_RTL_FUNCTIONS(LOAD_ASAN_FUNCTION)
103 :
104 : #undef LOAD_ASAN_FUNCTION
105 :
106 E : heap_ = HeapCreateFunction(0, 0, 0);
107 E : ASSERT_TRUE(heap_ != NULL);
108 E : }
109 :
110 E : void TearDown() OVERRIDE {
111 E : if (heap_ != NULL) {
112 E : HeapDestroyFunction(heap_);
113 E : heap_ = NULL;
114 : }
115 :
116 E : if (asan_rtl_ != NULL) {
117 E : ::FreeLibrary(asan_rtl_);
118 E : asan_rtl_ = NULL;
119 : }
120 :
121 E : testing::TestWithAsanLogger::TearDown();
122 E : }
123 :
124 : protected:
125 : void AllocMemoryBuffers(int32 length, int32 element_size);
126 : void FreeMemoryBuffers();
127 :
128 : // The ASAN runtime module to test.
129 : HMODULE asan_rtl_;
130 :
131 : // Scratch heap handle valid from SetUp to TearDown.
132 : HANDLE heap_;
133 :
134 : // Memory buffers used to test special instructions.
135 : void* memory_src_;
136 : void* memory_dst_;
137 : int32 memory_length_;
138 : int32 memory_size_;
139 :
140 : // Declare the function pointers.
141 : #define DECLARE_FUNCTION_PTR_VARIABLE(ret, name, args) \
142 : static name##FunctionPtr AsanRtlTest::name##Function;
143 :
144 : ASAN_RTL_FUNCTIONS(DECLARE_FUNCTION_PTR_VARIABLE)
145 :
146 : #undef DECLARE_FUNCTION_PTR_VARIABLE
147 : };
148 :
149 : // Define the function pointers.
150 : #define DEFINE_FUNCTION_PTR_VARIABLE(ret, name, args) \
151 : name##FunctionPtr AsanRtlTest::name##Function;
152 :
153 : ASAN_RTL_FUNCTIONS(DEFINE_FUNCTION_PTR_VARIABLE)
154 :
155 : #undef DEFINE_FUNCTION_PTR_VARIABLE
156 :
157 : #define RTL_CAPTURE_CONTEXT(context, expected_eip) { \
158 : /* Save caller save registers. */ \
159 : __asm push eax \
160 : __asm push ecx \
161 : __asm push edx \
162 : /* Call Capture context. */ \
163 : __asm push context \
164 : __asm call dword ptr[RtlCaptureContext] \
165 : /* Restore caller save registers. */ \
166 : __asm pop edx \
167 : __asm pop ecx \
168 : __asm pop eax \
169 : /* Restore registers which are stomped by RtlCaptureContext. */ \
170 : __asm push eax \
171 : __asm pushfd \
172 : __asm mov eax, context \
173 : __asm mov dword ptr[eax + CONTEXT.Ebp], ebp \
174 : __asm mov dword ptr[eax + CONTEXT.Esp], esp \
175 : /* NOTE: we need to add 8 bytes because EAX + EFLAGS are on the stack. */ \
176 : __asm add dword ptr[eax + CONTEXT.Esp], 8 \
177 : __asm mov dword ptr[eax + CONTEXT.Eip], offset expected_eip \
178 : __asm popfd \
179 : __asm pop eax \
180 : }
181 :
182 : // Check if the sections of 2 context are equals.
183 : // @param c1 The first context to check.
184 : // @param c2 The second context to check.
185 : // @param flags The sections to compare.
186 E : void ExpectEqualContexts(const CONTEXT& c1, const CONTEXT& c2, DWORD flags) {
187 E : if ((flags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS) {
188 E : EXPECT_EQ(c1.SegGs, c2.SegGs);
189 E : EXPECT_EQ(c1.SegFs, c2.SegFs);
190 E : EXPECT_EQ(c1.SegEs, c2.SegEs);
191 E : EXPECT_EQ(c1.SegDs, c2.SegDs);
192 : }
193 :
194 E : if ((flags & CONTEXT_INTEGER) == CONTEXT_INTEGER) {
195 E : EXPECT_EQ(c1.Edi, c2.Edi);
196 E : EXPECT_EQ(c1.Esi, c2.Esi);
197 E : EXPECT_EQ(c1.Ebx, c2.Ebx);
198 E : EXPECT_EQ(c1.Edx, c2.Edx);
199 E : EXPECT_EQ(c1.Ecx, c2.Ecx);
200 E : EXPECT_EQ(c1.Eax, c2.Eax);
201 : }
202 :
203 E : if ((flags & CONTEXT_CONTROL) == CONTEXT_CONTROL) {
204 E : EXPECT_EQ(c1.Ebp, c2.Ebp);
205 E : EXPECT_EQ(c1.Eip, c2.Eip);
206 E : EXPECT_EQ(c1.SegCs, c2.SegCs);
207 E : EXPECT_EQ(c1.EFlags, c2.EFlags);
208 E : EXPECT_EQ(c1.Esp, c2.Esp);
209 E : EXPECT_EQ(c1.SegSs, c2.SegSs);
210 : }
211 E : }
212 :
213 : void CheckAccessAndCaptureContexts(
214 i : CONTEXT* before, CONTEXT* after, void* location) {
215 : __asm {
216 i : pushad
217 i : pushfd
218 :
219 : // Avoid undefined behavior by forcing values.
220 i : mov eax, 0x01234567
221 i : mov ebx, 0x70123456
222 i : mov ecx, 0x12345678
223 i : mov edx, 0x56701234
224 i : mov esi, 0xCCAACCAA
225 i : mov edi, 0xAACCAACC
226 :
227 i : RTL_CAPTURE_CONTEXT(before, check_access_expected_eip)
228 :
229 : // Push EDX as we're required to do by the custom calling convention.
230 i : push edx
231 : // Ptr is the pointer to check.
232 i : mov edx, location
233 : // Call through.
234 i : call dword ptr[check_access_fn + 0]
235 : check_access_expected_eip:
236 :
237 i : RTL_CAPTURE_CONTEXT(after, check_access_expected_eip)
238 :
239 i : popfd
240 i : popad
241 : }
242 i : }
243 :
244 E : void CheckAccessAndCompareContexts(void* ptr) {
245 E : CONTEXT before = {};
246 E : CONTEXT after = {};
247 :
248 E : context_before_hook = &before;
249 E : CheckAccessAndCaptureContexts(&before, &after, ptr);
250 :
251 E : ExpectEqualContexts(before, after, CONTEXT_FULL);
252 :
253 E : context_before_hook = NULL;
254 E : }
255 :
256 : void CheckSpecialAccess(CONTEXT* before, CONTEXT* after,
257 i : void* dst, void* src, int len) {
258 : __asm {
259 i : pushad
260 i : pushfd
261 :
262 : // Override the direction flag.
263 i : cld
264 i : cmp direction_flag_forward, 0
265 i : jne skip_reverse_direction
266 i : std
267 : skip_reverse_direction:
268 :
269 : // Avoid undefined behavior by forcing values.
270 i : mov eax, 0x01234567
271 i : mov ebx, 0x70123456
272 i : mov edx, 0x56701234
273 :
274 : // Setup registers used by the special instruction.
275 i : mov ecx, len
276 i : mov esi, src
277 i : mov edi, dst
278 :
279 i : RTL_CAPTURE_CONTEXT(before, special_access_expected_eip)
280 :
281 : // Call through.
282 i : call dword ptr[check_access_fn + 0]
283 : special_access_expected_eip:
284 :
285 i : RTL_CAPTURE_CONTEXT(after, special_access_expected_eip)
286 :
287 i : popfd
288 i : popad
289 : }
290 i : }
291 :
292 E : void CheckSpecialAccessAndCompareContexts(void* dst, void* src, int len) {
293 E : CONTEXT before = {};
294 E : CONTEXT after = {};
295 :
296 E : context_before_hook = &before;
297 :
298 E : CheckSpecialAccess(&before, &after, dst, src, len);
299 :
300 E : ExpectEqualContexts(before, after, CONTEXT_FULL);
301 :
302 E : context_before_hook = NULL;
303 E : }
304 :
305 E : void AsanErrorCallback(CONTEXT* context, AsanErrorInfo* error_info) {
306 : // TODO(sebmarchand): Stash the error info in a fixture-static variable and
307 : // assert on specific conditions after the fact.
308 E : EXPECT_TRUE(context != NULL);
309 E : EXPECT_TRUE(context_before_hook != NULL);
310 E : EXPECT_NE(HeapProxy::UNKNOWN_BAD_ACCESS, error_info->error_type);
311 :
312 E : EXPECT_EQ(expected_error_type, error_info->error_type);
313 E : if (error_info->error_type != HeapProxy::WILD_ACCESS) {
314 : // We should at least have the stack trace of the allocation of this block.
315 E : EXPECT_GT(error_info->alloc_stack_size, 0U);
316 E : EXPECT_NE(0U, error_info->alloc_tid);
317 E : if (error_info->error_type == HeapProxy::USE_AFTER_FREE) {
318 E : EXPECT_GT(error_info->free_stack_size, 0U);
319 E : EXPECT_NE(0U, error_info->free_tid);
320 E : } else {
321 E : EXPECT_EQ(error_info->free_stack_size, 0U);
322 E : EXPECT_EQ(0U, error_info->free_tid);
323 : }
324 : }
325 :
326 E : if (error_info->error_type == HeapProxy::HEAP_BUFFER_OVERFLOW) {
327 E : EXPECT_TRUE(strstr(error_info->shadow_info, "beyond") != NULL);
328 E : } else if (error_info->error_type == HeapProxy::HEAP_BUFFER_UNDERFLOW) {
329 E : EXPECT_TRUE(strstr(error_info->shadow_info, "before") != NULL);
330 : }
331 :
332 E : memory_error_detected = true;
333 : ExpectEqualContexts(*context_before_hook,
334 : *context,
335 E : CONTEXT_INTEGER | CONTEXT_CONTROL);
336 E : }
337 :
338 : void AsanErrorCallbackWithoutComparingContext(CONTEXT* context,
339 E : AsanErrorInfo* error_info) {
340 E : memory_error_detected = true;
341 E : }
342 :
343 : void AssertMemoryErrorIsDetected(void* ptr,
344 E : HeapProxy::BadAccessKind bad_access_type) {
345 E : expected_error_type = bad_access_type;
346 E : memory_error_detected = false;
347 E : CheckAccessAndCompareContexts(ptr);
348 E : ASSERT_TRUE(memory_error_detected);
349 E : }
350 :
351 : void ExpectSpecialMemoryErrorIsDetected(bool expected,
352 : void* dst, void* src, int32 length,
353 E : HeapProxy::BadAccessKind bad_access_type) {
354 E : DCHECK(dst != NULL);
355 E : DCHECK(src != NULL);
356 E : ASSERT_TRUE(check_access_fn != NULL);
357 E : expected_error_type = bad_access_type;
358 :
359 : // Setup the callback to detect invalid accesses.
360 E : memory_error_detected = false;
361 :
362 : // Perform memory accesses inside the range.
363 : ASSERT_NO_FATAL_FAILURE(
364 E : CheckSpecialAccessAndCompareContexts(dst, src, length));
365 :
366 E : EXPECT_EQ(expected, memory_error_detected);
367 E : }
368 :
369 : } // namespace
370 :
371 E : TEST_F(AsanRtlTest, AsanCheckGoodAccess) {
372 : check_access_fn =
373 E : ::GetProcAddress(asan_rtl_, "asan_check_4_byte_read_access");
374 E : ASSERT_TRUE(check_access_fn != NULL);
375 :
376 : // Run through access checking an allocation that's larger than our
377 : // block size (8), but not a multiple thereof to exercise all paths
378 : // in the access check function (save for the failure path).
379 : uint8* mem = reinterpret_cast<uint8*>(
380 E : HeapAllocFunction(heap_, 0, kAllocSize));
381 E : ASSERT_TRUE(mem != NULL);
382 :
383 E : for (size_t i = 0; i < kAllocSize; ++i) {
384 E : ASSERT_NO_FATAL_FAILURE(CheckAccessAndCompareContexts(mem + i));
385 E : }
386 :
387 E : ASSERT_TRUE(HeapFreeFunction(heap_, 0, mem));
388 E : }
389 :
390 E : TEST_F(AsanRtlTest, AsanCheckHeapBufferOverflow) {
391 : check_access_fn =
392 E : ::GetProcAddress(asan_rtl_, "asan_check_4_byte_read_access");
393 E : ASSERT_TRUE(check_access_fn != NULL);
394 :
395 : uint8* mem = reinterpret_cast<uint8*>(
396 E : HeapAllocFunction(heap_, 0, kAllocSize));
397 E : ASSERT_TRUE(mem != NULL);
398 :
399 E : SetCallBackFunction(&AsanErrorCallback);
400 : AssertMemoryErrorIsDetected(mem + kAllocSize,
401 E : HeapProxy::HEAP_BUFFER_OVERFLOW);
402 E : EXPECT_TRUE(HeapFreeFunction(heap_, 0, mem));
403 E : EXPECT_TRUE(LogContains("previously allocated here"));
404 E : EXPECT_TRUE(LogContains(HeapProxy::kHeapBufferOverFlow));
405 E : }
406 :
407 E : TEST_F(AsanRtlTest, AsanCheckHeapBufferUnderflow) {
408 : check_access_fn =
409 E : ::GetProcAddress(asan_rtl_, "asan_check_4_byte_read_access");
410 E : ASSERT_TRUE(check_access_fn != NULL);
411 :
412 E : const size_t kAllocSize = 13;
413 : uint8* mem = reinterpret_cast<uint8*>(
414 E : HeapAllocFunction(heap_, 0, kAllocSize));
415 E : ASSERT_TRUE(mem != NULL);
416 :
417 E : SetCallBackFunction(&AsanErrorCallback);
418 E : AssertMemoryErrorIsDetected(mem - 1, HeapProxy::HEAP_BUFFER_UNDERFLOW);
419 E : EXPECT_TRUE(HeapFreeFunction(heap_, 0, mem));
420 E : EXPECT_TRUE(LogContains("previously allocated here"));
421 E : EXPECT_TRUE(LogContains(HeapProxy::kHeapBufferUnderFlow));
422 E : }
423 :
424 E : TEST_F(AsanRtlTest, AsanCheckUseAfterFree) {
425 : check_access_fn =
426 E : ::GetProcAddress(asan_rtl_, "asan_check_4_byte_read_access");
427 E : ASSERT_TRUE(check_access_fn != NULL);
428 :
429 E : const size_t kAllocSize = 13;
430 : uint8* mem = reinterpret_cast<uint8*>(
431 E : HeapAllocFunction(heap_, 0, kAllocSize));
432 E : ASSERT_TRUE(mem != NULL);
433 :
434 E : SetCallBackFunction(&AsanErrorCallback);
435 E : EXPECT_TRUE(HeapFreeFunction(heap_, 0, mem));
436 E : AssertMemoryErrorIsDetected(mem, HeapProxy::USE_AFTER_FREE);
437 E : EXPECT_TRUE(LogContains("previously allocated here"));
438 E : EXPECT_TRUE(LogContains("freed here"));
439 E : EXPECT_TRUE(LogContains(HeapProxy::kHeapUseAfterFree));
440 E : }
441 :
442 E : TEST_F(AsanRtlTest, AsanCheckDoubleFree) {
443 : check_access_fn =
444 E : ::GetProcAddress(asan_rtl_, "asan_check_4_byte_read_access");
445 E : ASSERT_TRUE(check_access_fn != NULL);
446 :
447 E : const size_t kAllocSize = 13;
448 : uint8* mem = reinterpret_cast<uint8*>(
449 E : HeapAllocFunction(heap_, 0, kAllocSize));
450 E : ASSERT_TRUE(mem != NULL);
451 :
452 E : CONTEXT context_before_error = {};
453 E : context_before_hook = &context_before_error;
454 E : SetCallBackFunction(&AsanErrorCallbackWithoutComparingContext);
455 E : EXPECT_TRUE(HeapFreeFunction(heap_, 0, mem));
456 E : EXPECT_FALSE(HeapFreeFunction(heap_, 0, mem));
457 E : EXPECT_TRUE(memory_error_detected);
458 E : EXPECT_TRUE(LogContains(HeapProxy::kAttemptingDoubleFree));
459 E : EXPECT_TRUE(LogContains("previously allocated here"));
460 E : EXPECT_TRUE(LogContains("freed here"));
461 E : }
462 :
463 E : TEST_F(AsanRtlTest, AsanCheckWildAccess) {
464 : check_access_fn =
465 E : ::GetProcAddress(asan_rtl_, "asan_check_4_byte_read_access");
466 E : ASSERT_TRUE(check_access_fn != NULL);
467 :
468 E : SetCallBackFunction(&AsanErrorCallback);
469 : AssertMemoryErrorIsDetected(reinterpret_cast<void*>(0x80000000),
470 E : HeapProxy::WILD_ACCESS);
471 E : EXPECT_TRUE(LogContains(HeapProxy::kWildAccess));
472 E : }
473 :
474 E : void AsanRtlTest::AllocMemoryBuffers(int32 length, int32 element_size) {
475 E : DCHECK(memory_src_ == NULL);
476 E : DCHECK(memory_dst_ == NULL);
477 E : DCHECK(memory_length_ == 0);
478 E : DCHECK(memory_size_ == 0);
479 :
480 : // Keep track of memory size.
481 E : memory_length_ = length;
482 E : memory_size_ = length * element_size;
483 :
484 : // Allocate memory space.
485 E : memory_src_ = HeapAllocFunction(heap_, 0, memory_size_);
486 E : ASSERT_TRUE(memory_src_ != NULL);
487 E : memory_dst_ = HeapAllocFunction(heap_, 0, memory_size_);
488 E : ASSERT_TRUE(memory_dst_ != NULL);
489 :
490 : // Initialize memory.
491 E : memset(memory_src_, 0, memory_size_);
492 E : memset(memory_dst_, 0, memory_size_);
493 E : }
494 :
495 E : void AsanRtlTest::FreeMemoryBuffers() {
496 E : DCHECK(memory_src_ != NULL);
497 E : DCHECK(memory_dst_ != NULL);
498 :
499 E : ASSERT_TRUE(HeapFreeFunction(heap_, 0, memory_src_));
500 E : ASSERT_TRUE(HeapFreeFunction(heap_, 0, memory_dst_));
501 :
502 E : memory_length_ = 0;
503 E : memory_size_ = 0;
504 E : memory_src_ = NULL;
505 E : memory_dst_ = NULL;
506 E : }
507 :
508 E : TEST_F(AsanRtlTest, AsanSingleSpecial1byteInstructionCheckGoodAccess) {
509 : static const char* function_names[] = {
510 : "asan_check_1_byte_movs_access",
511 : "asan_check_1_byte_cmps_access",
512 : "asan_check_1_byte_stos_access"
513 : };
514 :
515 : // Setup the callback to detect invalid accesses.
516 E : SetCallBackFunction(&AsanErrorCallback);
517 :
518 : // Allocate memory space.
519 E : AllocMemoryBuffers(kAllocSize, sizeof(uint8));
520 E : uint8* src = reinterpret_cast<uint8*>(memory_src_);
521 E : uint8* dst = reinterpret_cast<uint8*>(memory_dst_);
522 :
523 : // Validate memory accesses.
524 E : for (int32 function = 0; function < arraysize(function_names); ++function) {
525 : check_access_fn =
526 E : ::GetProcAddress(asan_rtl_, function_names[function]);
527 E : ASSERT_TRUE(check_access_fn != NULL);
528 :
529 E : for (int32 i = 0; i < memory_length_; ++i)
530 : ExpectSpecialMemoryErrorIsDetected(false, &dst[i], &src[i], 0xDEADDEAD,
531 E : HeapProxy::UNKNOWN_BAD_ACCESS);
532 E : }
533 :
534 E : FreeMemoryBuffers();
535 E : }
536 :
537 E : TEST_F(AsanRtlTest, AsanSingleSpecial2byteInstructionCheckGoodAccess) {
538 : static const char* function_names[] = {
539 : "asan_check_2_byte_movs_access",
540 : "asan_check_2_byte_cmps_access",
541 : "asan_check_2_byte_stos_access"
542 : };
543 :
544 : // Setup the callback to detect invalid accesses.
545 E : SetCallBackFunction(&AsanErrorCallback);
546 :
547 : // Allocate memory space.
548 E : AllocMemoryBuffers(kAllocSize, sizeof(uint16));
549 E : uint16* src = reinterpret_cast<uint16*>(memory_src_);
550 E : uint16* dst = reinterpret_cast<uint16*>(memory_dst_);
551 :
552 : // Validate memory accesses.
553 E : for (int32 function = 0; function < arraysize(function_names); ++function) {
554 : check_access_fn =
555 E : ::GetProcAddress(asan_rtl_, function_names[function]);
556 E : ASSERT_TRUE(check_access_fn != NULL);
557 :
558 E : for (int32 i = 0; i < memory_length_; ++i)
559 : ExpectSpecialMemoryErrorIsDetected(false, &dst[i], &src[i], 0xDEADDEAD,
560 E : HeapProxy::UNKNOWN_BAD_ACCESS);
561 E : }
562 :
563 E : FreeMemoryBuffers();
564 E : }
565 :
566 E : TEST_F(AsanRtlTest, AsanSingleSpecial4byteInstructionCheckGoodAccess) {
567 : static const char* function_names[] = {
568 : "asan_check_4_byte_movs_access",
569 : "asan_check_4_byte_cmps_access",
570 : "asan_check_4_byte_stos_access"
571 : };
572 :
573 : // Setup the callback to detect invalid accesses.
574 E : SetCallBackFunction(&AsanErrorCallback);
575 :
576 : // Allocate memory space.
577 E : AllocMemoryBuffers(kAllocSize, sizeof(uint32));
578 E : uint32* src = reinterpret_cast<uint32*>(memory_src_);
579 E : uint32* dst = reinterpret_cast<uint32*>(memory_dst_);
580 :
581 : // Validate memory accesses.
582 E : for (int32 function = 0; function < arraysize(function_names); ++function) {
583 : check_access_fn =
584 E : ::GetProcAddress(asan_rtl_, function_names[function]);
585 E : ASSERT_TRUE(check_access_fn != NULL);
586 :
587 E : for (int32 i = 0; i < memory_length_; ++i)
588 : ExpectSpecialMemoryErrorIsDetected(false, &dst[i], &src[i], 0xDEADDEAD,
589 E : HeapProxy::UNKNOWN_BAD_ACCESS);
590 E : }
591 :
592 E : FreeMemoryBuffers();
593 E : }
594 :
595 E : TEST_F(AsanRtlTest, AsanSingleSpecialInstructionCheckBadAccess) {
596 : static const char* function_names[] = {
597 : "asan_check_1_byte_movs_access",
598 : "asan_check_1_byte_cmps_access",
599 : "asan_check_2_byte_movs_access",
600 : "asan_check_2_byte_cmps_access",
601 : "asan_check_4_byte_movs_access",
602 : "asan_check_4_byte_cmps_access"
603 : };
604 :
605 : // Setup the callback to detect invalid accesses.
606 E : SetCallBackFunction(&AsanErrorCallback);
607 :
608 : // Allocate memory space.
609 E : AllocMemoryBuffers(kAllocSize, sizeof(uint32));
610 E : uint32* src = reinterpret_cast<uint32*>(memory_src_);
611 E : uint32* dst = reinterpret_cast<uint32*>(memory_dst_);
612 :
613 : // Validate memory accesses.
614 E : for (int32 function = 0; function < arraysize(function_names); ++function) {
615 : check_access_fn =
616 E : ::GetProcAddress(asan_rtl_, function_names[function]);
617 E : ASSERT_TRUE(check_access_fn != NULL);
618 :
619 : ExpectSpecialMemoryErrorIsDetected(true, &dst[0], &src[-1], 0xDEADDEAD,
620 E : HeapProxy::HEAP_BUFFER_UNDERFLOW);
621 : ExpectSpecialMemoryErrorIsDetected(true, &dst[-1], &src[0], 0xDEADDEAD,
622 E : HeapProxy::HEAP_BUFFER_UNDERFLOW);
623 :
624 : ExpectSpecialMemoryErrorIsDetected(true, &dst[0], &src[memory_length_],
625 E : 0xDEADDEAD, HeapProxy::HEAP_BUFFER_OVERFLOW);
626 : ExpectSpecialMemoryErrorIsDetected(true, &dst[memory_length_], &src[0],
627 E : 0xDEADDEAD, HeapProxy::HEAP_BUFFER_OVERFLOW);
628 E : }
629 :
630 E : FreeMemoryBuffers();
631 E : }
632 :
633 E : TEST_F(AsanRtlTest, AsanSingleStoInstructionCheckBadAccess) {
634 : static const char* function_names[] = {
635 : "asan_check_1_byte_stos_access",
636 : "asan_check_2_byte_stos_access",
637 : "asan_check_4_byte_stos_access"
638 : };
639 :
640 : // Setup the callback to detect invalid accesses.
641 E : SetCallBackFunction(&AsanErrorCallback);
642 :
643 : // Allocate memory space.
644 E : AllocMemoryBuffers(kAllocSize, sizeof(uint32));
645 E : uint32* src = reinterpret_cast<uint32*>(memory_src_);
646 E : uint32* dst = reinterpret_cast<uint32*>(memory_dst_);
647 :
648 : // Validate memory accesses.
649 E : for (int32 function = 0; function < arraysize(function_names); ++function) {
650 : check_access_fn =
651 E : ::GetProcAddress(asan_rtl_, function_names[function]);
652 E : ASSERT_TRUE(check_access_fn != NULL);
653 :
654 : ExpectSpecialMemoryErrorIsDetected(false, &dst[0], &src[-1], 0xDEAD,
655 E : HeapProxy::HEAP_BUFFER_UNDERFLOW);
656 : ExpectSpecialMemoryErrorIsDetected(true, &dst[-1], &src[0], 0xDEAD,
657 E : HeapProxy::HEAP_BUFFER_UNDERFLOW);
658 :
659 : ExpectSpecialMemoryErrorIsDetected(false, &dst[0], &src[memory_length_],
660 E : 0xDEADDEAD, HeapProxy::HEAP_BUFFER_OVERFLOW);
661 : ExpectSpecialMemoryErrorIsDetected(true, &dst[memory_length_], &src[0],
662 E : 0xDEADDEAD, HeapProxy::HEAP_BUFFER_OVERFLOW);
663 E : }
664 :
665 E : FreeMemoryBuffers();
666 E : }
667 :
668 E : TEST_F(AsanRtlTest, AsanPrefixedSpecialInstructionCheckGoodAccess) {
669 : static const char* function_names[] = {
670 : "asan_check_repz_4_byte_movs_access",
671 : "asan_check_repz_4_byte_cmps_access",
672 : "asan_check_repz_4_byte_stos_access"
673 : };
674 :
675 : // Setup the callback to detect invalid accesses.
676 E : SetCallBackFunction(&AsanErrorCallback);
677 :
678 : // Allocate memory space.
679 E : AllocMemoryBuffers(kAllocSize, sizeof(uint32));
680 E : uint32* src = reinterpret_cast<uint32*>(memory_src_);
681 E : uint32* dst = reinterpret_cast<uint32*>(memory_dst_);
682 :
683 : // Validate memory accesses.
684 E : for (int32 function = 0; function < arraysize(function_names); ++function) {
685 : check_access_fn =
686 E : ::GetProcAddress(asan_rtl_, function_names[function]);
687 E : ASSERT_TRUE(check_access_fn != NULL);
688 :
689 : ExpectSpecialMemoryErrorIsDetected(false, &dst[0], &src[0], memory_length_,
690 E : HeapProxy::UNKNOWN_BAD_ACCESS);
691 E : }
692 :
693 E : FreeMemoryBuffers();
694 E : }
695 :
696 E : TEST_F(AsanRtlTest, AsanPrefixedSpecialInstructionCheckBadAccess) {
697 : static const char* function_names[] = {
698 : "asan_check_repz_4_byte_movs_access",
699 : "asan_check_repz_4_byte_cmps_access",
700 : "asan_check_repz_4_byte_stos_access"
701 : };
702 :
703 : // Setup the callback to detect invalid accesses.
704 E : SetCallBackFunction(&AsanErrorCallback);
705 :
706 : // Allocate memory space.
707 E : AllocMemoryBuffers(kAllocSize, sizeof(uint32));
708 E : uint32* src = reinterpret_cast<uint32*>(memory_src_);
709 E : uint32* dst = reinterpret_cast<uint32*>(memory_dst_);
710 :
711 : // Validate memory accesses.
712 E : for (int32 function = 0; function < arraysize(function_names); ++function) {
713 : check_access_fn =
714 E : ::GetProcAddress(asan_rtl_, function_names[function]);
715 E : ASSERT_TRUE(check_access_fn != NULL);
716 :
717 : ExpectSpecialMemoryErrorIsDetected(true, &dst[0], &src[0],
718 E : memory_length_ + 1, HeapProxy::HEAP_BUFFER_OVERFLOW);
719 : ExpectSpecialMemoryErrorIsDetected(true, &dst[-1], &src[-1],
720 E : memory_length_, HeapProxy::HEAP_BUFFER_UNDERFLOW);
721 : ExpectSpecialMemoryErrorIsDetected(true, &dst[-1], &src[0],
722 E : memory_length_, HeapProxy::HEAP_BUFFER_UNDERFLOW);
723 E : }
724 :
725 E : FreeMemoryBuffers();
726 E : }
727 :
728 E : TEST_F(AsanRtlTest, AsanDirectionSpecialInstructionCheckGoodAccess) {
729 : static const char* function_names[] = {
730 : "asan_check_repz_4_byte_movs_access",
731 : "asan_check_repz_4_byte_cmps_access",
732 : "asan_check_repz_4_byte_stos_access"
733 : };
734 :
735 : // Setup the callback to detect invalid accesses.
736 E : SetCallBackFunction(&AsanErrorCallback);
737 :
738 : // Force direction flag to backward.
739 E : direction_flag_forward = false;
740 :
741 : // Allocate memory space.
742 E : AllocMemoryBuffers(kAllocSize, sizeof(uint32));
743 E : uint32* src = reinterpret_cast<uint32*>(memory_src_);
744 E : uint32* dst = reinterpret_cast<uint32*>(memory_dst_);
745 :
746 : // Validate memory accesses.
747 E : for (int32 function = 0; function < arraysize(function_names); ++function) {
748 : check_access_fn =
749 E : ::GetProcAddress(asan_rtl_, function_names[function]);
750 E : ASSERT_TRUE(check_access_fn != NULL);
751 :
752 : ExpectSpecialMemoryErrorIsDetected(false, &dst[memory_length_ - 1],
753 : &src[memory_length_ - 1], memory_length_,
754 E : HeapProxy::UNKNOWN_BAD_ACCESS);
755 E : }
756 :
757 : // Reset direction flag to forward.
758 E : direction_flag_forward = true;
759 :
760 E : FreeMemoryBuffers();
761 E : }
762 :
763 E : TEST_F(AsanRtlTest, AsanSpecialInstructionCheckZeroAccess) {
764 : static const char* function_names[] = {
765 : "asan_check_repz_1_byte_movs_access",
766 : "asan_check_repz_1_byte_cmps_access",
767 : "asan_check_repz_1_byte_stos_access",
768 : "asan_check_repz_2_byte_movs_access",
769 : "asan_check_repz_2_byte_cmps_access",
770 : "asan_check_repz_2_byte_stos_access",
771 : "asan_check_repz_4_byte_movs_access",
772 : "asan_check_repz_4_byte_cmps_access",
773 : "asan_check_repz_4_byte_stos_access"
774 : };
775 :
776 : // Setup the callback to detect invalid accesses.
777 E : SetCallBackFunction(&AsanErrorCallback);
778 :
779 : // Allocate memory space.
780 E : AllocMemoryBuffers(kAllocSize, sizeof(uint32));
781 E : uint32* src = reinterpret_cast<uint32*>(memory_src_);
782 E : uint32* dst = reinterpret_cast<uint32*>(memory_dst_);
783 :
784 : // Validate memory accesses.
785 E : for (int32 function = 0; function < arraysize(function_names); ++function) {
786 : check_access_fn =
787 E : ::GetProcAddress(asan_rtl_, function_names[function]);
788 E : ASSERT_TRUE(check_access_fn != NULL);
789 :
790 : // A prefixed instruction with a count of zero do not have side effects.
791 : ExpectSpecialMemoryErrorIsDetected(false, &dst[-1], &src[-1], 0,
792 E : HeapProxy::UNKNOWN_BAD_ACCESS);
793 E : }
794 :
795 E : FreeMemoryBuffers();
796 E : }
797 :
798 E : TEST_F(AsanRtlTest, AsanSpecialInstructionCheckShortcutAccess) {
799 : static const char* function_names[] = {
800 : "asan_check_repz_1_byte_cmps_access",
801 : "asan_check_repz_2_byte_cmps_access",
802 : "asan_check_repz_4_byte_cmps_access",
803 : };
804 :
805 : // Setup the callback to detect invalid accesses.
806 E : SetCallBackFunction(&AsanErrorCallback);
807 :
808 : // Allocate memory space.
809 E : AllocMemoryBuffers(kAllocSize, sizeof(uint32));
810 E : uint32* src = reinterpret_cast<uint32*>(memory_src_);
811 E : uint32* dst = reinterpret_cast<uint32*>(memory_dst_);
812 :
813 E : src[1] = 0x12345667;
814 :
815 : // Validate memory accesses.
816 E : for (int32 function = 0; function < arraysize(function_names); ++function) {
817 : check_access_fn =
818 E : ::GetProcAddress(asan_rtl_, function_names[function]);
819 E : ASSERT_TRUE(check_access_fn != NULL);
820 :
821 : // Compare instruction stop their execution when values differ.
822 : ExpectSpecialMemoryErrorIsDetected(false, &dst[0], &src[0],
823 E : memory_length_ + 1, HeapProxy::UNKNOWN_BAD_ACCESS);
824 E : }
825 :
826 E : FreeMemoryBuffers();
827 E : }
828 :
829 : } // namespace asan
830 : } // namespace agent
|