Home | History | Annotate | Download | only in src
      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     ntdll_base_ = ::GetModuleHandle(L"ntdll.dll");
     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::Win2kResolverThunk> Win2kResolverTest;
     62 typedef ResolverThunkTest<sandbox::Win8ResolverThunk> Win8ResolverTest;
     63 typedef ResolverThunkTest<sandbox::Wow64ResolverThunk> Wow64ResolverTest;
     64 typedef ResolverThunkTest<sandbox::Wow64W8ResolverThunk> Wow64W8ResolverTest;
     65 #endif
     66 
     67 const BYTE kJump32 = 0xE9;
     68 
     69 void CheckJump(void* source, void* target) {
     70 #pragma pack(push)
     71 #pragma pack(1)
     72   struct Code {
     73     BYTE jump;
     74     ULONG delta;
     75   };
     76 #pragma pack(pop)
     77 
     78 #if defined(_WIN64)
     79   FAIL() << "Running 32-bit codepath";
     80 #else
     81   Code* patched = reinterpret_cast<Code*>(source);
     82   EXPECT_EQ(kJump32, patched->jump);
     83 
     84   ULONG source_addr = bit_cast<ULONG>(source);
     85   ULONG target_addr = bit_cast<ULONG>(target);
     86   EXPECT_EQ(target_addr + 19 - source_addr, patched->delta);
     87 #endif
     88 }
     89 
     90 NTSTATUS PatchNtdllWithResolver(const char* function, bool relaxed,
     91                                 sandbox::ServiceResolverThunk* resolver) {
     92   HMODULE ntdll_base = ::GetModuleHandle(L"ntdll.dll");
     93   EXPECT_TRUE(NULL != ntdll_base);
     94 
     95   void* target = ::GetProcAddress(ntdll_base, function);
     96   EXPECT_TRUE(NULL != target);
     97   if (NULL == target)
     98     return STATUS_UNSUCCESSFUL;
     99 
    100   BYTE service[50];
    101   memcpy(service, target, sizeof(service));
    102 
    103   static_cast<WinXpResolverTest*>(resolver)->set_target(service);
    104 
    105   // Any pointer will do as an interception_entry_point
    106   void* function_entry = resolver;
    107   size_t thunk_size = resolver->GetThunkSize();
    108   scoped_ptr<char[]> thunk(new char[thunk_size]);
    109   size_t used;
    110 
    111   NTSTATUS ret = resolver->Setup(ntdll_base, NULL, function, NULL,
    112                                  function_entry, thunk.get(), thunk_size,
    113                                  &used);
    114   if (NT_SUCCESS(ret)) {
    115     EXPECT_EQ(thunk_size, used);
    116     EXPECT_NE(0, memcmp(service, target, sizeof(service)));
    117     EXPECT_NE(kJump32, service[0]);
    118 
    119     if (relaxed) {
    120       // It's already patched, let's patch again, and simulate a direct patch.
    121       service[0] = kJump32;
    122       ret = resolver->Setup(ntdll_base, NULL, function, NULL, function_entry,
    123                             thunk.get(), thunk_size, &used);
    124       CheckJump(service, thunk.get());
    125     }
    126   }
    127 
    128   return ret;
    129 }
    130 
    131 sandbox::ServiceResolverThunk* GetTestResolver(bool relaxed) {
    132 #if defined(_WIN64)
    133   return new WinXpResolverTest(relaxed);
    134 #else
    135   base::win::OSInfo* os_info = base::win::OSInfo::GetInstance();
    136   if (os_info->wow64_status() == base::win::OSInfo::WOW64_ENABLED) {
    137     if (os_info->version() >= base::win::VERSION_WIN8)
    138       return new Wow64W8ResolverTest(relaxed);
    139     return new Wow64ResolverTest(relaxed);
    140   }
    141 
    142   if (!sandbox::IsXPSP2OrLater())
    143     return new Win2kResolverTest(relaxed);
    144 
    145   if (os_info->version() >= base::win::VERSION_WIN8)
    146     return new Win8ResolverTest(relaxed);
    147 
    148   return new WinXpResolverTest(relaxed);
    149 #endif
    150 }
    151 
    152 NTSTATUS PatchNtdll(const char* function, bool relaxed) {
    153   sandbox::ServiceResolverThunk* resolver = GetTestResolver(relaxed);
    154 
    155   NTSTATUS ret = PatchNtdllWithResolver(function, relaxed, resolver);
    156   delete resolver;
    157   return ret;
    158 }
    159 
    160 TEST(ServiceResolverTest, PatchesServices) {
    161   NTSTATUS ret = PatchNtdll("NtClose", false);
    162   EXPECT_EQ(STATUS_SUCCESS, ret) << "NtClose, last error: " << ::GetLastError();
    163 
    164   ret = PatchNtdll("NtCreateFile", false);
    165   EXPECT_EQ(STATUS_SUCCESS, ret) << "NtCreateFile, last error: " <<
    166     ::GetLastError();
    167 
    168   ret = PatchNtdll("NtCreateMutant", false);
    169   EXPECT_EQ(STATUS_SUCCESS, ret) << "NtCreateMutant, last error: " <<
    170     ::GetLastError();
    171 
    172   ret = PatchNtdll("NtMapViewOfSection", false);
    173   EXPECT_EQ(STATUS_SUCCESS, ret) << "NtMapViewOfSection, last error: " <<
    174     ::GetLastError();
    175 }
    176 
    177 TEST(ServiceResolverTest, FailsIfNotService) {
    178 #if !defined(_WIN64)
    179   EXPECT_NE(STATUS_SUCCESS, PatchNtdll("RtlUlongByteSwap", false));
    180 #endif
    181 
    182   EXPECT_NE(STATUS_SUCCESS, PatchNtdll("LdrLoadDll", false));
    183 }
    184 
    185 TEST(ServiceResolverTest, PatchesPatchedServices) {
    186 // We don't support "relaxed mode" for Win64 apps.
    187 #if !defined(_WIN64)
    188   NTSTATUS ret = PatchNtdll("NtClose", true);
    189   EXPECT_EQ(STATUS_SUCCESS, ret) << "NtClose, last error: " << ::GetLastError();
    190 
    191   ret = PatchNtdll("NtCreateFile", true);
    192   EXPECT_EQ(STATUS_SUCCESS, ret) << "NtCreateFile, last error: " <<
    193     ::GetLastError();
    194 
    195   ret = PatchNtdll("NtCreateMutant", true);
    196   EXPECT_EQ(STATUS_SUCCESS, ret) << "NtCreateMutant, last error: " <<
    197     ::GetLastError();
    198 
    199   ret = PatchNtdll("NtMapViewOfSection", true);
    200   EXPECT_EQ(STATUS_SUCCESS, ret) << "NtMapViewOfSection, last error: " <<
    201     ::GetLastError();
    202 #endif
    203 }
    204 
    205 TEST(ServiceResolverTest, MultiplePatchedServices) {
    206 // We don't support "relaxed mode" for Win64 apps.
    207 #if !defined(_WIN64)
    208   sandbox::ServiceResolverThunk* resolver = GetTestResolver(true);
    209   NTSTATUS ret = PatchNtdllWithResolver("NtClose", true, resolver);
    210   EXPECT_EQ(STATUS_SUCCESS, ret) << "NtClose, last error: " << ::GetLastError();
    211 
    212   ret = PatchNtdllWithResolver("NtCreateFile", true, resolver);
    213   EXPECT_EQ(STATUS_SUCCESS, ret) << "NtCreateFile, last error: " <<
    214     ::GetLastError();
    215 
    216   ret = PatchNtdllWithResolver("NtCreateMutant", true, resolver);
    217   EXPECT_EQ(STATUS_SUCCESS, ret) << "NtCreateMutant, last error: " <<
    218     ::GetLastError();
    219 
    220   ret = PatchNtdllWithResolver("NtMapViewOfSection", true, resolver);
    221   EXPECT_EQ(STATUS_SUCCESS, ret) << "NtMapViewOfSection, last error: " <<
    222     ::GetLastError();
    223   delete resolver;
    224 #endif
    225 }
    226 
    227 }  // namespace
    228