summaryrefslogtreecommitdiffstats
path: root/sandbox/src
diff options
context:
space:
mode:
authorjschuh@chromium.org <jschuh@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-06-24 22:17:06 +0000
committerjschuh@chromium.org <jschuh@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-06-24 22:17:06 +0000
commit284dadf39378ae2ef6b18edce0a7b4f54364f9a0 (patch)
tree538aaaa212067f195cb138d0d5a8322aea7d0d50 /sandbox/src
parent1f751e27b7e0153f718564989bd9064b461e8ed2 (diff)
downloadchromium_src-284dadf39378ae2ef6b18edce0a7b4f54364f9a0.zip
chromium_src-284dadf39378ae2ef6b18edce0a7b4f54364f9a0.tar.gz
chromium_src-284dadf39378ae2ef6b18edce0a7b4f54364f9a0.tar.bz2
Factor Windows handle enumeration code into its own classesI did some general cleanup and isolated out the handle enumeration.
TEST=sbox_unittests.exe --gtest_filter=HandleTable.* BUG=86521 Review URL: http://codereview.chromium.org/7206007 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@90449 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'sandbox/src')
-rw-r--r--sandbox/src/handle_table.cc195
-rw-r--r--sandbox/src/handle_table.h161
-rw-r--r--sandbox/src/handle_table_unittest.cc66
-rw-r--r--sandbox/src/nt_internals.h87
4 files changed, 509 insertions, 0 deletions
diff --git a/sandbox/src/handle_table.cc b/sandbox/src/handle_table.cc
new file mode 100644
index 0000000..be84fa3
--- /dev/null
+++ b/sandbox/src/handle_table.cc
@@ -0,0 +1,195 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/src/handle_table.h"
+
+#include <algorithm>
+#include <cstdlib>
+
+#include "base/memory/scoped_ptr.h"
+
+namespace {
+
+const wchar_t kNtdllDllName[] = L"ntdll.dll";
+
+bool CompareHandleEntries(const SYSTEM_HANDLE_INFORMATION& a,
+ const SYSTEM_HANDLE_INFORMATION& b) {
+ return a.ProcessId < b.ProcessId;
+}
+
+} // namespace
+
+namespace sandbox {
+
+HMODULE HandleTable::ntdll_ = 0;
+const char16* HandleTable::kTypeProcess = L"Process";
+const char16* HandleTable::kTypeThread = L"Thread";
+const char16* HandleTable::kTypeFile = L"File";
+const char16* HandleTable::kTypeDirectory = L"Directory";
+const char16* HandleTable::kTypeKey = L"Key";
+const char16* HandleTable::kTypeWindowStation = L"WindowStation";
+const char16* HandleTable::kTypeDesktop = L"Desktop";
+const char16* HandleTable::kTypeService = L"Service";
+const char16* HandleTable::kTypeMutex = L"Mutex";
+const char16* HandleTable::kTypeSemaphore = L"Semaphore";
+const char16* HandleTable::kTypeEvent = L"Event";
+const char16* HandleTable::kTypeTimer = L"Timer";
+const char16* HandleTable::kTypeNamedPipe = L"NamedPipe";
+const char16* HandleTable::kTypeJobObject = L"JobObject";
+const char16* HandleTable::kTypeFileMap = L"FileMap";
+const char16* HandleTable::kTypeAlpcPort = L"ALPC Port";
+
+HandleTable::HandleTable() {
+ static NtQuerySystemInformation QuerySystemInformation;
+ if (!QuerySystemInformation) {
+ if (!ntdll_ && !(ntdll_ = ::GetModuleHandle(kNtdllDllName)))
+ return;
+ QuerySystemInformation = reinterpret_cast<NtQuerySystemInformation>(
+ ::GetProcAddress(ntdll_, "NtQuerySystemInformation"));
+ if (!QuerySystemInformation)
+ return;
+ }
+
+ ULONG size = 0x15000;
+ NTSTATUS result;
+ do {
+ handle_info_buffer_.resize(size);
+ result = QuerySystemInformation(SystemHandleInformation,
+ handle_info_internal(), size, &size);
+ } while (result == STATUS_INFO_LENGTH_MISMATCH);
+
+ // We failed, so make an empty table.
+ if (!NT_SUCCESS(result)) {
+ handle_info_buffer_.resize(0);
+ return;
+ }
+
+ // Sort it to make process lookups faster.
+ std::sort(handle_info_internal()->Information,
+ handle_info_internal()->Information +
+ handle_info_internal()->NumberOfHandles, CompareHandleEntries);
+}
+
+HandleTable::Iterator HandleTable::HandlesForProcess(ULONG process_id) const {
+ SYSTEM_HANDLE_INFORMATION key;
+ key.ProcessId = process_id;
+
+ const SYSTEM_HANDLE_INFORMATION* start = handle_info()->Information;
+ const SYSTEM_HANDLE_INFORMATION* finish =
+ &handle_info()->Information[handle_info()->NumberOfHandles];
+
+ start = std::lower_bound(start, finish, key, CompareHandleEntries);
+ if (start->ProcessId != process_id)
+ return Iterator(*this, finish, finish);
+ finish = std::upper_bound(start, finish, key, CompareHandleEntries);
+ return Iterator(*this, start, finish);
+}
+
+HandleTable::HandleEntry::HandleEntry(
+ const SYSTEM_HANDLE_INFORMATION* handle_info_entry)
+ : handle_entry_(handle_info_entry), last_entry_(0) {
+}
+
+void HandleTable::HandleEntry::UpdateInfo(UpdateType flag) {
+ static NtQueryObject QueryObject;
+ if (!QueryObject) {
+ if (!ntdll_ && !(ntdll_ = ::GetModuleHandle(kNtdllDllName)))
+ return;
+ QueryObject = reinterpret_cast<NtQueryObject>(::GetProcAddress(ntdll_,
+ "NtQueryObject"));
+ if (!QueryObject)
+ return;
+ }
+
+ NTSTATUS result;
+
+ // Always update the basic type info, but grab the names as needed.
+ if (needs_info_update()) {
+ handle_name_.clear();
+ type_name_.clear();
+ last_entry_ = handle_entry_;
+
+ // Most handle names are very short, so start small and reuse this buffer.
+ if (type_info_buffer_.empty())
+ type_info_buffer_.resize(sizeof(OBJECT_TYPE_INFORMATION)
+ + (32 * sizeof(wchar_t)));
+ ULONG size = static_cast<ULONG>(type_info_buffer_.size());
+ result = QueryObject(reinterpret_cast<HANDLE>(handle_entry_->Handle),
+ ObjectTypeInformation, type_info_internal(), size, &size);
+ while (result == STATUS_INFO_LENGTH_MISMATCH) {
+ type_info_buffer_.resize(size);
+ result = QueryObject(reinterpret_cast<HANDLE>(handle_entry_->Handle),
+ ObjectTypeInformation, type_info_internal(), size, &size);
+ }
+
+ if (!NT_SUCCESS(result)) {
+ type_info_buffer_.clear();
+ return;
+ }
+ }
+
+ // Don't bother copying out names until we ask for them, and then cache them.
+ switch (flag) {
+ case UPDATE_INFO_AND_NAME:
+ if (type_info_buffer_.size() && handle_name_.empty()) {
+ ULONG size = MAX_PATH;
+ scoped_ptr<UNICODE_STRING> name;
+ do {
+ name.reset(reinterpret_cast<UNICODE_STRING*>(new BYTE[size]));
+ result = QueryObject(reinterpret_cast<HANDLE>(
+ handle_entry_->Handle), ObjectNameInformation, name.get(),
+ size, &size);
+ } while (result == STATUS_INFO_LENGTH_MISMATCH);
+
+ if (NT_SUCCESS(result)) {
+ handle_name_.assign(name->Buffer, name->Length / sizeof(wchar_t));
+ }
+ }
+ break;
+
+ case UPDATE_INFO_AND_TYPE_NAME:
+ if (!type_info_buffer_.empty() && type_info_internal()->Name.Buffer &&
+ type_name_.empty()) {
+ type_name_.assign(type_info_internal()->Name.Buffer,
+ type_info_internal()->Name.Length / sizeof(wchar_t));
+ }
+ break;
+ }
+}
+
+const OBJECT_TYPE_INFORMATION* HandleTable::HandleEntry::TypeInfo() {
+ UpdateInfo(UPDATE_INFO_ONLY);
+ return type_info_buffer_.empty() ? NULL : type_info_internal();
+}
+
+const string16& HandleTable::HandleEntry::Name() {
+ UpdateInfo(UPDATE_INFO_AND_NAME);
+ return handle_name_;
+}
+
+const string16& HandleTable::HandleEntry::Type() {
+ UpdateInfo(UPDATE_INFO_AND_TYPE_NAME);
+ return type_name_;
+}
+
+bool HandleTable::HandleEntry::IsType(const string16& type_string) {
+ UpdateInfo(UPDATE_INFO_ONLY);
+ if (type_info_buffer_.empty())
+ return false;
+ return type_string.compare(0,
+ type_info_internal()->Name.Length / sizeof(wchar_t),
+ type_info_internal()->Name.Buffer) == 0;
+}
+
+HandleTable::Iterator::Iterator(const HandleTable& table,
+ const SYSTEM_HANDLE_INFORMATION* start,
+ const SYSTEM_HANDLE_INFORMATION* end)
+ : table_(table), current_(start), end_(end) {
+}
+
+HandleTable::Iterator::Iterator(const Iterator& it)
+ : table_(it.table_), current_(it.current_.handle_entry_), end_(it.end_) {
+}
+
+} // namespace sandbox
diff --git a/sandbox/src/handle_table.h b/sandbox/src/handle_table.h
new file mode 100644
index 0000000..8d24524
--- /dev/null
+++ b/sandbox/src/handle_table.h
@@ -0,0 +1,161 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_HANDLE_TABLE_H_
+#define SANDBOX_SRC_HANDLE_TABLE_H_
+#pragma once
+
+#include <windows.h>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/string16.h"
+#include "sandbox/src/nt_internals.h"
+
+namespace sandbox {
+
+// HandleTable retrieves the global handle table and provides helper classes
+// for iterating through the table and retrieving handle info.
+class HandleTable {
+ public:
+ static const char16* HandleTable::kTypeProcess;
+ static const char16* HandleTable::kTypeThread;
+ static const char16* HandleTable::kTypeFile;
+ static const char16* HandleTable::kTypeDirectory;
+ static const char16* HandleTable::kTypeKey;
+ static const char16* HandleTable::kTypeWindowStation;
+ static const char16* HandleTable::kTypeDesktop;
+ static const char16* HandleTable::kTypeService;
+ static const char16* HandleTable::kTypeMutex;
+ static const char16* HandleTable::kTypeSemaphore;
+ static const char16* HandleTable::kTypeEvent;
+ static const char16* HandleTable::kTypeTimer;
+ static const char16* HandleTable::kTypeNamedPipe;
+ static const char16* HandleTable::kTypeJobObject;
+ static const char16* HandleTable::kTypeFileMap;
+ static const char16* HandleTable::kTypeAlpcPort;
+
+ class Iterator;
+
+ // Used by the iterator to provide simple caching accessors to handle data.
+ class HandleEntry {
+ public:
+ bool operator==(const HandleEntry& rhs) const {
+ return handle_entry_ == rhs.handle_entry_;
+ }
+
+ bool operator!=(const HandleEntry& rhs) const {
+ return handle_entry_ != rhs.handle_entry_;
+ }
+
+ const SYSTEM_HANDLE_INFORMATION* handle_entry() const {
+ return handle_entry_;
+ }
+
+ const OBJECT_TYPE_INFORMATION* TypeInfo();
+
+ const string16& Name();
+
+ const string16& Type();
+
+ bool IsType(const string16& type_string);
+
+ private:
+ friend class Iterator;
+ friend class HandleTable;
+
+ enum UpdateType {
+ UPDATE_INFO_ONLY,
+ UPDATE_INFO_AND_NAME,
+ UPDATE_INFO_AND_TYPE_NAME,
+ };
+
+ explicit HandleEntry(const SYSTEM_HANDLE_INFORMATION* handle_info_entry);
+
+ bool needs_info_update() { return handle_entry_ != last_entry_; }
+
+ void UpdateInfo(UpdateType flag);
+
+ OBJECT_TYPE_INFORMATION* type_info_internal() {
+ return reinterpret_cast<OBJECT_TYPE_INFORMATION*>(
+ &(type_info_buffer_[0]));
+ }
+
+ const SYSTEM_HANDLE_INFORMATION* handle_entry_;
+ const SYSTEM_HANDLE_INFORMATION* last_entry_;
+ std::vector<BYTE> type_info_buffer_;
+ string16 handle_name_;
+ string16 type_name_;
+
+ DISALLOW_COPY_AND_ASSIGN(HandleEntry);
+ };
+
+ class Iterator {
+ public:
+ Iterator(const HandleTable& table, const SYSTEM_HANDLE_INFORMATION* start,
+ const SYSTEM_HANDLE_INFORMATION* stop);
+
+ Iterator(const Iterator& it);
+
+ Iterator& operator++() {
+ if (++(current_.handle_entry_) == end_)
+ current_.handle_entry_ = table_.end();
+ return *this;
+ }
+
+ bool operator==(const Iterator& rhs) const {
+ return current_ == rhs.current_;
+ }
+
+ bool operator!=(const Iterator& rhs) const {
+ return current_ != rhs.current_;
+ }
+
+ HandleEntry& operator*() { return current_; }
+
+ operator const SYSTEM_HANDLE_INFORMATION*() {
+ return current_.handle_entry_;
+ }
+
+ HandleEntry* operator->() { return &current_; }
+
+ private:
+ const HandleTable& table_;
+ HandleEntry current_;
+ const SYSTEM_HANDLE_INFORMATION* end_;
+ };
+
+ HandleTable();
+
+ Iterator begin() const {
+ return Iterator(*this, handle_info()->Information,
+ &handle_info()->Information[handle_info()->NumberOfHandles]);
+ }
+
+ const SYSTEM_HANDLE_INFORMATION_EX* handle_info() const {
+ return reinterpret_cast<const SYSTEM_HANDLE_INFORMATION_EX*>(
+ &(handle_info_buffer_[0]));
+ }
+
+ // Returns an iterator to the handles for only the supplied process ID.
+ Iterator HandlesForProcess(ULONG process_id) const;
+ const SYSTEM_HANDLE_INFORMATION* end() const {
+ return &handle_info()->Information[handle_info()->NumberOfHandles];
+ }
+
+ private:
+ SYSTEM_HANDLE_INFORMATION_EX* handle_info_internal() {
+ return reinterpret_cast<SYSTEM_HANDLE_INFORMATION_EX*>(
+ &(handle_info_buffer_[0]));
+ }
+
+ std::vector<BYTE> handle_info_buffer_;
+ static HMODULE ntdll_;
+
+ DISALLOW_COPY_AND_ASSIGN(HandleTable);
+};
+
+} // namespace sandbox
+
+#endif // SANDBOX_SRC_HANDLE_TABLE_H_
diff --git a/sandbox/src/handle_table_unittest.cc b/sandbox/src/handle_table_unittest.cc
new file mode 100644
index 0000000..696037f
--- /dev/null
+++ b/sandbox/src/handle_table_unittest.cc
@@ -0,0 +1,66 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <windows.h>
+
+#include "sandbox/src/handle_table.h"
+#include "sandbox/tests/common/test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(HandleTable, IsTableValid) {
+ using sandbox::HandleTable;
+ const ULONG my_process_id = ::GetCurrentProcessId();
+ ULONG last_process_id = 0;
+ ULONG total_handles = 0;
+ bool found_my_process = false;
+ bool found_other_process = false;
+
+ HandleTable handles;
+ EXPECT_NE(0u, handles.handle_info()->NumberOfHandles);
+
+ for (HandleTable::Iterator it = handles.begin(); it != handles.end(); ++it) {
+ ULONG process_id = it->handle_entry()->ProcessId;
+ bool is_current_process = process_id == my_process_id;
+ found_my_process |= is_current_process;
+ found_other_process |= !is_current_process;
+
+ EXPECT_LE(last_process_id, process_id);
+ last_process_id = process_id;
+ total_handles++;
+ }
+
+ EXPECT_EQ(handles.handle_info()->NumberOfHandles, total_handles);
+ EXPECT_TRUE(found_my_process);
+ EXPECT_TRUE(found_other_process);
+}
+
+TEST(HandleTable, FindHandle) {
+ using sandbox::HandleTable;
+
+ // Create a temp file so we have a handle to find.
+ wchar_t temp_directory[MAX_PATH];
+ wchar_t my_file[MAX_PATH];
+ ASSERT_NE(::GetTempPath(MAX_PATH, temp_directory), 0u);
+ ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, my_file), 0u);
+ HANDLE file = ::CreateFile(my_file, FILE_ALL_ACCESS,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
+ OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE, NULL);
+ EXPECT_NE(INVALID_HANDLE_VALUE, file);
+
+ // Look for the handle in our process
+ bool handle_found = false;
+ HandleTable handles;
+ for (HandleTable::Iterator it =
+ handles.HandlesForProcess(::GetCurrentProcessId());
+ it != handles.end(); ++it) {
+ if (it->IsType(HandleTable::kTypeFile) && it->Name().compare(my_file)) {
+ handle_found = true;
+ break;
+ }
+ }
+ EXPECT_TRUE(handle_found);
+
+ // Clean up the file we made.
+ EXPECT_TRUE(::CloseHandle(file));
+}
diff --git a/sandbox/src/nt_internals.h b/sandbox/src/nt_internals.h
index fa6b59e..08bf1a1 100644
--- a/sandbox/src/nt_internals.h
+++ b/sandbox/src/nt_internals.h
@@ -16,6 +16,7 @@ typedef LONG NTSTATUS;
#define STATUS_BUFFER_OVERFLOW ((NTSTATUS)0x80000005L)
#define STATUS_UNSUCCESSFUL ((NTSTATUS)0xC0000001L)
#define STATUS_NOT_IMPLEMENTED ((NTSTATUS)0xC0000002L)
+#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L)
#ifndef STATUS_INVALID_PARAMETER
// It is now defined in Windows 2008 SDK.
#define STATUS_INVALID_PARAMETER ((NTSTATUS)0xC000000DL)
@@ -441,6 +442,35 @@ typedef enum _OBJECT_INFORMATION_CLASS {
ObjectDataInformation
} OBJECT_INFORMATION_CLASS, *POBJECT_INFORMATION_CLASS;
+typedef struct _OBJDIR_INFORMATION {
+ UNICODE_STRING ObjectName;
+ UNICODE_STRING ObjectTypeName;
+ BYTE Data[1];
+} OBJDIR_INFORMATION;
+
+typedef struct _PUBLIC_OBJECT_BASIC_INFORMATION {
+ ULONG Attributes;
+ ACCESS_MASK GrantedAccess;
+ ULONG HandleCount;
+ ULONG PointerCount;
+ ULONG Reserved[10]; // reserved for internal use
+ } PUBLIC_OBJECT_BASIC_INFORMATION, *PPUBLIC_OBJECT_BASIC_INFORMATION;
+
+typedef struct __PUBLIC_OBJECT_TYPE_INFORMATION {
+ UNICODE_STRING TypeName;
+ ULONG Reserved[22]; // reserved for internal use
+} PUBLIC_OBJECT_TYPE_INFORMATION, *PPUBLIC_OBJECT_TYPE_INFORMATION;
+
+typedef enum _POOL_TYPE {
+ NonPagedPool,
+ PagedPool,
+ NonPagedPoolMustSucceed,
+ ReservedType,
+ NonPagedPoolCacheAligned,
+ PagedPoolCacheAligned,
+ NonPagedPoolCacheAlignedMustS
+} POOL_TYPE;
+
typedef struct _OBJECT_BASIC_INFORMATION {
ULONG Attributes;
ACCESS_MASK GrantedAccess;
@@ -455,6 +485,50 @@ typedef struct _OBJECT_BASIC_INFORMATION {
LARGE_INTEGER CreateTime;
} OBJECT_BASIC_INFORMATION, *POBJECT_BASIC_INFORMATION;
+typedef struct _OBJECT_TYPE_INFORMATION {
+ UNICODE_STRING Name;
+ ULONG TotalNumberOfObjects;
+ ULONG TotalNumberOfHandles;
+ ULONG TotalPagedPoolUsage;
+ ULONG TotalNonPagedPoolUsage;
+ ULONG TotalNamePoolUsage;
+ ULONG TotalHandleTableUsage;
+ ULONG HighWaterNumberOfObjects;
+ ULONG HighWaterNumberOfHandles;
+ ULONG HighWaterPagedPoolUsage;
+ ULONG HighWaterNonPagedPoolUsage;
+ ULONG HighWaterNamePoolUsage;
+ ULONG HighWaterHandleTableUsage;
+ ULONG InvalidAttributes;
+ GENERIC_MAPPING GenericMapping;
+ ULONG ValidAccess;
+ BOOLEAN SecurityRequired;
+ BOOLEAN MaintainHandleCount;
+ USHORT MaintainTypeList;
+ POOL_TYPE PoolType;
+ ULONG PagedPoolUsage;
+ ULONG NonPagedPoolUsage;
+} OBJECT_TYPE_INFORMATION, *POBJECT_TYPE_INFORMATION;
+
+typedef enum _SYSTEM_INFORMATION_CLASS {
+ SystemHandleInformation = 16
+} SYSTEM_INFORMATION_CLASS;
+
+typedef struct _SYSTEM_HANDLE_INFORMATION {
+ USHORT ProcessId;
+ USHORT CreatorBackTraceIndex;
+ UCHAR ObjectTypeNumber;
+ UCHAR Flags;
+ USHORT Handle;
+ PVOID Object;
+ ACCESS_MASK GrantedAccess;
+} SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;
+
+typedef struct _SYSTEM_HANDLE_INFORMATION_EX {
+ ULONG NumberOfHandles;
+ SYSTEM_HANDLE_INFORMATION Information[1];
+} SYSTEM_HANDLE_INFORMATION_EX, *PSYSTEM_HANDLE_INFORMATION_EX;
+
typedef struct _OBJECT_NAME_INFORMATION {
UNICODE_STRING ObjectName;
} OBJECT_NAME_INFORMATION, *POBJECT_NAME_INFORMATION;
@@ -481,6 +555,19 @@ typedef NTSTATUS (WINAPI *NtSignalAndWaitForSingleObjectFunction)(
IN BOOLEAN Alertable,
IN PLARGE_INTEGER Timeout OPTIONAL);
+typedef NTSTATUS (WINAPI *NtQuerySystemInformation)(
+ IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
+ OUT PVOID SystemInformation,
+ IN ULONG SystemInformationLength,
+ OUT PULONG ReturnLength);
+
+typedef NTSTATUS (WINAPI *NtQueryObject)(
+ IN HANDLE Handle,
+ IN OBJECT_INFORMATION_CLASS ObjectInformationClass,
+ OUT PVOID ObjectInformation,
+ IN ULONG ObjectInformationLength,
+ OUT PULONG ReturnLength);
+
// -----------------------------------------------------------------------
// Strings