tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

scoped_handle_verifier.cc (9243B)


      1 // Copyright 2018 The Chromium Authors
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "base/win/scoped_handle_verifier.h"
      6 
      7 #include <windows.h>
      8 
      9 #include <stddef.h>
     10 
     11 #include <unordered_map>
     12 #include <utility>
     13 
     14 #include "base/auto_reset.h"
     15 #include "base/compiler_specific.h"
     16 #include "base/debug/alias.h"
     17 #include "base/debug/stack_trace.h"
     18 #include "base/memory/raw_ref.h"
     19 #include "base/synchronization/lock_impl.h"
     20 #include "base/trace_event/base_tracing.h"
     21 #include "base/win/base_win_buildflags.h"
     22 #include "base/win/current_module.h"
     23 #include "base/win/scoped_handle.h"
     24 #include "third_party/abseil-cpp/absl/base/attributes.h"
     25 
     26 extern "C" {
     27 __declspec(dllexport) void* GetHandleVerifier();
     28 
     29 void* GetHandleVerifier() {
     30  return base::win::internal::ScopedHandleVerifier::Get();
     31 }
     32 }  // extern C
     33 
     34 namespace base {
     35 namespace win {
     36 namespace internal {
     37 
     38 namespace {
     39 
     40 ScopedHandleVerifier* g_active_verifier = nullptr;
     41 ABSL_CONST_INIT thread_local bool closing = false;
     42 using GetHandleVerifierFn = void* (*)();
     43 using HandleMap =
     44    std::unordered_map<HANDLE, ScopedHandleVerifierInfo, HandleHash>;
     45 using NativeLock = base::internal::LockImpl;
     46 
     47 NOINLINE void ReportErrorOnScopedHandleOperation(
     48    const debug::StackTrace& creation_stack,
     49    HandleOperation operation) {
     50  auto creation_stack_copy = creation_stack;
     51  debug::Alias(&creation_stack_copy);
     52  debug::Alias(&operation);
     53  CHECK(false) << operation;
     54  __builtin_unreachable();
     55 }
     56 
     57 NOINLINE void ReportErrorOnScopedHandleOperation(
     58    const debug::StackTrace& creation_stack,
     59    const ScopedHandleVerifierInfo& other,
     60    HandleOperation operation) {
     61  auto other_stack_copy = *other.stack;
     62  debug::Alias(&other_stack_copy);
     63  auto creation_stack_copy = creation_stack;
     64  debug::Alias(&creation_stack_copy);
     65  debug::Alias(&operation);
     66  CHECK(false) << operation;
     67  __builtin_unreachable();
     68 }
     69 
     70 }  // namespace
     71 
     72 // Simple automatic locking using a native critical section so it supports
     73 // recursive locking.
     74 class AutoNativeLock {
     75 public:
     76  explicit AutoNativeLock(NativeLock& lock) : lock_(lock) { lock_->Lock(); }
     77 
     78  AutoNativeLock(const AutoNativeLock&) = delete;
     79  AutoNativeLock& operator=(const AutoNativeLock&) = delete;
     80 
     81  ~AutoNativeLock() { lock_->Unlock(); }
     82 
     83 private:
     84  const raw_ref<NativeLock> lock_;
     85 };
     86 
     87 ScopedHandleVerifierInfo::ScopedHandleVerifierInfo(
     88    const void* owner,
     89    const void* pc1,
     90    const void* pc2,
     91    std::unique_ptr<debug::StackTrace> stack,
     92    DWORD thread_id)
     93    : owner(owner),
     94      pc1(pc1),
     95      pc2(pc2),
     96      stack(std::move(stack)),
     97      thread_id(thread_id) {}
     98 
     99 ScopedHandleVerifierInfo::~ScopedHandleVerifierInfo() = default;
    100 
    101 ScopedHandleVerifierInfo::ScopedHandleVerifierInfo(
    102    ScopedHandleVerifierInfo&&) noexcept = default;
    103 ScopedHandleVerifierInfo& ScopedHandleVerifierInfo::operator=(
    104    ScopedHandleVerifierInfo&&) noexcept = default;
    105 
    106 ScopedHandleVerifier::ScopedHandleVerifier(bool enabled)
    107    : enabled_(enabled), lock_(GetLock()) {}
    108 
    109 // static
    110 ScopedHandleVerifier* ScopedHandleVerifier::Get() {
    111  if (!g_active_verifier)
    112    ScopedHandleVerifier::InstallVerifier();
    113 
    114  return g_active_verifier;
    115 }
    116 
    117 bool CloseHandleWrapper(HANDLE handle) {
    118  if (!::CloseHandle(handle))
    119    // Making this DCHECK on non-Nighly as we are hitting this frequently,
    120    // looks like we are closing handles twice somehow. See bug 1564899.
    121 #if defined(NIGHTLY_BUILD)
    122    CHECK(false) << "CloseHandle failed";
    123 #else
    124    DCHECK(false) << "CloseHandle failed";
    125 #endif
    126  return true;
    127 }
    128 
    129 // Assigns the g_active_verifier global within the ScopedHandleVerifier lock.
    130 // If |existing_verifier| is non-null then |enabled| is ignored.
    131 // static
    132 void ScopedHandleVerifier::ThreadSafeAssignOrCreateScopedHandleVerifier(
    133    ScopedHandleVerifier* existing_verifier,
    134    bool enabled) {
    135  AutoNativeLock lock(*GetLock());
    136  // Another thread in this module might be trying to assign the global
    137  // verifier, so check that within the lock here.
    138  if (g_active_verifier)
    139    return;
    140  g_active_verifier =
    141      existing_verifier ? existing_verifier : new ScopedHandleVerifier(enabled);
    142 }
    143 
    144 // static
    145 void ScopedHandleVerifier::InstallVerifier() {
    146 #if BUILDFLAG(SINGLE_MODULE_MODE_HANDLE_VERIFIER)
    147  // Component build has one Active Verifier per module.
    148  ThreadSafeAssignOrCreateScopedHandleVerifier(nullptr, true);
    149 #else
    150  // If you are reading this, wondering why your process seems deadlocked, take
    151  // a look at your DllMain code and remove things that should not be done
    152  // there, like doing whatever gave you that nice windows handle you are trying
    153  // to store in a ScopedHandle.
    154  HMODULE main_module = ::GetModuleHandle(NULL);
    155  GetHandleVerifierFn get_handle_verifier =
    156      reinterpret_cast<GetHandleVerifierFn>(
    157          ::GetProcAddress(main_module, "GetHandleVerifier"));
    158 
    159  // This should only happen if running in a DLL is linked with base but the
    160  // hosting EXE is not. In this case, create a ScopedHandleVerifier for the
    161  // current module but leave it disabled.
    162  if (!get_handle_verifier) {
    163    ThreadSafeAssignOrCreateScopedHandleVerifier(nullptr, false);
    164    return;
    165  }
    166 
    167  // Check if in the main module.
    168  if (get_handle_verifier == GetHandleVerifier) {
    169    ThreadSafeAssignOrCreateScopedHandleVerifier(nullptr, true);
    170    return;
    171  }
    172 
    173  ScopedHandleVerifier* main_module_verifier =
    174      reinterpret_cast<ScopedHandleVerifier*>(get_handle_verifier());
    175 
    176  // Main module should always on-demand create a verifier.
    177  DCHECK(main_module_verifier);
    178 
    179  ThreadSafeAssignOrCreateScopedHandleVerifier(main_module_verifier, false);
    180 #endif
    181 }
    182 
    183 bool ScopedHandleVerifier::CloseHandle(HANDLE handle) {
    184  if (!enabled_)
    185    return CloseHandleWrapper(handle);
    186 
    187  const AutoReset<bool> resetter(&closing, true);
    188  CloseHandleWrapper(handle);
    189 
    190  return true;
    191 }
    192 
    193 // static
    194 NativeLock* ScopedHandleVerifier::GetLock() {
    195  static auto* native_lock = new NativeLock();
    196  return native_lock;
    197 }
    198 
    199 void ScopedHandleVerifier::StartTracking(HANDLE handle,
    200                                         const void* owner,
    201                                         const void* pc1,
    202                                         const void* pc2) {
    203  if (enabled_)
    204    StartTrackingImpl(handle, owner, pc1, pc2);
    205 }
    206 
    207 void ScopedHandleVerifier::StopTracking(HANDLE handle,
    208                                        const void* owner,
    209                                        const void* pc1,
    210                                        const void* pc2) {
    211  if (enabled_)
    212    StopTrackingImpl(handle, owner, pc1, pc2);
    213 }
    214 
    215 void ScopedHandleVerifier::Disable() {
    216  enabled_ = false;
    217 }
    218 
    219 void ScopedHandleVerifier::OnHandleBeingClosed(HANDLE handle,
    220                                               HandleOperation operation) {
    221  if (enabled_)
    222    OnHandleBeingClosedImpl(handle, operation);
    223 }
    224 
    225 HMODULE ScopedHandleVerifier::GetModule() const {
    226  return CURRENT_MODULE();
    227 }
    228 
    229 NOINLINE void ScopedHandleVerifier::StartTrackingImpl(HANDLE handle,
    230                                                      const void* owner,
    231                                                      const void* pc1,
    232                                                      const void* pc2) {
    233  // Grab the thread id before the lock.
    234  DWORD thread_id = GetCurrentThreadId();
    235 
    236  // Grab the thread stacktrace before the lock.
    237  auto stacktrace = std::make_unique<debug::StackTrace>();
    238 
    239  AutoNativeLock lock(*lock_);
    240  std::pair<HandleMap::iterator, bool> result = map_.emplace(
    241      handle, ScopedHandleVerifierInfo{owner, pc1, pc2, std::move(stacktrace),
    242                                       thread_id});
    243  if (!result.second) {
    244    // Attempt to start tracking already tracked handle.
    245    ReportErrorOnScopedHandleOperation(creation_stack_, result.first->second,
    246                                       HandleOperation::kHandleAlreadyTracked);
    247  }
    248 }
    249 
    250 NOINLINE void ScopedHandleVerifier::StopTrackingImpl(HANDLE handle,
    251                                                     const void* owner,
    252                                                     const void* pc1,
    253                                                     const void* pc2) {
    254  AutoNativeLock lock(*lock_);
    255  HandleMap::iterator i = map_.find(handle);
    256  if (i == map_.end()) {
    257    // Attempting to close an untracked handle.
    258    ReportErrorOnScopedHandleOperation(creation_stack_,
    259                                       HandleOperation::kCloseHandleNotTracked);
    260  }
    261 
    262  if (i->second.owner != owner) {
    263    // Attempting to close a handle not owned by opener.
    264    ReportErrorOnScopedHandleOperation(creation_stack_, i->second,
    265                                       HandleOperation::kCloseHandleNotOwner);
    266  }
    267 
    268  map_.erase(i);
    269 }
    270 
    271 NOINLINE void ScopedHandleVerifier::OnHandleBeingClosedImpl(
    272    HANDLE handle,
    273    HandleOperation operation) {
    274  if (closing) {
    275    return;
    276  }
    277 
    278  AutoNativeLock lock(*lock_);
    279  HandleMap::iterator i = map_.find(handle);
    280  if (i != map_.end()) {
    281    // CloseHandle called on tracked handle.
    282    ReportErrorOnScopedHandleOperation(creation_stack_, i->second, operation);
    283  }
    284 }
    285 
    286 HMODULE GetHandleVerifierModuleForTesting() {
    287  return g_active_verifier->GetModule();
    288 }
    289 
    290 }  // namespace internal
    291 }  // namespace win
    292 }  // namespace base