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