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