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