diff options
Diffstat (limited to 'lib/interception')
| -rw-r--r-- | lib/interception/.clang-format | 2 | ||||
| -rw-r--r-- | lib/interception/CMakeLists.txt | 29 | ||||
| -rw-r--r-- | lib/interception/tests/CMakeLists.txt | 113 | ||||
| -rw-r--r-- | lib/interception/tests/interception_linux_test.cc | 68 | ||||
| -rw-r--r-- | lib/interception/tests/interception_test_main.cc | 22 | ||||
| -rw-r--r-- | lib/interception/tests/interception_win_test.cc | 637 |
6 files changed, 0 insertions, 871 deletions
diff --git a/lib/interception/.clang-format b/lib/interception/.clang-format deleted file mode 100644 index 560308c91deec..0000000000000 --- a/lib/interception/.clang-format +++ /dev/null @@ -1,2 +0,0 @@ -BasedOnStyle: Google -AllowShortIfStatementsOnASingleLine: false diff --git a/lib/interception/CMakeLists.txt b/lib/interception/CMakeLists.txt deleted file mode 100644 index c0ac974d726ae..0000000000000 --- a/lib/interception/CMakeLists.txt +++ /dev/null @@ -1,29 +0,0 @@ -# Build for the runtime interception helper library. - -set(INTERCEPTION_SOURCES - interception_linux.cc - interception_mac.cc - interception_win.cc - interception_type_test.cc) - -set(INTERCEPTION_HEADERS - interception.h - interception_linux.h - interception_mac.h - interception_win.h) - -include_directories(..) - -set(INTERCEPTION_CFLAGS ${SANITIZER_COMMON_CFLAGS}) -append_rtti_flag(OFF INTERCEPTION_CFLAGS) - -add_compiler_rt_object_libraries(RTInterception - OS ${SANITIZER_COMMON_SUPPORTED_OS} - ARCHS ${SANITIZER_COMMON_SUPPORTED_ARCH} - SOURCES ${INTERCEPTION_SOURCES} - ADDITIONAL_HEADERS ${INTERCEPTION_HEADERS} - CFLAGS ${INTERCEPTION_CFLAGS}) - -if(COMPILER_RT_INCLUDE_TESTS) - add_subdirectory(tests) -endif() diff --git a/lib/interception/tests/CMakeLists.txt b/lib/interception/tests/CMakeLists.txt deleted file mode 100644 index 1da0a455bf331..0000000000000 --- a/lib/interception/tests/CMakeLists.txt +++ /dev/null @@ -1,113 +0,0 @@ -include(CompilerRTCompile) - -filter_available_targets(INTERCEPTION_UNITTEST_SUPPORTED_ARCH x86_64 i386 mips64 mips64el) - -set(INTERCEPTION_UNITTESTS - interception_linux_test.cc - interception_test_main.cc - interception_win_test.cc -) - -set(INTERCEPTION_TEST_HEADERS) - -set(INTERCEPTION_TEST_CFLAGS_COMMON - ${COMPILER_RT_UNITTEST_CFLAGS} - ${COMPILER_RT_GTEST_CFLAGS} - -I${COMPILER_RT_SOURCE_DIR}/include - -I${COMPILER_RT_SOURCE_DIR}/lib - -I${COMPILER_RT_SOURCE_DIR}/lib/interception - -fno-rtti - -O2 - -Werror=sign-compare - -Wno-non-virtual-dtor) - -# -gline-tables-only must be enough for these tests, so use it if possible. -if(COMPILER_RT_TEST_COMPILER_ID MATCHES "Clang") - list(APPEND INTERCEPTION_TEST_CFLAGS_COMMON -gline-tables-only) -else() - list(APPEND INTERCEPTION_TEST_CFLAGS_COMMON -g) -endif() -if(MSVC) - list(APPEND INTERCEPTION_TEST_CFLAGS_COMMON -gcodeview) - list(APPEND INTERCEPTION_TEST_LINK_FLAGS_COMMON -Wl,-largeaddressaware) -endif() -list(APPEND INTERCEPTION_TEST_LINK_FLAGS_COMMON -g) - -if(NOT MSVC) - list(APPEND INTERCEPTION_TEST_LINK_FLAGS_COMMON --driver-mode=g++) -endif() - -if(ANDROID) - list(APPEND INTERCEPTION_TEST_LINK_FLAGS_COMMON -pie) -endif() - -set(INTERCEPTION_TEST_LINK_LIBS) -append_list_if(COMPILER_RT_HAS_LIBLOG log INTERCEPTION_TEST_LINK_LIBS) -# NDK r10 requires -latomic almost always. -append_list_if(ANDROID atomic INTERCEPTION_TEST_LINK_LIBS) - -append_list_if(COMPILER_RT_HAS_LIBDL -ldl INTERCEPTION_TEST_LINK_FLAGS_COMMON) -append_list_if(COMPILER_RT_HAS_LIBRT -lrt INTERCEPTION_TEST_LINK_FLAGS_COMMON) -append_list_if(COMPILER_RT_HAS_LIBPTHREAD -pthread INTERCEPTION_TEST_LINK_FLAGS_COMMON) -# x86_64 FreeBSD 9.2 additionally requires libc++ to build the tests. Also, -# 'libm' shall be specified explicitly to build i386 tests. -if(CMAKE_SYSTEM MATCHES "FreeBSD-9.2-RELEASE") - list(APPEND INTERCEPTION_TEST_LINK_FLAGS_COMMON "-lc++ -lm") -endif() - -include_directories(..) -include_directories(../..) - -# Adds static library which contains interception object file -# (universal binary on Mac and arch-specific object files on Linux). -macro(add_interceptor_lib library) - add_library(${library} STATIC ${ARGN}) - set_target_properties(${library} PROPERTIES - ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - FOLDER "Compiler-RT Runtime tests") -endmacro() - -function(get_interception_lib_for_arch arch lib) - if(APPLE) - set(tgt_name "RTInterception.test.osx") - else() - set(tgt_name "RTInterception.test.${arch}") - endif() - set(${lib} "${tgt_name}" PARENT_SCOPE) -endfunction() - -# Interception unit tests testsuite. -add_custom_target(InterceptionUnitTests) -set_target_properties(InterceptionUnitTests PROPERTIES - FOLDER "Compiler-RT Tests") - -# Adds interception tests for architecture. -macro(add_interception_tests_for_arch arch) - set(INTERCEPTION_TEST_OBJECTS) - get_interception_lib_for_arch(${arch} INTERCEPTION_COMMON_LIB) - generate_compiler_rt_tests(INTERCEPTION_TEST_OBJECTS - InterceptionUnitTests "Interception-${arch}-Test" ${arch} - RUNTIME ${INTERCEPTION_COMMON_LIB} - SOURCES ${INTERCEPTION_UNITTESTS} ${COMPILER_RT_GTEST_SOURCE} - COMPILE_DEPS ${INTERCEPTION_TEST_HEADERS} - DEPS gtest - CFLAGS ${INTERCEPTION_TEST_CFLAGS_COMMON} - LINK_FLAGS ${INTERCEPTION_TEST_LINK_FLAGS_COMMON}) -endmacro() - -if(COMPILER_RT_CAN_EXECUTE_TESTS AND NOT ANDROID AND NOT APPLE) - # We use just-built clang to build interception unittests, so we must - # be sure that produced binaries would work. - if(APPLE) - add_interceptor_lib("RTInterception.test.osx" - $<TARGET_OBJECTS:RTInterception.osx>) - else() - foreach(arch ${INTERCEPTION_UNITTEST_SUPPORTED_ARCH}) - add_interceptor_lib("RTInterception.test.${arch}" - $<TARGET_OBJECTS:RTInterception.${arch}>) - endforeach() - endif() - foreach(arch ${INTERCEPTION_UNITTEST_SUPPORTED_ARCH}) - add_interception_tests_for_arch(${arch}) - endforeach() -endif() diff --git a/lib/interception/tests/interception_linux_test.cc b/lib/interception/tests/interception_linux_test.cc deleted file mode 100644 index cc09aa09df3a4..0000000000000 --- a/lib/interception/tests/interception_linux_test.cc +++ /dev/null @@ -1,68 +0,0 @@ -//===-- interception_linux_test.cc ----------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file is a part of ThreadSanitizer/AddressSanitizer runtime. -// Tests for interception_linux.h. -// -//===----------------------------------------------------------------------===// - -// Do not declare isdigit in ctype.h. -#define __NO_CTYPE - -#include "interception/interception.h" - -#include "gtest/gtest.h" - -// Too slow for debug build -#if !SANITIZER_DEBUG -#if SANITIZER_LINUX - -static int InterceptorFunctionCalled; - -DECLARE_REAL(int, isdigit, int); - -INTERCEPTOR(int, isdigit, int d) { - ++InterceptorFunctionCalled; - return d >= '0' && d <= '9'; -} - -namespace __interception { - -TEST(Interception, GetRealFunctionAddress) { - uptr malloc_address = 0; - EXPECT_TRUE(GetRealFunctionAddress("malloc", &malloc_address, 0, 0)); - EXPECT_NE(0U, malloc_address); - - uptr dummy_address = 0; - EXPECT_TRUE( - GetRealFunctionAddress("dummy_doesnt_exist__", &dummy_address, 0, 0)); - EXPECT_EQ(0U, dummy_address); -} - -TEST(Interception, Basic) { - ASSERT_TRUE(INTERCEPT_FUNCTION(isdigit)); - - // After interception, the counter should be incremented. - InterceptorFunctionCalled = 0; - EXPECT_NE(0, isdigit('1')); - EXPECT_EQ(1, InterceptorFunctionCalled); - EXPECT_EQ(0, isdigit('a')); - EXPECT_EQ(2, InterceptorFunctionCalled); - - // Calling the REAL function should not affect the counter. - InterceptorFunctionCalled = 0; - EXPECT_NE(0, REAL(isdigit)('1')); - EXPECT_EQ(0, REAL(isdigit)('a')); - EXPECT_EQ(0, InterceptorFunctionCalled); -} - -} // namespace __interception - -#endif // SANITIZER_LINUX -#endif // #if !SANITIZER_DEBUG diff --git a/lib/interception/tests/interception_test_main.cc b/lib/interception/tests/interception_test_main.cc deleted file mode 100644 index 311da51ecfcec..0000000000000 --- a/lib/interception/tests/interception_test_main.cc +++ /dev/null @@ -1,22 +0,0 @@ -//===-- interception_test_main.cc------------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file is a part of AddressSanitizer, an address sanity checker. -// -// Testing the machinery for providing replacements/wrappers for system -// functions. -//===----------------------------------------------------------------------===// - -#include "gtest/gtest.h" - -int main(int argc, char **argv) { - testing::GTEST_FLAG(death_test_style) = "threadsafe"; - testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} diff --git a/lib/interception/tests/interception_win_test.cc b/lib/interception/tests/interception_win_test.cc deleted file mode 100644 index 37ef994f83da1..0000000000000 --- a/lib/interception/tests/interception_win_test.cc +++ /dev/null @@ -1,637 +0,0 @@ -//===-- interception_win_test.cc ------------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file is a part of ThreadSanitizer/AddressSanitizer runtime. -// Tests for interception_win.h. -// -//===----------------------------------------------------------------------===// -#include "interception/interception.h" - -#include "gtest/gtest.h" - -// Too slow for debug build -#if !SANITIZER_DEBUG -#if SANITIZER_WINDOWS - -#define WIN32_LEAN_AND_MEAN -#include <windows.h> - -namespace __interception { -namespace { - -enum FunctionPrefixKind { - FunctionPrefixNone, - FunctionPrefixPadding, - FunctionPrefixHotPatch, - FunctionPrefixDetour, -}; - -typedef bool (*TestOverrideFunction)(uptr, uptr, uptr*); -typedef int (*IdentityFunction)(int); - -#if SANITIZER_WINDOWS64 - -const u8 kIdentityCodeWithPrologue[] = { - 0x55, // push rbp - 0x48, 0x89, 0xE5, // mov rbp,rsp - 0x8B, 0xC1, // mov eax,ecx - 0x5D, // pop rbp - 0xC3, // ret -}; - -const u8 kIdentityCodeWithPushPop[] = { - 0x55, // push rbp - 0x48, 0x89, 0xE5, // mov rbp,rsp - 0x53, // push rbx - 0x50, // push rax - 0x58, // pop rax - 0x8B, 0xC1, // mov rax,rcx - 0x5B, // pop rbx - 0x5D, // pop rbp - 0xC3, // ret -}; - -const u8 kIdentityTwiceOffset = 16; -const u8 kIdentityTwice[] = { - 0x55, // push rbp - 0x48, 0x89, 0xE5, // mov rbp,rsp - 0x8B, 0xC1, // mov eax,ecx - 0x5D, // pop rbp - 0xC3, // ret - 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, - 0x55, // push rbp - 0x48, 0x89, 0xE5, // mov rbp,rsp - 0x8B, 0xC1, // mov eax,ecx - 0x5D, // pop rbp - 0xC3, // ret -}; - -const u8 kIdentityCodeWithMov[] = { - 0x89, 0xC8, // mov eax, ecx - 0xC3, // ret -}; - -const u8 kIdentityCodeWithJump[] = { - 0xE9, 0x04, 0x00, 0x00, - 0x00, // jmp + 4 - 0xCC, 0xCC, 0xCC, 0xCC, - 0x89, 0xC8, // mov eax, ecx - 0xC3, // ret -}; - -#else - -const u8 kIdentityCodeWithPrologue[] = { - 0x55, // push ebp - 0x8B, 0xEC, // mov ebp,esp - 0x8B, 0x45, 0x08, // mov eax,dword ptr [ebp + 8] - 0x5D, // pop ebp - 0xC3, // ret -}; - -const u8 kIdentityCodeWithPushPop[] = { - 0x55, // push ebp - 0x8B, 0xEC, // mov ebp,esp - 0x53, // push ebx - 0x50, // push eax - 0x58, // pop eax - 0x8B, 0x45, 0x08, // mov eax,dword ptr [ebp + 8] - 0x5B, // pop ebx - 0x5D, // pop ebp - 0xC3, // ret -}; - -const u8 kIdentityTwiceOffset = 8; -const u8 kIdentityTwice[] = { - 0x55, // push ebp - 0x8B, 0xEC, // mov ebp,esp - 0x8B, 0x45, 0x08, // mov eax,dword ptr [ebp + 8] - 0x5D, // pop ebp - 0xC3, // ret - 0x55, // push ebp - 0x8B, 0xEC, // mov ebp,esp - 0x8B, 0x45, 0x08, // mov eax,dword ptr [ebp + 8] - 0x5D, // pop ebp - 0xC3, // ret -}; - -const u8 kIdentityCodeWithMov[] = { - 0x8B, 0x44, 0x24, 0x04, // mov eax,dword ptr [esp + 4] - 0xC3, // ret -}; - -const u8 kIdentityCodeWithJump[] = { - 0xE9, 0x04, 0x00, 0x00, - 0x00, // jmp + 4 - 0xCC, 0xCC, 0xCC, 0xCC, - 0x8B, 0x44, 0x24, 0x04, // mov eax,dword ptr [esp + 4] - 0xC3, // ret -}; - -#endif - -const u8 kPatchableCode1[] = { - 0xB8, 0x4B, 0x00, 0x00, 0x00, // mov eax,4B - 0x33, 0xC9, // xor ecx,ecx - 0xC3, // ret -}; - -const u8 kPatchableCode2[] = { - 0x55, // push ebp - 0x8B, 0xEC, // mov ebp,esp - 0x33, 0xC0, // xor eax,eax - 0x5D, // pop ebp - 0xC3, // ret -}; - -const u8 kPatchableCode3[] = { - 0x55, // push ebp - 0x8B, 0xEC, // mov ebp,esp - 0x6A, 0x00, // push 0 - 0xE8, 0x3D, 0xFF, 0xFF, 0xFF, // call <func> -}; - -const u8 kPatchableCode4[] = { - 0xE9, 0xCC, 0xCC, 0xCC, 0xCC, // jmp <label> - 0x90, 0x90, 0x90, 0x90, -}; - -const u8 kPatchableCode5[] = { - 0x55, // push ebp - 0x8b, 0xec, // mov ebp,esp - 0x8d, 0xa4, 0x24, 0x30, 0xfd, 0xff, 0xff, // lea esp,[esp-2D0h] - 0x54, // push esp -}; - -#if SANITIZER_WINDOWS64 -u8 kLoadGlobalCode[] = { - 0x8B, 0x05, 0x00, 0x00, 0x00, 0x00, // mov eax [rip + global] - 0xC3, // ret -}; -#endif - -const u8 kUnpatchableCode1[] = { - 0xC3, // ret -}; - -const u8 kUnpatchableCode2[] = { - 0x33, 0xC9, // xor ecx,ecx - 0xC3, // ret -}; - -const u8 kUnpatchableCode3[] = { - 0x75, 0xCC, // jne <label> - 0x33, 0xC9, // xor ecx,ecx - 0xC3, // ret -}; - -const u8 kUnpatchableCode4[] = { - 0x74, 0xCC, // jne <label> - 0x33, 0xC9, // xor ecx,ecx - 0xC3, // ret -}; - -const u8 kUnpatchableCode5[] = { - 0xEB, 0x02, // jmp <label> - 0x33, 0xC9, // xor ecx,ecx - 0xC3, // ret -}; - -const u8 kUnpatchableCode6[] = { - 0xE8, 0xCC, 0xCC, 0xCC, 0xCC, // call <func> - 0x90, 0x90, 0x90, 0x90, -}; - -// A buffer holding the dynamically generated code under test. -u8* ActiveCode; -const size_t ActiveCodeLength = 4096; - -int InterceptorFunction(int x); - -/// Allocate code memory more than 2GB away from Base. -u8 *AllocateCode2GBAway(u8 *Base) { - // Find a 64K aligned location after Base plus 2GB. - size_t TwoGB = 0x80000000; - size_t AllocGranularity = 0x10000; - Base = (u8 *)((((uptr)Base + TwoGB + AllocGranularity)) & ~(AllocGranularity - 1)); - - // Check if that location is free, and if not, loop over regions until we find - // one that is. - MEMORY_BASIC_INFORMATION mbi = {}; - while (sizeof(mbi) == VirtualQuery(Base, &mbi, sizeof(mbi))) { - if (mbi.State & MEM_FREE) break; - Base += mbi.RegionSize; - } - - // Allocate one RWX page at the free location. - return (u8 *)::VirtualAlloc(Base, ActiveCodeLength, MEM_COMMIT | MEM_RESERVE, - PAGE_EXECUTE_READWRITE); -} - -template<class T> -static void LoadActiveCode( - const T &code, - uptr *entry_point, - FunctionPrefixKind prefix_kind = FunctionPrefixNone) { - if (ActiveCode == nullptr) { - ActiveCode = AllocateCode2GBAway((u8*)&InterceptorFunction); - ASSERT_NE(ActiveCode, nullptr) << "failed to allocate RWX memory 2GB away"; - } - - size_t position = 0; - - // Add padding to avoid memory violation when scanning the prefix. - for (int i = 0; i < 16; ++i) - ActiveCode[position++] = 0xC3; // Instruction 'ret'. - - // Add function padding. - size_t padding = 0; - if (prefix_kind == FunctionPrefixPadding) - padding = 16; - else if (prefix_kind == FunctionPrefixDetour || - prefix_kind == FunctionPrefixHotPatch) - padding = FIRST_32_SECOND_64(5, 6); - // Insert |padding| instructions 'nop'. - for (size_t i = 0; i < padding; ++i) - ActiveCode[position++] = 0x90; - - // Keep track of the entry point. - *entry_point = (uptr)&ActiveCode[position]; - - // Add the detour instruction (i.e. mov edi, edi) - if (prefix_kind == FunctionPrefixDetour) { -#if SANITIZER_WINDOWS64 - // Note that "mov edi,edi" is NOP in 32-bit only, in 64-bit it clears - // higher bits of RDI. - // Use 66,90H as NOP for Windows64. - ActiveCode[position++] = 0x66; - ActiveCode[position++] = 0x90; -#else - // mov edi,edi. - ActiveCode[position++] = 0x8B; - ActiveCode[position++] = 0xFF; -#endif - - } - - // Copy the function body. - for (size_t i = 0; i < sizeof(T); ++i) - ActiveCode[position++] = code[i]; -} - -int InterceptorFunctionCalled; -IdentityFunction InterceptedRealFunction; - -int InterceptorFunction(int x) { - ++InterceptorFunctionCalled; - return InterceptedRealFunction(x); -} - -} // namespace - -// Tests for interception_win.h -TEST(Interception, InternalGetProcAddress) { - HMODULE ntdll_handle = ::GetModuleHandle("ntdll"); - ASSERT_NE(nullptr, ntdll_handle); - uptr DbgPrint_expected = (uptr)::GetProcAddress(ntdll_handle, "DbgPrint"); - uptr isdigit_expected = (uptr)::GetProcAddress(ntdll_handle, "isdigit"); - uptr DbgPrint_adddress = InternalGetProcAddress(ntdll_handle, "DbgPrint"); - uptr isdigit_address = InternalGetProcAddress(ntdll_handle, "isdigit"); - - EXPECT_EQ(DbgPrint_expected, DbgPrint_adddress); - EXPECT_EQ(isdigit_expected, isdigit_address); - EXPECT_NE(DbgPrint_adddress, isdigit_address); -} - -template<class T> -static void TestIdentityFunctionPatching( - const T &code, - TestOverrideFunction override, - FunctionPrefixKind prefix_kind = FunctionPrefixNone) { - uptr identity_address; - LoadActiveCode(code, &identity_address, prefix_kind); - IdentityFunction identity = (IdentityFunction)identity_address; - - // Validate behavior before dynamic patching. - InterceptorFunctionCalled = 0; - EXPECT_EQ(0, identity(0)); - EXPECT_EQ(42, identity(42)); - EXPECT_EQ(0, InterceptorFunctionCalled); - - // Patch the function. - uptr real_identity_address = 0; - bool success = override(identity_address, - (uptr)&InterceptorFunction, - &real_identity_address); - EXPECT_TRUE(success); - EXPECT_NE(0U, real_identity_address); - IdentityFunction real_identity = (IdentityFunction)real_identity_address; - InterceptedRealFunction = real_identity; - - // Don't run tests if hooking failed or the real function is not valid. - if (!success || !real_identity_address) - return; - - // Calling the redirected function. - InterceptorFunctionCalled = 0; - EXPECT_EQ(0, identity(0)); - EXPECT_EQ(42, identity(42)); - EXPECT_EQ(2, InterceptorFunctionCalled); - - // Calling the real function. - InterceptorFunctionCalled = 0; - EXPECT_EQ(0, real_identity(0)); - EXPECT_EQ(42, real_identity(42)); - EXPECT_EQ(0, InterceptorFunctionCalled); - - TestOnlyReleaseTrampolineRegions(); -} - -#if !SANITIZER_WINDOWS64 -TEST(Interception, OverrideFunctionWithDetour) { - TestOverrideFunction override = OverrideFunctionWithDetour; - FunctionPrefixKind prefix = FunctionPrefixDetour; - TestIdentityFunctionPatching(kIdentityCodeWithPrologue, override, prefix); - TestIdentityFunctionPatching(kIdentityCodeWithPushPop, override, prefix); - TestIdentityFunctionPatching(kIdentityCodeWithMov, override, prefix); - TestIdentityFunctionPatching(kIdentityCodeWithJump, override, prefix); -} -#endif // !SANITIZER_WINDOWS64 - -TEST(Interception, OverrideFunctionWithRedirectJump) { - TestOverrideFunction override = OverrideFunctionWithRedirectJump; - TestIdentityFunctionPatching(kIdentityCodeWithJump, override); -} - -TEST(Interception, OverrideFunctionWithHotPatch) { - TestOverrideFunction override = OverrideFunctionWithHotPatch; - FunctionPrefixKind prefix = FunctionPrefixHotPatch; - TestIdentityFunctionPatching(kIdentityCodeWithMov, override, prefix); -} - -TEST(Interception, OverrideFunctionWithTrampoline) { - TestOverrideFunction override = OverrideFunctionWithTrampoline; - FunctionPrefixKind prefix = FunctionPrefixNone; - TestIdentityFunctionPatching(kIdentityCodeWithPrologue, override, prefix); - TestIdentityFunctionPatching(kIdentityCodeWithPushPop, override, prefix); - - prefix = FunctionPrefixPadding; - TestIdentityFunctionPatching(kIdentityCodeWithPrologue, override, prefix); - TestIdentityFunctionPatching(kIdentityCodeWithPushPop, override, prefix); -} - -TEST(Interception, OverrideFunction) { - TestOverrideFunction override = OverrideFunction; - FunctionPrefixKind prefix = FunctionPrefixNone; - TestIdentityFunctionPatching(kIdentityCodeWithPrologue, override, prefix); - TestIdentityFunctionPatching(kIdentityCodeWithPushPop, override, prefix); - TestIdentityFunctionPatching(kIdentityCodeWithJump, override, prefix); - - prefix = FunctionPrefixPadding; - TestIdentityFunctionPatching(kIdentityCodeWithPrologue, override, prefix); - TestIdentityFunctionPatching(kIdentityCodeWithPushPop, override, prefix); - TestIdentityFunctionPatching(kIdentityCodeWithMov, override, prefix); - TestIdentityFunctionPatching(kIdentityCodeWithJump, override, prefix); - - prefix = FunctionPrefixHotPatch; - TestIdentityFunctionPatching(kIdentityCodeWithPrologue, override, prefix); - TestIdentityFunctionPatching(kIdentityCodeWithPushPop, override, prefix); - TestIdentityFunctionPatching(kIdentityCodeWithMov, override, prefix); - TestIdentityFunctionPatching(kIdentityCodeWithJump, override, prefix); - - prefix = FunctionPrefixDetour; - TestIdentityFunctionPatching(kIdentityCodeWithPrologue, override, prefix); - TestIdentityFunctionPatching(kIdentityCodeWithPushPop, override, prefix); - TestIdentityFunctionPatching(kIdentityCodeWithMov, override, prefix); - TestIdentityFunctionPatching(kIdentityCodeWithJump, override, prefix); -} - -template<class T> -static void TestIdentityFunctionMultiplePatching( - const T &code, - TestOverrideFunction override, - FunctionPrefixKind prefix_kind = FunctionPrefixNone) { - uptr identity_address; - LoadActiveCode(code, &identity_address, prefix_kind); - - // Patch the function. - uptr real_identity_address = 0; - bool success = override(identity_address, - (uptr)&InterceptorFunction, - &real_identity_address); - EXPECT_TRUE(success); - EXPECT_NE(0U, real_identity_address); - - // Re-patching the function should not work. - success = override(identity_address, - (uptr)&InterceptorFunction, - &real_identity_address); - EXPECT_FALSE(success); - - TestOnlyReleaseTrampolineRegions(); -} - -TEST(Interception, OverrideFunctionMultiplePatchingIsFailing) { -#if !SANITIZER_WINDOWS64 - TestIdentityFunctionMultiplePatching(kIdentityCodeWithPrologue, - OverrideFunctionWithDetour, - FunctionPrefixDetour); -#endif - - TestIdentityFunctionMultiplePatching(kIdentityCodeWithMov, - OverrideFunctionWithHotPatch, - FunctionPrefixHotPatch); - - TestIdentityFunctionMultiplePatching(kIdentityCodeWithPushPop, - OverrideFunctionWithTrampoline, - FunctionPrefixPadding); -} - -TEST(Interception, OverrideFunctionTwice) { - uptr identity_address1; - LoadActiveCode(kIdentityTwice, &identity_address1); - uptr identity_address2 = identity_address1 + kIdentityTwiceOffset; - IdentityFunction identity1 = (IdentityFunction)identity_address1; - IdentityFunction identity2 = (IdentityFunction)identity_address2; - - // Patch the two functions. - uptr real_identity_address = 0; - EXPECT_TRUE(OverrideFunction(identity_address1, - (uptr)&InterceptorFunction, - &real_identity_address)); - EXPECT_TRUE(OverrideFunction(identity_address2, - (uptr)&InterceptorFunction, - &real_identity_address)); - IdentityFunction real_identity = (IdentityFunction)real_identity_address; - InterceptedRealFunction = real_identity; - - // Calling the redirected function. - InterceptorFunctionCalled = 0; - EXPECT_EQ(42, identity1(42)); - EXPECT_EQ(42, identity2(42)); - EXPECT_EQ(2, InterceptorFunctionCalled); - - TestOnlyReleaseTrampolineRegions(); -} - -template<class T> -static bool TestFunctionPatching( - const T &code, - TestOverrideFunction override, - FunctionPrefixKind prefix_kind = FunctionPrefixNone) { - uptr address; - LoadActiveCode(code, &address, prefix_kind); - uptr unused_real_address = 0; - bool result = override( - address, (uptr)&InterceptorFunction, &unused_real_address); - - TestOnlyReleaseTrampolineRegions(); - return result; -} - -TEST(Interception, PatchableFunction) { - TestOverrideFunction override = OverrideFunction; - // Test without function padding. - EXPECT_TRUE(TestFunctionPatching(kPatchableCode1, override)); - EXPECT_TRUE(TestFunctionPatching(kPatchableCode2, override)); -#if SANITIZER_WINDOWS64 - EXPECT_FALSE(TestFunctionPatching(kPatchableCode3, override)); -#else - EXPECT_TRUE(TestFunctionPatching(kPatchableCode3, override)); -#endif - EXPECT_TRUE(TestFunctionPatching(kPatchableCode4, override)); - EXPECT_TRUE(TestFunctionPatching(kPatchableCode5, override)); - -#if SANITIZER_WINDOWS64 - EXPECT_TRUE(TestFunctionPatching(kLoadGlobalCode, override)); -#endif - - EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode1, override)); - EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode2, override)); - EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode3, override)); - EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode4, override)); - EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode5, override)); - EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode6, override)); -} - -#if !SANITIZER_WINDOWS64 -TEST(Interception, PatchableFunctionWithDetour) { - TestOverrideFunction override = OverrideFunctionWithDetour; - // Without the prefix, no function can be detoured. - EXPECT_FALSE(TestFunctionPatching(kPatchableCode1, override)); - EXPECT_FALSE(TestFunctionPatching(kPatchableCode2, override)); - EXPECT_FALSE(TestFunctionPatching(kPatchableCode3, override)); - EXPECT_FALSE(TestFunctionPatching(kPatchableCode4, override)); - EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode1, override)); - EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode2, override)); - EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode3, override)); - EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode4, override)); - EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode5, override)); - EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode6, override)); - - // With the prefix, all functions can be detoured. - FunctionPrefixKind prefix = FunctionPrefixDetour; - EXPECT_TRUE(TestFunctionPatching(kPatchableCode1, override, prefix)); - EXPECT_TRUE(TestFunctionPatching(kPatchableCode2, override, prefix)); - EXPECT_TRUE(TestFunctionPatching(kPatchableCode3, override, prefix)); - EXPECT_TRUE(TestFunctionPatching(kPatchableCode4, override, prefix)); - EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode1, override, prefix)); - EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode2, override, prefix)); - EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode3, override, prefix)); - EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode4, override, prefix)); - EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode5, override, prefix)); - EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode6, override, prefix)); -} -#endif // !SANITIZER_WINDOWS64 - -TEST(Interception, PatchableFunctionWithRedirectJump) { - TestOverrideFunction override = OverrideFunctionWithRedirectJump; - EXPECT_FALSE(TestFunctionPatching(kPatchableCode1, override)); - EXPECT_FALSE(TestFunctionPatching(kPatchableCode2, override)); - EXPECT_FALSE(TestFunctionPatching(kPatchableCode3, override)); - EXPECT_TRUE(TestFunctionPatching(kPatchableCode4, override)); - EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode1, override)); - EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode2, override)); - EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode3, override)); - EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode4, override)); - EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode5, override)); - EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode6, override)); -} - -TEST(Interception, PatchableFunctionWithHotPatch) { - TestOverrideFunction override = OverrideFunctionWithHotPatch; - FunctionPrefixKind prefix = FunctionPrefixHotPatch; - - EXPECT_TRUE(TestFunctionPatching(kPatchableCode1, override, prefix)); - EXPECT_FALSE(TestFunctionPatching(kPatchableCode2, override, prefix)); - EXPECT_FALSE(TestFunctionPatching(kPatchableCode3, override, prefix)); - EXPECT_FALSE(TestFunctionPatching(kPatchableCode4, override, prefix)); - - EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode1, override, prefix)); - EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode2, override, prefix)); - EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode3, override, prefix)); - EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode4, override, prefix)); - EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode5, override, prefix)); - EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode6, override, prefix)); -} - -TEST(Interception, PatchableFunctionWithTrampoline) { - TestOverrideFunction override = OverrideFunctionWithTrampoline; - FunctionPrefixKind prefix = FunctionPrefixPadding; - - EXPECT_TRUE(TestFunctionPatching(kPatchableCode1, override, prefix)); - EXPECT_TRUE(TestFunctionPatching(kPatchableCode2, override, prefix)); -#if SANITIZER_WINDOWS64 - EXPECT_FALSE(TestFunctionPatching(kPatchableCode3, override, prefix)); -#else - EXPECT_TRUE(TestFunctionPatching(kPatchableCode3, override, prefix)); -#endif - EXPECT_FALSE(TestFunctionPatching(kPatchableCode4, override, prefix)); - - EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode1, override, prefix)); - EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode2, override, prefix)); - EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode3, override, prefix)); - EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode4, override, prefix)); - EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode5, override, prefix)); - EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode6, override, prefix)); -} - -TEST(Interception, PatchableFunctionPadding) { - TestOverrideFunction override = OverrideFunction; - FunctionPrefixKind prefix = FunctionPrefixPadding; - - EXPECT_TRUE(TestFunctionPatching(kPatchableCode1, override, prefix)); - EXPECT_TRUE(TestFunctionPatching(kPatchableCode2, override, prefix)); -#if SANITIZER_WINDOWS64 - EXPECT_FALSE(TestFunctionPatching(kPatchableCode3, override, prefix)); -#else - EXPECT_TRUE(TestFunctionPatching(kPatchableCode3, override, prefix)); -#endif - EXPECT_TRUE(TestFunctionPatching(kPatchableCode4, override, prefix)); - - EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode1, override, prefix)); - EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode2, override, prefix)); - EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode3, override, prefix)); - EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode4, override, prefix)); - EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode5, override, prefix)); - EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode6, override, prefix)); -} - -TEST(Interception, EmptyExportTable) { - // We try to get a pointer to a function from an executable that doesn't - // export any symbol (empty export table). - uptr FunPtr = InternalGetProcAddress((void *)GetModuleHandleA(0), "example"); - EXPECT_EQ(0U, FunPtr); -} - -} // namespace __interception - -#endif // SANITIZER_WINDOWS -#endif // #if !SANITIZER_DEBUG |
