Coverage for /Syzygy/agent/asan/syzyasan_rtl.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
85.1%74870.C++source

Line-by-line coverage:

   1    :  // Copyright 2012 Google Inc. All Rights Reserved.
   2    :  //
   3    :  // Licensed under the Apache License, Version 2.0 (the "License");
   4    :  // you may not use this file except in compliance with the License.
   5    :  // You may obtain a copy of the License at
   6    :  //
   7    :  //     http://www.apache.org/licenses/LICENSE-2.0
   8    :  //
   9    :  // Unless required by applicable law or agreed to in writing, software
  10    :  // distributed under the License is distributed on an "AS IS" BASIS,
  11    :  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12    :  // See the License for the specific language governing permissions and
  13    :  // limitations under the License.
  14    :  
  15    :  #include <windows.h>
  16    :  
  17    :  #include "base/at_exit.h"
  18    :  #include "base/bind.h"
  19    :  #include "base/command_line.h"
  20    :  #include "base/logging.h"
  21    :  #include "base/synchronization/lock.h"
  22    :  #include "syzygy/agent/asan/iat_patcher.h"
  23    :  #include "syzygy/agent/asan/memory_interceptors.h"
  24    :  #include "syzygy/agent/asan/rtl_impl.h"
  25    :  #include "syzygy/agent/asan/runtime.h"
  26    :  #include "syzygy/agent/asan/runtime_util.h"
  27    :  #include "syzygy/agent/common/agent.h"
  28    :  #include "syzygy/common/logging.h"
  29    :  
  30    :  namespace agent {
  31    :  namespace asan {
  32    :  namespace {
  33    :  
  34    :  struct AsanFeatureName {
  35    :    AsanFeature flag;
  36    :    const char* name;
  37    :  };
  38    :  
  39    :  static const AsanFeatureName kAsanFeatureNames[] = {
  40    :      {ASAN_FEATURE_ENABLE_PAGE_PROTECTIONS, "SyzyASANPageProtections"},
  41    :      {DEPRECATED_ASAN_FEATURE_ENABLE_CTMALLOC, nullptr},
  42    :      {ASAN_FEATURE_ENABLE_LARGE_BLOCK_HEAP, "SyzyASANLargeBlockHeap"},
  43    :      {DEPRECATED_ASAN_FEATURE_ENABLE_KASKO, nullptr},
  44    :      {ASAN_FEATURE_ENABLE_CRASHPAD, "SyzyASANCrashpad"},
  45    :  };
  46    :  
  47    :  // This lock guards against IAT patching on multiple threads concurrently.
  48  E :  base::Lock patch_lock;
  49    :  
  50    :  // The maximum number of patch attemps to tolerate.
  51    :  const size_t kPatchAttempsMax = 10;
  52    :  // Counts the number of patch attempts that have occurred. Under patch_lock.
  53    :  size_t patch_attempts = 0;
  54    :  // Set to true when patching has been successfully accomplished.
  55    :  bool patch_complete = false;
  56    :  
  57    :  // Our AtExit manager required by base.
  58    :  base::AtExitManager* at_exit = nullptr;
  59    :  
  60    :  // The asan runtime manager.
  61    :  AsanRuntime* asan_runtime = nullptr;
  62    :  
  63  E :  void SetUpAtExitManager() {
  64  E :    DCHECK_EQ(static_cast<base::AtExitManager*>(nullptr), at_exit);
  65  E :    at_exit = new base::AtExitManager();
  66  E :    CHECK_NE(static_cast<base::AtExitManager*>(nullptr), at_exit);
  67  E :  }
  68    :  
  69  E :  void TearDownAtExitManager() {
  70  E :    DCHECK_NE(static_cast<base::AtExitManager*>(nullptr), at_exit);
  71  E :    delete at_exit;
  72  E :    at_exit = nullptr;
  73  E :  }
  74    :  
  75  E :  MemoryAccessorMode SelectMemoryAccessorMode() {
  76    :    static uint64_t kOneGB = 1ull << 30;
  77    :  
  78    :    // If there is no runtime then use the noop probes.
  79  E :    if (asan_runtime == nullptr)
  80  i :      return MEMORY_ACCESSOR_MODE_NOOP;
  81    :  
  82    :    // Determine the amount of shadow memory allocated.
  83  E :    uint64_t gb = asan_runtime->shadow()->length();
  84  E :    gb <<= kShadowRatioLog;
  85  E :    gb /= kOneGB;
  86    :  
  87  E :    switch (gb) {
  88    :      case 2:
  89  E :        return MEMORY_ACCESSOR_MODE_2G;
  90    :      case 4:
  91  E :        return MEMORY_ACCESSOR_MODE_4G;
  92    :      // 1GB should never happen, and 3GB simply isn't properly supported.
  93    :      default:
  94  i :        return MEMORY_ACCESSOR_MODE_NOOP;
  95    :    }
  96  E :  }
  97    :  
  98  E :  MemoryAccessorMode OnRedirectStubEntry(const void* caller_address) {
  99    :    // This grabs the loader's lock, which could be a problem. If there are
 100    :    // multiple instrumented DLLs, or a single one executing on multiple threads,
 101    :    // there could be lock inversion here. The possibility seems remote, though.
 102    :    // Maybe locating the module associated with the caller_address can be done
 103    :    // with a VirtualQuery, with a fallback to the loader for an additional pair
 104    :    // of belt-and-suspenders...
 105  E :    const DWORD kFlags = GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
 106    :                         GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT;
 107  E :    HMODULE calling_module = nullptr;
 108  E :    BOOL success = ::GetModuleHandleEx(
 109    :        kFlags, reinterpret_cast<LPCWSTR>(caller_address), &calling_module);
 110  E :    CHECK_EQ(TRUE, success);
 111    :  
 112    :    // TODO(chrisha): Implement logic for selecting the noop mode if the system
 113    :    // isn't up to par, if so configured by Finch, if the shadow memory
 114    :    // allocation failed, etc.
 115  E :    MemoryAccessorMode mode = SelectMemoryAccessorMode();
 116    :  
 117    :    // If a runtime has been successfully allocated but for whatever reason the
 118    :    // noop instrumentation has been selected, then cleanup the runtime
 119    :    // allocation.
 120  E :    if (mode == MEMORY_ACCESSOR_MODE_NOOP && asan_runtime != nullptr)
 121  i :      TearDownAsanRuntime(&asan_runtime);
 122    :  
 123    :    // Build the IAT patch map.
 124  E :    IATPatchMap patch_map;
 125  E :    for (size_t i = 0; i < kNumMemoryAccessorVariants; ++i) {
 126  E :      patch_map.insert(
 127    :          std::make_pair(kMemoryAccessorVariants[i].name,
 128    :                         kMemoryAccessorVariants[i].accessors[mode]));
 129  E :    }
 130    :  
 131    :    // Grab the patching lock only while patching the caller's IAT. Assuming no
 132    :    // other parties are patching this IAT, this is sufficient to prevent
 133    :    // double-patching due to multiple threads invoking on instrumentation
 134    :    // concurrently idempotent.
 135  E :    base::AutoLock lock(patch_lock);
 136  E :    if (!patch_complete) {
 137  E :      ++patch_attempts;
 138  E :      auto result = PatchIATForModule(calling_module, patch_map);
 139    :      // If somebody is racing with us to patch our IAT we want to know about it.
 140  E :      CHECK_EQ(0u, result & PATCH_FAILED_RACY_WRITE);
 141    :  
 142    :      // Increment the counter on failure and potentially try again.
 143  E :      if (result != PATCH_SUCCEEDED) {
 144  i :        CHECK_LE(patch_attempts, kPatchAttempsMax);
 145  i :      } else {
 146  E :        patch_complete = true;
 147    :      }
 148    :    }
 149    :  
 150  E :    return mode;
 151  E :  }
 152    :  
 153    :  }  // namespace
 154    :  
 155    :  extern "C" {
 156    :  
 157  E :  BOOL WINAPI DllMain(HMODULE instance, DWORD reason, LPVOID reserved) {
 158  E :    agent::common::InitializeCrt();
 159    :  
 160  E :    switch (reason) {
 161    :      case DLL_PROCESS_ATTACH: {
 162    :        // Create the At-Exit manager.
 163  E :        SetUpAtExitManager();
 164    :  
 165    :        // Disable logging. In the case of Chrome this is running in a sandboxed
 166    :        // process where logging to file doesn't help us any. In other cases the
 167    :        // log output will still go to console.
 168  E :        base::CommandLine::Init(0, NULL);
 169  E :        ::common::InitLoggingForDll(L"asan");
 170    :  
 171    :        // Setup the ASAN runtime. If this fails then |asan_runtime| will remain
 172    :        // nullptr, and the stub redirection will enable the noop probes.
 173  E :        SetUpAsanRuntime(&asan_runtime);
 174    :  
 175    :        // Hookup IAT patching on redirector stub entry.
 176  E :        agent::asan::SetRedirectEntryCallback(base::Bind(OnRedirectStubEntry));
 177  E :        break;
 178    :      }
 179    :  
 180    :      case DLL_THREAD_ATTACH: {
 181  E :        agent::asan::AsanRuntime* runtime = agent::asan::AsanRuntime::runtime();
 182  E :        DCHECK_NE(static_cast<agent::asan::AsanRuntime*>(nullptr), runtime);
 183  E :        runtime->AddThreadId(::GetCurrentThreadId());
 184  E :        break;
 185    :      }
 186    :  
 187    :      case DLL_THREAD_DETACH:
 188    :        // Nothing to do here.
 189  i :        break;
 190    :  
 191    :      case DLL_PROCESS_DETACH: {
 192  E :        base::CommandLine::Reset();
 193    :        // This should be the last thing called in the agent DLL before it
 194    :        // gets unloaded. Everything should otherwise have been initialized
 195    :        // and we're now just cleaning it up again.
 196  E :        TearDownAsanRuntime(&asan_runtime);
 197  E :        TearDownAtExitManager();
 198  E :        break;
 199    :      }
 200    :  
 201    :      default:
 202  i :        NOTREACHED();
 203    :        break;
 204    :    }
 205    :  
 206  E :    return TRUE;
 207  E :  }
 208    :  
 209    :  // Enables the deferred free mechanism. This can be called only once per
 210    :  // execution.
 211  i :  VOID WINAPI asan_EnableDeferredFreeThread() {
 212  i :    asan_runtime->EnableDeferredFreeThread();
 213  i :  }
 214    :  
 215    :  // Disables the deferred free mechanism. This must be called before shutdown if
 216    :  // the thread was started.
 217  i :  VOID WINAPI asan_DisableDeferredFreeThread() {
 218  i :    asan_runtime->DisableDeferredFreeThread();
 219  i :  }
 220    :  
 221  E :  void WINAPI asan_EnumExperiments(AsanExperimentCallback callback) {
 222  E :    DCHECK(callback != nullptr);
 223    :  
 224    :    // Under the current implementation, each randomized feature is considered an
 225    :    // individual experiment, with two groups "Enabled" and "Disabled"
 226  E :    AsanFeatureSet enabled_features = asan_runtime->GetEnabledFeatureSet();
 227  E :    for (const auto& feature : kAsanFeatureNames) {
 228  E :      if (feature.name) {
 229  E :        const char* state = "Disabled";
 230  E :        if ((enabled_features & feature.flag) != 0)
 231  E :          state = "Enabled";
 232  E :        callback(feature.name, state);
 233  E :      } else {
 234    :        // Deprecated features should never be enabled.
 235  E :        DCHECK_EQ(0U, enabled_features & feature.flag);
 236    :      }
 237    :  
 238    :      // Mask out this feature.
 239  E :      enabled_features &= ~feature.flag;
 240  E :    }
 241    :  
 242    :    // Check that we had names for all the features.
 243  E :    DCHECK_EQ(0U, enabled_features);
 244  E :  }
 245    :  
 246    :  }  // extern "C"
 247    :  
 248    :  }  // namespace asan
 249    :  }  // namespace agent

Coverage information generated Fri Jul 29 11:00:21 2016.