security/sandbox/win/src/service_resolver_unittest.cc

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
michael@0 2 // Use of this source code is governed by a BSD-style license that can be
michael@0 3 // found in the LICENSE file.
michael@0 4
michael@0 5 // This file contains unit tests for ServiceResolverThunk.
michael@0 6
michael@0 7 #include "base/basictypes.h"
michael@0 8 #include "base/memory/scoped_ptr.h"
michael@0 9 #include "base/win/windows_version.h"
michael@0 10 #include "sandbox/win/src/resolver.h"
michael@0 11 #include "sandbox/win/src/sandbox_utils.h"
michael@0 12 #include "sandbox/win/src/service_resolver.h"
michael@0 13 #include "testing/gtest/include/gtest/gtest.h"
michael@0 14
michael@0 15 namespace {
michael@0 16
michael@0 17 // This is the concrete resolver used to perform service-call type functions
michael@0 18 // inside ntdll.dll.
michael@0 19 template<typename T>
michael@0 20 class ResolverThunkTest : public T {
michael@0 21 public:
michael@0 22 // The service resolver needs a child process to write to.
michael@0 23 explicit ResolverThunkTest(bool relaxed)
michael@0 24 : T(::GetCurrentProcess(), relaxed) {}
michael@0 25
michael@0 26 // Sets the interception target to the desired address.
michael@0 27 void set_target(void* target) {
michael@0 28 fake_target_ = target;
michael@0 29 }
michael@0 30
michael@0 31 protected:
michael@0 32 // Overrides Resolver::Init
michael@0 33 virtual NTSTATUS Init(const void* target_module,
michael@0 34 const void* interceptor_module,
michael@0 35 const char* target_name,
michael@0 36 const char* interceptor_name,
michael@0 37 const void* interceptor_entry_point,
michael@0 38 void* thunk_storage,
michael@0 39 size_t storage_bytes) {
michael@0 40 NTSTATUS ret = STATUS_SUCCESS;
michael@0 41 ret = ResolverThunk::Init(target_module, interceptor_module, target_name,
michael@0 42 interceptor_name, interceptor_entry_point,
michael@0 43 thunk_storage, storage_bytes);
michael@0 44 EXPECT_EQ(STATUS_SUCCESS, ret);
michael@0 45
michael@0 46 target_ = fake_target_;
michael@0 47 ntdll_base_ = ::GetModuleHandle(L"ntdll.dll");
michael@0 48 return ret;
michael@0 49 };
michael@0 50
michael@0 51 private:
michael@0 52 // Holds the address of the fake target.
michael@0 53 void* fake_target_;
michael@0 54
michael@0 55 DISALLOW_COPY_AND_ASSIGN(ResolverThunkTest);
michael@0 56 };
michael@0 57
michael@0 58 typedef ResolverThunkTest<sandbox::ServiceResolverThunk> WinXpResolverTest;
michael@0 59
michael@0 60 #if !defined(_WIN64)
michael@0 61 typedef ResolverThunkTest<sandbox::Win2kResolverThunk> Win2kResolverTest;
michael@0 62 typedef ResolverThunkTest<sandbox::Win8ResolverThunk> Win8ResolverTest;
michael@0 63 typedef ResolverThunkTest<sandbox::Wow64ResolverThunk> Wow64ResolverTest;
michael@0 64 typedef ResolverThunkTest<sandbox::Wow64W8ResolverThunk> Wow64W8ResolverTest;
michael@0 65 #endif
michael@0 66
michael@0 67 const BYTE kJump32 = 0xE9;
michael@0 68
michael@0 69 void CheckJump(void* source, void* target) {
michael@0 70 #pragma pack(push)
michael@0 71 #pragma pack(1)
michael@0 72 struct Code {
michael@0 73 BYTE jump;
michael@0 74 ULONG delta;
michael@0 75 };
michael@0 76 #pragma pack(pop)
michael@0 77
michael@0 78 #if defined(_WIN64)
michael@0 79 FAIL() << "Running 32-bit codepath";
michael@0 80 #else
michael@0 81 Code* patched = reinterpret_cast<Code*>(source);
michael@0 82 EXPECT_EQ(kJump32, patched->jump);
michael@0 83
michael@0 84 ULONG source_addr = bit_cast<ULONG>(source);
michael@0 85 ULONG target_addr = bit_cast<ULONG>(target);
michael@0 86 EXPECT_EQ(target_addr + 19 - source_addr, patched->delta);
michael@0 87 #endif
michael@0 88 }
michael@0 89
michael@0 90 NTSTATUS PatchNtdllWithResolver(const char* function, bool relaxed,
michael@0 91 sandbox::ServiceResolverThunk* resolver) {
michael@0 92 HMODULE ntdll_base = ::GetModuleHandle(L"ntdll.dll");
michael@0 93 EXPECT_TRUE(NULL != ntdll_base);
michael@0 94
michael@0 95 void* target = ::GetProcAddress(ntdll_base, function);
michael@0 96 EXPECT_TRUE(NULL != target);
michael@0 97 if (NULL == target)
michael@0 98 return STATUS_UNSUCCESSFUL;
michael@0 99
michael@0 100 BYTE service[50];
michael@0 101 memcpy(service, target, sizeof(service));
michael@0 102
michael@0 103 static_cast<WinXpResolverTest*>(resolver)->set_target(service);
michael@0 104
michael@0 105 // Any pointer will do as an interception_entry_point
michael@0 106 void* function_entry = resolver;
michael@0 107 size_t thunk_size = resolver->GetThunkSize();
michael@0 108 scoped_ptr<char[]> thunk(new char[thunk_size]);
michael@0 109 size_t used;
michael@0 110
michael@0 111 NTSTATUS ret = resolver->Setup(ntdll_base, NULL, function, NULL,
michael@0 112 function_entry, thunk.get(), thunk_size,
michael@0 113 &used);
michael@0 114 if (NT_SUCCESS(ret)) {
michael@0 115 EXPECT_EQ(thunk_size, used);
michael@0 116 EXPECT_NE(0, memcmp(service, target, sizeof(service)));
michael@0 117 EXPECT_NE(kJump32, service[0]);
michael@0 118
michael@0 119 if (relaxed) {
michael@0 120 // It's already patched, let's patch again, and simulate a direct patch.
michael@0 121 service[0] = kJump32;
michael@0 122 ret = resolver->Setup(ntdll_base, NULL, function, NULL, function_entry,
michael@0 123 thunk.get(), thunk_size, &used);
michael@0 124 CheckJump(service, thunk.get());
michael@0 125 }
michael@0 126 }
michael@0 127
michael@0 128 return ret;
michael@0 129 }
michael@0 130
michael@0 131 sandbox::ServiceResolverThunk* GetTestResolver(bool relaxed) {
michael@0 132 #if defined(_WIN64)
michael@0 133 return new WinXpResolverTest(relaxed);
michael@0 134 #else
michael@0 135 base::win::OSInfo* os_info = base::win::OSInfo::GetInstance();
michael@0 136 if (os_info->wow64_status() == base::win::OSInfo::WOW64_ENABLED) {
michael@0 137 if (os_info->version() >= base::win::VERSION_WIN8)
michael@0 138 return new Wow64W8ResolverTest(relaxed);
michael@0 139 return new Wow64ResolverTest(relaxed);
michael@0 140 }
michael@0 141
michael@0 142 if (!sandbox::IsXPSP2OrLater())
michael@0 143 return new Win2kResolverTest(relaxed);
michael@0 144
michael@0 145 if (os_info->version() >= base::win::VERSION_WIN8)
michael@0 146 return new Win8ResolverTest(relaxed);
michael@0 147
michael@0 148 return new WinXpResolverTest(relaxed);
michael@0 149 #endif
michael@0 150 }
michael@0 151
michael@0 152 NTSTATUS PatchNtdll(const char* function, bool relaxed) {
michael@0 153 sandbox::ServiceResolverThunk* resolver = GetTestResolver(relaxed);
michael@0 154
michael@0 155 NTSTATUS ret = PatchNtdllWithResolver(function, relaxed, resolver);
michael@0 156 delete resolver;
michael@0 157 return ret;
michael@0 158 }
michael@0 159
michael@0 160 TEST(ServiceResolverTest, PatchesServices) {
michael@0 161 NTSTATUS ret = PatchNtdll("NtClose", false);
michael@0 162 EXPECT_EQ(STATUS_SUCCESS, ret) << "NtClose, last error: " << ::GetLastError();
michael@0 163
michael@0 164 ret = PatchNtdll("NtCreateFile", false);
michael@0 165 EXPECT_EQ(STATUS_SUCCESS, ret) << "NtCreateFile, last error: " <<
michael@0 166 ::GetLastError();
michael@0 167
michael@0 168 ret = PatchNtdll("NtCreateMutant", false);
michael@0 169 EXPECT_EQ(STATUS_SUCCESS, ret) << "NtCreateMutant, last error: " <<
michael@0 170 ::GetLastError();
michael@0 171
michael@0 172 ret = PatchNtdll("NtMapViewOfSection", false);
michael@0 173 EXPECT_EQ(STATUS_SUCCESS, ret) << "NtMapViewOfSection, last error: " <<
michael@0 174 ::GetLastError();
michael@0 175 }
michael@0 176
michael@0 177 TEST(ServiceResolverTest, FailsIfNotService) {
michael@0 178 #if !defined(_WIN64)
michael@0 179 EXPECT_NE(STATUS_SUCCESS, PatchNtdll("RtlUlongByteSwap", false));
michael@0 180 #endif
michael@0 181
michael@0 182 EXPECT_NE(STATUS_SUCCESS, PatchNtdll("LdrLoadDll", false));
michael@0 183 }
michael@0 184
michael@0 185 TEST(ServiceResolverTest, PatchesPatchedServices) {
michael@0 186 // We don't support "relaxed mode" for Win64 apps.
michael@0 187 #if !defined(_WIN64)
michael@0 188 NTSTATUS ret = PatchNtdll("NtClose", true);
michael@0 189 EXPECT_EQ(STATUS_SUCCESS, ret) << "NtClose, last error: " << ::GetLastError();
michael@0 190
michael@0 191 ret = PatchNtdll("NtCreateFile", true);
michael@0 192 EXPECT_EQ(STATUS_SUCCESS, ret) << "NtCreateFile, last error: " <<
michael@0 193 ::GetLastError();
michael@0 194
michael@0 195 ret = PatchNtdll("NtCreateMutant", true);
michael@0 196 EXPECT_EQ(STATUS_SUCCESS, ret) << "NtCreateMutant, last error: " <<
michael@0 197 ::GetLastError();
michael@0 198
michael@0 199 ret = PatchNtdll("NtMapViewOfSection", true);
michael@0 200 EXPECT_EQ(STATUS_SUCCESS, ret) << "NtMapViewOfSection, last error: " <<
michael@0 201 ::GetLastError();
michael@0 202 #endif
michael@0 203 }
michael@0 204
michael@0 205 TEST(ServiceResolverTest, MultiplePatchedServices) {
michael@0 206 // We don't support "relaxed mode" for Win64 apps.
michael@0 207 #if !defined(_WIN64)
michael@0 208 sandbox::ServiceResolverThunk* resolver = GetTestResolver(true);
michael@0 209 NTSTATUS ret = PatchNtdllWithResolver("NtClose", true, resolver);
michael@0 210 EXPECT_EQ(STATUS_SUCCESS, ret) << "NtClose, last error: " << ::GetLastError();
michael@0 211
michael@0 212 ret = PatchNtdllWithResolver("NtCreateFile", true, resolver);
michael@0 213 EXPECT_EQ(STATUS_SUCCESS, ret) << "NtCreateFile, last error: " <<
michael@0 214 ::GetLastError();
michael@0 215
michael@0 216 ret = PatchNtdllWithResolver("NtCreateMutant", true, resolver);
michael@0 217 EXPECT_EQ(STATUS_SUCCESS, ret) << "NtCreateMutant, last error: " <<
michael@0 218 ::GetLastError();
michael@0 219
michael@0 220 ret = PatchNtdllWithResolver("NtMapViewOfSection", true, resolver);
michael@0 221 EXPECT_EQ(STATUS_SUCCESS, ret) << "NtMapViewOfSection, last error: " <<
michael@0 222 ::GetLastError();
michael@0 223 delete resolver;
michael@0 224 #endif
michael@0 225 }
michael@0 226
michael@0 227 } // namespace

mercurial