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

Unified 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: . 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 side-by-side diff with in-line comments
Download patch
Index: util/win/process_info.cc
diff --git a/util/win/process_info.cc b/util/win/process_info.cc
index fa413cc3c8c51ecd04b2f6e5b96dfbc037defad7..2fa8ce4bee9d97a0aa10c3656ec011280eb40c14 100644
--- a/util/win/process_info.cc
+++ b/util/win/process_info.cc
@@ -20,12 +20,15 @@
#include <limits>
#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
#include "base/strings/stringprintf.h"
#include "base/template_util.h"
#include "build/build_config.h"
#include "util/numeric/safe_assignment.h"
+#include "util/win/nt_internals.h"
#include "util/win/ntstatus_logging.h"
#include "util/win/process_structs.h"
+#include "util/win/scoped_handle.h"
namespace crashpad {
@@ -127,6 +130,31 @@ MEMORY_BASIC_INFORMATION64 MemoryBasicInformationToMemoryBasicInformation64(
return mbi64;
}
+// NtQueryObject with a retry for size mismatch and a hint for initial size.
+scoped_ptr<uint8_t[]> QueryObject(
+ HANDLE handle,
+ OBJECT_INFORMATION_CLASS object_information_class,
+ ULONG size) {
+ ULONG return_length;
+ scoped_ptr<uint8_t[]> buffer(new uint8_t[size]);
+ NTSTATUS status = crashpad::NtQueryObject(
+ handle, object_information_class, buffer.get(), size, &return_length);
+ if (status == STATUS_INFO_LENGTH_MISMATCH) {
+ DCHECK_GE(return_length, size);
Mark Mentovai 2015/10/15 05:25:17 DCHECK_GT, not DCHECK_GE.
scottmg 2015/10/15 21:38:45 Done.
+ size = return_length;
+ buffer.reset(new uint8_t[size]);
+ status = crashpad::NtQueryObject(
+ handle, object_information_class, buffer.get(), size, &return_length);
+ }
+
+ if (!NT_SUCCESS(status)) {
+ NTSTATUS_LOG(ERROR, status) << "NtQueryObject";
+ return scoped_ptr<uint8_t[]>();
+ }
+
+ return buffer.Pass();
Mark Mentovai 2015/10/15 05:25:17 buffer.resize(return_length) to trim any excess. (
Mark Mentovai 2015/10/15 15:07:22 Mark Mentovai wrote:
Mark Mentovai 2015/10/15 15:28:53 I wrote:
scottmg 2015/10/15 21:38:45 Done.
+}
+
} // namespace
template <class Traits>
@@ -314,12 +342,134 @@ bool ReadMemoryInfo(HANDLE process, bool is_64_bit, ProcessInfo* process_info) {
return true;
}
+template <class Traits>
+std::vector<ProcessInfo::Handle> ProcessInfo::BuildHandleVector(
+ HANDLE process) const {
+ ULONG buffer_size = 2 * 1024 * 1024;
Mark Mentovai 2015/10/15 05:25:17 Pretty huge buffer. At its minimum size, it’s room
scottmg 2015/10/15 21:38:44 Unfortunately yes. I have ~110k handles on my syst
+ scoped_ptr<uint8_t[]> buffer(new uint8_t[buffer_size]);
+
+ // Typically if the buffer were too small, STATUS_INFO_LENGTH_MISMATCH would
+ // return the correct size in the final argument, but it does not in for this
Mark Mentovai 2015/10/15 05:25:17 “in for this” → “for”
scottmg 2015/10/15 21:38:45 Done.
+ // SYSTEM_INFORMATION_CLASS, so we loop and attempt larger sizes.
Mark Mentovai 2015/10/15 05:25:17 Is the returned size correct when this returns suc
scottmg 2015/10/15 21:38:45 Not doing anything here per vector/scoped_ptr.
+ NTSTATUS status;
+ for (int tries = 0; tries < 5; ++tries) {
+ status = crashpad::NtQuerySystemInformation(
+ static_cast<SYSTEM_INFORMATION_CLASS>(SystemExtendedHandleInformation),
+ buffer.get(),
+ buffer_size,
+ nullptr);
+ if (NT_SUCCESS(status)) {
+ break;
+ } else if (status == STATUS_INFO_LENGTH_MISMATCH) {
Mark Mentovai 2015/10/15 05:25:17 If status is not this and not success, I don’t thi
scottmg 2015/10/15 21:38:45 Done.
+ buffer_size *= 2;
+ buffer.reset(new uint8_t[buffer_size]);
+ }
+ }
+
+ if (!NT_SUCCESS(status)) {
+ NTSTATUS_LOG(ERROR, status)
+ << "NtQuerySystemInformation SystemExtendedHandleInformation";
+ return std::vector<Handle>();
+ }
+
+ const auto* system_handle_information_ex =
Mark Mentovai 2015/10/15 05:25:17 Could be & instead of *.
scottmg 2015/10/15 21:38:45 Done.
+ reinterpret_cast<process_types::SYSTEM_HANDLE_INFORMATION_EX<Traits>*>(
Mark Mentovai 2015/10/15 05:25:17 Since this is system-specific and not process-spec
scottmg 2015/10/15 21:38:45 Done.
+ buffer.get());
+
+ std::vector<Handle> handles;
+
+ for (size_t i = 0; i < system_handle_information_ex->NumberOfHandles; ++i) {
Mark Mentovai 2015/10/15 05:25:17 Before entering the loop, make sure that offsetof(
Mark Mentovai 2015/10/15 15:28:53 I wrote:
scottmg 2015/10/15 21:38:45 Done.
+ const auto& handle = system_handle_information_ex->Handles[i];
+ if (handle.UniqueProcessId != process_id_)
Mark Mentovai 2015/10/15 05:25:16 Noticing that handle.UniqueProcessId might be 64 b
scottmg 2015/10/15 21:38:45 Yeah, good point, it's a bit weird. Since they're
+ continue;
+
+ // TODO(scottmg): Could special case for self.
+ HANDLE dup_handle;
+ if (!DuplicateHandle(process,
+ reinterpret_cast<HANDLE>(handle.HandleValue),
+ GetCurrentProcess(),
+ &dup_handle,
+ 0,
+ false,
+ DUPLICATE_SAME_ACCESS)) {
+ // Some handles cannot be duplicated, for example, handles of type
+ // EtwRegistration. If we fail to duplicate, then we can't gather any more
+ // information, so just include the handle the list with what we do have.
+ Handle result_handle;
+ result_handle.handle = static_cast<uint32_t>(handle.HandleValue);
+ result_handle.attributes = handle.HandleAttributes;
+ result_handle.granted_access = handle.GrantedAccess;
+ handles.push_back(result_handle);
+ continue;
+ }
+ ScopedKernelHANDLE scoped_dup_handle(dup_handle);
+
+ scoped_ptr<uint8_t[]> object_basic_information_buffer =
+ QueryObject(dup_handle,
+ ObjectBasicInformation,
+ sizeof(PUBLIC_OBJECT_BASIC_INFORMATION));
+ if (!object_basic_information_buffer)
+ continue;
Mark Mentovai 2015/10/15 05:25:17 Worthwhile to add the data we could get from SYSTE
scottmg 2015/10/15 21:38:45 Done.
+
+ scoped_ptr<uint8_t[]> object_type_information_buffer =
+ QueryObject(dup_handle,
+ ObjectTypeInformation,
+ sizeof(PUBLIC_OBJECT_TYPE_INFORMATION));
+ if (!object_type_information_buffer)
+ continue;
+
+ PUBLIC_OBJECT_BASIC_INFORMATION* object_basic_information =
+ reinterpret_cast<PUBLIC_OBJECT_BASIC_INFORMATION*>(
+ object_basic_information_buffer.get());
+ PUBLIC_OBJECT_TYPE_INFORMATION* object_type_information =
+ reinterpret_cast<PUBLIC_OBJECT_TYPE_INFORMATION*>(
+ object_type_information_buffer.get());
+
+ Handle result_handle;
Mark Mentovai 2015/10/15 05:25:17 Didn’t you find that MSVS 2015 didn’t like shadowi
scottmg 2015/10/15 21:38:45 With your better version above, this disappears.
+ DCHECK_EQ(object_type_information->TypeName.Length %
+ sizeof(result_handle.type_name[0]),
+ 0u);
+ result_handle.type_name =
+ std::wstring(object_type_information->TypeName.Buffer,
+ object_type_information->TypeName.Length /
+ sizeof(result_handle.type_name[0]));
+
+ result_handle.handle = static_cast<uint32_t>(handle.HandleValue);
+ // The Attributes and GrantedAccess sometimes differ slightly between the
Mark Mentovai 2015/10/15 05:25:17 Blank before. And also a blank before pointer_coun
scottmg 2015/10/15 21:38:44 Done.
+ // data retrieved in SYSTEM_HANDLE_INFORMATION_EX and
+ // PUBLIC_OBJECT_TYPE_INFORMATION. We prefer the values in
+ // SYSTEM_HANDLE_INFORMATION_EX because they were retrieved from the target
+ // process, rather than on the duplicated handle.
+ result_handle.attributes = handle.HandleAttributes;
+ result_handle.granted_access = handle.GrantedAccess;
+ result_handle.pointer_count = object_basic_information->PointerCount;
Mark Mentovai 2015/10/15 05:25:17 Just confirming: making a duplicate doesn’t actual
scottmg 2015/10/15 21:38:45 That one's harder to test, but I believe it's actu
+
+ // Subtract one to account for our DuplicateHandle().
+ DCHECK_GT(object_basic_information->HandleCount, 1u);
+ result_handle.handle_count = object_basic_information->HandleCount - 1;
+ handles.push_back(result_handle);
Mark Mentovai 2015/10/15 05:25:16 Blank before this, too.
scottmg 2015/10/15 21:38:45 Done.
+ }
+ return handles;
+}
+
ProcessInfo::Module::Module() : name(), dll_base(0), size(0), timestamp() {
}
ProcessInfo::Module::~Module() {
}
+ProcessInfo::Handle::Handle()
+ : type_name(),
+ handle(0),
+ attributes(0),
+ granted_access(0),
+ pointer_count(0),
+ handle_count(0) {
+}
+
+ProcessInfo::Handle::~Handle() {
+}
+
ProcessInfo::ProcessInfo()
: process_id_(),
inherited_from_process_id_(),
@@ -328,6 +478,7 @@ ProcessInfo::ProcessInfo()
peb_size_(0),
modules_(),
memory_info_(),
+ handles_(),
is_64_bit_(false),
is_wow64_(false),
initialized_() {
@@ -387,6 +538,11 @@ bool ProcessInfo::Initialize(HANDLE process) {
return false;
}
+ if (is_64_bit_)
+ handles_ = BuildHandleVector<process_types::internal::Traits64>(process);
Mark Mentovai 2015/10/15 05:25:17 Since this can’t do anything but get all handles s
scottmg 2015/10/15 21:38:45 Done.
+ else
+ handles_ = BuildHandleVector<process_types::internal::Traits32>(process);
+
INITIALIZATION_STATE_SET_VALID(initialized_);
return true;
}

Powered by Google App Engine
This is Rietveld 408576698