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/process_info.h" | 15 #include "util/win/process_info.h" |
16 | 16 |
17 #include <winternl.h> | 17 #include <winternl.h> |
18 | 18 |
19 #include <algorithm> | 19 #include <algorithm> |
20 #include <limits> | 20 #include <limits> |
21 | 21 |
22 #include "base/logging.h" | 22 #include "base/logging.h" |
23 #include "base/memory/scoped_ptr.h" | |
23 #include "base/strings/stringprintf.h" | 24 #include "base/strings/stringprintf.h" |
24 #include "base/template_util.h" | 25 #include "base/template_util.h" |
25 #include "build/build_config.h" | 26 #include "build/build_config.h" |
26 #include "util/numeric/safe_assignment.h" | 27 #include "util/numeric/safe_assignment.h" |
28 #include "util/win/nt_internals.h" | |
27 #include "util/win/ntstatus_logging.h" | 29 #include "util/win/ntstatus_logging.h" |
28 #include "util/win/process_structs.h" | 30 #include "util/win/process_structs.h" |
31 #include "util/win/scoped_handle.h" | |
29 | 32 |
30 namespace crashpad { | 33 namespace crashpad { |
31 | 34 |
32 namespace { | 35 namespace { |
33 | 36 |
34 NTSTATUS NtQueryInformationProcess(HANDLE process_handle, | 37 NTSTATUS NtQueryInformationProcess(HANDLE process_handle, |
35 PROCESSINFOCLASS process_information_class, | 38 PROCESSINFOCLASS process_information_class, |
36 PVOID process_information, | 39 PVOID process_information, |
37 ULONG process_information_length, | 40 ULONG process_information_length, |
38 PULONG return_length) { | 41 PULONG return_length) { |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
120 mbi64.BaseAddress = reinterpret_cast<ULONGLONG>(mbi.BaseAddress); | 123 mbi64.BaseAddress = reinterpret_cast<ULONGLONG>(mbi.BaseAddress); |
121 mbi64.AllocationBase = reinterpret_cast<ULONGLONG>(mbi.AllocationBase); | 124 mbi64.AllocationBase = reinterpret_cast<ULONGLONG>(mbi.AllocationBase); |
122 mbi64.AllocationProtect = mbi.AllocationProtect; | 125 mbi64.AllocationProtect = mbi.AllocationProtect; |
123 mbi64.RegionSize = mbi.RegionSize; | 126 mbi64.RegionSize = mbi.RegionSize; |
124 mbi64.State = mbi.State; | 127 mbi64.State = mbi.State; |
125 mbi64.Protect = mbi.Protect; | 128 mbi64.Protect = mbi.Protect; |
126 mbi64.Type = mbi.Type; | 129 mbi64.Type = mbi.Type; |
127 return mbi64; | 130 return mbi64; |
128 } | 131 } |
129 | 132 |
133 // NtQueryObject with a retry for size mismatch and a hint for initial size. | |
134 scoped_ptr<uint8_t[]> QueryObject( | |
135 HANDLE handle, | |
136 OBJECT_INFORMATION_CLASS object_information_class, | |
137 size_t size) { | |
138 ULONG return_length; | |
139 scoped_ptr<uint8_t[]> buffer(new uint8_t[size]); | |
140 NTSTATUS status = crashpad::NtQueryObject( | |
141 handle, object_information_class, buffer.get(), size, &return_length); | |
142 if (status == STATUS_INFO_LENGTH_MISMATCH) { | |
143 DCHECK_GE(return_length, size); | |
144 size = return_length; | |
145 buffer.reset(new uint8_t[size]); | |
146 status = crashpad::NtQueryObject( | |
147 handle, object_information_class, buffer.get(), size, &return_length); | |
148 if (!NT_SUCCESS(status)) { | |
149 NTSTATUS_LOG(ERROR, status) << "NtQueryObject"; | |
150 return scoped_ptr<uint8_t[]>(); | |
151 } | |
152 } | |
Mark Mentovai
2015/10/14 22:49:55
} else if (!NT_SUCCESS(status)) {
NTSTATUS_LOG
scottmg
2015/10/15 00:17:41
Done.
| |
153 | |
154 return buffer.Pass(); | |
155 } | |
156 | |
130 } // namespace | 157 } // namespace |
131 | 158 |
132 template <class Traits> | 159 template <class Traits> |
133 bool GetProcessBasicInformation(HANDLE process, | 160 bool GetProcessBasicInformation(HANDLE process, |
134 bool is_wow64, | 161 bool is_wow64, |
135 ProcessInfo* process_info, | 162 ProcessInfo* process_info, |
136 WinVMAddress* peb_address, | 163 WinVMAddress* peb_address, |
137 WinVMSize* peb_size) { | 164 WinVMSize* peb_size) { |
138 ULONG bytes_returned; | 165 ULONG bytes_returned; |
139 process_types::PROCESS_BASIC_INFORMATION<Traits> process_basic_information; | 166 process_types::PROCESS_BASIC_INFORMATION<Traits> process_basic_information; |
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
307 | 334 |
308 if (memory_basic_information.RegionSize == 0) { | 335 if (memory_basic_information.RegionSize == 0) { |
309 LOG(ERROR) << "RegionSize == 0"; | 336 LOG(ERROR) << "RegionSize == 0"; |
310 return false; | 337 return false; |
311 } | 338 } |
312 } | 339 } |
313 | 340 |
314 return true; | 341 return true; |
315 } | 342 } |
316 | 343 |
344 template <class Traits> | |
345 std::vector<ProcessInfo::Handle> ProcessInfo::BuildHandleVector( | |
346 HANDLE process) const { | |
347 size_t buffer_size = 2 * 1024 * 1024; | |
348 scoped_ptr<uint8_t[]> buffer(new uint8_t[buffer_size]); | |
349 | |
350 // Typically if the buffer were too small, STATUS_INFO_LENGTH_MISMATCH would | |
351 // return the correct size in the final argument, but it does not in for this | |
352 // SYSTEM_INFORMATION_CLASS, so we loop and attempt larger sizes. | |
353 NTSTATUS status; | |
354 for (int tries = 0; tries < 5; ++tries) { | |
355 status = crashpad::NtQuerySystemInformation( | |
Mark Mentovai
2015/10/14 22:49:55
Do you want a QuerySystemInformation() wrapper for
scottmg
2015/10/15 00:17:41
It's only done once at the moment, so I think it's
| |
356 static_cast<SYSTEM_INFORMATION_CLASS>(SystemExtendedHandleInformation), | |
357 buffer.get(), | |
358 buffer_size, | |
359 nullptr); | |
360 if (NT_SUCCESS(status)) { | |
361 break; | |
362 } else if (status == STATUS_INFO_LENGTH_MISMATCH) { | |
363 buffer_size *= 2; | |
Mark Mentovai
2015/10/14 22:49:55
Why don’t you use the ReturnLength argument to tel
scottmg
2015/10/15 00:17:41
That's the comment above the loop -- it doesn't pr
| |
364 buffer.reset(new uint8_t[buffer_size]); | |
365 } | |
366 } | |
367 | |
368 if (!NT_SUCCESS(status)) { | |
369 NTSTATUS_LOG(ERROR, status) | |
370 << "NtQuerySystemInformation SystemExtendedHandleInformation"; | |
371 return std::vector<Handle>(); | |
372 } | |
373 | |
374 process_types::SYSTEM_HANDLE_INFORMATION_EX< | |
375 Traits>* system_handle_information_ex = | |
Mark Mentovai
2015/10/14 22:49:55
Weird formatting (did clang-format do this?!)
scottmg
2015/10/15 00:17:41
Yup. A little better with an auto*?
| |
376 reinterpret_cast<process_types::SYSTEM_HANDLE_INFORMATION_EX<Traits>*>( | |
377 buffer.get()); | |
378 | |
379 std::vector<Handle> handles; | |
380 | |
381 for (size_t i = 0; i < system_handle_information_ex->NumberOfHandles; ++i) { | |
382 const auto& handle = system_handle_information_ex->Handles[i]; | |
383 if (handle.UniqueProcessId != process_id_) | |
384 continue; | |
385 | |
386 // TODO(scottmg): Could special case for self. | |
387 HANDLE dup_handle; | |
388 if (!DuplicateHandle(process, | |
Mark Mentovai
2015/10/14 22:49:55
In https://code.google.com/p/crashpad/issues/detai
scottmg
2015/10/15 00:17:41
DuplicateHandle()ing into ourselves scared me at f
| |
389 reinterpret_cast<HANDLE>(handle.HandleValue), | |
390 GetCurrentProcess(), | |
391 &dup_handle, | |
392 0, | |
393 false, | |
394 DUPLICATE_SAME_ACCESS)) { | |
395 // Some handles cannot be duplicated, for example handles of type | |
396 // EtwRegistration, so we simply drop these. (We also do not strictly know | |
Mark Mentovai
2015/10/14 22:49:55
Does MiniDumpWriteDump() lose these too?
Is there
scottmg
2015/10/15 00:17:41
Just confirmed with MiniDumpWriteDump() via https:
| |
397 // that we're suspended here, so there's a race between here and | |
398 // collecting them, though in practice the target process will always be | |
399 // suspended.) | |
400 continue; | |
401 } | |
402 ScopedKernelHANDLE scoped_dup_handle(dup_handle); | |
403 | |
404 scoped_ptr<uint8_t[]> object_basic_information_buffer = | |
405 QueryObject(dup_handle, | |
406 ObjectBasicInformation, | |
407 sizeof(PUBLIC_OBJECT_BASIC_INFORMATION)); | |
408 if (!object_basic_information_buffer) | |
409 continue; | |
410 | |
411 scoped_ptr<uint8_t[]> object_type_information_buffer = | |
412 QueryObject(dup_handle, | |
413 ObjectTypeInformation, | |
414 sizeof(PUBLIC_OBJECT_TYPE_INFORMATION)); | |
415 if (!object_type_information_buffer) | |
416 continue; | |
417 | |
418 PUBLIC_OBJECT_BASIC_INFORMATION* object_basic_information = | |
419 reinterpret_cast<PUBLIC_OBJECT_BASIC_INFORMATION*>( | |
420 object_basic_information_buffer.get()); | |
421 PUBLIC_OBJECT_TYPE_INFORMATION* object_type_information = | |
422 reinterpret_cast<PUBLIC_OBJECT_TYPE_INFORMATION*>( | |
423 object_type_information_buffer.get()); | |
424 | |
425 Handle result_handle; | |
426 result_handle.type_name = | |
427 std::wstring(object_type_information->TypeName.Buffer, | |
428 object_type_information->TypeName.Length / | |
Mark Mentovai
2015/10/14 22:49:55
DCHECK that Length % sizeof(result_handle.type_nam
scottmg
2015/10/15 00:17:41
Done.
| |
429 sizeof(result_handle.type_name[0])); | |
430 result_handle.handle = static_cast<uint32_t>(handle.HandleValue); | |
431 // The Attributes and GrantedAccess sometimes differ slightly between the | |
Mark Mentovai
2015/10/14 22:49:55
Blank before. Same on 439.
scottmg
2015/10/15 00:17:41
Done.
| |
432 // data retrieved in SYSTEM_HANDLE_INFORMATION_EX and | |
433 // PUBLIC_OBJECT_TYPE_INFORMATION. We prefer the values in | |
434 // SYSTEM_HANDLE_INFORMATION_EX because they were retrieved from the target | |
435 // process, rather than on the duplicated handle. | |
436 result_handle.attributes = handle.HandleAttributes; | |
437 result_handle.granted_access = handle.GrantedAccess; | |
438 result_handle.pointer_count = object_basic_information->PointerCount; | |
439 // Subtract one to account for our DuplicateHandle(). | |
440 DCHECK_GT(object_basic_information->HandleCount, 0u); | |
Mark Mentovai
2015/10/14 22:49:55
Should this be > 1? At least one original referenc
scottmg
2015/10/15 00:17:41
Yeah, done.
| |
441 result_handle.handle_count = object_basic_information->HandleCount - 1; | |
Mark Mentovai
2015/10/14 22:49:55
Happy to see this accounted for!
| |
442 handles.push_back(result_handle); | |
443 } | |
444 return handles; | |
445 } | |
446 | |
317 ProcessInfo::Module::Module() : name(), dll_base(0), size(0), timestamp() { | 447 ProcessInfo::Module::Module() : name(), dll_base(0), size(0), timestamp() { |
318 } | 448 } |
319 | 449 |
320 ProcessInfo::Module::~Module() { | 450 ProcessInfo::Module::~Module() { |
321 } | 451 } |
322 | 452 |
453 ProcessInfo::Handle::Handle() | |
454 : type_name(), | |
455 handle(), | |
Mark Mentovai
2015/10/14 22:49:55
Zeroes in the integer fields.
scottmg
2015/10/15 00:17:41
Done.
| |
456 attributes(), | |
457 granted_access(), | |
458 pointer_count(), | |
459 handle_count() { | |
460 } | |
461 | |
462 ProcessInfo::Handle::~Handle() { | |
463 } | |
464 | |
323 ProcessInfo::ProcessInfo() | 465 ProcessInfo::ProcessInfo() |
324 : process_id_(), | 466 : process_id_(), |
325 inherited_from_process_id_(), | 467 inherited_from_process_id_(), |
326 command_line_(), | 468 command_line_(), |
327 peb_address_(0), | 469 peb_address_(0), |
328 peb_size_(0), | 470 peb_size_(0), |
329 modules_(), | 471 modules_(), |
330 memory_info_(), | 472 memory_info_(), |
331 is_64_bit_(false), | 473 is_64_bit_(false), |
Mark Mentovai
2015/10/14 22:49:55
handles_()
scottmg
2015/10/15 00:17:41
Done.
| |
332 is_wow64_(false), | 474 is_wow64_(false), |
333 initialized_() { | 475 initialized_() { |
334 } | 476 } |
335 | 477 |
336 ProcessInfo::~ProcessInfo() { | 478 ProcessInfo::~ProcessInfo() { |
337 } | 479 } |
338 | 480 |
339 bool ProcessInfo::Initialize(HANDLE process) { | 481 bool ProcessInfo::Initialize(HANDLE process) { |
340 INITIALIZATION_STATE_SET_INITIALIZING(initialized_); | 482 INITIALIZATION_STATE_SET_INITIALIZING(initialized_); |
341 | 483 |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
380 if (!result) { | 522 if (!result) { |
381 LOG(ERROR) << "ReadProcessData failed"; | 523 LOG(ERROR) << "ReadProcessData failed"; |
382 return false; | 524 return false; |
383 } | 525 } |
384 | 526 |
385 if (!ReadMemoryInfo(process, is_64_bit_, this)) { | 527 if (!ReadMemoryInfo(process, is_64_bit_, this)) { |
386 LOG(ERROR) << "ReadMemoryInfo failed"; | 528 LOG(ERROR) << "ReadMemoryInfo failed"; |
387 return false; | 529 return false; |
388 } | 530 } |
389 | 531 |
532 if (is_64_bit_) | |
533 handles_ = BuildHandleVector<process_types::internal::Traits64>(process); | |
534 else | |
535 handles_ = BuildHandleVector<process_types::internal::Traits32>(process); | |
536 | |
390 INITIALIZATION_STATE_SET_VALID(initialized_); | 537 INITIALIZATION_STATE_SET_VALID(initialized_); |
391 return true; | 538 return true; |
392 } | 539 } |
393 | 540 |
394 bool ProcessInfo::Is64Bit() const { | 541 bool ProcessInfo::Is64Bit() const { |
395 INITIALIZATION_STATE_DCHECK_VALID(initialized_); | 542 INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
396 return is_64_bit_; | 543 return is_64_bit_; |
397 } | 544 } |
398 | 545 |
399 bool ProcessInfo::IsWow64() const { | 546 bool ProcessInfo::IsWow64() const { |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
495 } else { | 642 } else { |
496 result.push_back(as_ranges[i]); | 643 result.push_back(as_ranges[i]); |
497 } | 644 } |
498 DCHECK(result.back().IsValid()); | 645 DCHECK(result.back().IsValid()); |
499 } | 646 } |
500 | 647 |
501 return result; | 648 return result; |
502 } | 649 } |
503 | 650 |
504 } // namespace crashpad | 651 } // namespace crashpad |
OLD | NEW |