• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
GetHandleVerifier()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 
ReportErrorOnScopedHandleOperation(const debug::StackTrace & creation_stack,HandleOperation operation)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 
ReportErrorOnScopedHandleOperation(const debug::StackTrace & creation_stack,const ScopedHandleVerifierInfo & other,HandleOperation operation)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:
AutoNativeLock(NativeLock & lock)76   explicit AutoNativeLock(NativeLock& lock) : lock_(lock) { lock_->Lock(); }
77 
78   AutoNativeLock(const AutoNativeLock&) = delete;
79   AutoNativeLock& operator=(const AutoNativeLock&) = delete;
80 
~AutoNativeLock()81   ~AutoNativeLock() { lock_->Unlock(); }
82 
83  private:
84   const raw_ref<NativeLock> lock_;
85 };
86 
ScopedHandleVerifierInfo(const void * owner,const void * pc1,const void * pc2,std::unique_ptr<debug::StackTrace> stack,DWORD thread_id)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 
ScopedHandleVerifier(bool enabled)106 ScopedHandleVerifier::ScopedHandleVerifier(bool enabled)
107     : enabled_(enabled), lock_(GetLock()) {}
108 
109 // static
Get()110 ScopedHandleVerifier* ScopedHandleVerifier::Get() {
111   if (!g_active_verifier)
112     ScopedHandleVerifier::InstallVerifier();
113 
114   return g_active_verifier;
115 }
116 
CloseHandleWrapper(HANDLE handle)117 bool CloseHandleWrapper(HANDLE handle) {
118   if (!::CloseHandle(handle))
119     CHECK(false) << "CloseHandle failed";
120   return true;
121 }
122 
123 // Assigns the g_active_verifier global within the ScopedHandleVerifier lock.
124 // If |existing_verifier| is non-null then |enabled| is ignored.
125 // static
ThreadSafeAssignOrCreateScopedHandleVerifier(ScopedHandleVerifier * existing_verifier,bool enabled)126 void ScopedHandleVerifier::ThreadSafeAssignOrCreateScopedHandleVerifier(
127     ScopedHandleVerifier* existing_verifier,
128     bool enabled) {
129   AutoNativeLock lock(*GetLock());
130   // Another thread in this module might be trying to assign the global
131   // verifier, so check that within the lock here.
132   if (g_active_verifier)
133     return;
134   g_active_verifier =
135       existing_verifier ? existing_verifier : new ScopedHandleVerifier(enabled);
136 }
137 
138 // static
InstallVerifier()139 void ScopedHandleVerifier::InstallVerifier() {
140 #if BUILDFLAG(SINGLE_MODULE_MODE_HANDLE_VERIFIER)
141   // Component build has one Active Verifier per module.
142   ThreadSafeAssignOrCreateScopedHandleVerifier(nullptr, true);
143 #else
144   // If you are reading this, wondering why your process seems deadlocked, take
145   // a look at your DllMain code and remove things that should not be done
146   // there, like doing whatever gave you that nice windows handle you are trying
147   // to store in a ScopedHandle.
148   HMODULE main_module = ::GetModuleHandle(NULL);
149   GetHandleVerifierFn get_handle_verifier =
150       reinterpret_cast<GetHandleVerifierFn>(
151           ::GetProcAddress(main_module, "GetHandleVerifier"));
152 
153   // This should only happen if running in a DLL is linked with base but the
154   // hosting EXE is not. In this case, create a ScopedHandleVerifier for the
155   // current module but leave it disabled.
156   if (!get_handle_verifier) {
157     ThreadSafeAssignOrCreateScopedHandleVerifier(nullptr, false);
158     return;
159   }
160 
161   // Check if in the main module.
162   if (get_handle_verifier == GetHandleVerifier) {
163     ThreadSafeAssignOrCreateScopedHandleVerifier(nullptr, true);
164     return;
165   }
166 
167   ScopedHandleVerifier* main_module_verifier =
168       reinterpret_cast<ScopedHandleVerifier*>(get_handle_verifier());
169 
170   // Main module should always on-demand create a verifier.
171   DCHECK(main_module_verifier);
172 
173   ThreadSafeAssignOrCreateScopedHandleVerifier(main_module_verifier, false);
174 #endif
175 }
176 
CloseHandle(HANDLE handle)177 bool ScopedHandleVerifier::CloseHandle(HANDLE handle) {
178   if (!enabled_)
179     return CloseHandleWrapper(handle);
180 
181   const AutoReset<bool> resetter(&closing, true);
182   CloseHandleWrapper(handle);
183 
184   return true;
185 }
186 
187 // static
GetLock()188 NativeLock* ScopedHandleVerifier::GetLock() {
189   static auto* native_lock = new NativeLock();
190   return native_lock;
191 }
192 
StartTracking(HANDLE handle,const void * owner,const void * pc1,const void * pc2)193 void ScopedHandleVerifier::StartTracking(HANDLE handle,
194                                          const void* owner,
195                                          const void* pc1,
196                                          const void* pc2) {
197   if (enabled_)
198     StartTrackingImpl(handle, owner, pc1, pc2);
199 }
200 
StopTracking(HANDLE handle,const void * owner,const void * pc1,const void * pc2)201 void ScopedHandleVerifier::StopTracking(HANDLE handle,
202                                         const void* owner,
203                                         const void* pc1,
204                                         const void* pc2) {
205   if (enabled_)
206     StopTrackingImpl(handle, owner, pc1, pc2);
207 }
208 
Disable()209 void ScopedHandleVerifier::Disable() {
210   enabled_ = false;
211 }
212 
OnHandleBeingClosed(HANDLE handle,HandleOperation operation)213 void ScopedHandleVerifier::OnHandleBeingClosed(HANDLE handle,
214                                                HandleOperation operation) {
215   if (enabled_)
216     OnHandleBeingClosedImpl(handle, operation);
217 }
218 
GetModule() const219 HMODULE ScopedHandleVerifier::GetModule() const {
220   return CURRENT_MODULE();
221 }
222 
StartTrackingImpl(HANDLE handle,const void * owner,const void * pc1,const void * pc2)223 NOINLINE void ScopedHandleVerifier::StartTrackingImpl(HANDLE handle,
224                                                       const void* owner,
225                                                       const void* pc1,
226                                                       const void* pc2) {
227   // Grab the thread id before the lock.
228   DWORD thread_id = GetCurrentThreadId();
229 
230   // Grab the thread stacktrace before the lock.
231   auto stacktrace = std::make_unique<debug::StackTrace>();
232 
233   AutoNativeLock lock(*lock_);
234   std::pair<HandleMap::iterator, bool> result = map_.emplace(
235       handle, ScopedHandleVerifierInfo{owner, pc1, pc2, std::move(stacktrace),
236                                        thread_id});
237   if (!result.second) {
238     // Attempt to start tracking already tracked handle.
239     ReportErrorOnScopedHandleOperation(creation_stack_, result.first->second,
240                                        HandleOperation::kHandleAlreadyTracked);
241   }
242 }
243 
StopTrackingImpl(HANDLE handle,const void * owner,const void * pc1,const void * pc2)244 NOINLINE void ScopedHandleVerifier::StopTrackingImpl(HANDLE handle,
245                                                      const void* owner,
246                                                      const void* pc1,
247                                                      const void* pc2) {
248   AutoNativeLock lock(*lock_);
249   HandleMap::iterator i = map_.find(handle);
250   if (i == map_.end()) {
251     // Attempting to close an untracked handle.
252     ReportErrorOnScopedHandleOperation(creation_stack_,
253                                        HandleOperation::kCloseHandleNotTracked);
254   }
255 
256   if (i->second.owner != owner) {
257     // Attempting to close a handle not owned by opener.
258     ReportErrorOnScopedHandleOperation(creation_stack_, i->second,
259                                        HandleOperation::kCloseHandleNotOwner);
260   }
261 
262   map_.erase(i);
263 }
264 
OnHandleBeingClosedImpl(HANDLE handle,HandleOperation operation)265 NOINLINE void ScopedHandleVerifier::OnHandleBeingClosedImpl(
266     HANDLE handle,
267     HandleOperation operation) {
268   if (closing) {
269     return;
270   }
271 
272   AutoNativeLock lock(*lock_);
273   HandleMap::iterator i = map_.find(handle);
274   if (i != map_.end()) {
275     // CloseHandle called on tracked handle.
276     ReportErrorOnScopedHandleOperation(creation_stack_, i->second, operation);
277   }
278 }
279 
GetHandleVerifierModuleForTesting()280 HMODULE GetHandleVerifierModuleForTesting() {
281   return g_active_verifier->GetModule();
282 }
283 
284 }  // namespace internal
285 }  // namespace win
286 }  // namespace base
287