Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(174)

Side by Side Diff: util/win/process_info.cc

Issue 1400413002: win: Add Handles() to ProcessInfo (Closed) Base URL: https://chromium.googlesource.com/crashpad/crashpad@master
Patch Set: rebase Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « util/win/process_info.h ('k') | util/win/process_info_test.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
OLDNEW
« no previous file with comments | « util/win/process_info.h ('k') | util/win/process_info_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698