security/sandbox/win/src/interception.cc

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/security/sandbox/win/src/interception.cc	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,550 @@
     1.4 +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
     1.5 +// Use of this source code is governed by a BSD-style license that can be
     1.6 +// found in the LICENSE file.
     1.7 +
     1.8 +// For information about interceptions as a whole see
     1.9 +// http://dev.chromium.org/developers/design-documents/sandbox .
    1.10 +
    1.11 +#include <set>
    1.12 +
    1.13 +#include "sandbox/win/src/interception.h"
    1.14 +
    1.15 +#include "base/logging.h"
    1.16 +#include "base/memory/scoped_ptr.h"
    1.17 +#include "base/win/pe_image.h"
    1.18 +#include "base/win/windows_version.h"
    1.19 +#include "sandbox/win/src/interception_internal.h"
    1.20 +#include "sandbox/win/src/interceptors.h"
    1.21 +#include "sandbox/win/src/sandbox.h"
    1.22 +#include "sandbox/win/src/sandbox_utils.h"
    1.23 +#include "sandbox/win/src/service_resolver.h"
    1.24 +#include "sandbox/win/src/target_interceptions.h"
    1.25 +#include "sandbox/win/src/target_process.h"
    1.26 +#include "sandbox/win/src/wow64.h"
    1.27 +
    1.28 +namespace {
    1.29 +
    1.30 +const char kMapViewOfSectionName[] = "NtMapViewOfSection";
    1.31 +const char kUnmapViewOfSectionName[] = "NtUnmapViewOfSection";
    1.32 +
    1.33 +// Standard allocation granularity and page size for Windows.
    1.34 +const size_t kAllocGranularity = 65536;
    1.35 +const size_t kPageSize = 4096;
    1.36 +
    1.37 +// Find a random offset within 64k and aligned to ceil(log2(size)).
    1.38 +size_t GetGranularAlignedRandomOffset(size_t size) {
    1.39 +  CHECK_LE(size, kAllocGranularity);
    1.40 +  unsigned int offset;
    1.41 +
    1.42 +  do {
    1.43 +    rand_s(&offset);
    1.44 +    offset &= (kAllocGranularity - 1);
    1.45 +  } while (offset > (kAllocGranularity - size));
    1.46 +
    1.47 +  // Find an alignment between 64 and the page size (4096).
    1.48 +  size_t align_size = kPageSize;
    1.49 +  for (size_t new_size = align_size / 2;  new_size >= size; new_size /= 2) {
    1.50 +    align_size = new_size;
    1.51 +  }
    1.52 +  return offset & ~(align_size - 1);
    1.53 +}
    1.54 +
    1.55 +}  // namespace
    1.56 +
    1.57 +namespace sandbox {
    1.58 +
    1.59 +SANDBOX_INTERCEPT SharedMemory* g_interceptions;
    1.60 +
    1.61 +// Table of the unpatched functions that we intercept. Mapped from the parent.
    1.62 +SANDBOX_INTERCEPT OriginalFunctions g_originals = { NULL };
    1.63 +
    1.64 +// Magic constant that identifies that this function is not to be patched.
    1.65 +const char kUnloadDLLDummyFunction[] = "@";
    1.66 +
    1.67 +InterceptionManager::InterceptionManager(TargetProcess* child_process,
    1.68 +                                         bool relaxed)
    1.69 +    : child_(child_process), names_used_(false), relaxed_(relaxed) {
    1.70 +  child_->AddRef();
    1.71 +}
    1.72 +InterceptionManager::~InterceptionManager() {
    1.73 +  child_->Release();
    1.74 +}
    1.75 +
    1.76 +bool InterceptionManager::AddToPatchedFunctions(
    1.77 +    const wchar_t* dll_name, const char* function_name,
    1.78 +    InterceptionType interception_type, const void* replacement_code_address,
    1.79 +    InterceptorId id) {
    1.80 +  InterceptionData function;
    1.81 +  function.type = interception_type;
    1.82 +  function.id = id;
    1.83 +  function.dll = dll_name;
    1.84 +  function.function = function_name;
    1.85 +  function.interceptor_address = replacement_code_address;
    1.86 +
    1.87 +  interceptions_.push_back(function);
    1.88 +  return true;
    1.89 +}
    1.90 +
    1.91 +bool InterceptionManager::AddToPatchedFunctions(
    1.92 +    const wchar_t* dll_name, const char* function_name,
    1.93 +    InterceptionType interception_type, const char* replacement_function_name,
    1.94 +    InterceptorId id) {
    1.95 +  InterceptionData function;
    1.96 +  function.type = interception_type;
    1.97 +  function.id = id;
    1.98 +  function.dll = dll_name;
    1.99 +  function.function = function_name;
   1.100 +  function.interceptor = replacement_function_name;
   1.101 +  function.interceptor_address = NULL;
   1.102 +
   1.103 +  interceptions_.push_back(function);
   1.104 +  names_used_ = true;
   1.105 +  return true;
   1.106 +}
   1.107 +
   1.108 +bool InterceptionManager::AddToUnloadModules(const wchar_t* dll_name) {
   1.109 +  InterceptionData module_to_unload;
   1.110 +  module_to_unload.type = INTERCEPTION_UNLOAD_MODULE;
   1.111 +  module_to_unload.dll = dll_name;
   1.112 +  // The next two are dummy values that make the structures regular, instead
   1.113 +  // of having special cases. They should not be used.
   1.114 +  module_to_unload.function = kUnloadDLLDummyFunction;
   1.115 +  module_to_unload.interceptor_address = reinterpret_cast<void*>(1);
   1.116 +
   1.117 +  interceptions_.push_back(module_to_unload);
   1.118 +  return true;
   1.119 +}
   1.120 +
   1.121 +bool InterceptionManager::InitializeInterceptions() {
   1.122 +  if (interceptions_.empty())
   1.123 +    return true;  // Nothing to do here
   1.124 +
   1.125 +  size_t buffer_bytes = GetBufferSize();
   1.126 +  scoped_ptr<char[]> local_buffer(new char[buffer_bytes]);
   1.127 +
   1.128 +  if (!SetupConfigBuffer(local_buffer.get(), buffer_bytes))
   1.129 +    return false;
   1.130 +
   1.131 +  void* remote_buffer;
   1.132 +  if (!CopyDataToChild(local_buffer.get(), buffer_bytes, &remote_buffer))
   1.133 +    return false;
   1.134 +
   1.135 +  bool hot_patch_needed = (0 != buffer_bytes);
   1.136 +  if (!PatchNtdll(hot_patch_needed))
   1.137 +    return false;
   1.138 +
   1.139 +  g_interceptions = reinterpret_cast<SharedMemory*>(remote_buffer);
   1.140 +  ResultCode rc = child_->TransferVariable("g_interceptions",
   1.141 +                                           &g_interceptions,
   1.142 +                                           sizeof(g_interceptions));
   1.143 +  return (SBOX_ALL_OK == rc);
   1.144 +}
   1.145 +
   1.146 +size_t InterceptionManager::GetBufferSize() const {
   1.147 +  std::set<std::wstring> dlls;
   1.148 +  size_t buffer_bytes = 0;
   1.149 +
   1.150 +  std::list<InterceptionData>::const_iterator it = interceptions_.begin();
   1.151 +  for (; it != interceptions_.end(); ++it) {
   1.152 +    // skip interceptions that are performed from the parent
   1.153 +    if (!IsInterceptionPerformedByChild(*it))
   1.154 +      continue;
   1.155 +
   1.156 +    if (!dlls.count(it->dll)) {
   1.157 +      // NULL terminate the dll name on the structure
   1.158 +      size_t dll_name_bytes = (it->dll.size() + 1) * sizeof(wchar_t);
   1.159 +
   1.160 +      // include the dll related size
   1.161 +      buffer_bytes += RoundUpToMultiple(offsetof(DllPatchInfo, dll_name) +
   1.162 +                                            dll_name_bytes, sizeof(size_t));
   1.163 +      dlls.insert(it->dll);
   1.164 +    }
   1.165 +
   1.166 +    // we have to NULL terminate the strings on the structure
   1.167 +    size_t strings_chars = it->function.size() + it->interceptor.size() + 2;
   1.168 +
   1.169 +    // a new FunctionInfo is required per function
   1.170 +    size_t record_bytes = offsetof(FunctionInfo, function) + strings_chars;
   1.171 +    record_bytes = RoundUpToMultiple(record_bytes, sizeof(size_t));
   1.172 +    buffer_bytes += record_bytes;
   1.173 +  }
   1.174 +
   1.175 +  if (0 != buffer_bytes)
   1.176 +    // add the part of SharedMemory that we have not counted yet
   1.177 +    buffer_bytes += offsetof(SharedMemory, dll_list);
   1.178 +
   1.179 +  return buffer_bytes;
   1.180 +}
   1.181 +
   1.182 +// Basically, walk the list of interceptions moving them to the config buffer,
   1.183 +// but keeping together all interceptions that belong to the same dll.
   1.184 +// The config buffer is a local buffer, not the one allocated on the child.
   1.185 +bool InterceptionManager::SetupConfigBuffer(void* buffer, size_t buffer_bytes) {
   1.186 +  if (0 == buffer_bytes)
   1.187 +    return true;
   1.188 +
   1.189 +  DCHECK(buffer_bytes > sizeof(SharedMemory));
   1.190 +
   1.191 +  SharedMemory* shared_memory = reinterpret_cast<SharedMemory*>(buffer);
   1.192 +  DllPatchInfo* dll_info = shared_memory->dll_list;
   1.193 +  int num_dlls = 0;
   1.194 +
   1.195 +  shared_memory->interceptor_base = names_used_ ? child_->MainModule() : NULL;
   1.196 +
   1.197 +  buffer_bytes -= offsetof(SharedMemory, dll_list);
   1.198 +  buffer = dll_info;
   1.199 +
   1.200 +  std::list<InterceptionData>::iterator it = interceptions_.begin();
   1.201 +  for (; it != interceptions_.end();) {
   1.202 +    // skip interceptions that are performed from the parent
   1.203 +    if (!IsInterceptionPerformedByChild(*it)) {
   1.204 +      ++it;
   1.205 +      continue;
   1.206 +    }
   1.207 +
   1.208 +    const std::wstring dll = it->dll;
   1.209 +    if (!SetupDllInfo(*it, &buffer, &buffer_bytes))
   1.210 +      return false;
   1.211 +
   1.212 +    // walk the interceptions from this point, saving the ones that are
   1.213 +    // performed on this dll, and removing the entry from the list.
   1.214 +    // advance the iterator before removing the element from the list
   1.215 +    std::list<InterceptionData>::iterator rest = it;
   1.216 +    for (; rest != interceptions_.end();) {
   1.217 +      if (rest->dll == dll) {
   1.218 +        if (!SetupInterceptionInfo(*rest, &buffer, &buffer_bytes, dll_info))
   1.219 +          return false;
   1.220 +        if (it == rest)
   1.221 +          ++it;
   1.222 +        rest = interceptions_.erase(rest);
   1.223 +      } else {
   1.224 +        ++rest;
   1.225 +      }
   1.226 +    }
   1.227 +    dll_info = reinterpret_cast<DllPatchInfo*>(buffer);
   1.228 +    ++num_dlls;
   1.229 +  }
   1.230 +
   1.231 +  shared_memory->num_intercepted_dlls = num_dlls;
   1.232 +  return true;
   1.233 +}
   1.234 +
   1.235 +// Fills up just the part that depends on the dll, not the info that depends on
   1.236 +// the actual interception.
   1.237 +bool InterceptionManager::SetupDllInfo(const InterceptionData& data,
   1.238 +                                       void** buffer,
   1.239 +                                       size_t* buffer_bytes) const {
   1.240 +  DCHECK(buffer_bytes);
   1.241 +  DCHECK(buffer);
   1.242 +  DCHECK(*buffer);
   1.243 +
   1.244 +  DllPatchInfo* dll_info = reinterpret_cast<DllPatchInfo*>(*buffer);
   1.245 +
   1.246 +  // the strings have to be zero terminated
   1.247 +  size_t required = offsetof(DllPatchInfo, dll_name) +
   1.248 +                    (data.dll.size() + 1) * sizeof(wchar_t);
   1.249 +  required = RoundUpToMultiple(required, sizeof(size_t));
   1.250 +  if (*buffer_bytes < required)
   1.251 +    return false;
   1.252 +
   1.253 +  *buffer_bytes -= required;
   1.254 +  *buffer = reinterpret_cast<char*>(*buffer) + required;
   1.255 +
   1.256 +  // set up the dll info to be what we know about it at this time
   1.257 +  dll_info->unload_module = (data.type == INTERCEPTION_UNLOAD_MODULE);
   1.258 +  dll_info->record_bytes = required;
   1.259 +  dll_info->offset_to_functions = required;
   1.260 +  dll_info->num_functions = 0;
   1.261 +  data.dll._Copy_s(dll_info->dll_name, data.dll.size(), data.dll.size());
   1.262 +  dll_info->dll_name[data.dll.size()] = L'\0';
   1.263 +
   1.264 +  return true;
   1.265 +}
   1.266 +
   1.267 +bool InterceptionManager::SetupInterceptionInfo(const InterceptionData& data,
   1.268 +                                                void** buffer,
   1.269 +                                                size_t* buffer_bytes,
   1.270 +                                                DllPatchInfo* dll_info) const {
   1.271 +  DCHECK(buffer_bytes);
   1.272 +  DCHECK(buffer);
   1.273 +  DCHECK(*buffer);
   1.274 +
   1.275 +  if ((dll_info->unload_module) &&
   1.276 +      (data.function != kUnloadDLLDummyFunction)) {
   1.277 +    // Can't specify a dll for both patch and unload.
   1.278 +    NOTREACHED();
   1.279 +  }
   1.280 +
   1.281 +  FunctionInfo* function = reinterpret_cast<FunctionInfo*>(*buffer);
   1.282 +
   1.283 +  size_t name_bytes = data.function.size();
   1.284 +  size_t interceptor_bytes = data.interceptor.size();
   1.285 +
   1.286 +  // the strings at the end of the structure are zero terminated
   1.287 +  size_t required = offsetof(FunctionInfo, function) +
   1.288 +                    name_bytes + interceptor_bytes + 2;
   1.289 +  required = RoundUpToMultiple(required, sizeof(size_t));
   1.290 +  if (*buffer_bytes < required)
   1.291 +    return false;
   1.292 +
   1.293 +  // update the caller's values
   1.294 +  *buffer_bytes -= required;
   1.295 +  *buffer = reinterpret_cast<char*>(*buffer) + required;
   1.296 +
   1.297 +  function->record_bytes = required;
   1.298 +  function->type = data.type;
   1.299 +  function->id = data.id;
   1.300 +  function->interceptor_address = data.interceptor_address;
   1.301 +  char* names = function->function;
   1.302 +
   1.303 +  data.function._Copy_s(names, name_bytes, name_bytes);
   1.304 +  names += name_bytes;
   1.305 +  *names++ = '\0';
   1.306 +
   1.307 +  // interceptor follows the function_name
   1.308 +  data.interceptor._Copy_s(names, interceptor_bytes, interceptor_bytes);
   1.309 +  names += interceptor_bytes;
   1.310 +  *names++ = '\0';
   1.311 +
   1.312 +  // update the dll table
   1.313 +  dll_info->num_functions++;
   1.314 +  dll_info->record_bytes += required;
   1.315 +
   1.316 +  return true;
   1.317 +}
   1.318 +
   1.319 +bool InterceptionManager::CopyDataToChild(const void* local_buffer,
   1.320 +                                          size_t buffer_bytes,
   1.321 +                                          void** remote_buffer) const {
   1.322 +  DCHECK(NULL != remote_buffer);
   1.323 +  if (0 == buffer_bytes) {
   1.324 +    *remote_buffer = NULL;
   1.325 +    return true;
   1.326 +  }
   1.327 +
   1.328 +  HANDLE child = child_->Process();
   1.329 +
   1.330 +  // Allocate memory on the target process without specifying the address
   1.331 +  void* remote_data = ::VirtualAllocEx(child, NULL, buffer_bytes,
   1.332 +                                       MEM_COMMIT, PAGE_READWRITE);
   1.333 +  if (NULL == remote_data)
   1.334 +    return false;
   1.335 +
   1.336 +  SIZE_T bytes_written;
   1.337 +  BOOL success = ::WriteProcessMemory(child, remote_data, local_buffer,
   1.338 +                                      buffer_bytes, &bytes_written);
   1.339 +  if (FALSE == success || bytes_written != buffer_bytes) {
   1.340 +    ::VirtualFreeEx(child, remote_data, 0, MEM_RELEASE);
   1.341 +    return false;
   1.342 +  }
   1.343 +
   1.344 +  *remote_buffer = remote_data;
   1.345 +
   1.346 +  return true;
   1.347 +}
   1.348 +
   1.349 +// Only return true if the child should be able to perform this interception.
   1.350 +bool InterceptionManager::IsInterceptionPerformedByChild(
   1.351 +    const InterceptionData& data) const {
   1.352 +  if (INTERCEPTION_INVALID == data.type)
   1.353 +    return false;
   1.354 +
   1.355 +  if (INTERCEPTION_SERVICE_CALL == data.type)
   1.356 +    return false;
   1.357 +
   1.358 +  if (data.type >= INTERCEPTION_LAST)
   1.359 +    return false;
   1.360 +
   1.361 +  std::wstring ntdll(kNtdllName);
   1.362 +  if (ntdll == data.dll)
   1.363 +    return false;  // ntdll has to be intercepted from the parent
   1.364 +
   1.365 +  return true;
   1.366 +}
   1.367 +
   1.368 +bool InterceptionManager::PatchNtdll(bool hot_patch_needed) {
   1.369 +  // Maybe there is nothing to do
   1.370 +  if (!hot_patch_needed && interceptions_.empty())
   1.371 +    return true;
   1.372 +
   1.373 +  if (hot_patch_needed) {
   1.374 +#if SANDBOX_EXPORTS
   1.375 +    // Make sure the functions are not excluded by the linker.
   1.376 +#if defined(_WIN64)
   1.377 +    #pragma comment(linker, "/include:TargetNtMapViewOfSection64")
   1.378 +    #pragma comment(linker, "/include:TargetNtUnmapViewOfSection64")
   1.379 +#else
   1.380 +    #pragma comment(linker, "/include:_TargetNtMapViewOfSection@44")
   1.381 +    #pragma comment(linker, "/include:_TargetNtUnmapViewOfSection@12")
   1.382 +#endif
   1.383 +#endif
   1.384 +    ADD_NT_INTERCEPTION(NtMapViewOfSection, MAP_VIEW_OF_SECTION_ID, 44);
   1.385 +    ADD_NT_INTERCEPTION(NtUnmapViewOfSection, UNMAP_VIEW_OF_SECTION_ID, 12);
   1.386 +  }
   1.387 +
   1.388 +  // Reserve a full 64k memory range in the child process.
   1.389 +  HANDLE child = child_->Process();
   1.390 +  BYTE* thunk_base = reinterpret_cast<BYTE*>(
   1.391 +                         ::VirtualAllocEx(child, NULL, kAllocGranularity,
   1.392 +                                          MEM_RESERVE, PAGE_NOACCESS));
   1.393 +
   1.394 +  // Find an aligned, random location within the reserved range.
   1.395 +  size_t thunk_bytes = interceptions_.size() * sizeof(ThunkData) +
   1.396 +                       sizeof(DllInterceptionData);
   1.397 +  size_t thunk_offset = GetGranularAlignedRandomOffset(thunk_bytes);
   1.398 +
   1.399 +  // Split the base and offset along page boundaries.
   1.400 +  thunk_base += thunk_offset & ~(kPageSize - 1);
   1.401 +  thunk_offset &= kPageSize - 1;
   1.402 +
   1.403 +  // Make an aligned, padded allocation, and move the pointer to our chunk.
   1.404 +  size_t thunk_bytes_padded = (thunk_bytes + kPageSize - 1) & kPageSize;
   1.405 +  thunk_base = reinterpret_cast<BYTE*>(
   1.406 +                   ::VirtualAllocEx(child, thunk_base, thunk_bytes_padded,
   1.407 +                                    MEM_COMMIT, PAGE_EXECUTE_READWRITE));
   1.408 +  CHECK(thunk_base);  // If this fails we'd crash anyway on an invalid access.
   1.409 +  DllInterceptionData* thunks = reinterpret_cast<DllInterceptionData*>(
   1.410 +                                    thunk_base + thunk_offset);
   1.411 +
   1.412 +  DllInterceptionData dll_data;
   1.413 +  dll_data.data_bytes = thunk_bytes;
   1.414 +  dll_data.num_thunks = 0;
   1.415 +  dll_data.used_bytes = offsetof(DllInterceptionData, thunks);
   1.416 +
   1.417 +  // Reset all helpers for a new child.
   1.418 +  memset(g_originals, 0, sizeof(g_originals));
   1.419 +
   1.420 +  // this should write all the individual thunks to the child's memory
   1.421 +  if (!PatchClientFunctions(thunks, thunk_bytes, &dll_data))
   1.422 +    return false;
   1.423 +
   1.424 +  // and now write the first part of the table to the child's memory
   1.425 +  SIZE_T written;
   1.426 +  bool ok = FALSE != ::WriteProcessMemory(child, thunks, &dll_data,
   1.427 +                                          offsetof(DllInterceptionData, thunks),
   1.428 +                                          &written);
   1.429 +
   1.430 +  if (!ok || (offsetof(DllInterceptionData, thunks) != written))
   1.431 +    return false;
   1.432 +
   1.433 +  // Attempt to protect all the thunks, but ignore failure
   1.434 +  DWORD old_protection;
   1.435 +  ::VirtualProtectEx(child, thunks, thunk_bytes,
   1.436 +                     PAGE_EXECUTE_READ, &old_protection);
   1.437 +
   1.438 +  ResultCode ret = child_->TransferVariable("g_originals", g_originals,
   1.439 +                                            sizeof(g_originals));
   1.440 +  return (SBOX_ALL_OK == ret);
   1.441 +}
   1.442 +
   1.443 +bool InterceptionManager::PatchClientFunctions(DllInterceptionData* thunks,
   1.444 +                                               size_t thunk_bytes,
   1.445 +                                               DllInterceptionData* dll_data) {
   1.446 +  DCHECK(NULL != thunks);
   1.447 +  DCHECK(NULL != dll_data);
   1.448 +
   1.449 +  HMODULE ntdll_base = ::GetModuleHandle(kNtdllName);
   1.450 +  if (!ntdll_base)
   1.451 +    return false;
   1.452 +
   1.453 +  base::win::PEImage ntdll_image(ntdll_base);
   1.454 +
   1.455 +  // Bypass purify's interception.
   1.456 +  wchar_t* loader_get = reinterpret_cast<wchar_t*>(
   1.457 +                            ntdll_image.GetProcAddress("LdrGetDllHandle"));
   1.458 +  if (loader_get) {
   1.459 +    if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
   1.460 +                               GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
   1.461 +                           loader_get, &ntdll_base))
   1.462 +      return false;
   1.463 +  }
   1.464 +
   1.465 +  if (base::win::GetVersion() <= base::win::VERSION_VISTA) {
   1.466 +    Wow64 WowHelper(child_, ntdll_base);
   1.467 +    if (!WowHelper.WaitForNtdll())
   1.468 +      return false;
   1.469 +  }
   1.470 +
   1.471 +  char* interceptor_base = NULL;
   1.472 +
   1.473 +#if SANDBOX_EXPORTS
   1.474 +  interceptor_base = reinterpret_cast<char*>(child_->MainModule());
   1.475 +  HMODULE local_interceptor = ::LoadLibrary(child_->Name());
   1.476 +#endif
   1.477 +
   1.478 +  ServiceResolverThunk* thunk;
   1.479 +#if defined(_WIN64)
   1.480 +  thunk = new ServiceResolverThunk(child_->Process(), relaxed_);
   1.481 +#else
   1.482 +  base::win::OSInfo* os_info = base::win::OSInfo::GetInstance();
   1.483 +  if (os_info->wow64_status() == base::win::OSInfo::WOW64_ENABLED) {
   1.484 +    if (os_info->version() >= base::win::VERSION_WIN8)
   1.485 +      thunk = new Wow64W8ResolverThunk(child_->Process(), relaxed_);
   1.486 +    else
   1.487 +      thunk = new Wow64ResolverThunk(child_->Process(), relaxed_);
   1.488 +  } else if (!IsXPSP2OrLater()) {
   1.489 +    thunk = new Win2kResolverThunk(child_->Process(), relaxed_);
   1.490 +  } else if (os_info->version() >= base::win::VERSION_WIN8) {
   1.491 +    thunk = new Win8ResolverThunk(child_->Process(), relaxed_);
   1.492 +  } else {
   1.493 +    thunk = new ServiceResolverThunk(child_->Process(), relaxed_);
   1.494 +  }
   1.495 +#endif
   1.496 +
   1.497 +  std::list<InterceptionData>::iterator it = interceptions_.begin();
   1.498 +  for (; it != interceptions_.end(); ++it) {
   1.499 +    const std::wstring ntdll(kNtdllName);
   1.500 +    if (it->dll != ntdll)
   1.501 +      break;
   1.502 +
   1.503 +    if (INTERCEPTION_SERVICE_CALL != it->type)
   1.504 +      break;
   1.505 +
   1.506 +#if SANDBOX_EXPORTS
   1.507 +    // We may be trying to patch by function name.
   1.508 +    if (NULL == it->interceptor_address) {
   1.509 +      const char* address;
   1.510 +      NTSTATUS ret = thunk->ResolveInterceptor(local_interceptor,
   1.511 +                                               it->interceptor.c_str(),
   1.512 +                                               reinterpret_cast<const void**>(
   1.513 +                                               &address));
   1.514 +      if (!NT_SUCCESS(ret))
   1.515 +        break;
   1.516 +
   1.517 +      // Translate the local address to an address on the child.
   1.518 +      it->interceptor_address = interceptor_base + (address -
   1.519 +                                    reinterpret_cast<char*>(local_interceptor));
   1.520 +    }
   1.521 +#endif
   1.522 +    NTSTATUS ret = thunk->Setup(ntdll_base,
   1.523 +                                interceptor_base,
   1.524 +                                it->function.c_str(),
   1.525 +                                it->interceptor.c_str(),
   1.526 +                                it->interceptor_address,
   1.527 +                                &thunks->thunks[dll_data->num_thunks],
   1.528 +                                thunk_bytes - dll_data->used_bytes,
   1.529 +                                NULL);
   1.530 +    if (!NT_SUCCESS(ret))
   1.531 +      break;
   1.532 +
   1.533 +    DCHECK(!g_originals[it->id]);
   1.534 +    g_originals[it->id] = &thunks->thunks[dll_data->num_thunks];
   1.535 +
   1.536 +    dll_data->num_thunks++;
   1.537 +    dll_data->used_bytes += sizeof(ThunkData);
   1.538 +  }
   1.539 +
   1.540 +  delete(thunk);
   1.541 +
   1.542 +#if SANDBOX_EXPORTS
   1.543 +  if (NULL != local_interceptor)
   1.544 +    ::FreeLibrary(local_interceptor);
   1.545 +#endif
   1.546 +
   1.547 +  if (it != interceptions_.end())
   1.548 +    return false;
   1.549 +
   1.550 +  return true;
   1.551 +}
   1.552 +
   1.553 +}  // namespace sandbox

mercurial