1 : // Copyright 2013 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 : #ifndef SYZYGY_AGENT_ASAN_UNITTEST_UTIL_H_
16 : #define SYZYGY_AGENT_ASAN_UNITTEST_UTIL_H_
17 :
18 : #include <string>
19 : #include <utility>
20 : #include <vector>
21 :
22 : #include "base/bind.h"
23 : #include "base/files/file_util.h"
24 : #include "base/files/scoped_temp_dir.h"
25 : #include "base/memory/ref_counted.h"
26 : #include "base/strings/string_piece.h"
27 : #include "gmock/gmock.h"
28 : #include "gtest/gtest.h"
29 : #include "syzygy/agent/asan/block.h"
30 : #include "syzygy/agent/asan/error_info.h"
31 : #include "syzygy/agent/asan/heap.h"
32 : #include "syzygy/agent/asan/logger.h"
33 : #include "syzygy/agent/asan/memory_notifier.h"
34 : #include "syzygy/agent/asan/page_protection_helpers.h"
35 : #include "syzygy/agent/asan/runtime.h"
36 : #include "syzygy/agent/asan/shadow.h"
37 : #include "syzygy/agent/asan/stack_capture_cache.h"
38 : #include "syzygy/agent/asan/memory_notifiers/null_memory_notifier.h"
39 : #include "syzygy/agent/common/stack_capture.h"
40 : #include "syzygy/core/address.h"
41 : #include "syzygy/core/address_space.h"
42 : #include "syzygy/core/unittest_util.h"
43 : #include "syzygy/trace/agent_logger/agent_logger.h"
44 : #include "syzygy/trace/agent_logger/agent_logger_rpc_impl.h"
45 :
46 : namespace testing {
47 :
48 : using agent::asan::AsanErrorInfo;
49 : using agent::asan::memory_notifiers::NullMemoryNotifier;
50 : using agent::asan::Shadow;
51 : using agent::asan::StackCaptureCache;
52 :
53 : // The default name of the runtime library DLL.
54 : extern const wchar_t kSyzyAsanRtlDll[];
55 :
56 : // A unittest fixture that sets up a OnExceptionCallback for use with
57 : // BlockInfoFromMemory and BlockGetHeaderFromBody. This is the base fixture
58 : // class for all ASAN-related test fixtures declared in this file.
59 : class LenientOnExceptionCallbackTest : public testing::Test {
60 : public:
61 E : MOCK_METHOD1(OnExceptionCallback, void(EXCEPTION_POINTERS*));
62 :
63 E : void SetUp() override {
64 E : testing::Test::SetUp();
65 E : agent::asan::SetOnExceptionCallback(
66 : base::Bind(&LenientOnExceptionCallbackTest::OnExceptionCallback,
67 : base::Unretained(this)));
68 E : }
69 :
70 E : void TearDown() override {
71 E : agent::asan::ClearOnExceptionCallback();
72 E : testing::Test::TearDown();
73 E : }
74 : };
75 : typedef testing::StrictMock<LenientOnExceptionCallbackTest>
76 : OnExceptionCallbackTest;
77 :
78 : // A unittest fixture that ensures that an Asan logger instance is up and
79 : // running for the duration of the test. Output is captured to a file so that
80 : // its contents can be read after the test if necessary.
81 : class TestWithAsanLogger : public OnExceptionCallbackTest {
82 : public:
83 : TestWithAsanLogger();
84 :
85 : // @name testing::Test overrides.
86 : // @{
87 : void SetUp() override;
88 : void TearDown() override;
89 : // @}
90 :
91 : // @name Accessors.
92 : // @{
93 : const std::wstring& instance_id() const { return instance_id_; }
94 : const base::FilePath& log_file_path() const { return log_file_path_; }
95 : const base::FilePath& temp_dir() const { return temp_dir_.path(); }
96 : // @}
97 :
98 : bool LogContains(const base::StringPiece& message);
99 :
100 : // Delete the temporary file used for the logging and its directory.
101 : void DeleteTempFileAndDirectory();
102 :
103 : // Starts the logger process.
104 : void StartLogger();
105 :
106 : // Stops the logger process.
107 : void StopLogger();
108 :
109 : // Reset the log contents.
110 : void ResetLog();
111 :
112 : // Appends @p instance to the RPC logger instance environment variable.
113 : void AppendToLoggerEnv(const std::string &instance);
114 :
115 : private:
116 : // The instance ID used by the running logger instance.
117 : std::wstring instance_id_;
118 :
119 : // The path to the log file where the the logger instance will write.
120 : base::FilePath log_file_path_;
121 :
122 : // Status of the logger process.
123 : bool logger_running_;
124 :
125 : // A temporary directory into which the log file will be written.
126 : base::ScopedTempDir temp_dir_;
127 :
128 : // The contents of the log. These are read by calling LogContains.
129 : bool log_contents_read_;
130 : std::string log_contents_;
131 :
132 : // Value of the logger instance environment variable before SetUp.
133 : std::string old_logger_env_;
134 :
135 : // Redirection files for the logger.
136 : base::ScopedFILE logger_stdin_file_;
137 : base::ScopedFILE logger_stdout_file_;
138 : base::ScopedFILE logger_stderr_file_;
139 : };
140 :
141 : // Shorthand for discussing all the asan runtime functions.
142 : #define ASAN_RTL_FUNCTIONS(F) \
143 : F(WINAPI, HANDLE, GetProcessHeap, (), ()) \
144 : F(WINAPI, HANDLE, HeapCreate, \
145 : (DWORD options, SIZE_T initial_size, SIZE_T maximum_size), \
146 : (options, initial_size, maximum_size)) \
147 : F(WINAPI, BOOL, HeapDestroy, \
148 : (HANDLE heap), (heap)) \
149 : F(WINAPI, LPVOID, HeapAlloc, \
150 : (HANDLE heap, DWORD flags, SIZE_T bytes), (heap, flags, bytes)) \
151 : F(WINAPI, LPVOID, HeapReAlloc, \
152 : (HANDLE heap, DWORD flags, LPVOID mem, SIZE_T bytes), \
153 : (heap, flags, mem, bytes)) \
154 : F(WINAPI, BOOL, HeapFree, \
155 : (HANDLE heap, DWORD flags, LPVOID mem), (heap, flags, mem)) \
156 : F(WINAPI, SIZE_T, HeapSize, \
157 : (HANDLE heap, DWORD flags, LPCVOID mem), (heap, flags, mem)) \
158 : F(WINAPI, BOOL, HeapValidate, \
159 : (HANDLE heap, DWORD flags, LPCVOID mem), (heap, flags, mem)) \
160 : F(WINAPI, SIZE_T, HeapCompact, \
161 : (HANDLE heap, DWORD flags), (heap, flags)) \
162 : F(WINAPI, BOOL, HeapLock, (HANDLE heap), (heap)) \
163 : F(WINAPI, BOOL, HeapUnlock, (HANDLE heap), (heap)) \
164 : F(WINAPI, BOOL, HeapWalk, \
165 : (HANDLE heap, LPPROCESS_HEAP_ENTRY entry), (heap, entry)) \
166 : F(WINAPI, BOOL, HeapSetInformation, \
167 : (HANDLE heap, HEAP_INFORMATION_CLASS info_class, \
168 : PVOID info, SIZE_T info_length), \
169 : (heap, info_class, info, info_length)) \
170 : F(WINAPI, BOOL, HeapQueryInformation, \
171 : (HANDLE heap, HEAP_INFORMATION_CLASS info_class, \
172 : PVOID info, SIZE_T info_length, PSIZE_T return_length), \
173 : (heap, info_class, info, info_length, return_length)) \
174 : F(WINAPI, void, SetCallBack, \
175 : (void (*callback)(AsanErrorInfo* error_info)), \
176 : (callback)) \
177 : F(_cdecl, void*, memcpy, \
178 : (void* destination, const void* source, size_t num), \
179 : (destination, source, num)) \
180 : F(_cdecl, void*, memmove, \
181 : (void* destination, const void* source, size_t num), \
182 : (destination, source, num)) \
183 : F(_cdecl, void*, memset, (void* ptr, int value, size_t num), \
184 : (ptr, value, num)) \
185 : F(_cdecl, const void*, memchr, (const void* ptr, int value, size_t num), \
186 : (ptr, value, num)) \
187 : F(_cdecl, size_t, strcspn, (const char* str1, const char* str2), \
188 : (str1, str2)) \
189 : F(_cdecl, size_t, strlen, (const char* str), (str)) \
190 : F(_cdecl, size_t, strnlen, (const char* str, size_t max_len), \
191 : (str, max_len)) \
192 : F(_cdecl, const char*, strrchr, (const char* str, int character), \
193 : (str, character)) \
194 : F(_cdecl, const wchar_t*, wcsrchr, (const wchar_t* str, int character), \
195 : (str, character)) \
196 : F(_cdecl, const wchar_t*, wcschr, (const wchar_t* str, int character), \
197 : (str, character)) \
198 : F(_cdecl, int, strcmp, (const char* str1, const char* str2), \
199 : (str1, str2)) \
200 : F(_cdecl, const char*, strpbrk, (const char* str1, const char* str2), \
201 : (str1, str2)) \
202 : F(_cdecl, const char*, strstr, (const char* str1, const char* str2), \
203 : (str1, str2)) \
204 : F(_cdecl, size_t, wcsnlen, (const wchar_t* str, size_t max_len), \
205 : (str, max_len)) \
206 : F(_cdecl, const wchar_t*, wcsstr, (const wchar_t* str1, \
207 : const wchar_t* str2), (str1, str2)) \
208 : F(_cdecl, size_t, strspn, (const char* str1, const char* str2), \
209 : (str1, str2)) \
210 : F(_cdecl, char*, strncpy, \
211 : (char* destination, const char* source, size_t num), \
212 : (destination, source, num)) \
213 : F(_cdecl, char*, strncat, \
214 : (char* destination, const char* source, size_t num), \
215 : (destination, source, num)) \
216 : F(WINAPI, BOOL, ReadFile, \
217 : (HANDLE file_handle, LPVOID buffer, DWORD bytes_to_read, \
218 : LPDWORD bytes_read, LPOVERLAPPED overlapped), \
219 : (file_handle, buffer, bytes_to_read, bytes_read, overlapped)) \
220 : F(WINAPI, BOOL, WriteFile, \
221 : (HANDLE file_handle, LPCVOID buffer, DWORD bytes_to_write, \
222 : LPDWORD bytes_written, LPOVERLAPPED overlapped), \
223 : (file_handle, buffer, bytes_to_write, bytes_written, overlapped)) \
224 : F(_cdecl, void, SetInterceptorCallback, (void (*callback)()), (callback)) \
225 : F(WINAPI, agent::asan::AsanRuntime*, GetActiveRuntime, (), ()) \
226 : F(WINAPI, void, SetAllocationFilterFlag, (), ()) \
227 : F(WINAPI, void, ClearAllocationFilterFlag, (), ())
228 :
229 : // Declare pointer types for the intercepted functions.
230 : #define DECLARE_ASAN_FUNCTION_PTR(convention, ret, name, args, argnames) \
231 : typedef ret (convention* name##FunctionPtr)args;
232 : ASAN_RTL_FUNCTIONS(DECLARE_ASAN_FUNCTION_PTR)
233 : #undef DECLARE_ASAN_FUNCTION_PTR
234 :
235 : class TestAsanRtl : public testing::TestWithAsanLogger {
236 : public:
237 E : TestAsanRtl() : asan_rtl_(NULL), heap_(NULL) {
238 E : }
239 :
240 E : void SetUp() override {
241 E : testing::TestWithAsanLogger::SetUp();
242 :
243 : // Load the Asan runtime library.
244 : base::FilePath asan_rtl_path =
245 E : testing::GetExeRelativePath(L"syzyasan_rtl.dll");
246 E : asan_rtl_ = ::LoadLibrary(asan_rtl_path.value().c_str());
247 E : ASSERT_TRUE(asan_rtl_ != NULL);
248 :
249 : // Load all the functions and assert that we find them.
250 : #define LOAD_ASAN_FUNCTION(convention, ret, name, args, argnames) \
251 : name##Function = reinterpret_cast<name##FunctionPtr>( \
252 : ::GetProcAddress(asan_rtl_, "asan_" #name)); \
253 : ASSERT_TRUE(name##Function != NULL);
254 :
255 E : ASAN_RTL_FUNCTIONS(LOAD_ASAN_FUNCTION)
256 :
257 : #undef LOAD_ASAN_FUNCTION
258 :
259 E : heap_ = HeapCreateFunction(0, 0, 0);
260 E : ASSERT_TRUE(heap_ != NULL);
261 :
262 E : agent::asan::AsanRuntime* runtime = GetActiveRuntimeFunction();
263 E : ASSERT_NE(reinterpret_cast<agent::asan::AsanRuntime*>(NULL), runtime);
264 : // Disable the heap checking as this really slows down the unittests.
265 E : runtime->params().check_heap_on_failure = false;
266 E : }
267 :
268 E : void TearDown() override {
269 E : if (heap_ != NULL) {
270 E : HeapDestroyFunction(heap_);
271 E : heap_ = NULL;
272 : }
273 :
274 E : if (asan_rtl_ != NULL) {
275 E : ::FreeLibrary(asan_rtl_);
276 E : asan_rtl_ = NULL;
277 : }
278 :
279 E : testing::TestWithAsanLogger::TearDown();
280 E : }
281 :
282 E : HANDLE heap() { return heap_; }
283 :
284 : // Declare pointers to intercepted functions.
285 : #define DECLARE_FUNCTION_PTR_VARIABLE(convention, ret, name, args, argnames) \
286 : static name##FunctionPtr name##Function;
287 : ASAN_RTL_FUNCTIONS(DECLARE_FUNCTION_PTR_VARIABLE)
288 : #undef DECLARE_FUNCTION_PTR_VARIABLE
289 :
290 : // Define versions of all of the functions that expect an error to be thrown
291 : // by the AsanErrorCallback, and in turn raise an exception if the underlying
292 : // function didn't fail.
293 : #define DECLARE_FAILING_FUNCTION(convention, ret, name, args, argnames) \
294 : static void name##FunctionFailing args;
295 : ASAN_RTL_FUNCTIONS(DECLARE_FAILING_FUNCTION)
296 : #undef DECLARE_FAILING_FUNCTION
297 :
298 : protected:
299 : // The AsanAsan runtime module to test.
300 : HMODULE asan_rtl_;
301 :
302 : // Scratch heap handle valid from SetUp to TearDown.
303 : HANDLE heap_;
304 : };
305 :
306 : // A helper struct to be passed as a destructor of Asan scoped allocation.
307 : struct AsanDeleteHelper {
308 E : explicit AsanDeleteHelper(TestAsanRtl* asan_rtl)
309 E : : asan_rtl_(asan_rtl) {
310 E : }
311 :
312 E : void operator()(void* ptr) {
313 E : asan_rtl_->HeapFreeFunction(asan_rtl_->heap(), 0, ptr);
314 E : }
315 : TestAsanRtl* asan_rtl_;
316 : };
317 :
318 : // A std::unique_ptr specialization for the Asan allocations.
319 : template <typename T>
320 : class ScopedAsanAlloc : public std::unique_ptr<T, AsanDeleteHelper> {
321 : public:
322 : explicit ScopedAsanAlloc(TestAsanRtl* asan_rtl)
323 : : std::unique_ptr<T, AsanDeleteHelper>(NULL, AsanDeleteHelper(asan_rtl)) {
324 : }
325 :
326 : ScopedAsanAlloc(TestAsanRtl* asan_rtl, size_t size)
327 E : : std::unique_ptr<T, AsanDeleteHelper>(NULL, AsanDeleteHelper(asan_rtl)) {
328 E : Allocate(asan_rtl, size);
329 E : }
330 :
331 : ScopedAsanAlloc(TestAsanRtl* asan_rtl, size_t size, const T* value)
332 E : : std::unique_ptr<T, AsanDeleteHelper>(NULL, AsanDeleteHelper(asan_rtl)) {
333 E : Allocate(asan_rtl, size);
334 E : ::memcpy(get(), value, size * sizeof(T));
335 E : }
336 :
337 : template <typename T2>
338 E : T2* GetAs() {
339 E : return reinterpret_cast<T2*>(get());
340 E : }
341 :
342 E : void Allocate(TestAsanRtl* asan_rtl, size_t size) {
343 E : ASSERT_TRUE(asan_rtl != NULL);
344 E : reset(reinterpret_cast<T*>(
345 : asan_rtl->HeapAllocFunction(asan_rtl->heap(), 0, size * sizeof(T))));
346 E : ::memset(get(), 0, size * sizeof(T));
347 E : }
348 :
349 : T operator[](int i) const {
350 : CHECK(get() != NULL);
351 : return get()[i];
352 : }
353 :
354 E : T& operator[](int i) {
355 E : CHECK(get() != NULL);
356 E : return get()[i];
357 E : }
358 : };
359 :
360 : // A unittest fixture that initializes an Asan runtime instance.
361 : class TestWithAsanRuntime : public OnExceptionCallbackTest {
362 : public:
363 E : TestWithAsanRuntime() {
364 E : runtime_ = new agent::asan::AsanRuntime();
365 E : owns_runtime_ = true;
366 E : }
367 :
368 E : explicit TestWithAsanRuntime(agent::asan::AsanRuntime* runtime)
369 E : : runtime_(runtime), owns_runtime_(false) {
370 E : CHECK_NE(reinterpret_cast<agent::asan::AsanRuntime*>(NULL), runtime_);
371 E : }
372 :
373 E : ~TestWithAsanRuntime() {
374 E : CHECK_NE(reinterpret_cast<agent::asan::AsanRuntime*>(NULL), runtime_);
375 E : if (owns_runtime_)
376 E : delete runtime_;
377 E : runtime_ = NULL;
378 E : }
379 :
380 E : void SetUp() override {
381 E : CHECK_NE(reinterpret_cast<agent::asan::AsanRuntime*>(NULL), runtime_);
382 E : testing::Test::SetUp();
383 E : runtime_->SetUp(L"");
384 E : }
385 :
386 E : void TearDown() override {
387 E : CHECK_NE(reinterpret_cast<agent::asan::AsanRuntime*>(NULL), runtime_);
388 E : runtime_->TearDown();
389 E : testing::Test::TearDown();
390 E : }
391 :
392 : protected:
393 : // The runtime instance used by the tests.
394 : agent::asan::AsanRuntime* runtime_;
395 :
396 : // Indicates if we own the runtime instance.
397 : bool owns_runtime_;
398 : };
399 :
400 : // A unittest fixture to test the bookkeeping functions.
401 : struct FakeAsanBlock {
402 : static const size_t kMaxAlignmentLog = 13;
403 : static const size_t kMaxAlignment = 1 << kMaxAlignmentLog;
404 : // If we want to test the alignments up to 4096 we need a buffer of at least
405 : // 3 * 4096 bytes:
406 : // +--- 0 <= size < 4096 bytes---+---4096 bytes---+--4096 bytes--+
407 : // ^buffer ^aligned_buffer ^user_pointer
408 : static const size_t kBufferSize = 3 * kMaxAlignment;
409 : static const uint8_t kBufferHeaderValue = 0xAE;
410 : static const uint8_t kBufferTrailerValue = 0xEA;
411 :
412 : FakeAsanBlock(Shadow* shadow,
413 : size_t alloc_alignment_log,
414 : StackCaptureCache* stack_cache);
415 :
416 : ~FakeAsanBlock();
417 :
418 : // Initialize an Asan block in the buffer.
419 : // @param alloc_size The user size of the Asan block.
420 : // @returns true on success, false otherwise.
421 : bool InitializeBlock(size_t alloc_size);
422 :
423 : // Ensures that this block has a valid block header.
424 : bool TestBlockMetadata();
425 :
426 : // Mark the current Asan block as quarantined.
427 : bool MarkBlockAsQuarantinedImpl(bool flood_filled);
428 :
429 : // Mark the current Asan block as quarantined.
430 : bool MarkBlockAsQuarantined();
431 :
432 : // Mark the current Asan block as quarantined and flooded.
433 : bool MarkBlockAsQuarantinedFlooded();
434 :
435 : // The buffer we use internally.
436 : uint8_t buffer[kBufferSize];
437 :
438 : // The information about the block once it has been initialized.
439 : agent::asan::BlockInfo block_info;
440 :
441 : // The alignment of the current allocation.
442 : size_t alloc_alignment;
443 : size_t alloc_alignment_log;
444 :
445 : // The sizes of the different sub-structures in the buffer.
446 : size_t buffer_header_size;
447 : size_t buffer_trailer_size;
448 :
449 : // The pointers to the different sub-structures in the buffer.
450 : uint8_t* buffer_align_begin;
451 :
452 : // Indicate if the buffer has been initialized.
453 : bool is_initialized;
454 :
455 : // The shadow memory that will be modified.
456 : Shadow* shadow_;
457 :
458 : // The cache that will store the stack traces of this block.
459 : StackCaptureCache* stack_cache;
460 : };
461 :
462 : // A mock memory notifier. Useful when testing objects that have a memory
463 : // notifier dependency.
464 : class MockMemoryNotifier : public agent::asan::MemoryNotifierInterface {
465 : public:
466 : // Constructor.
467 E : MockMemoryNotifier() { }
468 :
469 : // Virtual destructor.
470 E : virtual ~MockMemoryNotifier() { }
471 :
472 : // @name MemoryNotifierInterface implementation.
473 : // @{
474 E : MOCK_METHOD2(NotifyInternalUse, void(const void*, size_t));
475 E : MOCK_METHOD2(NotifyFutureHeapUse, void(const void*, size_t));
476 E : MOCK_METHOD2(NotifyReturnedToOS, void(const void*, size_t));
477 : // @}
478 :
479 : private:
480 : DISALLOW_COPY_AND_ASSIGN(MockMemoryNotifier);
481 : };
482 :
483 : // A mock HeapInterface.
484 : class LenientMockHeap : public agent::asan::HeapInterface {
485 : public:
486 E : LenientMockHeap() { }
487 E : virtual ~LenientMockHeap() { }
488 i : MOCK_CONST_METHOD0(GetHeapType, agent::asan::HeapType());
489 E : MOCK_CONST_METHOD0(GetHeapFeatures, uint32_t());
490 E : MOCK_METHOD1(Allocate, void*(size_t));
491 E : MOCK_METHOD1(Free, bool(void*));
492 i : MOCK_METHOD1(IsAllocated, bool(const void*));
493 i : MOCK_METHOD1(GetAllocationSize, size_t(const void*));
494 i : MOCK_METHOD0(Lock, void());
495 i : MOCK_METHOD0(Unlock, void());
496 i : MOCK_METHOD0(TryLock, bool());
497 : };
498 : typedef testing::StrictMock<LenientMockHeap> MockHeap;
499 :
500 : typedef std::vector<agent::asan::AsanBlockInfo> AsanBlockInfoVector;
501 : typedef std::pair<agent::asan::AsanCorruptBlockRange, AsanBlockInfoVector>
502 : CorruptRangeInfo;
503 : typedef std::vector<CorruptRangeInfo> CorruptRangeVector;
504 :
505 : // A helper for testing SyzyAsan memory accessor instrumentation functions.
506 : class MemoryAccessorTester {
507 : public:
508 : typedef agent::asan::BadAccessKind BadAccessKind;
509 :
510 : enum IgnoreFlags {
511 : IGNORE_FLAGS
512 : };
513 : MemoryAccessorTester();
514 : explicit MemoryAccessorTester(IgnoreFlags ignore_flags);
515 : ~MemoryAccessorTester();
516 :
517 : // Checks that @p access_fn doesn't raise exceptions on access checking
518 : // @p ptr, and that @p access_fn doesn't modify any registers or flags
519 : // when executed.
520 : void CheckAccessAndCompareContexts(FARPROC access_fn, void* ptr);
521 :
522 : // Checks that @p access_fn generates @p bad_access_type on checking @p ptr.
523 : void AssertMemoryErrorIsDetected(
524 : FARPROC access_fn, void* ptr, BadAccessKind bad_access_type);
525 :
526 : enum StringOperationDirection {
527 : DIRECTION_FORWARD,
528 : DIRECTION_BACKWARD
529 : };
530 : // Checks that @p access_fn doesn't raise exceptions on access checking
531 : // for a given @p direction, @p src, @p dst and @p len.
532 : void CheckSpecialAccessAndCompareContexts(
533 : FARPROC access_fn, StringOperationDirection direction,
534 : void* dst, void* src, int len);
535 :
536 : // Checks that @p access_fn generates @p bad_access_type on access checking
537 : // for a given @p direction, @p src, @p dst and @p len.
538 : void ExpectSpecialMemoryErrorIsDetected(FARPROC access_fn,
539 : StringOperationDirection direction,
540 : bool expect_error,
541 : void* dst,
542 : void* src,
543 : int32_t length,
544 : BadAccessKind bad_access_type);
545 :
546 : static void AsanErrorCallback(AsanErrorInfo* error_info);
547 :
548 E : void set_expected_error_type(BadAccessKind expected) {
549 E : expected_error_type_ = expected;
550 E : }
551 E : bool memory_error_detected() const { return memory_error_detected_; }
552 E : void set_memory_error_detected(bool memory_error_detected) {
553 E : memory_error_detected_ = memory_error_detected;
554 E : }
555 :
556 E : const AsanErrorInfo& last_error_info() const { return last_error_info_; }
557 E : const CorruptRangeVector& last_corrupt_ranges() const {
558 E : return last_corrupt_ranges_;
559 E : }
560 :
561 : private:
562 : void Initialize();
563 : void AsanErrorCallbackImpl(AsanErrorInfo* error_info);
564 :
565 : // This will be used in the asan callback to ensure that we detect the right
566 : // error.
567 : BadAccessKind expected_error_type_;
568 : // A flag used in asan callback to ensure that a memory error has been
569 : // detected.
570 : bool memory_error_detected_;
571 :
572 : // Indicates whether to ignore changes to the flags register.
573 : bool ignore_flags_;
574 :
575 : // The pre- and post-invocation contexts.
576 : CONTEXT context_before_hook_;
577 : CONTEXT context_after_hook_;
578 : // Context captured on error.
579 : CONTEXT error_context_;
580 :
581 : // The information about the last error.
582 : AsanErrorInfo last_error_info_;
583 : CorruptRangeVector last_corrupt_ranges_;
584 :
585 : // There shall be only one!
586 : static MemoryAccessorTester* instance_;
587 : };
588 :
589 : // A fixture class for testing memory interceptors.
590 : class TestMemoryInterceptors : public TestWithAsanLogger {
591 : public:
592 : // Redefine some enums for local use.
593 : enum AccessMode {
594 : AsanReadAccess = agent::asan::ASAN_READ_ACCESS,
595 : AsanWriteAccess = agent::asan::ASAN_WRITE_ACCESS,
596 : AsanUnknownAccess = agent::asan::ASAN_UNKNOWN_ACCESS,
597 : };
598 :
599 : struct InterceptFunction {
600 : void(*function)();
601 : size_t size;
602 : };
603 :
604 : struct StringInterceptFunction {
605 : void(*function)();
606 : size_t size;
607 : AccessMode dst_access_mode;
608 : AccessMode src_access_mode;
609 : bool uses_counter;
610 : };
611 :
612 : static const bool kCounterInit_ecx = true;
613 : static const bool kCounterInit_1 = false;
614 :
615 : TestMemoryInterceptors();
616 : void SetUp() override;
617 : void TearDown() override;
618 :
619 : template <size_t N>
620 E : void TestValidAccess(const InterceptFunction (&fns)[N]) {
621 E : TestValidAccess(fns, N);
622 E : }
623 : template <size_t N>
624 E : void TestValidAccessIgnoreFlags(const InterceptFunction (&fns)[N]) {
625 E : TestValidAccessIgnoreFlags(fns, N);
626 E : }
627 : template <size_t N>
628 E : void TestOverrunAccess(const InterceptFunction (&fns)[N]) {
629 E : TestOverrunAccess(fns, N);
630 E : }
631 : template <size_t N>
632 E : void TestOverrunAccessIgnoreFlags(const InterceptFunction (&fns)[N]) {
633 E : TestOverrunAccessIgnoreFlags(fns, N);
634 E : }
635 : template <size_t N>
636 E : void TestUnderrunAccess(const InterceptFunction (&fns)[N]) {
637 E : TestUnderrunAccess(fns, N);
638 E : }
639 : template <size_t N>
640 E : void TestUnderrunAccessIgnoreFlags(const InterceptFunction (&fns)[N]) {
641 E : TestUnderrunAccessIgnoreFlags(fns, N);
642 E : }
643 : template <size_t N>
644 E : void TestStringValidAccess(const StringInterceptFunction (&fns)[N]) {
645 E : TestStringValidAccess(fns, N);
646 E : }
647 : template <size_t N>
648 E : void TestStringOverrunAccess(const StringInterceptFunction (&fns)[N]) {
649 E : TestStringOverrunAccess(fns, N);
650 E : }
651 :
652 : protected:
653 : void TestValidAccess(const InterceptFunction* fns, size_t num_fns);
654 : void TestValidAccessIgnoreFlags(const InterceptFunction* fns,
655 : size_t num_fns);
656 : void TestOverrunAccess(const InterceptFunction* fns, size_t num_fns);
657 : void TestOverrunAccessIgnoreFlags(const InterceptFunction* fns,
658 : size_t num_fns);
659 : void TestUnderrunAccess(const InterceptFunction* fns, size_t num_fns);
660 : void TestUnderrunAccessIgnoreFlags(const InterceptFunction* fns,
661 : size_t num_fns);
662 : void TestStringValidAccess(
663 : const StringInterceptFunction* fns, size_t num_fns);
664 : void TestStringOverrunAccess(
665 : const StringInterceptFunction* fns, size_t num_fns);
666 :
667 E : const size_t kAllocSize = 64;
668 :
669 : agent::asan::AsanRuntime asan_runtime_;
670 : HANDLE heap_;
671 :
672 : // Convenience allocs of kAllocSize. Valid from SetUp to TearDown.
673 : byte* src_;
674 : byte* dst_;
675 : };
676 :
677 : // A very lightweight dummy heap to be used in stress testing the
678 : // HeapAllocator. Lock and Unlock are noops, so this is not thread
679 : // safe.
680 : class DummyHeap : public agent::asan::HeapInterface {
681 : public:
682 E : virtual ~DummyHeap() { }
683 i : virtual agent::asan::HeapType GetHeapType() const {
684 i : return agent::asan::kUnknownHeapType;
685 i : }
686 E : virtual uint32_t GetHeapFeatures() const { return 0; }
687 E : virtual void* Allocate(size_t bytes) { return ::malloc(bytes); }
688 E : virtual bool Free(void* alloc) { ::free(alloc); return true; }
689 i : virtual bool IsAllocated(const void* alloc) { return false; }
690 i : virtual size_t GetAllocationSize(const void* alloc) { return 0; }
691 E : virtual void Lock() { return; }
692 E : virtual void Unlock() { return; }
693 E : virtual bool TryLock() { return true; }
694 : };
695 :
696 : // Test read and write access.
697 : // Use carefully, since it will try to overwrite the value at @p address with 0.
698 : // @returns true if the address is readable and writable, false otherwise.
699 : bool IsAccessible(void* address);
700 :
701 : // Test read and write access.
702 : // Use carefully, since it will try to overwrite the value at @p address with 0.
703 : // @returns true if the address is neither readable nor writable,
704 : // false otherwise.
705 : bool IsNotAccessible(void* address);
706 :
707 : // A scoped block access helper. Removes block protections when created via
708 : // BlockProtectNone, and restores them via BlockProtectAuto.
709 : // TODO(chrisha): Consider recording the fact the block protections on this
710 : // block are being blocked in some synchronous manner. This will prevent
711 : // the page protections from being added during the lifetime of this
712 : // object.
713 : class ScopedBlockAccess {
714 : public:
715 : // Constructor. Unprotects the provided block.
716 : // @param block_info The block whose protections are to be modified.
717 : // @parma shadow The shadow memory to be updated.
718 E : explicit ScopedBlockAccess(const agent::asan::BlockInfo& block_info,
719 : Shadow* shadow)
720 E : : block_info_(block_info), shadow_(shadow) {
721 E : BlockProtectNone(block_info_, shadow_);
722 E : }
723 :
724 : // Destructor. Restores protections on the provided block.
725 E : ~ScopedBlockAccess() { BlockProtectAuto(block_info_, shadow_); }
726 :
727 : private:
728 : const agent::asan::BlockInfo& block_info_;
729 : Shadow* shadow_;
730 : };
731 :
732 : // A debugging shadow class. This keeps extra details in the form of an address
733 : // space with stack traces. This makes it much easier to track down
734 : // inconsistencies in the shadow memory.
735 : class DebugShadow : public Shadow {
736 : public:
737 : using ShadowMarker = agent::asan::ShadowMarker;
738 :
739 : DebugShadow() : Shadow() {
740 : }
741 :
742 : explicit DebugShadow(size_t length)
743 : : Shadow(length) {
744 : }
745 :
746 : ~DebugShadow() override {
747 : // If the shadow has been properly used it will be completely empty by the
748 : // time it is torn down.
749 : CHECK(shadow_address_space_.empty());
750 : }
751 :
752 : protected:
753 : // @name Shadow implementation.
754 : // @{
755 : void SetShadowMemory(
756 : const void* address, size_t length, ShadowMarker marker) override;
757 : void GetPointerAndSizeImpl(void const** self, size_t* size) const override;
758 : // @}
759 :
760 : private:
761 : using StackCapture = agent::common::StackCapture;
762 :
763 : // Holds details about a given range of shadow memory. Persists the
764 : // original size of a region, even if it is subsequently fragmented.
765 : struct Metadata {
766 : const void* address;
767 : size_t size;
768 : ShadowMarker marker;
769 : StackCapture stack_capture;
770 :
771 : // Explicitly enable copy and assignment.
772 : Metadata();
773 : Metadata(const void* address, size_t size, ShadowMarker marker);
774 : Metadata(const Metadata& rhs);
775 : Metadata& operator=(const Metadata& rhs);
776 : };
777 : using ShadowAddressSpace =
778 : core::AddressSpace<uintptr_t, size_t, Metadata>;
779 : using Range = ShadowAddressSpace::Range;
780 :
781 : // Ensure that the given range has been cleared from the address-space,
782 : // readying it for a subsequent insertion.
783 : void ClearIntersection(const void* addr, size_t size);
784 :
785 : // An alternative view of shadow memory. Accessible regions are not
786 : // displayed. Neighboring regions of the same type are merged.
787 : ShadowAddressSpace shadow_address_space_;
788 : };
789 :
790 : } // namespace testing
791 :
792 : #endif // SYZYGY_AGENT_ASAN_UNITTEST_UTIL_H_
|