1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/sandbox/win/src/handle_closer_agent.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,145 @@ 1.4 +// Copyright (c) 2012 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_closer_agent.h" 1.9 + 1.10 +#include "base/logging.h" 1.11 +#include "sandbox/win/src/nt_internals.h" 1.12 +#include "sandbox/win/src/win_utils.h" 1.13 + 1.14 +namespace { 1.15 + 1.16 +// Returns type infomation for an NT object. This routine is expected to be 1.17 +// called for invalid handles so it catches STATUS_INVALID_HANDLE exceptions 1.18 +// that can be generated when handle tracing is enabled. 1.19 +NTSTATUS QueryObjectTypeInformation(HANDLE handle, 1.20 + void* buffer, 1.21 + ULONG* size) { 1.22 + static NtQueryObject QueryObject = NULL; 1.23 + if (!QueryObject) 1.24 + ResolveNTFunctionPtr("NtQueryObject", &QueryObject); 1.25 + 1.26 + NTSTATUS status = STATUS_UNSUCCESSFUL; 1.27 + __try { 1.28 + status = QueryObject(handle, ObjectTypeInformation, buffer, *size, size); 1.29 + } __except(GetExceptionCode() == STATUS_INVALID_HANDLE ? 1.30 + EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { 1.31 + status = STATUS_INVALID_HANDLE; 1.32 + } 1.33 + return status; 1.34 +} 1.35 + 1.36 +} // namespace 1.37 + 1.38 +namespace sandbox { 1.39 + 1.40 +// Memory buffer mapped from the parent, with the list of handles. 1.41 +SANDBOX_INTERCEPT HandleCloserInfo* g_handles_to_close = NULL; 1.42 + 1.43 +bool HandleCloserAgent::NeedsHandlesClosed() { 1.44 + return g_handles_to_close != NULL; 1.45 +} 1.46 + 1.47 +// Reads g_handles_to_close and creates the lookup map. 1.48 +void HandleCloserAgent::InitializeHandlesToClose() { 1.49 + CHECK(g_handles_to_close != NULL); 1.50 + 1.51 + // Grab the header. 1.52 + HandleListEntry* entry = g_handles_to_close->handle_entries; 1.53 + for (size_t i = 0; i < g_handles_to_close->num_handle_types; ++i) { 1.54 + // Set the type name. 1.55 + char16* input = entry->handle_type; 1.56 + HandleMap::mapped_type& handle_names = handles_to_close_[input]; 1.57 + input = reinterpret_cast<char16*>(reinterpret_cast<char*>(entry) 1.58 + + entry->offset_to_names); 1.59 + // Grab all the handle names. 1.60 + for (size_t j = 0; j < entry->name_count; ++j) { 1.61 + std::pair<HandleMap::mapped_type::iterator, bool> name 1.62 + = handle_names.insert(input); 1.63 + CHECK(name.second); 1.64 + input += name.first->size() + 1; 1.65 + } 1.66 + 1.67 + // Move on to the next entry. 1.68 + entry = reinterpret_cast<HandleListEntry*>(reinterpret_cast<char*>(entry) 1.69 + + entry->record_bytes); 1.70 + 1.71 + DCHECK(reinterpret_cast<char16*>(entry) >= input); 1.72 + DCHECK(reinterpret_cast<char16*>(entry) - input < 1.73 + sizeof(size_t) / sizeof(char16)); 1.74 + } 1.75 + 1.76 + // Clean up the memory we copied over. 1.77 + ::VirtualFree(g_handles_to_close, 0, MEM_RELEASE); 1.78 + g_handles_to_close = NULL; 1.79 +} 1.80 + 1.81 +bool HandleCloserAgent::CloseHandles() { 1.82 + DWORD handle_count = UINT_MAX; 1.83 + const int kInvalidHandleThreshold = 100; 1.84 + const size_t kHandleOffset = sizeof(HANDLE); 1.85 + 1.86 + if (!::GetProcessHandleCount(::GetCurrentProcess(), &handle_count)) 1.87 + return false; 1.88 + 1.89 + // Set up buffers for the type info and the name. 1.90 + std::vector<BYTE> type_info_buffer(sizeof(OBJECT_TYPE_INFORMATION) + 1.91 + 32 * sizeof(wchar_t)); 1.92 + OBJECT_TYPE_INFORMATION* type_info = 1.93 + reinterpret_cast<OBJECT_TYPE_INFORMATION*>(&(type_info_buffer[0])); 1.94 + string16 handle_name; 1.95 + HANDLE handle = NULL; 1.96 + int invalid_count = 0; 1.97 + 1.98 + // Keep incrementing until we hit the number of handles reported by 1.99 + // GetProcessHandleCount(). If we hit a very long sequence of invalid 1.100 + // handles we assume that we've run past the end of the table. 1.101 + while (handle_count && invalid_count < kInvalidHandleThreshold) { 1.102 + reinterpret_cast<size_t&>(handle) += kHandleOffset; 1.103 + NTSTATUS rc; 1.104 + 1.105 + // Get the type name, reusing the buffer. 1.106 + ULONG size = static_cast<ULONG>(type_info_buffer.size()); 1.107 + rc = QueryObjectTypeInformation(handle, type_info, &size); 1.108 + while (rc == STATUS_INFO_LENGTH_MISMATCH || 1.109 + rc == STATUS_BUFFER_OVERFLOW) { 1.110 + type_info_buffer.resize(size + sizeof(wchar_t)); 1.111 + type_info = reinterpret_cast<OBJECT_TYPE_INFORMATION*>( 1.112 + &(type_info_buffer[0])); 1.113 + rc = QueryObjectTypeInformation(handle, type_info, &size); 1.114 + // Leave padding for the nul terminator. 1.115 + if (NT_SUCCESS(rc) && size == type_info_buffer.size()) 1.116 + rc = STATUS_INFO_LENGTH_MISMATCH; 1.117 + } 1.118 + if (!NT_SUCCESS(rc) || !type_info->Name.Buffer) { 1.119 + ++invalid_count; 1.120 + continue; 1.121 + } 1.122 + 1.123 + --handle_count; 1.124 + type_info->Name.Buffer[type_info->Name.Length / sizeof(wchar_t)] = L'\0'; 1.125 + 1.126 + // Check if we're looking for this type of handle. 1.127 + HandleMap::iterator result = 1.128 + handles_to_close_.find(type_info->Name.Buffer); 1.129 + if (result != handles_to_close_.end()) { 1.130 + HandleMap::mapped_type& names = result->second; 1.131 + // Empty set means close all handles of this type; otherwise check name. 1.132 + if (!names.empty()) { 1.133 + // Move on to the next handle if this name doesn't match. 1.134 + if (!GetHandleName(handle, &handle_name) || !names.count(handle_name)) 1.135 + continue; 1.136 + } 1.137 + 1.138 + if (!::SetHandleInformation(handle, HANDLE_FLAG_PROTECT_FROM_CLOSE, 0)) 1.139 + return false; 1.140 + if (!::CloseHandle(handle)) 1.141 + return false; 1.142 + } 1.143 + } 1.144 + 1.145 + return true; 1.146 +} 1.147 + 1.148 +} // namespace sandbox