| // Copyright 2013 Google Inc. All Rights Reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| // This file declares some functions used to do the integration tests of the |
| // Asan interceptor functions. |
| #ifndef SYZYGY_INTEGRATION_TESTS_ASAN_INTERCEPTORS_TESTS_H_ |
| #define SYZYGY_INTEGRATION_TESTS_ASAN_INTERCEPTORS_TESTS_H_ |
| |
| #include <windows.h> // NOLINT |
| |
| #include "syzygy/integration_tests/asan_check_tests.h" |
| |
| namespace testing { |
| |
| // Disable the intrinsic versions of the intercepted functions. |
| #pragma function(memset, memcpy, strlen, strcmp) |
| |
| // Helper function to make sure that a memory read access doesn't get |
| // instrumented. |
| // @tparam type The type of the value to be read. |
| // @param location The location where to read from. |
| // @returns the value at |location| |
| template<typename type> |
| type NonInterceptedRead(type* location) { |
| // The try-except statement prevents the function from being instrumented. |
| __try { |
| return *location; |
| } __except(EXCEPTION_CONTINUE_SEARCH) { |
| // Nothing to do here. |
| } |
| return static_cast<type>(0); |
| } |
| |
| // Helper function to do non instrumented reads from an array. |
| // @tparam type The type of the values to be read. |
| // @param src The array where to read from. |
| // @param size The size of the array. |
| // @param dst The destination array. |
| template<typename type> |
| void NonInterceptedReads(type* src, size_t size, type* dst) { |
| for (size_t i = 0; i < size; ++i) |
| *dst++ = NonInterceptedRead(src + i); |
| } |
| |
| // Helper function to make sure that a memory write access didn't get |
| // instrumented. |
| // @tparam type The type of the value to be written. |
| // @param location The location where to write to. |
| // @param val The value to write. |
| template<typename type> |
| void NonInterceptedWrite(type* location, type val) { |
| // The try-except statement prevents the function from being instrumented. |
| __try { |
| *location = val; |
| } __except(EXCEPTION_CONTINUE_SEARCH) { |
| // Nothing to do here. |
| } |
| } |
| |
| // Helper function to do non instrumented writes from an array. |
| // @tparam type The type of the values to be written. |
| // @param src The array where to read from. |
| // @param size The size of the array. |
| // @param dst The address where to write to. |
| template<typename type> |
| void NonInterceptedWrites(type* src, size_t size, type* dst) { |
| for (size_t i = 0; i < size; ++i) |
| NonInterceptedWrite(dst++, src[i]); |
| } |
| |
| template<typename type> |
| static type AsanMemsetOverflow() { |
| const size_t kArraySize = 10; |
| type* ptr = new type[kArraySize]; |
| type first_trailer_val = NonInterceptedRead(ptr + kArraySize); |
| TryInvalidCall3(&::memset, static_cast<void*>(ptr), 0xFF, |
| kArraySize * sizeof(type) + 1); |
| NonInterceptedWrite(ptr + kArraySize, first_trailer_val); |
| delete[] ptr; |
| return 0; |
| } |
| |
| template<typename type> |
| static type AsanMemsetUnderflow() { |
| const size_t kArraySize = 10; |
| type* ptr = new type[kArraySize]; |
| type last_header_val = NonInterceptedRead(ptr - 1); |
| uint8_t* underflow_address = reinterpret_cast<uint8_t*>(ptr) - 1; |
| TryInvalidCall3(&::memset, static_cast<void*>(underflow_address), 0xFF, |
| kArraySize * sizeof(type)); |
| NonInterceptedWrite(ptr - 1, last_header_val); |
| delete[] ptr; |
| return 0; |
| } |
| |
| template<typename type> |
| static type AsanMemsetUseAfterFree() { |
| const size_t kArraySize = 10; |
| type* ptr = new type[kArraySize]; |
| delete[] ptr; |
| TryInvalidCall3(&::memset, static_cast<void*>(ptr), 0xFF, |
| kArraySize * sizeof(type)); |
| return 0; |
| } |
| |
| template<typename type> |
| static type AsanMemchrOverflow() { |
| const size_t kArraySize = 10; |
| type* ptr = new type[kArraySize]; |
| ::memset(ptr, 0xAA, kArraySize * sizeof(type)); |
| TryInvalidCall3(static_cast<void* (*)(void*, int, size_t)>(&::memchr), |
| static_cast<void*>(ptr), |
| 0xFF, |
| kArraySize * sizeof(type) + 1); |
| delete[] ptr; |
| return 0; |
| } |
| |
| template<typename type> |
| static type AsanMemchrUnderflow() { |
| const size_t kArraySize = 10; |
| type* ptr = new type[kArraySize]; |
| ::memset(ptr, 0xAA, kArraySize * sizeof(type)); |
| uint8_t* underflow_address = reinterpret_cast<uint8_t*>(ptr) - 1; |
| TryInvalidCall3(static_cast<void* (*)(void*, int, size_t)>(&::memchr), |
| static_cast<void*>(underflow_address), |
| 0xFF, |
| kArraySize * sizeof(type)); |
| delete[] ptr; |
| return 0; |
| } |
| |
| template<typename type> |
| static type AsanMemchrUseAfterFree() { |
| const size_t kArraySize = 10; |
| type* ptr = new type[kArraySize]; |
| ::memset(ptr, 0xAA, kArraySize * sizeof(type)); |
| delete[] ptr; |
| TryInvalidCall3(static_cast<void* (*)(void*, int, size_t)>(&::memchr), |
| static_cast<void*>(ptr), 0xFF, |
| kArraySize * sizeof(type)); |
| return 0; |
| } |
| |
| template<typename type> |
| static type AsanMemmoveWriteOverflow() { |
| const size_t kArraySize = 10; |
| type* ptr = new type[kArraySize]; |
| type first_trailer_val = NonInterceptedRead(ptr + kArraySize); |
| ::memset(ptr, 0xAA, kArraySize * sizeof(type)); |
| uint8_t* dst = reinterpret_cast<uint8_t*>(ptr) + 1; |
| TryInvalidCall3(&::memmove, |
| static_cast<void*>(dst), |
| static_cast<const void*>(ptr), |
| kArraySize * sizeof(type)); |
| NonInterceptedWrite(ptr + kArraySize, first_trailer_val); |
| delete[] ptr; |
| return 0; |
| } |
| |
| template<typename type> |
| static type AsanMemmoveWriteUnderflow() { |
| const size_t kArraySize = 10; |
| type* ptr = new type[kArraySize]; |
| type last_header_val = NonInterceptedRead(ptr - 1); |
| ::memset(ptr, 0xAA, kArraySize * sizeof(type)); |
| uint8_t* underflow_address = reinterpret_cast<uint8_t*>(ptr) - 1; |
| TryInvalidCall3(&::memmove, |
| static_cast<void*>(underflow_address), |
| static_cast<const void*>(ptr), |
| kArraySize * sizeof(type)); |
| NonInterceptedWrite(ptr - 1, last_header_val); |
| delete[] ptr; |
| return 0; |
| } |
| |
| template<typename type> |
| static type AsanMemmoveReadOverflow() { |
| const size_t kArraySize = 10; |
| type* ptr = new type[kArraySize]; |
| ::memset(ptr, 0xAA, kArraySize * sizeof(type)); |
| uint8_t* src = reinterpret_cast<uint8_t*>(ptr) + 1; |
| TryInvalidCall3(&::memmove, |
| static_cast<void*>(ptr), |
| static_cast<const void*>(src), |
| kArraySize * sizeof(type)); |
| delete[] ptr; |
| return 0; |
| } |
| |
| template<typename type> |
| static type AsanMemmoveReadUnderflow() { |
| const size_t kArraySize = 10; |
| type* ptr = new type[kArraySize]; |
| ::memset(ptr, 0xAA, kArraySize * sizeof(type)); |
| uint8_t* underflow_address = reinterpret_cast<uint8_t*>(ptr) - 1; |
| TryInvalidCall3(&memmove, |
| static_cast<void*>(ptr), |
| static_cast<const void*>(underflow_address), |
| kArraySize * sizeof(type)); |
| delete[] ptr; |
| return 0; |
| } |
| |
| template<typename type> |
| static type AsanMemmoveUseAfterFree() { |
| const size_t kArraySize = 10; |
| type* ptr = new type[kArraySize]; |
| ::memset(ptr, 0xAA, kArraySize * sizeof(type)); |
| delete[] ptr; |
| TryInvalidCall3(&::memmove, |
| static_cast<void*>(ptr), |
| static_cast<const void*>(ptr), |
| kArraySize * sizeof(type)); |
| return 0; |
| } |
| |
| template<typename type> |
| static type AsanMemcpyWriteOverflow() { |
| const size_t kArraySize = 10; |
| type* src = new type[kArraySize]; |
| type* dst = new type[kArraySize]; |
| type first_trailer_val = NonInterceptedRead(dst + kArraySize); |
| ::memset(src, 0xAA, kArraySize * sizeof(type)); |
| uint8_t* overflow_dst = reinterpret_cast<uint8_t*>(dst) + 1; |
| TryInvalidCall3(&::memcpy, |
| static_cast<void*>(overflow_dst), |
| static_cast<const void*>(src), |
| kArraySize * sizeof(type)); |
| NonInterceptedWrite(dst + kArraySize, first_trailer_val); |
| delete[] src; |
| delete[] dst; |
| return 0; |
| } |
| |
| template<typename type> |
| static type AsanMemcpyWriteUnderflow() { |
| const size_t kArraySize = 10; |
| type* src = new type[kArraySize]; |
| type* dst = new type[kArraySize]; |
| type last_header_val = NonInterceptedRead(dst - 1); |
| ::memset(src, 0xAA, kArraySize * sizeof(type)); |
| uint8_t* underflow_dst = reinterpret_cast<uint8_t*>(dst) - 1; |
| TryInvalidCall3(&::memcpy, |
| static_cast<void*>(underflow_dst), |
| static_cast<const void*>(src), |
| kArraySize * sizeof(type)); |
| NonInterceptedWrite(dst - 1, last_header_val); |
| delete[] src; |
| delete[] dst; |
| return 0; |
| } |
| |
| template<typename type> |
| static type AsanMemcpyReadOverflow() { |
| const size_t kArraySize = 10; |
| type* src = new type[kArraySize]; |
| type* dst = new type[kArraySize]; |
| ::memset(src, 0xAA, kArraySize * sizeof(type)); |
| uint8_t* overflow_src = reinterpret_cast<uint8_t*>(src) + 1; |
| TryInvalidCall3(&::memcpy, |
| static_cast<void*>(dst), |
| static_cast<const void*>(overflow_src), |
| kArraySize * sizeof(type)); |
| delete[] src; |
| delete[] dst; |
| return 0; |
| } |
| |
| template<typename type> |
| static type AsanMemcpyReadUnderflow() { |
| const size_t kArraySize = 10; |
| type* src = new type[kArraySize]; |
| type* dst = new type[kArraySize]; |
| ::memset(src, 0xAA, kArraySize * sizeof(type)); |
| uint8_t* underflow_src = reinterpret_cast<uint8_t*>(src) - 1; |
| TryInvalidCall3(&::memcpy, |
| static_cast<void*>(dst), |
| static_cast<const void*>(underflow_src), |
| kArraySize * sizeof(type)); |
| delete[] src; |
| delete[] dst; |
| return 0; |
| } |
| |
| template<typename type> |
| static type AsanMemcpyUseAfterFree() { |
| const size_t kArraySize = 10; |
| type* src = new type[kArraySize]; |
| type* dst = new type[kArraySize]; |
| ::memset(src, 0xAA, kArraySize * sizeof(type)); |
| delete[] src; |
| TryInvalidCall3(&::memcpy, |
| static_cast<void*>(dst), |
| static_cast<const void*>(src), |
| kArraySize * sizeof(type)); |
| delete[] dst; |
| return 0; |
| } |
| |
| size_t AsanStrcspnKeysOverflow(); |
| |
| size_t AsanStrcspnKeysUnderflow(); |
| |
| size_t AsanStrcspnKeysUseAfterFree(); |
| |
| size_t AsanStrcspnSrcOverflow(); |
| |
| size_t AsanStrcspnSrcUnderflow(); |
| |
| size_t AsanStrcspnSrcUseAfterFree(); |
| |
| size_t AsanStrlenOverflow(); |
| |
| size_t AsanStrlenUnderflow(); |
| |
| size_t AsanStrlenUseAfterFree(); |
| |
| size_t AsanStrnlenOverflow(); |
| |
| size_t AsanStrnlenUnderflow(); |
| |
| size_t AsanStrnlenUseAfterFree(); |
| |
| size_t AsanWcsnlenOverflow(); |
| |
| size_t AsanWcsnlenUnderflow(); |
| |
| size_t AsanWcsnlenUseAfterFree(); |
| |
| size_t AsanStrrchrOverflow(); |
| |
| size_t AsanStrrchrUnderflow(); |
| |
| size_t AsanStrrchrUseAfterFree(); |
| |
| size_t AsanWcsrchrOverflow(); |
| |
| size_t AsanWcsrchrUnderflow(); |
| |
| size_t AsanWcsrchrUseAfterFree(); |
| |
| size_t AsanWcschrOverflow(); |
| |
| size_t AsanWcschrUnderflow(); |
| |
| size_t AsanWcschrUseAfterFree(); |
| |
| size_t AsanStrcmpSrc1Overflow(); |
| |
| size_t AsanStrcmpSrc1Underflow(); |
| |
| size_t AsanStrcmpSrc1UseAfterFree(); |
| |
| size_t AsanStrcmpSrc2Overflow(); |
| |
| size_t AsanStrcmpSrc2Underflow(); |
| |
| size_t AsanStrcmpSrc2UseAfterFree(); |
| |
| size_t AsanStrpbrkKeysOverflow(); |
| |
| size_t AsanStrpbrkKeysUnderflow(); |
| |
| size_t AsanStrpbrkKeysUseAfterFree(); |
| |
| size_t AsanStrpbrkSrcOverflow(); |
| |
| size_t AsanStrpbrkSrcUnderflow(); |
| |
| size_t AsanStrpbrkSrcUseAfterFree(); |
| |
| size_t AsanStrstrSrc1Overflow(); |
| |
| size_t AsanStrstrSrc1Underflow(); |
| |
| size_t AsanStrstrSrc1UseAfterFree(); |
| |
| size_t AsanStrstrSrc2Overflow(); |
| |
| size_t AsanStrstrSrc2Underflow(); |
| |
| size_t AsanStrstrSrc2UseAfterFree(); |
| |
| size_t AsanWcsstrKeysOverflow(); |
| |
| size_t AsanStrspnKeysOverflow(); |
| |
| size_t AsanStrspnKeysUnderflow(); |
| |
| size_t AsanStrspnKeysUseAfterFree(); |
| |
| size_t AsanStrspnSrcOverflow(); |
| |
| size_t AsanStrspnSrcUnderflow(); |
| |
| size_t AsanStrspnSrcUseAfterFree(); |
| |
| size_t AsanStrncpySrcOverflow(); |
| |
| size_t AsanStrncpySrcUnderflow(); |
| |
| size_t AsanStrncpySrcUseAfterFree(); |
| |
| size_t AsanStrncpyDstOverflow(); |
| |
| size_t AsanStrncpyDstUnderflow(); |
| |
| size_t AsanStrncpyDstUseAfterFree(); |
| |
| size_t AsanStrncatSuffixOverflow(); |
| |
| size_t AsanStrncatSuffixUnderflow(); |
| |
| size_t AsanStrncatSuffixUseAfterFree(); |
| |
| size_t AsanStrncatDstOverflow(); |
| |
| size_t AsanStrncatDstUnderflow(); |
| |
| size_t AsanStrncatDstUseAfterFree(); |
| |
| size_t AsanReadFileOverflow(); |
| |
| size_t AsanReadFileUseAfterFree(); |
| |
| size_t AsanWriteFileOverflow(); |
| |
| size_t AsanWriteFileUseAfterFree(); |
| |
| size_t AsanCorruptBlock(); |
| |
| size_t AsanCorruptBlockInQuarantine(); |
| |
| // Non-Asan errors that are meant to be caught by the heap checker after |
| // an exception is caught by the unfiltered exception handler. |
| size_t AsanInvalidAccessWithCorruptAllocatedBlockHeader(); |
| size_t AsanInvalidAccessWithCorruptAllocatedBlockTrailer(); |
| size_t AsanInvalidAccessWithCorruptFreedBlock(); |
| |
| // Generates a call to memcmp that will cause an access violation to be |
| // raised. Catches and swallows the access violation by itself. When |
| // instrumented, this should be caught by the SyzyAsan exception handler. |
| size_t AsanMemcmpAccessViolation(); |
| |
| // Null and near-null pointers access exceptions should not be reported by |
| // SyzyASAN unless we detect heap corruption. In the "instrumented" tests, the |
| // invalid accesses will be caught by the Shadow memory and the RTL, whereas the |
| // "uninstrumented" tests will cause an access violation exception to be thrown. |
| size_t AsanNearNullptrAccessHeapCorruptionInstrumented(); |
| size_t AsanNearNullptrAccessHeapCorruptionUninstrumented(); |
| size_t AsanNearNullptrAccessNoHeapCorruptionInstrumented(); |
| size_t AsanNearNullptrAccessNoHeapCorruptionUninstrumented(); |
| size_t AsanNullptrAccessNoHeapCorruptionUninstrumented(); |
| |
| } // namespace testing |
| |
| #endif // SYZYGY_INTEGRATION_TESTS_ASAN_INTERCEPTORS_TESTS_H_ |