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 : agent::asan::SetOnExceptionCallback(
66 : base::Bind(&LenientOnExceptionCallbackTest::OnExceptionCallback,
67 E : 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, const char*, strrchr, (const char* str, int character), \
191 : (str, character)) \
192 : F(_cdecl, const wchar_t*, wcsrchr, (const wchar_t* str, int character), \
193 : (str, character)) \
194 : F(_cdecl, const wchar_t*, wcschr, (const wchar_t* str, int character), \
195 : (str, character)) \
196 : F(_cdecl, int, strcmp, (const char* str1, const char* str2), \
197 : (str1, str2)) \
198 : F(_cdecl, const char*, strpbrk, (const char* str1, const char* str2), \
199 : (str1, str2)) \
200 : F(_cdecl, const char*, strstr, (const char* str1, const char* str2), \
201 : (str1, str2)) \
202 : F(_cdecl, const wchar_t*, wcsstr, (const wchar_t* str1, \
203 : const wchar_t* str2), (str1, str2)) \
204 : F(_cdecl, size_t, strspn, (const char* str1, const char* str2), \
205 : (str1, str2)) \
206 : F(_cdecl, char*, strncpy, \
207 : (char* destination, const char* source, size_t num), \
208 : (destination, source, num)) \
209 : F(_cdecl, char*, strncat, \
210 : (char* destination, const char* source, size_t num), \
211 : (destination, source, num)) \
212 : F(WINAPI, BOOL, ReadFile, \
213 : (HANDLE file_handle, LPVOID buffer, DWORD bytes_to_read, \
214 : LPDWORD bytes_read, LPOVERLAPPED overlapped), \
215 : (file_handle, buffer, bytes_to_read, bytes_read, overlapped)) \
216 : F(WINAPI, BOOL, WriteFile, \
217 : (HANDLE file_handle, LPCVOID buffer, DWORD bytes_to_write, \
218 : LPDWORD bytes_written, LPOVERLAPPED overlapped), \
219 : (file_handle, buffer, bytes_to_write, bytes_written, overlapped)) \
220 : F(_cdecl, void, SetInterceptorCallback, (void (*callback)()), (callback)) \
221 : F(WINAPI, agent::asan::AsanRuntime*, GetActiveRuntime, (), ()) \
222 : F(WINAPI, void, SetAllocationFilterFlag, (), ()) \
223 : F(WINAPI, void, ClearAllocationFilterFlag, (), ())
224 :
225 : // Declare pointer types for the intercepted functions.
226 : #define DECLARE_ASAN_FUNCTION_PTR(convention, ret, name, args, argnames) \
227 : typedef ret (convention* name##FunctionPtr)args;
228 : ASAN_RTL_FUNCTIONS(DECLARE_ASAN_FUNCTION_PTR)
229 : #undef DECLARE_ASAN_FUNCTION_PTR
230 :
231 : class TestAsanRtl : public testing::TestWithAsanLogger {
232 : public:
233 E : TestAsanRtl() : asan_rtl_(NULL), heap_(NULL) {
234 E : }
235 :
236 E : void SetUp() override {
237 E : testing::TestWithAsanLogger::SetUp();
238 :
239 : // Load the Asan runtime library.
240 : base::FilePath asan_rtl_path =
241 E : testing::GetExeRelativePath(L"syzyasan_rtl.dll");
242 E : asan_rtl_ = ::LoadLibrary(asan_rtl_path.value().c_str());
243 E : ASSERT_TRUE(asan_rtl_ != NULL);
244 :
245 : // Load all the functions and assert that we find them.
246 : #define LOAD_ASAN_FUNCTION(convention, ret, name, args, argnames) \
247 : name##Function = reinterpret_cast<name##FunctionPtr>( \
248 : ::GetProcAddress(asan_rtl_, "asan_" #name)); \
249 : ASSERT_TRUE(name##Function != NULL);
250 :
251 E : ASAN_RTL_FUNCTIONS(LOAD_ASAN_FUNCTION)
252 :
253 : #undef LOAD_ASAN_FUNCTION
254 :
255 E : heap_ = HeapCreateFunction(0, 0, 0);
256 E : ASSERT_TRUE(heap_ != NULL);
257 :
258 E : agent::asan::AsanRuntime* runtime = GetActiveRuntimeFunction();
259 E : ASSERT_NE(reinterpret_cast<agent::asan::AsanRuntime*>(NULL), runtime);
260 : // Disable the heap checking as this really slows down the unittests.
261 E : runtime->params().check_heap_on_failure = false;
262 E : }
263 :
264 E : void TearDown() override {
265 E : if (heap_ != NULL) {
266 E : HeapDestroyFunction(heap_);
267 E : heap_ = NULL;
268 : }
269 :
270 E : if (asan_rtl_ != NULL) {
271 E : ::FreeLibrary(asan_rtl_);
272 E : asan_rtl_ = NULL;
273 : }
274 :
275 E : testing::TestWithAsanLogger::TearDown();
276 E : }
277 :
278 E : HANDLE heap() { return heap_; }
279 :
280 : // Declare pointers to intercepted functions.
281 : #define DECLARE_FUNCTION_PTR_VARIABLE(convention, ret, name, args, argnames) \
282 : static name##FunctionPtr name##Function;
283 : ASAN_RTL_FUNCTIONS(DECLARE_FUNCTION_PTR_VARIABLE)
284 : #undef DECLARE_FUNCTION_PTR_VARIABLE
285 :
286 : // Define versions of all of the functions that expect an error to be thrown
287 : // by the AsanErrorCallback, and in turn raise an exception if the underlying
288 : // function didn't fail.
289 : #define DECLARE_FAILING_FUNCTION(convention, ret, name, args, argnames) \
290 : static void name##FunctionFailing args;
291 : ASAN_RTL_FUNCTIONS(DECLARE_FAILING_FUNCTION)
292 : #undef DECLARE_FAILING_FUNCTION
293 :
294 : protected:
295 : // The AsanAsan runtime module to test.
296 : HMODULE asan_rtl_;
297 :
298 : // Scratch heap handle valid from SetUp to TearDown.
299 : HANDLE heap_;
300 : };
301 :
302 : // A helper struct to be passed as a destructor of Asan scoped allocation.
303 : struct AsanDeleteHelper {
304 E : explicit AsanDeleteHelper(TestAsanRtl* asan_rtl)
305 : : asan_rtl_(asan_rtl) {
306 E : }
307 :
308 E : void operator()(void* ptr) {
309 E : asan_rtl_->HeapFreeFunction(asan_rtl_->heap(), 0, ptr);
310 E : }
311 : TestAsanRtl* asan_rtl_;
312 : };
313 :
314 : // A scoped_ptr specialization for the Asan allocations.
315 : template <typename T>
316 : class ScopedAsanAlloc : public scoped_ptr<T, AsanDeleteHelper> {
317 : public:
318 : explicit ScopedAsanAlloc(TestAsanRtl* asan_rtl)
319 : : scoped_ptr(NULL, AsanDeleteHelper(asan_rtl)) {
320 : }
321 :
322 E : ScopedAsanAlloc(TestAsanRtl* asan_rtl, size_t size)
323 : : scoped_ptr(NULL, AsanDeleteHelper(asan_rtl)) {
324 E : Allocate(asan_rtl, size);
325 E : }
326 :
327 E : ScopedAsanAlloc(TestAsanRtl* asan_rtl, size_t size, const T* value)
328 : : scoped_ptr(NULL, AsanDeleteHelper(asan_rtl)) {
329 E : Allocate(asan_rtl, size);
330 E : ::memcpy(get(), value, size * sizeof(T));
331 E : }
332 :
333 : template <typename T2>
334 E : T2* GetAs() {
335 E : return reinterpret_cast<T2*>(get());
336 E : }
337 :
338 E : void Allocate(TestAsanRtl* asan_rtl, size_t size) {
339 E : ASSERT_TRUE(asan_rtl != NULL);
340 : reset(reinterpret_cast<T*>(
341 E : asan_rtl->HeapAllocFunction(asan_rtl->heap(), 0, size * sizeof(T))));
342 E : ::memset(get(), 0, size * sizeof(T));
343 E : }
344 :
345 : T operator[](int i) const {
346 : CHECK(get() != NULL);
347 : return get()[i];
348 : }
349 :
350 E : T& operator[](int i) {
351 E : CHECK(get() != NULL);
352 E : return get()[i];
353 E : }
354 : };
355 :
356 : // A unittest fixture that initializes an Asan runtime instance.
357 : class TestWithAsanRuntime : public OnExceptionCallbackTest {
358 : public:
359 E : TestWithAsanRuntime() {
360 E : runtime_ = new agent::asan::AsanRuntime();
361 E : owns_runtime_ = true;
362 E : }
363 :
364 E : explicit TestWithAsanRuntime(agent::asan::AsanRuntime* runtime)
365 : : runtime_(runtime), owns_runtime_(false) {
366 E : CHECK_NE(reinterpret_cast<agent::asan::AsanRuntime*>(NULL), runtime_);
367 E : }
368 :
369 E : ~TestWithAsanRuntime() {
370 E : CHECK_NE(reinterpret_cast<agent::asan::AsanRuntime*>(NULL), runtime_);
371 E : if (owns_runtime_)
372 E : delete runtime_;
373 E : runtime_ = NULL;
374 E : }
375 :
376 E : virtual void SetUp() override {
377 E : CHECK_NE(reinterpret_cast<agent::asan::AsanRuntime*>(NULL), runtime_);
378 E : testing::Test::SetUp();
379 E : runtime_->SetUp(L"");
380 E : }
381 :
382 E : virtual void TearDown() override {
383 E : CHECK_NE(reinterpret_cast<agent::asan::AsanRuntime*>(NULL), runtime_);
384 E : runtime_->TearDown();
385 E : testing::Test::TearDown();
386 E : }
387 :
388 : protected:
389 : // The runtime instance used by the tests.
390 : agent::asan::AsanRuntime* runtime_;
391 :
392 : // Indicates if we own the runtime instance.
393 : bool owns_runtime_;
394 : };
395 :
396 : // A unittest fixture to test the bookkeeping functions.
397 : struct FakeAsanBlock {
398 : static const size_t kMaxAlignmentLog = 13;
399 : static const size_t kMaxAlignment = 1 << kMaxAlignmentLog;
400 : // If we want to test the alignments up to 4096 we need a buffer of at least
401 : // 3 * 4096 bytes:
402 : // +--- 0 <= size < 4096 bytes---+---4096 bytes---+--4096 bytes--+
403 : // ^buffer ^aligned_buffer ^user_pointer
404 : static const size_t kBufferSize = 3 * kMaxAlignment;
405 : static const uint8 kBufferHeaderValue = 0xAE;
406 : static const uint8 kBufferTrailerValue = 0xEA;
407 :
408 : FakeAsanBlock(Shadow* shadow,
409 : size_t alloc_alignment_log,
410 : StackCaptureCache* stack_cache);
411 :
412 : ~FakeAsanBlock();
413 :
414 : // Initialize an Asan block in the buffer.
415 : // @param alloc_size The user size of the Asan block.
416 : // @returns true on success, false otherwise.
417 : bool InitializeBlock(size_t alloc_size);
418 :
419 : // Ensures that this block has a valid block header.
420 : bool TestBlockMetadata();
421 :
422 : // Mark the current Asan block as quarantined.
423 : bool MarkBlockAsQuarantinedImpl(bool flood_filled);
424 :
425 : // Mark the current Asan block as quarantined.
426 : bool MarkBlockAsQuarantined();
427 :
428 : // Mark the current Asan block as quarantined and flooded.
429 : bool MarkBlockAsQuarantinedFlooded();
430 :
431 : // The buffer we use internally.
432 : uint8 buffer[kBufferSize];
433 :
434 : // The information about the block once it has been initialized.
435 : agent::asan::BlockInfo block_info;
436 :
437 : // The alignment of the current allocation.
438 : size_t alloc_alignment;
439 : size_t alloc_alignment_log;
440 :
441 : // The sizes of the different sub-structures in the buffer.
442 : size_t buffer_header_size;
443 : size_t buffer_trailer_size;
444 :
445 : // The pointers to the different sub-structures in the buffer.
446 : uint8* buffer_align_begin;
447 :
448 : // Indicate if the buffer has been initialized.
449 : bool is_initialized;
450 :
451 : // The shadow memory that will be modified.
452 : Shadow* shadow_;
453 :
454 : // The cache that will store the stack traces of this block.
455 : StackCaptureCache* stack_cache;
456 : };
457 :
458 : // A mock memory notifier. Useful when testing objects that have a memory
459 : // notifier dependency.
460 : class MockMemoryNotifier : public agent::asan::MemoryNotifierInterface {
461 : public:
462 : // Constructor.
463 E : MockMemoryNotifier() { }
464 :
465 : // Virtual destructor.
466 E : virtual ~MockMemoryNotifier() { }
467 :
468 : // @name MemoryNotifierInterface implementation.
469 : // @{
470 E : MOCK_METHOD2(NotifyInternalUse, void(const void*, size_t));
471 E : MOCK_METHOD2(NotifyFutureHeapUse, void(const void*, size_t));
472 E : MOCK_METHOD2(NotifyReturnedToOS, void(const void*, size_t));
473 : // @}
474 :
475 : private:
476 : DISALLOW_COPY_AND_ASSIGN(MockMemoryNotifier);
477 : };
478 :
479 : // A mock HeapInterface.
480 : class LenientMockHeap : public agent::asan::HeapInterface {
481 : public:
482 E : LenientMockHeap() { }
483 E : virtual ~LenientMockHeap() { }
484 i : MOCK_CONST_METHOD0(GetHeapType, agent::asan::HeapType());
485 E : MOCK_CONST_METHOD0(GetHeapFeatures, uint32());
486 E : MOCK_METHOD1(Allocate, void*(size_t));
487 E : MOCK_METHOD1(Free, bool(void*));
488 i : MOCK_METHOD1(IsAllocated, bool(const void*));
489 i : MOCK_METHOD1(GetAllocationSize, size_t(const void*));
490 i : MOCK_METHOD0(Lock, void());
491 i : MOCK_METHOD0(Unlock, void());
492 i : MOCK_METHOD0(TryLock, bool());
493 : };
494 : typedef testing::StrictMock<LenientMockHeap> MockHeap;
495 :
496 : typedef std::vector<agent::asan::AsanBlockInfo> AsanBlockInfoVector;
497 : typedef std::pair<agent::asan::AsanCorruptBlockRange, AsanBlockInfoVector>
498 : CorruptRangeInfo;
499 : typedef std::vector<CorruptRangeInfo> CorruptRangeVector;
500 :
501 : // A helper for testing SyzyAsan memory accessor instrumentation functions.
502 : class MemoryAccessorTester {
503 : public:
504 : typedef agent::asan::BadAccessKind BadAccessKind;
505 :
506 : enum IgnoreFlags {
507 : IGNORE_FLAGS
508 : };
509 : MemoryAccessorTester();
510 : explicit MemoryAccessorTester(IgnoreFlags ignore_flags);
511 : ~MemoryAccessorTester();
512 :
513 : // Checks that @p access_fn doesn't raise exceptions on access checking
514 : // @p ptr, and that @p access_fn doesn't modify any registers or flags
515 : // when executed.
516 : void CheckAccessAndCompareContexts(FARPROC access_fn, void* ptr);
517 :
518 : // Checks that @p access_fn generates @p bad_access_type on checking @p ptr.
519 : void AssertMemoryErrorIsDetected(
520 : FARPROC access_fn, void* ptr, BadAccessKind bad_access_type);
521 :
522 : enum StringOperationDirection {
523 : DIRECTION_FORWARD,
524 : DIRECTION_BACKWARD
525 : };
526 : // Checks that @p access_fn doesn't raise exceptions on access checking
527 : // for a given @p direction, @p src, @p dst and @p len.
528 : void CheckSpecialAccessAndCompareContexts(
529 : FARPROC access_fn, StringOperationDirection direction,
530 : void* dst, void* src, int len);
531 :
532 : // Checks that @p access_fn generates @p bad_access_type on access checking
533 : // for a given @p direction, @p src, @p dst and @p len.
534 : void ExpectSpecialMemoryErrorIsDetected(
535 : FARPROC access_fn, StringOperationDirection direction,
536 : bool expect_error, void* dst, void* src, int32 length,
537 : BadAccessKind bad_access_type);
538 :
539 : static void AsanErrorCallback(AsanErrorInfo* error_info);
540 :
541 E : void set_expected_error_type(BadAccessKind expected) {
542 E : expected_error_type_ = expected;
543 E : }
544 E : bool memory_error_detected() const { return memory_error_detected_; }
545 E : void set_memory_error_detected(bool memory_error_detected) {
546 E : memory_error_detected_ = memory_error_detected;
547 E : }
548 :
549 E : const AsanErrorInfo& last_error_info() const { return last_error_info_; }
550 E : const CorruptRangeVector& last_corrupt_ranges() const {
551 E : return last_corrupt_ranges_;
552 E : }
553 :
554 : private:
555 : void Initialize();
556 : void AsanErrorCallbackImpl(AsanErrorInfo* error_info);
557 :
558 : // This will be used in the asan callback to ensure that we detect the right
559 : // error.
560 : BadAccessKind expected_error_type_;
561 : // A flag used in asan callback to ensure that a memory error has been
562 : // detected.
563 : bool memory_error_detected_;
564 :
565 : // Indicates whether to ignore changes to the flags register.
566 : bool ignore_flags_;
567 :
568 : // The pre- and post-invocation contexts.
569 : CONTEXT context_before_hook_;
570 : CONTEXT context_after_hook_;
571 : // Context captured on error.
572 : CONTEXT error_context_;
573 :
574 : // The information about the last error.
575 : AsanErrorInfo last_error_info_;
576 : CorruptRangeVector last_corrupt_ranges_;
577 :
578 : // There shall be only one!
579 : static MemoryAccessorTester* instance_;
580 : };
581 :
582 : // A fixture class for testing memory interceptors.
583 : class TestMemoryInterceptors : public TestWithAsanLogger {
584 : public:
585 : // Redefine some enums for local use.
586 : enum AccessMode {
587 : AsanReadAccess = agent::asan::ASAN_READ_ACCESS,
588 : AsanWriteAccess = agent::asan::ASAN_WRITE_ACCESS,
589 : AsanUnknownAccess = agent::asan::ASAN_UNKNOWN_ACCESS,
590 : };
591 :
592 : struct InterceptFunction {
593 : void(*function)();
594 : size_t size;
595 : };
596 :
597 : struct StringInterceptFunction {
598 : void(*function)();
599 : size_t size;
600 : AccessMode dst_access_mode;
601 : AccessMode src_access_mode;
602 : bool uses_counter;
603 : };
604 :
605 : static const bool kCounterInit_ecx = true;
606 : static const bool kCounterInit_1 = false;
607 :
608 : TestMemoryInterceptors();
609 : void SetUp() override;
610 : void TearDown() override;
611 :
612 : template <size_t N>
613 E : void TestValidAccess(const InterceptFunction (&fns)[N]) {
614 E : TestValidAccess(fns, N);
615 E : }
616 : template <size_t N>
617 E : void TestValidAccessIgnoreFlags(const InterceptFunction (&fns)[N]) {
618 E : TestValidAccessIgnoreFlags(fns, N);
619 E : }
620 : template <size_t N>
621 E : void TestOverrunAccess(const InterceptFunction (&fns)[N]) {
622 E : TestOverrunAccess(fns, N);
623 E : }
624 : template <size_t N>
625 E : void TestOverrunAccessIgnoreFlags(const InterceptFunction (&fns)[N]) {
626 E : TestOverrunAccessIgnoreFlags(fns, N);
627 E : }
628 : template <size_t N>
629 E : void TestUnderrunAccess(const InterceptFunction (&fns)[N]) {
630 E : TestUnderrunAccess(fns, N);
631 E : }
632 : template <size_t N>
633 E : void TestUnderrunAccessIgnoreFlags(const InterceptFunction (&fns)[N]) {
634 E : TestUnderrunAccessIgnoreFlags(fns, N);
635 E : }
636 : template <size_t N>
637 E : void TestStringValidAccess(const StringInterceptFunction (&fns)[N]) {
638 E : TestStringValidAccess(fns, N);
639 E : }
640 : template <size_t N>
641 E : void TestStringOverrunAccess(const StringInterceptFunction (&fns)[N]) {
642 E : TestStringOverrunAccess(fns, N);
643 E : }
644 :
645 : protected:
646 : void TestValidAccess(const InterceptFunction* fns, size_t num_fns);
647 : void TestValidAccessIgnoreFlags(const InterceptFunction* fns,
648 : size_t num_fns);
649 : void TestOverrunAccess(const InterceptFunction* fns, size_t num_fns);
650 : void TestOverrunAccessIgnoreFlags(const InterceptFunction* fns,
651 : size_t num_fns);
652 : void TestUnderrunAccess(const InterceptFunction* fns, size_t num_fns);
653 : void TestUnderrunAccessIgnoreFlags(const InterceptFunction* fns,
654 : size_t num_fns);
655 : void TestStringValidAccess(
656 : const StringInterceptFunction* fns, size_t num_fns);
657 : void TestStringOverrunAccess(
658 : const StringInterceptFunction* fns, size_t num_fns);
659 :
660 : const size_t kAllocSize = 64;
661 :
662 : agent::asan::AsanRuntime asan_runtime_;
663 : HANDLE heap_;
664 :
665 : // Convenience allocs of kAllocSize. Valid from SetUp to TearDown.
666 : byte* src_;
667 : byte* dst_;
668 : };
669 :
670 : // A very lightweight dummy heap to be used in stress testing the
671 : // HeapAllocator. Lock and Unlock are noops, so this is not thread
672 : // safe.
673 : class DummyHeap : public agent::asan::HeapInterface {
674 : public:
675 E : virtual ~DummyHeap() { }
676 i : virtual agent::asan::HeapType GetHeapType() const {
677 i : return agent::asan::kUnknownHeapType;
678 i : }
679 E : virtual uint32 GetHeapFeatures() const { return 0; }
680 E : virtual void* Allocate(size_t bytes) { return ::malloc(bytes); }
681 E : virtual bool Free(void* alloc) { ::free(alloc); return true; }
682 i : virtual bool IsAllocated(const void* alloc) { return false; }
683 i : virtual size_t GetAllocationSize(const void* alloc) { return 0; }
684 E : virtual void Lock() { return; }
685 E : virtual void Unlock() { return; }
686 E : virtual bool TryLock() { return true; }
687 : };
688 :
689 : // Test read and write access.
690 : // Use carefully, since it will try to overwrite the value at @p address with 0.
691 : // @returns true if the address is readable and writable, false otherwise.
692 : bool IsAccessible(void* address);
693 :
694 : // Test read and write access.
695 : // Use carefully, since it will try to overwrite the value at @p address with 0.
696 : // @returns true if the address is neither readable nor writable,
697 : // false otherwise.
698 : bool IsNotAccessible(void* address);
699 :
700 : // A scoped block access helper. Removes block protections when created via
701 : // BlockProtectNone, and restores them via BlockProtectAuto.
702 : // TODO(chrisha): Consider recording the fact the block protections on this
703 : // block are being blocked in some synchronous manner. This will prevent
704 : // the page protections from being added during the lifetime of this
705 : // object.
706 : class ScopedBlockAccess {
707 : public:
708 : // Constructor. Unprotects the provided block.
709 : // @param block_info The block whose protections are to be modified.
710 : // @parma shadow The shadow memory to be updated.
711 E : explicit ScopedBlockAccess(const agent::asan::BlockInfo& block_info,
712 : Shadow* shadow)
713 : : block_info_(block_info), shadow_(shadow) {
714 E : BlockProtectNone(block_info_, shadow_);
715 E : }
716 :
717 : // Destructor. Restores protections on the provided block.
718 E : ~ScopedBlockAccess() { BlockProtectAuto(block_info_, shadow_); }
719 :
720 : private:
721 : const agent::asan::BlockInfo& block_info_;
722 : Shadow* shadow_;
723 : };
724 :
725 : // A debugging shadow class. This keeps extra details in the form of an address
726 : // space with stack traces. This makes it much easier to track down
727 : // inconsistencies in the shadow memory.
728 : class DebugShadow : public Shadow {
729 : public:
730 : using ShadowMarker = agent::asan::ShadowMarker;
731 :
732 : DebugShadow() : Shadow() {
733 : }
734 :
735 : explicit DebugShadow(size_t length)
736 : : Shadow(length) {
737 : }
738 :
739 : ~DebugShadow() override {
740 : // If the shadow has been properly used it will be completely empty by the
741 : // time it is torn down.
742 : CHECK(shadow_address_space_.empty());
743 : }
744 :
745 : protected:
746 : // @name Shadow implementation.
747 : // @{
748 : void SetShadowMemory(
749 : const void* address, size_t length, ShadowMarker marker) override;
750 : void GetPointerAndSizeImpl(void const** self, size_t* size) const override;
751 : // @}
752 :
753 : private:
754 : using StackCapture = agent::common::StackCapture;
755 :
756 : // Holds details about a given range of shadow memory. Persists the
757 : // original size of a region, even if it is subsequently fragmented.
758 : struct Metadata {
759 : const void* address;
760 : size_t size;
761 : ShadowMarker marker;
762 : StackCapture stack_capture;
763 :
764 : // Explicitly enable copy and assignment.
765 : Metadata();
766 : Metadata(const void* address, size_t size, ShadowMarker marker);
767 : Metadata(const Metadata& rhs);
768 : Metadata& operator=(const Metadata& rhs);
769 : };
770 : using ShadowAddressSpace =
771 : core::AddressSpace<uintptr_t, size_t, Metadata>;
772 : using Range = ShadowAddressSpace::Range;
773 :
774 : // Ensure that the given range has been cleared from the address-space,
775 : // readying it for a subsequent insertion.
776 : void ClearIntersection(const void* addr, size_t size);
777 :
778 : // An alternative view of shadow memory. Accessible regions are not
779 : // displayed. Neighboring regions of the same type are merged.
780 : ShadowAddressSpace shadow_address_space_;
781 : };
782 :
783 : } // namespace testing
784 :
785 : #endif // SYZYGY_AGENT_ASAN_UNITTEST_UTIL_H_
|