| Index: sandbox/win/src/service_resolver_unittest.cc
|
| diff --git a/sandbox/win/src/service_resolver_unittest.cc b/sandbox/win/src/service_resolver_unittest.cc
|
| deleted file mode 100644
|
| index 25d087573238233ff64d1b4ae5a37bfad9b01740..0000000000000000000000000000000000000000
|
| --- a/sandbox/win/src/service_resolver_unittest.cc
|
| +++ /dev/null
|
| @@ -1,268 +0,0 @@
|
| -// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -// This file contains unit tests for ServiceResolverThunk.
|
| -
|
| -#include <stddef.h>
|
| -
|
| -#include "base/bit_cast.h"
|
| -#include "base/macros.h"
|
| -#include "base/memory/scoped_ptr.h"
|
| -#include "base/win/windows_version.h"
|
| -#include "sandbox/win/src/resolver.h"
|
| -#include "sandbox/win/src/sandbox_utils.h"
|
| -#include "sandbox/win/src/service_resolver.h"
|
| -#include "testing/gtest/include/gtest/gtest.h"
|
| -
|
| -namespace {
|
| -
|
| -// This is the concrete resolver used to perform service-call type functions
|
| -// inside ntdll.dll.
|
| -template<typename T>
|
| -class ResolverThunkTest : public T {
|
| - public:
|
| - // The service resolver needs a child process to write to.
|
| - explicit ResolverThunkTest(bool relaxed)
|
| - : T(::GetCurrentProcess(), relaxed) {}
|
| -
|
| - // Sets the interception target to the desired address.
|
| - void set_target(void* target) {
|
| - fake_target_ = target;
|
| - }
|
| -
|
| - protected:
|
| - // Overrides Resolver::Init
|
| - virtual NTSTATUS Init(const void* target_module,
|
| - const void* interceptor_module,
|
| - const char* target_name,
|
| - const char* interceptor_name,
|
| - const void* interceptor_entry_point,
|
| - void* thunk_storage,
|
| - size_t storage_bytes) {
|
| - NTSTATUS ret = STATUS_SUCCESS;
|
| - ret = T::Init(target_module, interceptor_module, target_name,
|
| - interceptor_name, interceptor_entry_point, thunk_storage,
|
| - storage_bytes);
|
| - EXPECT_EQ(STATUS_SUCCESS, ret);
|
| -
|
| - this->target_ = fake_target_;
|
| -
|
| - return ret;
|
| - };
|
| -
|
| - private:
|
| - // Holds the address of the fake target.
|
| - void* fake_target_;
|
| -
|
| - DISALLOW_COPY_AND_ASSIGN(ResolverThunkTest);
|
| -};
|
| -
|
| -typedef ResolverThunkTest<sandbox::ServiceResolverThunk> WinXpResolverTest;
|
| -
|
| -#if !defined(_WIN64)
|
| -typedef ResolverThunkTest<sandbox::Win8ResolverThunk> Win8ResolverTest;
|
| -typedef ResolverThunkTest<sandbox::Wow64ResolverThunk> Wow64ResolverTest;
|
| -typedef ResolverThunkTest<sandbox::Wow64W8ResolverThunk> Wow64W8ResolverTest;
|
| -typedef ResolverThunkTest<sandbox::Wow64W10ResolverThunk> Wow64W10ResolverTest;
|
| -#endif
|
| -
|
| -const BYTE kJump32 = 0xE9;
|
| -
|
| -void CheckJump(void* source, void* target) {
|
| -#pragma pack(push)
|
| -#pragma pack(1)
|
| - struct Code {
|
| - BYTE jump;
|
| - ULONG delta;
|
| - };
|
| -#pragma pack(pop)
|
| -
|
| -#if defined(_WIN64)
|
| - FAIL() << "Running 32-bit codepath";
|
| -#else
|
| - Code* patched = reinterpret_cast<Code*>(source);
|
| - EXPECT_EQ(kJump32, patched->jump);
|
| -
|
| - ULONG source_addr = bit_cast<ULONG>(source);
|
| - ULONG target_addr = bit_cast<ULONG>(target);
|
| - EXPECT_EQ(target_addr + 19 - source_addr, patched->delta);
|
| -#endif
|
| -}
|
| -
|
| -NTSTATUS PatchNtdllWithResolver(const char* function, bool relaxed,
|
| - sandbox::ServiceResolverThunk* resolver) {
|
| - HMODULE ntdll_base = ::GetModuleHandle(L"ntdll.dll");
|
| - EXPECT_TRUE(NULL != ntdll_base);
|
| -
|
| - void* target = ::GetProcAddress(ntdll_base, function);
|
| - EXPECT_TRUE(NULL != target);
|
| - if (NULL == target)
|
| - return STATUS_UNSUCCESSFUL;
|
| -
|
| - BYTE service[50];
|
| - memcpy(service, target, sizeof(service));
|
| -
|
| - static_cast<WinXpResolverTest*>(resolver)->set_target(service);
|
| -
|
| - // Any pointer will do as an interception_entry_point
|
| - void* function_entry = resolver;
|
| - size_t thunk_size = resolver->GetThunkSize();
|
| - scoped_ptr<char[]> thunk(new char[thunk_size]);
|
| - size_t used;
|
| -
|
| - resolver->AllowLocalPatches();
|
| -
|
| - NTSTATUS ret = resolver->Setup(ntdll_base, NULL, function, NULL,
|
| - function_entry, thunk.get(), thunk_size,
|
| - &used);
|
| - if (NT_SUCCESS(ret)) {
|
| - EXPECT_EQ(thunk_size, used);
|
| - EXPECT_NE(0, memcmp(service, target, sizeof(service)));
|
| - EXPECT_NE(kJump32, service[0]);
|
| -
|
| - if (relaxed) {
|
| - // It's already patched, let's patch again, and simulate a direct patch.
|
| - service[0] = kJump32;
|
| - ret = resolver->Setup(ntdll_base, NULL, function, NULL, function_entry,
|
| - thunk.get(), thunk_size, &used);
|
| - CheckJump(service, thunk.get());
|
| - }
|
| - }
|
| -
|
| - return ret;
|
| -}
|
| -
|
| -sandbox::ServiceResolverThunk* GetTestResolver(bool relaxed) {
|
| -#if defined(_WIN64)
|
| - return new WinXpResolverTest(relaxed);
|
| -#else
|
| - base::win::OSInfo* os_info = base::win::OSInfo::GetInstance();
|
| - if (os_info->wow64_status() == base::win::OSInfo::WOW64_ENABLED) {
|
| - if (os_info->version() >= base::win::VERSION_WIN10)
|
| - return new Wow64W10ResolverTest(relaxed);
|
| - if (os_info->version() >= base::win::VERSION_WIN8)
|
| - return new Wow64W8ResolverTest(relaxed);
|
| - return new Wow64ResolverTest(relaxed);
|
| - }
|
| -
|
| - if (os_info->version() >= base::win::VERSION_WIN8)
|
| - return new Win8ResolverTest(relaxed);
|
| -
|
| - return new WinXpResolverTest(relaxed);
|
| -#endif
|
| -}
|
| -
|
| -NTSTATUS PatchNtdll(const char* function, bool relaxed) {
|
| - sandbox::ServiceResolverThunk* resolver = GetTestResolver(relaxed);
|
| -
|
| - NTSTATUS ret = PatchNtdllWithResolver(function, relaxed, resolver);
|
| - delete resolver;
|
| - return ret;
|
| -}
|
| -
|
| -TEST(ServiceResolverTest, PatchesServices) {
|
| - NTSTATUS ret = PatchNtdll("NtClose", false);
|
| - EXPECT_EQ(STATUS_SUCCESS, ret) << "NtClose, last error: " << ::GetLastError();
|
| -
|
| - ret = PatchNtdll("NtCreateFile", false);
|
| - EXPECT_EQ(STATUS_SUCCESS, ret) << "NtCreateFile, last error: " <<
|
| - ::GetLastError();
|
| -
|
| - ret = PatchNtdll("NtCreateMutant", false);
|
| - EXPECT_EQ(STATUS_SUCCESS, ret) << "NtCreateMutant, last error: " <<
|
| - ::GetLastError();
|
| -
|
| - ret = PatchNtdll("NtMapViewOfSection", false);
|
| - EXPECT_EQ(STATUS_SUCCESS, ret) << "NtMapViewOfSection, last error: " <<
|
| - ::GetLastError();
|
| -}
|
| -
|
| -TEST(ServiceResolverTest, FailsIfNotService) {
|
| -#if !defined(_WIN64)
|
| - EXPECT_NE(STATUS_SUCCESS, PatchNtdll("RtlUlongByteSwap", false));
|
| -#endif
|
| -
|
| - EXPECT_NE(STATUS_SUCCESS, PatchNtdll("LdrLoadDll", false));
|
| -}
|
| -
|
| -TEST(ServiceResolverTest, PatchesPatchedServices) {
|
| -// We don't support "relaxed mode" for Win64 apps.
|
| -#if !defined(_WIN64)
|
| - NTSTATUS ret = PatchNtdll("NtClose", true);
|
| - EXPECT_EQ(STATUS_SUCCESS, ret) << "NtClose, last error: " << ::GetLastError();
|
| -
|
| - ret = PatchNtdll("NtCreateFile", true);
|
| - EXPECT_EQ(STATUS_SUCCESS, ret) << "NtCreateFile, last error: " <<
|
| - ::GetLastError();
|
| -
|
| - ret = PatchNtdll("NtCreateMutant", true);
|
| - EXPECT_EQ(STATUS_SUCCESS, ret) << "NtCreateMutant, last error: " <<
|
| - ::GetLastError();
|
| -
|
| - ret = PatchNtdll("NtMapViewOfSection", true);
|
| - EXPECT_EQ(STATUS_SUCCESS, ret) << "NtMapViewOfSection, last error: " <<
|
| - ::GetLastError();
|
| -#endif
|
| -}
|
| -
|
| -TEST(ServiceResolverTest, MultiplePatchedServices) {
|
| -// We don't support "relaxed mode" for Win64 apps.
|
| -#if !defined(_WIN64)
|
| - sandbox::ServiceResolverThunk* resolver = GetTestResolver(true);
|
| - NTSTATUS ret = PatchNtdllWithResolver("NtClose", true, resolver);
|
| - EXPECT_EQ(STATUS_SUCCESS, ret) << "NtClose, last error: " << ::GetLastError();
|
| -
|
| - ret = PatchNtdllWithResolver("NtCreateFile", true, resolver);
|
| - EXPECT_EQ(STATUS_SUCCESS, ret) << "NtCreateFile, last error: " <<
|
| - ::GetLastError();
|
| -
|
| - ret = PatchNtdllWithResolver("NtCreateMutant", true, resolver);
|
| - EXPECT_EQ(STATUS_SUCCESS, ret) << "NtCreateMutant, last error: " <<
|
| - ::GetLastError();
|
| -
|
| - ret = PatchNtdllWithResolver("NtMapViewOfSection", true, resolver);
|
| - EXPECT_EQ(STATUS_SUCCESS, ret) << "NtMapViewOfSection, last error: " <<
|
| - ::GetLastError();
|
| - delete resolver;
|
| -#endif
|
| -}
|
| -
|
| -TEST(ServiceResolverTest, LocalPatchesAllowed) {
|
| - sandbox::ServiceResolverThunk* resolver = GetTestResolver(true);
|
| -
|
| - HMODULE ntdll_base = ::GetModuleHandle(L"ntdll.dll");
|
| - ASSERT_TRUE(NULL != ntdll_base);
|
| -
|
| - const char kFunctionName[] = "NtClose";
|
| -
|
| - void* target = ::GetProcAddress(ntdll_base, kFunctionName);
|
| - ASSERT_TRUE(NULL != target);
|
| -
|
| - BYTE service[50];
|
| - memcpy(service, target, sizeof(service));
|
| - static_cast<WinXpResolverTest*>(resolver)->set_target(service);
|
| -
|
| - // Any pointer will do as an interception_entry_point
|
| - void* function_entry = resolver;
|
| - size_t thunk_size = resolver->GetThunkSize();
|
| - scoped_ptr<char[]> thunk(new char[thunk_size]);
|
| - size_t used;
|
| -
|
| - NTSTATUS ret = STATUS_UNSUCCESSFUL;
|
| -
|
| - // First try patching without having allowed local patches.
|
| - ret = resolver->Setup(ntdll_base, NULL, kFunctionName, NULL,
|
| - function_entry, thunk.get(), thunk_size,
|
| - &used);
|
| - EXPECT_FALSE(NT_SUCCESS(ret));
|
| -
|
| - // Now allow local patches and check that things work.
|
| - resolver->AllowLocalPatches();
|
| - ret = resolver->Setup(ntdll_base, NULL, kFunctionName, NULL,
|
| - function_entry, thunk.get(), thunk_size,
|
| - &used);
|
| - EXPECT_EQ(STATUS_SUCCESS, ret);
|
| -}
|
| -
|
| -} // namespace
|
|
|