mirror of
https://github.com/chromium/crashpad.git
synced 2025-03-09 14:06:33 +00:00
win: Add Handles() to ProcessInfo
To eventually be used to fill out MINIDUMP_HANDLE_DESCRIPTOR. R=mark@chromium.org BUG=crashpad:21, crashpad:46, crashpad:52 Review URL: https://codereview.chromium.org/1400413002 .
This commit is contained in:
parent
d1e49bd221
commit
7de04b02f8
@ -72,6 +72,22 @@ NTSTATUS NtOpenThread(PHANDLE thread_handle,
|
|||||||
static_cast<const void*>(client_id));
|
static_cast<const void*>(client_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NTSTATUS NtQueryObject(HANDLE handle,
|
||||||
|
OBJECT_INFORMATION_CLASS object_information_class,
|
||||||
|
void* object_information,
|
||||||
|
ULONG object_information_length,
|
||||||
|
ULONG* return_length) {
|
||||||
|
static decltype(::NtQueryObject)* nt_query_object =
|
||||||
|
reinterpret_cast<decltype(::NtQueryObject)*>(
|
||||||
|
GetProcAddress(LoadLibrary(L"ntdll.dll"), "NtQueryObject"));
|
||||||
|
DCHECK(nt_query_object);
|
||||||
|
return nt_query_object(handle,
|
||||||
|
object_information_class,
|
||||||
|
object_information,
|
||||||
|
object_information_length,
|
||||||
|
return_length);
|
||||||
|
}
|
||||||
|
|
||||||
// Explicit instantiations with the only 2 valid template arguments to avoid
|
// Explicit instantiations with the only 2 valid template arguments to avoid
|
||||||
// putting the body of the function in the header.
|
// putting the body of the function in the header.
|
||||||
template NTSTATUS NtOpenThread<process_types::internal::Traits32>(
|
template NTSTATUS NtOpenThread<process_types::internal::Traits32>(
|
||||||
|
@ -27,6 +27,9 @@ namespace crashpad {
|
|||||||
// winternal.h defines THREADINFOCLASS, but not all members.
|
// winternal.h defines THREADINFOCLASS, but not all members.
|
||||||
enum { ThreadBasicInformation = 0 };
|
enum { ThreadBasicInformation = 0 };
|
||||||
|
|
||||||
|
// winternal.h defines SYSTEM_INFORMATION_CLASS, but not all members.
|
||||||
|
enum { SystemExtendedHandleInformation = 64 };
|
||||||
|
|
||||||
NTSTATUS NtQuerySystemInformation(
|
NTSTATUS NtQuerySystemInformation(
|
||||||
SYSTEM_INFORMATION_CLASS system_information_class,
|
SYSTEM_INFORMATION_CLASS system_information_class,
|
||||||
PVOID system_information,
|
PVOID system_information,
|
||||||
@ -45,4 +48,10 @@ NTSTATUS NtOpenThread(PHANDLE thread_handle,
|
|||||||
POBJECT_ATTRIBUTES object_attributes,
|
POBJECT_ATTRIBUTES object_attributes,
|
||||||
const process_types::CLIENT_ID<Traits>* client_id);
|
const process_types::CLIENT_ID<Traits>* client_id);
|
||||||
|
|
||||||
|
NTSTATUS NtQueryObject(HANDLE handle,
|
||||||
|
OBJECT_INFORMATION_CLASS object_information_class,
|
||||||
|
void* object_information,
|
||||||
|
ULONG object_information_length,
|
||||||
|
ULONG* return_length);
|
||||||
|
|
||||||
} // namespace crashpad
|
} // namespace crashpad
|
||||||
|
@ -20,12 +20,15 @@
|
|||||||
#include <limits>
|
#include <limits>
|
||||||
|
|
||||||
#include "base/logging.h"
|
#include "base/logging.h"
|
||||||
|
#include "base/memory/scoped_ptr.h"
|
||||||
#include "base/strings/stringprintf.h"
|
#include "base/strings/stringprintf.h"
|
||||||
#include "base/template_util.h"
|
#include "base/template_util.h"
|
||||||
#include "build/build_config.h"
|
#include "build/build_config.h"
|
||||||
#include "util/numeric/safe_assignment.h"
|
#include "util/numeric/safe_assignment.h"
|
||||||
|
#include "util/win/nt_internals.h"
|
||||||
#include "util/win/ntstatus_logging.h"
|
#include "util/win/ntstatus_logging.h"
|
||||||
#include "util/win/process_structs.h"
|
#include "util/win/process_structs.h"
|
||||||
|
#include "util/win/scoped_handle.h"
|
||||||
|
|
||||||
namespace crashpad {
|
namespace crashpad {
|
||||||
|
|
||||||
@ -127,6 +130,34 @@ MEMORY_BASIC_INFORMATION64 MemoryBasicInformationToMemoryBasicInformation64(
|
|||||||
return mbi64;
|
return mbi64;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NtQueryObject with a retry for size mismatch as well as a minimum size to
|
||||||
|
// retrieve (and expect).
|
||||||
|
scoped_ptr<uint8_t[]> QueryObject(
|
||||||
|
HANDLE handle,
|
||||||
|
OBJECT_INFORMATION_CLASS object_information_class,
|
||||||
|
ULONG minimum_size) {
|
||||||
|
ULONG size = minimum_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_GT(return_length, size);
|
||||||
|
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[]>();
|
||||||
|
}
|
||||||
|
|
||||||
|
DCHECK_GE(return_length, minimum_size);
|
||||||
|
return buffer.Pass();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
template <class Traits>
|
template <class Traits>
|
||||||
@ -314,20 +345,150 @@ bool ReadMemoryInfo(HANDLE process, bool is_64_bit, ProcessInfo* process_info) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<ProcessInfo::Handle> ProcessInfo::BuildHandleVector(
|
||||||
|
HANDLE process) const {
|
||||||
|
ULONG buffer_size = 2 * 1024 * 1024;
|
||||||
|
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 for
|
||||||
|
// SystemExtendedHandleInformation, so we loop and attempt larger sizes.
|
||||||
|
NTSTATUS status;
|
||||||
|
ULONG returned_length;
|
||||||
|
for (int tries = 0; tries < 5; ++tries) {
|
||||||
|
status = crashpad::NtQuerySystemInformation(
|
||||||
|
static_cast<SYSTEM_INFORMATION_CLASS>(SystemExtendedHandleInformation),
|
||||||
|
buffer.get(),
|
||||||
|
buffer_size,
|
||||||
|
&returned_length);
|
||||||
|
if (NT_SUCCESS(status) || status != STATUS_INFO_LENGTH_MISMATCH)
|
||||||
|
break;
|
||||||
|
|
||||||
|
buffer_size *= 2;
|
||||||
|
buffer.reset();
|
||||||
|
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 =
|
||||||
|
*reinterpret_cast<process_types::SYSTEM_HANDLE_INFORMATION_EX*>(
|
||||||
|
buffer.get());
|
||||||
|
|
||||||
|
DCHECK_LE(offsetof(process_types::SYSTEM_HANDLE_INFORMATION_EX, Handles) +
|
||||||
|
system_handle_information_ex.NumberOfHandles *
|
||||||
|
sizeof(system_handle_information_ex.Handles[0]),
|
||||||
|
returned_length);
|
||||||
|
|
||||||
|
std::vector<Handle> handles;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < system_handle_information_ex.NumberOfHandles; ++i) {
|
||||||
|
const auto& handle = system_handle_information_ex.Handles[i];
|
||||||
|
if (handle.UniqueProcessId != process_id_)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Handle result_handle;
|
||||||
|
result_handle.handle =
|
||||||
|
static_cast<uint32_t>(reinterpret_cast<uintptr_t>(handle.HandleValue));
|
||||||
|
result_handle.attributes = handle.HandleAttributes;
|
||||||
|
result_handle.granted_access = handle.GrantedAccess;
|
||||||
|
|
||||||
|
// 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, but include the information that we do have already.
|
||||||
|
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) {
|
||||||
|
PUBLIC_OBJECT_BASIC_INFORMATION* object_basic_information =
|
||||||
|
reinterpret_cast<PUBLIC_OBJECT_BASIC_INFORMATION*>(
|
||||||
|
object_basic_information_buffer.get());
|
||||||
|
// The Attributes and GrantedAccess sometimes differ slightly between
|
||||||
|
// the 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, so don't use
|
||||||
|
// them here.
|
||||||
|
|
||||||
|
// Subtract one to account for our DuplicateHandle() and another for
|
||||||
|
// NtQueryObject() while the query was being executed.
|
||||||
|
DCHECK_GT(object_basic_information->PointerCount, 2u);
|
||||||
|
result_handle.pointer_count =
|
||||||
|
object_basic_information->PointerCount - 2;
|
||||||
|
|
||||||
|
// Subtract one to account for our DuplicateHandle().
|
||||||
|
DCHECK_GT(object_basic_information->HandleCount, 1u);
|
||||||
|
result_handle.handle_count = object_basic_information->HandleCount - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
scoped_ptr<uint8_t[]> object_type_information_buffer =
|
||||||
|
QueryObject(dup_handle,
|
||||||
|
ObjectTypeInformation,
|
||||||
|
sizeof(PUBLIC_OBJECT_TYPE_INFORMATION));
|
||||||
|
if (object_type_information_buffer) {
|
||||||
|
PUBLIC_OBJECT_TYPE_INFORMATION* object_type_information =
|
||||||
|
reinterpret_cast<PUBLIC_OBJECT_TYPE_INFORMATION*>(
|
||||||
|
object_type_information_buffer.get());
|
||||||
|
|
||||||
|
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]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handles.push_back(result_handle);
|
||||||
|
}
|
||||||
|
return handles;
|
||||||
|
}
|
||||||
|
|
||||||
ProcessInfo::Module::Module() : name(), dll_base(0), size(0), timestamp() {
|
ProcessInfo::Module::Module() : name(), dll_base(0), size(0), timestamp() {
|
||||||
}
|
}
|
||||||
|
|
||||||
ProcessInfo::Module::~Module() {
|
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()
|
ProcessInfo::ProcessInfo()
|
||||||
: process_id_(),
|
: process_id_(),
|
||||||
inherited_from_process_id_(),
|
inherited_from_process_id_(),
|
||||||
|
process_(),
|
||||||
command_line_(),
|
command_line_(),
|
||||||
peb_address_(0),
|
peb_address_(0),
|
||||||
peb_size_(0),
|
peb_size_(0),
|
||||||
modules_(),
|
modules_(),
|
||||||
memory_info_(),
|
memory_info_(),
|
||||||
|
handles_(),
|
||||||
is_64_bit_(false),
|
is_64_bit_(false),
|
||||||
is_wow64_(false),
|
is_wow64_(false),
|
||||||
initialized_() {
|
initialized_() {
|
||||||
@ -339,6 +500,8 @@ ProcessInfo::~ProcessInfo() {
|
|||||||
bool ProcessInfo::Initialize(HANDLE process) {
|
bool ProcessInfo::Initialize(HANDLE process) {
|
||||||
INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
|
INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
|
||||||
|
|
||||||
|
process_ = process;
|
||||||
|
|
||||||
is_wow64_ = IsProcessWow64(process);
|
is_wow64_ = IsProcessWow64(process);
|
||||||
|
|
||||||
if (is_wow64_) {
|
if (is_wow64_) {
|
||||||
@ -439,6 +602,13 @@ ProcessInfo::GetReadableRanges(
|
|||||||
return GetReadableRangesOfMemoryMap(range, MemoryInfo());
|
return GetReadableRangesOfMemoryMap(range, MemoryInfo());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::vector<ProcessInfo::Handle>& ProcessInfo::Handles() {
|
||||||
|
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||||
|
if (handles_.empty())
|
||||||
|
handles_ = BuildHandleVector(process_);
|
||||||
|
return handles_;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<CheckedRange<WinVMAddress, WinVMSize>> GetReadableRangesOfMemoryMap(
|
std::vector<CheckedRange<WinVMAddress, WinVMSize>> GetReadableRangesOfMemoryMap(
|
||||||
const CheckedRange<WinVMAddress, WinVMSize>& range,
|
const CheckedRange<WinVMAddress, WinVMSize>& range,
|
||||||
const std::vector<MEMORY_BASIC_INFORMATION64>& memory_info) {
|
const std::vector<MEMORY_BASIC_INFORMATION64>& memory_info) {
|
||||||
|
@ -50,6 +50,39 @@ class ProcessInfo {
|
|||||||
time_t timestamp;
|
time_t timestamp;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Handle {
|
||||||
|
Handle();
|
||||||
|
~Handle();
|
||||||
|
|
||||||
|
//! \brief A string representation of the handle's type.
|
||||||
|
std::wstring type_name;
|
||||||
|
|
||||||
|
//! \brief The handle's value.
|
||||||
|
//!
|
||||||
|
//! See https://msdn.microsoft.com/en-us/library/windows/desktop/aa384203 on
|
||||||
|
//! 32 bits being the correct size for `HANDLE`s, even on Windows x64.
|
||||||
|
uint32_t handle;
|
||||||
|
|
||||||
|
//! \brief The attributes for the handle, e.g. `OBJ_INHERIT`,
|
||||||
|
//! `OBJ_CASE_INSENSITIVE`, etc.
|
||||||
|
uint32_t attributes;
|
||||||
|
|
||||||
|
//! \brief The `ACCESS_MASK` for the handle in this process.
|
||||||
|
//!
|
||||||
|
//! See
|
||||||
|
//! http://blogs.msdn.com/b/openspecification/archive/2010/04/01/about-the-access-mask-structure.aspx
|
||||||
|
//! for more information.
|
||||||
|
uint32_t granted_access;
|
||||||
|
|
||||||
|
//! \brief The number of kernel references to the object that this handle
|
||||||
|
//! refers to.
|
||||||
|
uint32_t pointer_count;
|
||||||
|
|
||||||
|
//! \brief The number of open handles to the object that this handle refers
|
||||||
|
//! to.
|
||||||
|
uint32_t handle_count;
|
||||||
|
};
|
||||||
|
|
||||||
ProcessInfo();
|
ProcessInfo();
|
||||||
~ProcessInfo();
|
~ProcessInfo();
|
||||||
|
|
||||||
@ -106,6 +139,9 @@ class ProcessInfo {
|
|||||||
std::vector<CheckedRange<WinVMAddress, WinVMSize>> GetReadableRanges(
|
std::vector<CheckedRange<WinVMAddress, WinVMSize>> GetReadableRanges(
|
||||||
const CheckedRange<WinVMAddress, WinVMSize>& range) const;
|
const CheckedRange<WinVMAddress, WinVMSize>& range) const;
|
||||||
|
|
||||||
|
//! \brief Retrieves information about open handles in the target process.
|
||||||
|
const std::vector<Handle>& Handles();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template <class Traits>
|
template <class Traits>
|
||||||
friend bool GetProcessBasicInformation(HANDLE process,
|
friend bool GetProcessBasicInformation(HANDLE process,
|
||||||
@ -122,13 +158,17 @@ class ProcessInfo {
|
|||||||
bool is_64_bit,
|
bool is_64_bit,
|
||||||
ProcessInfo* process_info);
|
ProcessInfo* process_info);
|
||||||
|
|
||||||
|
std::vector<Handle> BuildHandleVector(HANDLE process) const;
|
||||||
|
|
||||||
pid_t process_id_;
|
pid_t process_id_;
|
||||||
pid_t inherited_from_process_id_;
|
pid_t inherited_from_process_id_;
|
||||||
|
HANDLE process_;
|
||||||
std::wstring command_line_;
|
std::wstring command_line_;
|
||||||
WinVMAddress peb_address_;
|
WinVMAddress peb_address_;
|
||||||
WinVMSize peb_size_;
|
WinVMSize peb_size_;
|
||||||
std::vector<Module> modules_;
|
std::vector<Module> modules_;
|
||||||
std::vector<MEMORY_BASIC_INFORMATION64> memory_info_;
|
std::vector<MEMORY_BASIC_INFORMATION64> memory_info_;
|
||||||
|
std::vector<Handle> handles_;
|
||||||
bool is_64_bit_;
|
bool is_64_bit_;
|
||||||
bool is_wow64_;
|
bool is_wow64_;
|
||||||
InitializationStateDcheck initialized_;
|
InitializationStateDcheck initialized_;
|
||||||
|
@ -20,8 +20,12 @@
|
|||||||
|
|
||||||
#include "base/files/file_path.h"
|
#include "base/files/file_path.h"
|
||||||
#include "base/memory/scoped_ptr.h"
|
#include "base/memory/scoped_ptr.h"
|
||||||
|
#include "base/rand_util.h"
|
||||||
|
#include "base/strings/stringprintf.h"
|
||||||
|
#include "base/strings/utf_string_conversions.h"
|
||||||
#include "build/build_config.h"
|
#include "build/build_config.h"
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
|
#include "test/scoped_temp_dir.h"
|
||||||
#include "test/paths.h"
|
#include "test/paths.h"
|
||||||
#include "test/win/child_launcher.h"
|
#include "test/win/child_launcher.h"
|
||||||
#include "util/file/file_io.h"
|
#include "util/file/file_io.h"
|
||||||
@ -510,6 +514,114 @@ TEST(ProcessInfo, ReadableRanges) {
|
|||||||
&bytes_read));
|
&bytes_read));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ScopedRegistryKeyCloseTraits {
|
||||||
|
static HKEY InvalidValue() {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
static void Free(HKEY key) {
|
||||||
|
RegCloseKey(key);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
using ScopedRegistryKey =
|
||||||
|
base::ScopedGeneric<HKEY, ScopedRegistryKeyCloseTraits>;
|
||||||
|
|
||||||
|
TEST(ProcessInfo, Handles) {
|
||||||
|
ScopedTempDir temp_dir;
|
||||||
|
|
||||||
|
ScopedFileHandle file(LoggingOpenFileForWrite(
|
||||||
|
temp_dir.path().Append(FILE_PATH_LITERAL("test_file")),
|
||||||
|
FileWriteMode::kTruncateOrCreate,
|
||||||
|
FilePermissions::kWorldReadable));
|
||||||
|
ASSERT_TRUE(file.is_valid());
|
||||||
|
|
||||||
|
SECURITY_ATTRIBUTES security_attributes = {0};
|
||||||
|
security_attributes.bInheritHandle = true;
|
||||||
|
ScopedFileHandle inherited_file(CreateFile(L"CONOUT$",
|
||||||
|
GENERIC_WRITE,
|
||||||
|
0,
|
||||||
|
&security_attributes,
|
||||||
|
OPEN_EXISTING,
|
||||||
|
FILE_ATTRIBUTE_NORMAL,
|
||||||
|
nullptr));
|
||||||
|
ASSERT_TRUE(inherited_file.is_valid());
|
||||||
|
|
||||||
|
HKEY key;
|
||||||
|
ASSERT_EQ(ERROR_SUCCESS,
|
||||||
|
RegOpenKeyEx(
|
||||||
|
HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft", 0, KEY_READ, &key));
|
||||||
|
ScopedRegistryKey scoped_key(key);
|
||||||
|
ASSERT_TRUE(scoped_key.is_valid());
|
||||||
|
|
||||||
|
std::wstring mapping_name =
|
||||||
|
base::UTF8ToUTF16(base::StringPrintf("Global\\test_mapping_%d_%I64x",
|
||||||
|
GetCurrentProcessId(),
|
||||||
|
base::RandUint64()));
|
||||||
|
ScopedKernelHANDLE mapping(CreateFileMapping(INVALID_HANDLE_VALUE,
|
||||||
|
nullptr,
|
||||||
|
PAGE_READWRITE,
|
||||||
|
0,
|
||||||
|
1024,
|
||||||
|
mapping_name.c_str()));
|
||||||
|
ASSERT_TRUE(mapping.is_valid());
|
||||||
|
|
||||||
|
ProcessInfo info;
|
||||||
|
info.Initialize(GetCurrentProcess());
|
||||||
|
bool found_file_handle = false;
|
||||||
|
bool found_inherited_file_handle = false;
|
||||||
|
bool found_key_handle = false;
|
||||||
|
bool found_mapping_handle = false;
|
||||||
|
for (auto handle : info.Handles()) {
|
||||||
|
if (reinterpret_cast<uint32_t>(file.get()) == handle.handle) {
|
||||||
|
EXPECT_FALSE(found_file_handle);
|
||||||
|
found_file_handle = true;
|
||||||
|
EXPECT_EQ(L"File", handle.type_name);
|
||||||
|
EXPECT_EQ(1, handle.handle_count);
|
||||||
|
EXPECT_NE(0u, handle.pointer_count);
|
||||||
|
EXPECT_EQ(STANDARD_RIGHTS_READ | STANDARD_RIGHTS_WRITE | SYNCHRONIZE,
|
||||||
|
handle.granted_access & STANDARD_RIGHTS_ALL);
|
||||||
|
EXPECT_EQ(0, handle.attributes);
|
||||||
|
}
|
||||||
|
if (reinterpret_cast<uint32_t>(inherited_file.get()) == handle.handle) {
|
||||||
|
EXPECT_FALSE(found_inherited_file_handle);
|
||||||
|
found_inherited_file_handle = true;
|
||||||
|
EXPECT_EQ(L"File", handle.type_name);
|
||||||
|
EXPECT_EQ(1, handle.handle_count);
|
||||||
|
EXPECT_NE(0u, handle.pointer_count);
|
||||||
|
EXPECT_EQ(STANDARD_RIGHTS_READ | STANDARD_RIGHTS_WRITE | SYNCHRONIZE,
|
||||||
|
handle.granted_access & STANDARD_RIGHTS_ALL);
|
||||||
|
|
||||||
|
// OBJ_INHERIT from ntdef.h, but including that conflicts with other
|
||||||
|
// headers.
|
||||||
|
const int kObjInherit = 0x2;
|
||||||
|
EXPECT_EQ(kObjInherit, handle.attributes);
|
||||||
|
}
|
||||||
|
if (reinterpret_cast<uint32_t>(scoped_key.get()) == handle.handle) {
|
||||||
|
EXPECT_FALSE(found_key_handle);
|
||||||
|
found_key_handle = true;
|
||||||
|
EXPECT_EQ(L"Key", handle.type_name);
|
||||||
|
EXPECT_EQ(1, handle.handle_count);
|
||||||
|
EXPECT_NE(0u, handle.pointer_count);
|
||||||
|
EXPECT_EQ(STANDARD_RIGHTS_READ,
|
||||||
|
handle.granted_access & STANDARD_RIGHTS_ALL);
|
||||||
|
EXPECT_EQ(0, handle.attributes);
|
||||||
|
}
|
||||||
|
if (reinterpret_cast<uint32_t>(mapping.get()) == handle.handle) {
|
||||||
|
EXPECT_FALSE(found_mapping_handle);
|
||||||
|
found_mapping_handle = true;
|
||||||
|
EXPECT_EQ(L"Section", handle.type_name);
|
||||||
|
EXPECT_EQ(1, handle.handle_count);
|
||||||
|
EXPECT_NE(0u, handle.pointer_count);
|
||||||
|
EXPECT_EQ(DELETE | READ_CONTROL | WRITE_DAC | WRITE_OWNER |
|
||||||
|
STANDARD_RIGHTS_READ | STANDARD_RIGHTS_WRITE,
|
||||||
|
handle.granted_access & STANDARD_RIGHTS_ALL);
|
||||||
|
EXPECT_EQ(0, handle.attributes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EXPECT_TRUE(found_file_handle);
|
||||||
|
EXPECT_TRUE(found_key_handle);
|
||||||
|
EXPECT_TRUE(found_mapping_handle);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
} // namespace test
|
} // namespace test
|
||||||
} // namespace crashpad
|
} // namespace crashpad
|
||||||
|
@ -484,6 +484,23 @@ struct RTL_CRITICAL_SECTION_DEBUG {
|
|||||||
WORD SpareWORD;
|
WORD SpareWORD;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX {
|
||||||
|
void* Object;
|
||||||
|
ULONG_PTR UniqueProcessId;
|
||||||
|
HANDLE HandleValue;
|
||||||
|
ULONG GrantedAccess;
|
||||||
|
USHORT CreatorBackTraceIndex;
|
||||||
|
USHORT ObjectTypeIndex;
|
||||||
|
ULONG HandleAttributes;
|
||||||
|
ULONG Reserved;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SYSTEM_HANDLE_INFORMATION_EX {
|
||||||
|
ULONG_PTR NumberOfHandles;
|
||||||
|
ULONG_PTR Reserved;
|
||||||
|
SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX Handles[1];
|
||||||
|
};
|
||||||
|
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user