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