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

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: test 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
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 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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698