OLD | NEW |
1 // Copyright 2015 The Crashpad Authors. All rights reserved. | 1 // Copyright 2015 The Crashpad Authors. All rights reserved. |
2 // | 2 // |
3 // Licensed under the Apache License, Version 2.0 (the "License"); | 3 // Licensed under the Apache License, Version 2.0 (the "License"); |
4 // you may not use this file except in compliance with the License. | 4 // you may not use this file except in compliance with the License. |
5 // You may obtain a copy of the License at | 5 // You may obtain a copy of the License at |
6 // | 6 // |
7 // http://www.apache.org/licenses/LICENSE-2.0 | 7 // http://www.apache.org/licenses/LICENSE-2.0 |
8 // | 8 // |
9 // Unless required by applicable law or agreed to in writing, software | 9 // Unless required by applicable law or agreed to in writing, software |
10 // distributed under the License is distributed on an "AS IS" BASIS, | 10 // distributed under the License is distributed on an "AS IS" BASIS, |
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 // See the License for the specific language governing permissions and | 12 // See the License for the specific language governing permissions and |
13 // limitations under the License. | 13 // limitations under the License. |
14 | 14 |
15 #include "util/win/exception_handler_server.h" | 15 #include "util/win/exception_handler_server.h" |
16 | 16 |
17 #include <sddl.h> | |
18 #include <stdint.h> | 17 #include <stdint.h> |
19 #include <string.h> | 18 #include <string.h> |
20 #include <sys/types.h> | 19 #include <sys/types.h> |
21 | 20 |
22 #include <utility> | 21 #include <utility> |
23 | 22 |
24 #include "base/logging.h" | 23 #include "base/logging.h" |
25 #include "base/numerics/safe_conversions.h" | 24 #include "base/numerics/safe_conversions.h" |
26 #include "base/rand_util.h" | 25 #include "base/rand_util.h" |
27 #include "base/strings/stringprintf.h" | 26 #include "base/strings/stringprintf.h" |
28 #include "base/strings/utf_string_conversions.h" | 27 #include "base/strings/utf_string_conversions.h" |
29 #include "minidump/minidump_file_writer.h" | 28 #include "minidump/minidump_file_writer.h" |
30 #include "snapshot/crashpad_info_client_options.h" | 29 #include "snapshot/crashpad_info_client_options.h" |
31 #include "snapshot/win/process_snapshot_win.h" | 30 #include "snapshot/win/process_snapshot_win.h" |
32 #include "util/file/file_writer.h" | 31 #include "util/file/file_writer.h" |
33 #include "util/misc/random_string.h" | |
34 #include "util/misc/tri_state.h" | 32 #include "util/misc/tri_state.h" |
35 #include "util/misc/uuid.h" | 33 #include "util/misc/uuid.h" |
36 #include "util/win/get_function.h" | 34 #include "util/win/get_function.h" |
37 #include "util/win/handle.h" | 35 #include "util/win/handle.h" |
38 #include "util/win/registration_protocol_win.h" | 36 #include "util/win/registration_protocol_win.h" |
39 #include "util/win/scoped_local_alloc.h" | |
40 #include "util/win/xp_compat.h" | 37 #include "util/win/xp_compat.h" |
41 | 38 |
42 namespace crashpad { | 39 namespace crashpad { |
43 | 40 |
44 namespace { | 41 namespace { |
45 | 42 |
46 // We create two pipe instances, so that there's one listening while the | |
47 // PipeServiceProc is processing a registration. | |
48 const size_t kPipeInstances = 2; | |
49 | |
50 // Wraps CreateNamedPipe() to create a single named pipe instance. | |
51 // | |
52 // If first_instance is true, the named pipe instance will be created with | |
53 // FILE_FLAG_FIRST_PIPE_INSTANCE. This ensures that the the pipe name is not | |
54 // already in use when created. The first instance will be created with an | |
55 // untrusted integrity SACL so instances of this pipe can be connected to by | |
56 // processes of any integrity level. | |
57 HANDLE CreateNamedPipeInstance(const std::wstring& pipe_name, | |
58 bool first_instance) { | |
59 SECURITY_ATTRIBUTES security_attributes; | |
60 SECURITY_ATTRIBUTES* security_attributes_pointer = nullptr; | |
61 ScopedLocalAlloc scoped_sec_desc; | |
62 | |
63 if (first_instance) { | |
64 // Pre-Vista does not have integrity levels. | |
65 const DWORD version = GetVersion(); | |
66 const DWORD major_version = LOBYTE(LOWORD(version)); | |
67 const bool is_vista_or_later = major_version >= 6; | |
68 if (is_vista_or_later) { | |
69 // Mandatory Label, no ACE flags, no ObjectType, integrity level | |
70 // untrusted. | |
71 const wchar_t kSddl[] = L"S:(ML;;;;;S-1-16-0)"; | |
72 | |
73 PSECURITY_DESCRIPTOR sec_desc; | |
74 PCHECK(ConvertStringSecurityDescriptorToSecurityDescriptor( | |
75 kSddl, SDDL_REVISION_1, &sec_desc, nullptr)) | |
76 << "ConvertStringSecurityDescriptorToSecurityDescriptor"; | |
77 | |
78 // Take ownership of the allocated SECURITY_DESCRIPTOR. | |
79 scoped_sec_desc.reset(sec_desc); | |
80 | |
81 memset(&security_attributes, 0, sizeof(security_attributes)); | |
82 security_attributes.nLength = sizeof(SECURITY_ATTRIBUTES); | |
83 security_attributes.lpSecurityDescriptor = sec_desc; | |
84 security_attributes.bInheritHandle = FALSE; | |
85 security_attributes_pointer = &security_attributes; | |
86 } | |
87 } | |
88 | |
89 return CreateNamedPipe( | |
90 pipe_name.c_str(), | |
91 PIPE_ACCESS_DUPLEX | (first_instance ? FILE_FLAG_FIRST_PIPE_INSTANCE : 0), | |
92 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, | |
93 kPipeInstances, | |
94 512, | |
95 512, | |
96 0, | |
97 security_attributes_pointer); | |
98 } | |
99 | |
100 decltype(GetNamedPipeClientProcessId)* GetNamedPipeClientProcessIdFunction() { | 43 decltype(GetNamedPipeClientProcessId)* GetNamedPipeClientProcessIdFunction() { |
101 static const auto get_named_pipe_client_process_id = | 44 static const auto get_named_pipe_client_process_id = |
102 GET_FUNCTION(L"kernel32.dll", ::GetNamedPipeClientProcessId); | 45 GET_FUNCTION(L"kernel32.dll", ::GetNamedPipeClientProcessId); |
103 return get_named_pipe_client_process_id; | 46 return get_named_pipe_client_process_id; |
104 } | 47 } |
105 | 48 |
106 HANDLE DuplicateEvent(HANDLE process, HANDLE event) { | 49 HANDLE DuplicateEvent(HANDLE process, HANDLE event) { |
107 HANDLE handle; | 50 HANDLE handle; |
108 if (DuplicateHandle(GetCurrentProcess(), | 51 if (DuplicateHandle(GetCurrentProcess(), |
109 event, | 52 event, |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
158 //! \brief The context data for registered threadpool waits. | 101 //! \brief The context data for registered threadpool waits. |
159 //! | 102 //! |
160 //! This object must be created and destroyed on the main thread. Access must be | 103 //! This object must be created and destroyed on the main thread. Access must be |
161 //! guarded by use of the lock() with the exception of the threadpool wait | 104 //! guarded by use of the lock() with the exception of the threadpool wait |
162 //! variables which are accessed only by the main thread. | 105 //! variables which are accessed only by the main thread. |
163 class ClientData { | 106 class ClientData { |
164 public: | 107 public: |
165 ClientData(HANDLE port, | 108 ClientData(HANDLE port, |
166 ExceptionHandlerServer::Delegate* delegate, | 109 ExceptionHandlerServer::Delegate* delegate, |
167 ScopedKernelHANDLE process, | 110 ScopedKernelHANDLE process, |
| 111 ScopedKernelHANDLE crash_dump_requested_event, |
| 112 ScopedKernelHANDLE non_crash_dump_requested_event, |
| 113 ScopedKernelHANDLE non_crash_dump_completed_event, |
168 WinVMAddress crash_exception_information_address, | 114 WinVMAddress crash_exception_information_address, |
169 WinVMAddress non_crash_exception_information_address, | 115 WinVMAddress non_crash_exception_information_address, |
170 WinVMAddress debug_critical_section_address, | 116 WinVMAddress debug_critical_section_address, |
171 WAITORTIMERCALLBACK crash_dump_request_callback, | 117 WAITORTIMERCALLBACK crash_dump_request_callback, |
172 WAITORTIMERCALLBACK non_crash_dump_request_callback, | 118 WAITORTIMERCALLBACK non_crash_dump_request_callback, |
173 WAITORTIMERCALLBACK process_end_callback) | 119 WAITORTIMERCALLBACK process_end_callback) |
174 : crash_dump_request_thread_pool_wait_(INVALID_HANDLE_VALUE), | 120 : crash_dump_request_thread_pool_wait_(INVALID_HANDLE_VALUE), |
175 non_crash_dump_request_thread_pool_wait_(INVALID_HANDLE_VALUE), | 121 non_crash_dump_request_thread_pool_wait_(INVALID_HANDLE_VALUE), |
176 process_end_thread_pool_wait_(INVALID_HANDLE_VALUE), | 122 process_end_thread_pool_wait_(INVALID_HANDLE_VALUE), |
177 lock_(), | 123 lock_(), |
178 port_(port), | 124 port_(port), |
179 delegate_(delegate), | 125 delegate_(delegate), |
180 crash_dump_requested_event_( | 126 crash_dump_requested_event_(std::move(crash_dump_requested_event)), |
181 CreateEvent(nullptr, false /* auto reset */, false, nullptr)), | |
182 non_crash_dump_requested_event_( | 127 non_crash_dump_requested_event_( |
183 CreateEvent(nullptr, false /* auto reset */, false, nullptr)), | 128 std::move(non_crash_dump_requested_event)), |
184 non_crash_dump_completed_event_( | 129 non_crash_dump_completed_event_( |
185 CreateEvent(nullptr, false /* auto reset */, false, nullptr)), | 130 std::move(non_crash_dump_completed_event)), |
186 process_(std::move(process)), | 131 process_(std::move(process)), |
187 crash_exception_information_address_( | 132 crash_exception_information_address_( |
188 crash_exception_information_address), | 133 crash_exception_information_address), |
189 non_crash_exception_information_address_( | 134 non_crash_exception_information_address_( |
190 non_crash_exception_information_address), | 135 non_crash_exception_information_address), |
191 debug_critical_section_address_(debug_critical_section_address) { | 136 debug_critical_section_address_(debug_critical_section_address) { |
192 RegisterThreadPoolWaits(crash_dump_request_callback, | 137 RegisterThreadPoolWaits(crash_dump_request_callback, |
193 non_crash_dump_request_callback, | 138 non_crash_dump_request_callback, |
194 process_end_callback); | 139 process_end_callback); |
195 } | 140 } |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
308 ExceptionHandlerServer::~ExceptionHandlerServer() { | 253 ExceptionHandlerServer::~ExceptionHandlerServer() { |
309 } | 254 } |
310 | 255 |
311 void ExceptionHandlerServer::SetPipeName(const std::wstring& pipe_name) { | 256 void ExceptionHandlerServer::SetPipeName(const std::wstring& pipe_name) { |
312 DCHECK(pipe_name_.empty()); | 257 DCHECK(pipe_name_.empty()); |
313 DCHECK(!pipe_name.empty()); | 258 DCHECK(!pipe_name.empty()); |
314 | 259 |
315 pipe_name_ = pipe_name; | 260 pipe_name_ = pipe_name; |
316 } | 261 } |
317 | 262 |
318 std::wstring ExceptionHandlerServer::CreatePipe() { | 263 void ExceptionHandlerServer::InitializeWithInheritedDataForInitialClient( |
| 264 const InitialClientData& initial_client_data, |
| 265 Delegate* delegate) { |
| 266 DCHECK(pipe_name_.empty()); |
319 DCHECK(!first_pipe_instance_.is_valid()); | 267 DCHECK(!first_pipe_instance_.is_valid()); |
320 | 268 |
321 int tries = 5; | 269 first_pipe_instance_.reset(initial_client_data.first_pipe_instance()); |
322 std::string pipe_name_base = | |
323 base::StringPrintf("\\\\.\\pipe\\crashpad_%d_", GetCurrentProcessId()); | |
324 std::wstring pipe_name; | |
325 do { | |
326 pipe_name = base::UTF8ToUTF16(pipe_name_base + RandomString()); | |
327 | 270 |
328 first_pipe_instance_.reset(CreateNamedPipeInstance(pipe_name, true)); | 271 // TODO(scottmg): Vista+. Might need to pass through or possibly find an Nt*. |
| 272 size_t bytes = sizeof(wchar_t) * _MAX_PATH + sizeof(FILE_NAME_INFO); |
| 273 std::unique_ptr<uint8_t[]> data(new uint8_t[bytes]); |
| 274 if (!GetFileInformationByHandleEx(first_pipe_instance_.get(), |
| 275 FileNameInfo, |
| 276 data.get(), |
| 277 static_cast<DWORD>(bytes))) { |
| 278 PLOG(FATAL) << "GetFileInformationByHandleEx"; |
| 279 } |
| 280 FILE_NAME_INFO* file_name_info = |
| 281 reinterpret_cast<FILE_NAME_INFO*>(data.get()); |
| 282 pipe_name_ = |
| 283 L"\\\\.\\pipe" + std::wstring(file_name_info->FileName, |
| 284 file_name_info->FileNameLength / |
| 285 sizeof(file_name_info->FileName[0])); |
329 | 286 |
330 // CreateNamedPipe() is documented as setting the error to | 287 { |
331 // ERROR_ACCESS_DENIED if FILE_FLAG_FIRST_PIPE_INSTANCE is specified and the | 288 base::AutoLock lock(clients_lock_); |
332 // pipe name is already in use. However it may set the error to other codes | 289 internal::ClientData* client = new internal::ClientData( |
333 // such as ERROR_PIPE_BUSY (if the pipe already exists and has reached its | 290 port_.get(), |
334 // maximum instance count) or ERROR_INVALID_PARAMETER (if the pipe already | 291 delegate, |
335 // exists and its attributes differ from those specified to | 292 ScopedKernelHANDLE(initial_client_data.client_process()), |
336 // CreateNamedPipe()). Some of these errors may be ambiguous: for example, | 293 ScopedKernelHANDLE(initial_client_data.request_crash_dump()), |
337 // ERROR_INVALID_PARAMETER may also occur if CreateNamedPipe() is called | 294 ScopedKernelHANDLE(initial_client_data.request_non_crash_dump()), |
338 // incorrectly even in the absence of an existing pipe by the same name. | 295 ScopedKernelHANDLE(initial_client_data.non_crash_dump_completed()), |
339 // | 296 initial_client_data.crash_exception_information(), |
340 // Rather than chasing down all of the possible errors that might indicate | 297 initial_client_data.non_crash_exception_information(), |
341 // that a pipe name is already in use, retry up to a few times on any error. | 298 initial_client_data.debug_critical_section_address(), |
342 } while (!first_pipe_instance_.is_valid() && --tries); | 299 &OnCrashDumpEvent, |
343 | 300 &OnNonCrashDumpEvent, |
344 PCHECK(first_pipe_instance_.is_valid()) << "CreateNamedPipe"; | 301 &OnProcessEnd); |
345 | 302 clients_.insert(client); |
346 SetPipeName(pipe_name); | 303 } |
347 return pipe_name; | |
348 } | 304 } |
349 | 305 |
350 void ExceptionHandlerServer::Run(Delegate* delegate) { | 306 void ExceptionHandlerServer::Run(Delegate* delegate) { |
351 uint64_t shutdown_token = base::RandUint64(); | 307 uint64_t shutdown_token = base::RandUint64(); |
352 ScopedKernelHANDLE thread_handles[kPipeInstances]; | 308 ScopedKernelHANDLE thread_handles[kPipeInstances]; |
353 for (size_t i = 0; i < arraysize(thread_handles); ++i) { | 309 for (size_t i = 0; i < arraysize(thread_handles); ++i) { |
354 HANDLE pipe; | 310 HANDLE pipe; |
355 if (first_pipe_instance_.is_valid()) { | 311 if (first_pipe_instance_.is_valid()) { |
356 pipe = first_pipe_instance_.release(); | 312 pipe = first_pipe_instance_.release(); |
357 } else { | 313 } else { |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
450 << message.shutdown.token; | 406 << message.shutdown.token; |
451 return false; | 407 return false; |
452 } | 408 } |
453 ServerToClientMessage shutdown_response = {}; | 409 ServerToClientMessage shutdown_response = {}; |
454 LoggingWriteFile(service_context.pipe(), | 410 LoggingWriteFile(service_context.pipe(), |
455 &shutdown_response, | 411 &shutdown_response, |
456 sizeof(shutdown_response)); | 412 sizeof(shutdown_response)); |
457 return true; | 413 return true; |
458 } | 414 } |
459 | 415 |
| 416 case ClientToServerMessage::kPing: { |
| 417 // No action required, the fact that the message was processed is |
| 418 // sufficient. |
| 419 ServerToClientMessage shutdown_response = {}; |
| 420 LoggingWriteFile(service_context.pipe(), |
| 421 &shutdown_response, |
| 422 sizeof(shutdown_response)); |
| 423 return false; |
| 424 } |
| 425 |
460 case ClientToServerMessage::kRegister: | 426 case ClientToServerMessage::kRegister: |
461 // Handled below. | 427 // Handled below. |
462 break; | 428 break; |
463 | 429 |
464 default: | 430 default: |
465 LOG(ERROR) << "unhandled message type: " << message.type; | 431 LOG(ERROR) << "unhandled message type: " << message.type; |
466 return false; | 432 return false; |
467 } | 433 } |
468 | 434 |
469 if (message.registration.version != RegistrationRequest::kMessageVersion) { | 435 if (message.registration.version != RegistrationRequest::kMessageVersion) { |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
506 } | 472 } |
507 } | 473 } |
508 | 474 |
509 internal::ClientData* client; | 475 internal::ClientData* client; |
510 { | 476 { |
511 base::AutoLock lock(*service_context.clients_lock()); | 477 base::AutoLock lock(*service_context.clients_lock()); |
512 client = new internal::ClientData( | 478 client = new internal::ClientData( |
513 service_context.port(), | 479 service_context.port(), |
514 service_context.delegate(), | 480 service_context.delegate(), |
515 ScopedKernelHANDLE(client_process), | 481 ScopedKernelHANDLE(client_process), |
| 482 ScopedKernelHANDLE( |
| 483 CreateEvent(nullptr, false /* auto reset */, false, nullptr)), |
| 484 ScopedKernelHANDLE( |
| 485 CreateEvent(nullptr, false /* auto reset */, false, nullptr)), |
| 486 ScopedKernelHANDLE( |
| 487 CreateEvent(nullptr, false /* auto reset */, false, nullptr)), |
516 message.registration.crash_exception_information, | 488 message.registration.crash_exception_information, |
517 message.registration.non_crash_exception_information, | 489 message.registration.non_crash_exception_information, |
518 message.registration.critical_section_address, | 490 message.registration.critical_section_address, |
519 &OnCrashDumpEvent, | 491 &OnCrashDumpEvent, |
520 &OnNonCrashDumpEvent, | 492 &OnNonCrashDumpEvent, |
521 &OnProcessEnd); | 493 &OnProcessEnd); |
522 service_context.clients()->insert(client); | 494 service_context.clients()->insert(client); |
523 } | 495 } |
524 | 496 |
525 // Duplicate the events back to the client so they can request a dump. | 497 // Duplicate the events back to the client so they can request a dump. |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
596 void __stdcall ExceptionHandlerServer::OnProcessEnd(void* ctx, BOOLEAN) { | 568 void __stdcall ExceptionHandlerServer::OnProcessEnd(void* ctx, BOOLEAN) { |
597 // This function is executed on the thread pool. | 569 // This function is executed on the thread pool. |
598 internal::ClientData* client = reinterpret_cast<internal::ClientData*>(ctx); | 570 internal::ClientData* client = reinterpret_cast<internal::ClientData*>(ctx); |
599 base::AutoLock lock(*client->lock()); | 571 base::AutoLock lock(*client->lock()); |
600 | 572 |
601 // Post back to the main thread to have it delete this client record. | 573 // Post back to the main thread to have it delete this client record. |
602 PostQueuedCompletionStatus(client->port(), 0, ULONG_PTR(client), nullptr); | 574 PostQueuedCompletionStatus(client->port(), 0, ULONG_PTR(client), nullptr); |
603 } | 575 } |
604 | 576 |
605 } // namespace crashpad | 577 } // namespace crashpad |
OLD | NEW |