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

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
0.0%0088.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  m :  namespace agent {
  31  m :  namespace asan {
  32  m :  namespace {
  33    :  
  34    :  // This lock guards against IAT patching on multiple threads concurrently.
  35  m :  base::Lock patch_lock;
  36    :  
  37    :  // Our AtExit manager required by base.
  38  m :  base::AtExitManager* at_exit = nullptr;
  39    :  
  40    :  // The asan runtime manager.
  41  m :  AsanRuntime* asan_runtime = nullptr;
  42    :  
  43  m :  void SetUpAtExitManager() {
  44  m :    DCHECK_EQ(static_cast<base::AtExitManager*>(nullptr), at_exit);
  45  m :    at_exit = new base::AtExitManager();
  46  m :    CHECK_NE(static_cast<base::AtExitManager*>(nullptr), at_exit);
  47  m :  }
  48    :  
  49  m :  void TearDownAtExitManager() {
  50  m :    DCHECK_NE(static_cast<base::AtExitManager*>(nullptr), at_exit);
  51  m :    delete at_exit;
  52  m :    at_exit = nullptr;
  53  m :  }
  54    :  
  55  m :  MemoryAccessorMode SelectMemoryAccessorMode() {
  56  m :    static uint64_t kOneGB = 1ull << 30;
  57    :  
  58    :    // If there is no runtime then use the noop probes.
  59  m :    if (asan_runtime == nullptr)
  60  m :      return MEMORY_ACCESSOR_MODE_NOOP;
  61    :  
  62    :    // Determine the amount of shadow memory allocated.
  63  m :    uint64_t gb = asan_runtime->shadow()->length();
  64  m :    gb <<= kShadowRatioLog;
  65  m :    gb /= kOneGB;
  66    :  
  67  m :    switch (gb) {
  68  m :      case 2:
  69  m :        return MEMORY_ACCESSOR_MODE_2G;
  70  m :      case 4:
  71  m :        return MEMORY_ACCESSOR_MODE_4G;
  72    :      // 1GB should never happen, and 3GB simply isn't properly supported.
  73  m :      default:
  74  m :        return MEMORY_ACCESSOR_MODE_NOOP;
  75  m :    }
  76  m :  }
  77    :  
  78  m :  MemoryAccessorMode OnRedirectStubEntry(const void* caller_address) {
  79    :    // This grabs the loader's lock, which could be a problem. If there are
  80    :    // multiple instrumented DLLs, or a single one executing on multiple threads,
  81    :    // there could be lock inversion here. The possibility seems remote, though.
  82    :    // Maybe locating the module associated with the caller_address can be done
  83    :    // with a VirtualQuery, with a fallback to the loader for an additional pair
  84    :    // of belt-and-suspenders...
  85  m :    const DWORD kFlags = GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
  86  m :                         GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT;
  87  m :    HMODULE calling_module = nullptr;
  88  m :    BOOL success = ::GetModuleHandleEx(
  89  m :        kFlags, reinterpret_cast<LPCWSTR>(caller_address), &calling_module);
  90  m :    CHECK_EQ(TRUE, success);
  91    :  
  92    :    // TODO(chrisha): Implement logic for selecting the noop mode if the system
  93    :    // isn't up to par, if so configured by Finch, if the shadow memory
  94    :    // allocation failed, etc.
  95  m :    MemoryAccessorMode mode = SelectMemoryAccessorMode();
  96    :  
  97    :    // If a runtime has been successfully allocated but for whatever reason the
  98    :    // noop instrumentation has been selected, then cleanup the runtime
  99    :    // allocation.
 100  m :    if (mode == MEMORY_ACCESSOR_MODE_NOOP && asan_runtime != nullptr)
 101  m :      TearDownAsanRuntime(&asan_runtime);
 102    :  
 103    :    // Build the IAT patch map.
 104  m :    IATPatchMap patch_map;
 105  m :    for (size_t i = 0; i < kNumMemoryAccessorVariants; ++i) {
 106  m :      patch_map.insert(
 107  m :          std::make_pair(kMemoryAccessorVariants[i].name,
 108  m :                         kMemoryAccessorVariants[i].accessors[mode]));
 109  m :    }
 110    :  
 111    :    // Grab the patching lock only while patching the caller's IAT. Assuming no
 112    :    // other parties are patching this IAT, this is sufficient to make
 113    :    // double-patching due to multiple threads invoking on instrumentation
 114    :    // concurrently idempotent.
 115  m :    base::AutoLock lock(patch_lock);
 116  m :    CHECK(PatchIATForModule(calling_module, patch_map));
 117    :  
 118  m :    return mode;
 119  m :  }
 120    :  
 121  m :  }  // namespace
 122    :  
 123  m :  extern "C" {
 124    :  
 125  m :  BOOL WINAPI DllMain(HMODULE instance, DWORD reason, LPVOID reserved) {
 126  m :    agent::common::InitializeCrt();
 127    :  
 128  m :    switch (reason) {
 129  m :      case DLL_PROCESS_ATTACH: {
 130    :        // Create the At-Exit manager.
 131  m :        SetUpAtExitManager();
 132    :  
 133    :        // Disable logging. In the case of Chrome this is running in a sandboxed
 134    :        // process where logging to file doesn't help us any. In other cases the
 135    :        // log output will still go to console.
 136  m :        base::CommandLine::Init(0, NULL);
 137  m :        ::common::InitLoggingForDll(L"asan");
 138    :  
 139    :        // Setup the ASAN runtime. If this fails then |asan_runtime| will remain
 140    :        // nullptr, and the stub redirection will enable the noop probes.
 141  m :        SetUpAsanRuntime(&asan_runtime);
 142    :  
 143    :        // Hookup IAT patching on redirector stub entry.
 144  m :        agent::asan::SetRedirectEntryCallback(base::Bind(OnRedirectStubEntry));
 145  m :        break;
 146  m :      }
 147    :  
 148  m :      case DLL_THREAD_ATTACH: {
 149  m :        agent::asan::AsanRuntime* runtime = agent::asan::AsanRuntime::runtime();
 150  m :        DCHECK_NE(static_cast<agent::asan::AsanRuntime*>(nullptr), runtime);
 151  m :        runtime->AddThreadId(::GetCurrentThreadId());
 152  m :        break;
 153  m :      }
 154    :  
 155  m :      case DLL_THREAD_DETACH:
 156    :        // Nothing to do here.
 157  m :        break;
 158    :  
 159  m :      case DLL_PROCESS_DETACH: {
 160  m :        base::CommandLine::Reset();
 161    :        // This should be the last thing called in the agent DLL before it
 162    :        // gets unloaded. Everything should otherwise have been initialized
 163    :        // and we're now just cleaning it up again.
 164  m :        TearDownAsanRuntime(&asan_runtime);
 165  m :        TearDownAtExitManager();
 166  m :        break;
 167  m :      }
 168    :  
 169  m :      default:
 170  m :        NOTREACHED();
 171  m :        break;
 172  m :    }
 173    :  
 174  m :    return TRUE;
 175  m :  }
 176    :  
 177  m :  }  // extern "C"
 178    :  
 179  m :  }  // namespace asan
 180  m :  }  // namespace agent

Coverage information generated Thu Jan 14 17:40:38 2016.