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 as well as a minimum size to |
| 134 // retrieve (and expect). |
| 135 scoped_ptr<uint8_t[]> QueryObject( |
| 136 HANDLE handle, |
| 137 OBJECT_INFORMATION_CLASS object_information_class, |
| 138 ULONG minimum_size) { |
| 139 ULONG size = minimum_size; |
| 140 ULONG return_length; |
| 141 scoped_ptr<uint8_t[]> buffer(new uint8_t[size]); |
| 142 NTSTATUS status = crashpad::NtQueryObject( |
| 143 handle, object_information_class, buffer.get(), size, &return_length); |
| 144 if (status == STATUS_INFO_LENGTH_MISMATCH) { |
| 145 DCHECK_GT(return_length, size); |
| 146 size = return_length; |
| 147 buffer.reset(new uint8_t[size]); |
| 148 status = crashpad::NtQueryObject( |
| 149 handle, object_information_class, buffer.get(), size, &return_length); |
| 150 } |
| 151 |
| 152 if (!NT_SUCCESS(status)) { |
| 153 NTSTATUS_LOG(ERROR, status) << "NtQueryObject"; |
| 154 return scoped_ptr<uint8_t[]>(); |
| 155 } |
| 156 |
| 157 DCHECK_GE(return_length, minimum_size); |
| 158 return buffer.Pass(); |
| 159 } |
| 160 |
130 } // namespace | 161 } // namespace |
131 | 162 |
132 template <class Traits> | 163 template <class Traits> |
133 bool GetProcessBasicInformation(HANDLE process, | 164 bool GetProcessBasicInformation(HANDLE process, |
134 bool is_wow64, | 165 bool is_wow64, |
135 ProcessInfo* process_info, | 166 ProcessInfo* process_info, |
136 WinVMAddress* peb_address, | 167 WinVMAddress* peb_address, |
137 WinVMSize* peb_size) { | 168 WinVMSize* peb_size) { |
138 ULONG bytes_returned; | 169 ULONG bytes_returned; |
139 process_types::PROCESS_BASIC_INFORMATION<Traits> process_basic_information; | 170 process_types::PROCESS_BASIC_INFORMATION<Traits> process_basic_information; |
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
307 | 338 |
308 if (memory_basic_information.RegionSize == 0) { | 339 if (memory_basic_information.RegionSize == 0) { |
309 LOG(ERROR) << "RegionSize == 0"; | 340 LOG(ERROR) << "RegionSize == 0"; |
310 return false; | 341 return false; |
311 } | 342 } |
312 } | 343 } |
313 | 344 |
314 return true; | 345 return true; |
315 } | 346 } |
316 | 347 |
| 348 std::vector<ProcessInfo::Handle> ProcessInfo::BuildHandleVector( |
| 349 HANDLE process) const { |
| 350 ULONG buffer_size = 2 * 1024 * 1024; |
| 351 scoped_ptr<uint8_t[]> buffer(new uint8_t[buffer_size]); |
| 352 |
| 353 // Typically if the buffer were too small, STATUS_INFO_LENGTH_MISMATCH would |
| 354 // return the correct size in the final argument, but it does not for |
| 355 // SystemExtendedHandleInformation, so we loop and attempt larger sizes. |
| 356 NTSTATUS status; |
| 357 ULONG returned_length; |
| 358 for (int tries = 0; tries < 5; ++tries) { |
| 359 status = crashpad::NtQuerySystemInformation( |
| 360 static_cast<SYSTEM_INFORMATION_CLASS>(SystemExtendedHandleInformation), |
| 361 buffer.get(), |
| 362 buffer_size, |
| 363 &returned_length); |
| 364 if (NT_SUCCESS(status) || status != STATUS_INFO_LENGTH_MISMATCH) |
| 365 break; |
| 366 |
| 367 buffer_size *= 2; |
| 368 buffer.reset(); |
| 369 buffer.reset(new uint8_t[buffer_size]); |
| 370 } |
| 371 |
| 372 if (!NT_SUCCESS(status)) { |
| 373 NTSTATUS_LOG(ERROR, status) |
| 374 << "NtQuerySystemInformation SystemExtendedHandleInformation"; |
| 375 return std::vector<Handle>(); |
| 376 } |
| 377 |
| 378 const auto& system_handle_information_ex = |
| 379 *reinterpret_cast<process_types::SYSTEM_HANDLE_INFORMATION_EX*>( |
| 380 buffer.get()); |
| 381 |
| 382 DCHECK_LE(offsetof(process_types::SYSTEM_HANDLE_INFORMATION_EX, Handles) + |
| 383 system_handle_information_ex.NumberOfHandles * |
| 384 sizeof(system_handle_information_ex.Handles[0]), |
| 385 returned_length); |
| 386 |
| 387 std::vector<Handle> handles; |
| 388 |
| 389 for (size_t i = 0; i < system_handle_information_ex.NumberOfHandles; ++i) { |
| 390 const auto& handle = system_handle_information_ex.Handles[i]; |
| 391 if (handle.UniqueProcessId != process_id_) |
| 392 continue; |
| 393 |
| 394 Handle result_handle; |
| 395 result_handle.handle = |
| 396 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(handle.HandleValue)); |
| 397 result_handle.attributes = handle.HandleAttributes; |
| 398 result_handle.granted_access = handle.GrantedAccess; |
| 399 |
| 400 // TODO(scottmg): Could special case for self. |
| 401 HANDLE dup_handle; |
| 402 if (DuplicateHandle(process, |
| 403 reinterpret_cast<HANDLE>(handle.HandleValue), |
| 404 GetCurrentProcess(), |
| 405 &dup_handle, |
| 406 0, |
| 407 false, |
| 408 DUPLICATE_SAME_ACCESS)) { |
| 409 // Some handles cannot be duplicated, for example, handles of type |
| 410 // EtwRegistration. If we fail to duplicate, then we can't gather any more |
| 411 // information, but include the information that we do have already. |
| 412 ScopedKernelHANDLE scoped_dup_handle(dup_handle); |
| 413 |
| 414 scoped_ptr<uint8_t[]> object_basic_information_buffer = |
| 415 QueryObject(dup_handle, |
| 416 ObjectBasicInformation, |
| 417 sizeof(PUBLIC_OBJECT_BASIC_INFORMATION)); |
| 418 if (object_basic_information_buffer) { |
| 419 PUBLIC_OBJECT_BASIC_INFORMATION* object_basic_information = |
| 420 reinterpret_cast<PUBLIC_OBJECT_BASIC_INFORMATION*>( |
| 421 object_basic_information_buffer.get()); |
| 422 // The Attributes and GrantedAccess sometimes differ slightly between |
| 423 // the data retrieved in SYSTEM_HANDLE_INFORMATION_EX and |
| 424 // PUBLIC_OBJECT_TYPE_INFORMATION. We prefer the values in |
| 425 // SYSTEM_HANDLE_INFORMATION_EX because they were retrieved from the |
| 426 // target process, rather than on the duplicated handle, so don't use |
| 427 // them here. |
| 428 |
| 429 // Subtract one to account for our DuplicateHandle() and another for |
| 430 // NtQueryObject() while the query was being executed. |
| 431 DCHECK_GT(object_basic_information->PointerCount, 2u); |
| 432 result_handle.pointer_count = |
| 433 object_basic_information->PointerCount - 2; |
| 434 |
| 435 // Subtract one to account for our DuplicateHandle(). |
| 436 DCHECK_GT(object_basic_information->HandleCount, 1u); |
| 437 result_handle.handle_count = object_basic_information->HandleCount - 1; |
| 438 } |
| 439 |
| 440 scoped_ptr<uint8_t[]> object_type_information_buffer = |
| 441 QueryObject(dup_handle, |
| 442 ObjectTypeInformation, |
| 443 sizeof(PUBLIC_OBJECT_TYPE_INFORMATION)); |
| 444 if (object_type_information_buffer) { |
| 445 PUBLIC_OBJECT_TYPE_INFORMATION* object_type_information = |
| 446 reinterpret_cast<PUBLIC_OBJECT_TYPE_INFORMATION*>( |
| 447 object_type_information_buffer.get()); |
| 448 |
| 449 DCHECK_EQ(object_type_information->TypeName.Length % |
| 450 sizeof(result_handle.type_name[0]), |
| 451 0u); |
| 452 result_handle.type_name = |
| 453 std::wstring(object_type_information->TypeName.Buffer, |
| 454 object_type_information->TypeName.Length / |
| 455 sizeof(result_handle.type_name[0])); |
| 456 } |
| 457 } |
| 458 |
| 459 handles.push_back(result_handle); |
| 460 } |
| 461 return handles; |
| 462 } |
| 463 |
317 ProcessInfo::Module::Module() : name(), dll_base(0), size(0), timestamp() { | 464 ProcessInfo::Module::Module() : name(), dll_base(0), size(0), timestamp() { |
318 } | 465 } |
319 | 466 |
320 ProcessInfo::Module::~Module() { | 467 ProcessInfo::Module::~Module() { |
321 } | 468 } |
322 | 469 |
| 470 ProcessInfo::Handle::Handle() |
| 471 : type_name(), |
| 472 handle(0), |
| 473 attributes(0), |
| 474 granted_access(0), |
| 475 pointer_count(0), |
| 476 handle_count(0) { |
| 477 } |
| 478 |
| 479 ProcessInfo::Handle::~Handle() { |
| 480 } |
| 481 |
323 ProcessInfo::ProcessInfo() | 482 ProcessInfo::ProcessInfo() |
324 : process_id_(), | 483 : process_id_(), |
325 inherited_from_process_id_(), | 484 inherited_from_process_id_(), |
| 485 process_(), |
326 command_line_(), | 486 command_line_(), |
327 peb_address_(0), | 487 peb_address_(0), |
328 peb_size_(0), | 488 peb_size_(0), |
329 modules_(), | 489 modules_(), |
330 memory_info_(), | 490 memory_info_(), |
| 491 handles_(), |
331 is_64_bit_(false), | 492 is_64_bit_(false), |
332 is_wow64_(false), | 493 is_wow64_(false), |
333 initialized_() { | 494 initialized_() { |
334 } | 495 } |
335 | 496 |
336 ProcessInfo::~ProcessInfo() { | 497 ProcessInfo::~ProcessInfo() { |
337 } | 498 } |
338 | 499 |
339 bool ProcessInfo::Initialize(HANDLE process) { | 500 bool ProcessInfo::Initialize(HANDLE process) { |
340 INITIALIZATION_STATE_SET_INITIALIZING(initialized_); | 501 INITIALIZATION_STATE_SET_INITIALIZING(initialized_); |
341 | 502 |
| 503 process_ = process; |
| 504 |
342 is_wow64_ = IsProcessWow64(process); | 505 is_wow64_ = IsProcessWow64(process); |
343 | 506 |
344 if (is_wow64_) { | 507 if (is_wow64_) { |
345 // If it's WoW64, then it's 32-on-64. | 508 // If it's WoW64, then it's 32-on-64. |
346 is_64_bit_ = false; | 509 is_64_bit_ = false; |
347 } else { | 510 } else { |
348 // Otherwise, it's either 32 on 32, or 64 on 64. Use GetSystemInfo() to | 511 // Otherwise, it's either 32 on 32, or 64 on 64. Use GetSystemInfo() to |
349 // distinguish between these two cases. | 512 // distinguish between these two cases. |
350 SYSTEM_INFO system_info; | 513 SYSTEM_INFO system_info; |
351 GetSystemInfo(&system_info); | 514 GetSystemInfo(&system_info); |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
432 INITIALIZATION_STATE_DCHECK_VALID(initialized_); | 595 INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
433 return memory_info_; | 596 return memory_info_; |
434 } | 597 } |
435 | 598 |
436 std::vector<CheckedRange<WinVMAddress, WinVMSize>> | 599 std::vector<CheckedRange<WinVMAddress, WinVMSize>> |
437 ProcessInfo::GetReadableRanges( | 600 ProcessInfo::GetReadableRanges( |
438 const CheckedRange<WinVMAddress, WinVMSize>& range) const { | 601 const CheckedRange<WinVMAddress, WinVMSize>& range) const { |
439 return GetReadableRangesOfMemoryMap(range, MemoryInfo()); | 602 return GetReadableRangesOfMemoryMap(range, MemoryInfo()); |
440 } | 603 } |
441 | 604 |
| 605 const std::vector<ProcessInfo::Handle>& ProcessInfo::Handles() { |
| 606 INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| 607 if (handles_.empty()) |
| 608 handles_ = BuildHandleVector(process_); |
| 609 return handles_; |
| 610 } |
| 611 |
442 std::vector<CheckedRange<WinVMAddress, WinVMSize>> GetReadableRangesOfMemoryMap( | 612 std::vector<CheckedRange<WinVMAddress, WinVMSize>> GetReadableRangesOfMemoryMap( |
443 const CheckedRange<WinVMAddress, WinVMSize>& range, | 613 const CheckedRange<WinVMAddress, WinVMSize>& range, |
444 const std::vector<MEMORY_BASIC_INFORMATION64>& memory_info) { | 614 const std::vector<MEMORY_BASIC_INFORMATION64>& memory_info) { |
445 using Range = CheckedRange<WinVMAddress, WinVMSize>; | 615 using Range = CheckedRange<WinVMAddress, WinVMSize>; |
446 | 616 |
447 // Find all the ranges that overlap the target range, maintaining their order. | 617 // Find all the ranges that overlap the target range, maintaining their order. |
448 std::vector<MEMORY_BASIC_INFORMATION64> overlapping; | 618 std::vector<MEMORY_BASIC_INFORMATION64> overlapping; |
449 for (const auto& mi : memory_info) { | 619 for (const auto& mi : memory_info) { |
450 static_assert(base::is_same<decltype(mi.BaseAddress), WinVMAddress>::value, | 620 static_assert(base::is_same<decltype(mi.BaseAddress), WinVMAddress>::value, |
451 "expected range address to be WinVMAddress"); | 621 "expected range address to be WinVMAddress"); |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
495 } else { | 665 } else { |
496 result.push_back(as_ranges[i]); | 666 result.push_back(as_ranges[i]); |
497 } | 667 } |
498 DCHECK(result.back().IsValid()); | 668 DCHECK(result.back().IsValid()); |
499 } | 669 } |
500 | 670 |
501 return result; | 671 return result; |
502 } | 672 } |
503 | 673 |
504 } // namespace crashpad | 674 } // namespace crashpad |
OLD | NEW |