1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/sandbox/win/src/handle_closer.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,202 @@ 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_closer.h" 1.9 + 1.10 +#include "base/logging.h" 1.11 +#include "base/memory/scoped_ptr.h" 1.12 +#include "base/win/windows_version.h" 1.13 +#include "sandbox/win/src/interceptors.h" 1.14 +#include "sandbox/win/src/internal_types.h" 1.15 +#include "sandbox/win/src/nt_internals.h" 1.16 +#include "sandbox/win/src/process_thread_interception.h" 1.17 +#include "sandbox/win/src/win_utils.h" 1.18 + 1.19 +namespace { 1.20 + 1.21 +template<typename T> T RoundUpToWordSize(T v) { 1.22 + if (size_t mod = v % sizeof(size_t)) 1.23 + v += sizeof(size_t) - mod; 1.24 + return v; 1.25 +} 1.26 + 1.27 +template<typename T> T* RoundUpToWordSize(T* v) { 1.28 + return reinterpret_cast<T*>(RoundUpToWordSize(reinterpret_cast<size_t>(v))); 1.29 +} 1.30 + 1.31 +} // namespace 1.32 + 1.33 +namespace sandbox { 1.34 + 1.35 +// Memory buffer mapped from the parent, with the list of handles. 1.36 +SANDBOX_INTERCEPT HandleCloserInfo* g_handles_to_close; 1.37 + 1.38 +HandleCloser::HandleCloser() {} 1.39 + 1.40 +ResultCode HandleCloser::AddHandle(const char16* handle_type, 1.41 + const char16* handle_name) { 1.42 + if (!handle_type) 1.43 + return SBOX_ERROR_BAD_PARAMS; 1.44 + 1.45 + HandleMap::iterator names = handles_to_close_.find(handle_type); 1.46 + if (names == handles_to_close_.end()) { // We have no entries for this type. 1.47 + std::pair<HandleMap::iterator, bool> result = handles_to_close_.insert( 1.48 + HandleMap::value_type(handle_type, HandleMap::mapped_type())); 1.49 + names = result.first; 1.50 + if (handle_name) 1.51 + names->second.insert(handle_name); 1.52 + } else if (!handle_name) { // Now we need to close all handles of this type. 1.53 + names->second.clear(); 1.54 + } else if (!names->second.empty()) { // Add another name for this type. 1.55 + names->second.insert(handle_name); 1.56 + } // If we're already closing all handles of type then we're done. 1.57 + 1.58 + return SBOX_ALL_OK; 1.59 +} 1.60 + 1.61 +size_t HandleCloser::GetBufferSize() { 1.62 + size_t bytes_total = offsetof(HandleCloserInfo, handle_entries); 1.63 + 1.64 + for (HandleMap::iterator i = handles_to_close_.begin(); 1.65 + i != handles_to_close_.end(); ++i) { 1.66 + size_t bytes_entry = offsetof(HandleListEntry, handle_type) + 1.67 + (i->first.size() + 1) * sizeof(char16); 1.68 + for (HandleMap::mapped_type::iterator j = i->second.begin(); 1.69 + j != i->second.end(); ++j) { 1.70 + bytes_entry += ((*j).size() + 1) * sizeof(char16); 1.71 + } 1.72 + 1.73 + // Round up to the nearest multiple of word size. 1.74 + bytes_entry = RoundUpToWordSize(bytes_entry); 1.75 + bytes_total += bytes_entry; 1.76 + } 1.77 + 1.78 + return bytes_total; 1.79 +} 1.80 + 1.81 +bool HandleCloser::InitializeTargetHandles(TargetProcess* target) { 1.82 + // Do nothing on an empty list (global pointer already initialized to NULL). 1.83 + if (handles_to_close_.empty()) 1.84 + return true; 1.85 + 1.86 + size_t bytes_needed = GetBufferSize(); 1.87 + scoped_ptr<size_t[]> local_buffer( 1.88 + new size_t[bytes_needed / sizeof(size_t)]); 1.89 + 1.90 + if (!SetupHandleList(local_buffer.get(), bytes_needed)) 1.91 + return false; 1.92 + 1.93 + HANDLE child = target->Process(); 1.94 + 1.95 + // Allocate memory in the target process without specifying the address 1.96 + void* remote_data = ::VirtualAllocEx(child, NULL, bytes_needed, 1.97 + MEM_COMMIT, PAGE_READWRITE); 1.98 + if (NULL == remote_data) 1.99 + return false; 1.100 + 1.101 + // Copy the handle buffer over. 1.102 + SIZE_T bytes_written; 1.103 + BOOL result = ::WriteProcessMemory(child, remote_data, local_buffer.get(), 1.104 + bytes_needed, &bytes_written); 1.105 + if (!result || bytes_written != bytes_needed) { 1.106 + ::VirtualFreeEx(child, remote_data, 0, MEM_RELEASE); 1.107 + return false; 1.108 + } 1.109 + 1.110 + g_handles_to_close = reinterpret_cast<HandleCloserInfo*>(remote_data); 1.111 + 1.112 + ResultCode rc = target->TransferVariable("g_handles_to_close", 1.113 + &g_handles_to_close, 1.114 + sizeof(g_handles_to_close)); 1.115 + 1.116 + return (SBOX_ALL_OK == rc); 1.117 +} 1.118 + 1.119 +bool HandleCloser::SetupHandleList(void* buffer, size_t buffer_bytes) { 1.120 + ::ZeroMemory(buffer, buffer_bytes); 1.121 + HandleCloserInfo* handle_info = reinterpret_cast<HandleCloserInfo*>(buffer); 1.122 + handle_info->record_bytes = buffer_bytes; 1.123 + handle_info->num_handle_types = handles_to_close_.size(); 1.124 + 1.125 + char16* output = reinterpret_cast<char16*>(&handle_info->handle_entries[0]); 1.126 + char16* end = reinterpret_cast<char16*>( 1.127 + reinterpret_cast<char*>(buffer) + buffer_bytes); 1.128 + for (HandleMap::iterator i = handles_to_close_.begin(); 1.129 + i != handles_to_close_.end(); ++i) { 1.130 + if (output >= end) 1.131 + return false; 1.132 + HandleListEntry* list_entry = reinterpret_cast<HandleListEntry*>(output); 1.133 + output = &list_entry->handle_type[0]; 1.134 + 1.135 + // Copy the typename and set the offset and count. 1.136 + i->first._Copy_s(output, i->first.size(), i->first.size()); 1.137 + *(output += i->first.size()) = L'\0'; 1.138 + output++; 1.139 + list_entry->offset_to_names = reinterpret_cast<char*>(output) - 1.140 + reinterpret_cast<char*>(list_entry); 1.141 + list_entry->name_count = i->second.size(); 1.142 + 1.143 + // Copy the handle names. 1.144 + for (HandleMap::mapped_type::iterator j = i->second.begin(); 1.145 + j != i->second.end(); ++j) { 1.146 + output = std::copy((*j).begin(), (*j).end(), output) + 1; 1.147 + } 1.148 + 1.149 + // Round up to the nearest multiple of sizeof(size_t). 1.150 + output = RoundUpToWordSize(output); 1.151 + list_entry->record_bytes = reinterpret_cast<char*>(output) - 1.152 + reinterpret_cast<char*>(list_entry); 1.153 + } 1.154 + 1.155 + DCHECK_EQ(reinterpret_cast<size_t>(output), reinterpret_cast<size_t>(end)); 1.156 + return output <= end; 1.157 +} 1.158 + 1.159 +bool HandleCloser::SetupHandleInterceptions(InterceptionManager* manager) { 1.160 + // We need to intercept CreateThread if we're closing ALPC port clients. 1.161 + HandleMap::iterator names = handles_to_close_.find(L"ALPC Port"); 1.162 + if (base::win::GetVersion() >= base::win::VERSION_VISTA && 1.163 + names != handles_to_close_.end() && 1.164 + (names->second.empty() || names->second.size() == 0)) { 1.165 + if (!INTERCEPT_EAT(manager, kKerneldllName, CreateThread, 1.166 + CREATE_THREAD_ID, 28)) { 1.167 + return false; 1.168 + } 1.169 + if (!INTERCEPT_EAT(manager, kKerneldllName, GetUserDefaultLCID, 1.170 + GET_USER_DEFAULT_LCID_ID, 4)) { 1.171 + return false; 1.172 + } 1.173 + 1.174 + return true; 1.175 + } 1.176 + 1.177 + return true; 1.178 +} 1.179 + 1.180 +bool GetHandleName(HANDLE handle, string16* handle_name) { 1.181 + static NtQueryObject QueryObject = NULL; 1.182 + if (!QueryObject) 1.183 + ResolveNTFunctionPtr("NtQueryObject", &QueryObject); 1.184 + 1.185 + ULONG size = MAX_PATH; 1.186 + scoped_ptr<UNICODE_STRING, base::FreeDeleter> name; 1.187 + NTSTATUS result; 1.188 + 1.189 + do { 1.190 + name.reset(static_cast<UNICODE_STRING*>(malloc(size))); 1.191 + DCHECK(name.get()); 1.192 + result = QueryObject(handle, ObjectNameInformation, name.get(), 1.193 + size, &size); 1.194 + } while (result == STATUS_INFO_LENGTH_MISMATCH || 1.195 + result == STATUS_BUFFER_OVERFLOW); 1.196 + 1.197 + if (NT_SUCCESS(result) && name->Buffer && name->Length) 1.198 + handle_name->assign(name->Buffer, name->Length / sizeof(wchar_t)); 1.199 + else 1.200 + handle_name->clear(); 1.201 + 1.202 + return NT_SUCCESS(result); 1.203 +} 1.204 + 1.205 +} // namespace sandbox