1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/sandbox/win/src/handle_table.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,183 @@ 1.4 +// Copyright (c) 2011 The Chromium Authors. All rights reserved. 1.5 +// Use of this source code is governed by a BSD-style license that can be 1.6 +// found in the LICENSE file. 1.7 + 1.8 +#include "sandbox/win/src/handle_table.h" 1.9 + 1.10 +#include <algorithm> 1.11 +#include <cstdlib> 1.12 + 1.13 +#include "base/logging.h" 1.14 +#include "base/memory/scoped_ptr.h" 1.15 +#include "sandbox/win/src/win_utils.h" 1.16 + 1.17 +namespace { 1.18 + 1.19 +bool CompareHandleEntries(const SYSTEM_HANDLE_INFORMATION& a, 1.20 + const SYSTEM_HANDLE_INFORMATION& b) { 1.21 + return a.ProcessId < b.ProcessId; 1.22 +} 1.23 + 1.24 +} // namespace 1.25 + 1.26 +namespace sandbox { 1.27 + 1.28 +const char16* HandleTable::kTypeProcess = L"Process"; 1.29 +const char16* HandleTable::kTypeThread = L"Thread"; 1.30 +const char16* HandleTable::kTypeFile = L"File"; 1.31 +const char16* HandleTable::kTypeDirectory = L"Directory"; 1.32 +const char16* HandleTable::kTypeKey = L"Key"; 1.33 +const char16* HandleTable::kTypeWindowStation = L"WindowStation"; 1.34 +const char16* HandleTable::kTypeDesktop = L"Desktop"; 1.35 +const char16* HandleTable::kTypeService = L"Service"; 1.36 +const char16* HandleTable::kTypeMutex = L"Mutex"; 1.37 +const char16* HandleTable::kTypeSemaphore = L"Semaphore"; 1.38 +const char16* HandleTable::kTypeEvent = L"Event"; 1.39 +const char16* HandleTable::kTypeTimer = L"Timer"; 1.40 +const char16* HandleTable::kTypeNamedPipe = L"NamedPipe"; 1.41 +const char16* HandleTable::kTypeJobObject = L"JobObject"; 1.42 +const char16* HandleTable::kTypeFileMap = L"FileMap"; 1.43 +const char16* HandleTable::kTypeAlpcPort = L"ALPC Port"; 1.44 + 1.45 +HandleTable::HandleTable() { 1.46 + static NtQuerySystemInformation QuerySystemInformation = NULL; 1.47 + if (!QuerySystemInformation) 1.48 + ResolveNTFunctionPtr("NtQuerySystemInformation", &QuerySystemInformation); 1.49 + 1.50 + ULONG size = 0x15000; 1.51 + NTSTATUS result; 1.52 + do { 1.53 + handle_info_buffer_.resize(size); 1.54 + result = QuerySystemInformation(SystemHandleInformation, 1.55 + handle_info_internal(), size, &size); 1.56 + } while (result == STATUS_INFO_LENGTH_MISMATCH); 1.57 + 1.58 + // We failed, so make an empty table. 1.59 + if (!NT_SUCCESS(result)) { 1.60 + handle_info_buffer_.resize(0); 1.61 + return; 1.62 + } 1.63 + 1.64 + // Sort it to make process lookups faster. 1.65 + std::sort(handle_info_internal()->Information, 1.66 + handle_info_internal()->Information + 1.67 + handle_info_internal()->NumberOfHandles, CompareHandleEntries); 1.68 +} 1.69 + 1.70 +HandleTable::Iterator HandleTable::HandlesForProcess(ULONG process_id) const { 1.71 + SYSTEM_HANDLE_INFORMATION key; 1.72 + key.ProcessId = process_id; 1.73 + 1.74 + const SYSTEM_HANDLE_INFORMATION* start = handle_info()->Information; 1.75 + const SYSTEM_HANDLE_INFORMATION* finish = 1.76 + &handle_info()->Information[handle_info()->NumberOfHandles]; 1.77 + 1.78 + start = std::lower_bound(start, finish, key, CompareHandleEntries); 1.79 + if (start->ProcessId != process_id) 1.80 + return Iterator(*this, finish, finish); 1.81 + finish = std::upper_bound(start, finish, key, CompareHandleEntries); 1.82 + return Iterator(*this, start, finish); 1.83 +} 1.84 + 1.85 +HandleTable::HandleEntry::HandleEntry( 1.86 + const SYSTEM_HANDLE_INFORMATION* handle_info_entry) 1.87 + : handle_entry_(handle_info_entry), last_entry_(0) { 1.88 +} 1.89 + 1.90 +void HandleTable::HandleEntry::UpdateInfo(UpdateType flag) { 1.91 + static NtQueryObject QueryObject = NULL; 1.92 + if (!QueryObject) 1.93 + ResolveNTFunctionPtr("NtQueryObject", &QueryObject); 1.94 + 1.95 + NTSTATUS result; 1.96 + 1.97 + // Always update the basic type info, but grab the names as needed. 1.98 + if (needs_info_update()) { 1.99 + handle_name_.clear(); 1.100 + type_name_.clear(); 1.101 + last_entry_ = handle_entry_; 1.102 + 1.103 + // Most handle names are very short, so start small and reuse this buffer. 1.104 + if (type_info_buffer_.empty()) 1.105 + type_info_buffer_.resize(sizeof(OBJECT_TYPE_INFORMATION) 1.106 + + (32 * sizeof(wchar_t))); 1.107 + ULONG size = static_cast<ULONG>(type_info_buffer_.size()); 1.108 + result = QueryObject(reinterpret_cast<HANDLE>(handle_entry_->Handle), 1.109 + ObjectTypeInformation, type_info_internal(), size, &size); 1.110 + while (result == STATUS_INFO_LENGTH_MISMATCH) { 1.111 + type_info_buffer_.resize(size); 1.112 + result = QueryObject(reinterpret_cast<HANDLE>(handle_entry_->Handle), 1.113 + ObjectTypeInformation, type_info_internal(), size, &size); 1.114 + } 1.115 + 1.116 + if (!NT_SUCCESS(result)) { 1.117 + type_info_buffer_.clear(); 1.118 + return; 1.119 + } 1.120 + } 1.121 + 1.122 + // Don't bother copying out names until we ask for them, and then cache them. 1.123 + switch (flag) { 1.124 + case UPDATE_INFO_AND_NAME: 1.125 + if (type_info_buffer_.size() && handle_name_.empty()) { 1.126 + ULONG size = MAX_PATH; 1.127 + scoped_ptr<UNICODE_STRING, base::FreeDeleter> name; 1.128 + do { 1.129 + name.reset(static_cast<UNICODE_STRING*>(malloc(size))); 1.130 + DCHECK(name.get()); 1.131 + result = QueryObject(reinterpret_cast<HANDLE>( 1.132 + handle_entry_->Handle), ObjectNameInformation, name.get(), 1.133 + size, &size); 1.134 + } while (result == STATUS_INFO_LENGTH_MISMATCH); 1.135 + 1.136 + if (NT_SUCCESS(result)) { 1.137 + handle_name_.assign(name->Buffer, name->Length / sizeof(wchar_t)); 1.138 + } 1.139 + } 1.140 + break; 1.141 + 1.142 + case UPDATE_INFO_AND_TYPE_NAME: 1.143 + if (!type_info_buffer_.empty() && type_info_internal()->Name.Buffer && 1.144 + type_name_.empty()) { 1.145 + type_name_.assign(type_info_internal()->Name.Buffer, 1.146 + type_info_internal()->Name.Length / sizeof(wchar_t)); 1.147 + } 1.148 + break; 1.149 + } 1.150 +} 1.151 + 1.152 +const OBJECT_TYPE_INFORMATION* HandleTable::HandleEntry::TypeInfo() { 1.153 + UpdateInfo(UPDATE_INFO_ONLY); 1.154 + return type_info_buffer_.empty() ? NULL : type_info_internal(); 1.155 +} 1.156 + 1.157 +const string16& HandleTable::HandleEntry::Name() { 1.158 + UpdateInfo(UPDATE_INFO_AND_NAME); 1.159 + return handle_name_; 1.160 +} 1.161 + 1.162 +const string16& HandleTable::HandleEntry::Type() { 1.163 + UpdateInfo(UPDATE_INFO_AND_TYPE_NAME); 1.164 + return type_name_; 1.165 +} 1.166 + 1.167 +bool HandleTable::HandleEntry::IsType(const string16& type_string) { 1.168 + UpdateInfo(UPDATE_INFO_ONLY); 1.169 + if (type_info_buffer_.empty()) 1.170 + return false; 1.171 + return type_string.compare(0, 1.172 + type_info_internal()->Name.Length / sizeof(wchar_t), 1.173 + type_info_internal()->Name.Buffer) == 0; 1.174 +} 1.175 + 1.176 +HandleTable::Iterator::Iterator(const HandleTable& table, 1.177 + const SYSTEM_HANDLE_INFORMATION* start, 1.178 + const SYSTEM_HANDLE_INFORMATION* end) 1.179 + : table_(table), current_(start), end_(end) { 1.180 +} 1.181 + 1.182 +HandleTable::Iterator::Iterator(const Iterator& it) 1.183 + : table_(it.table_), current_(it.current_.handle_entry_), end_(it.end_) { 1.184 +} 1.185 + 1.186 +} // namespace sandbox