1// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "sandbox/win/src/handle_closer.h" 6 7#include "base/logging.h" 8#include "base/memory/scoped_ptr.h" 9#include "base/win/windows_version.h" 10#include "sandbox/win/src/interceptors.h" 11#include "sandbox/win/src/internal_types.h" 12#include "sandbox/win/src/nt_internals.h" 13#include "sandbox/win/src/process_thread_interception.h" 14#include "sandbox/win/src/win_utils.h" 15 16namespace { 17 18template<typename T> T RoundUpToWordSize(T v) { 19 if (size_t mod = v % sizeof(size_t)) 20 v += sizeof(size_t) - mod; 21 return v; 22} 23 24template<typename T> T* RoundUpToWordSize(T* v) { 25 return reinterpret_cast<T*>(RoundUpToWordSize(reinterpret_cast<size_t>(v))); 26} 27 28} // namespace 29 30namespace sandbox { 31 32// Memory buffer mapped from the parent, with the list of handles. 33SANDBOX_INTERCEPT HandleCloserInfo* g_handles_to_close; 34 35HandleCloser::HandleCloser() {} 36 37ResultCode HandleCloser::AddHandle(const base::char16* handle_type, 38 const base::char16* handle_name) { 39 if (!handle_type) 40 return SBOX_ERROR_BAD_PARAMS; 41 42 base::string16 resolved_name; 43 if (handle_name) { 44 resolved_name = handle_name; 45 if (handle_type == base::string16(L"Key")) 46 if (!ResolveRegistryName(resolved_name, &resolved_name)) 47 return SBOX_ERROR_BAD_PARAMS; 48 } 49 50 HandleMap::iterator names = handles_to_close_.find(handle_type); 51 if (names == handles_to_close_.end()) { // We have no entries for this type. 52 std::pair<HandleMap::iterator, bool> result = handles_to_close_.insert( 53 HandleMap::value_type(handle_type, HandleMap::mapped_type())); 54 names = result.first; 55 if (handle_name) 56 names->second.insert(resolved_name); 57 } else if (!handle_name) { // Now we need to close all handles of this type. 58 names->second.clear(); 59 } else if (!names->second.empty()) { // Add another name for this type. 60 names->second.insert(resolved_name); 61 } // If we're already closing all handles of type then we're done. 62 63 return SBOX_ALL_OK; 64} 65 66size_t HandleCloser::GetBufferSize() { 67 size_t bytes_total = offsetof(HandleCloserInfo, handle_entries); 68 69 for (HandleMap::iterator i = handles_to_close_.begin(); 70 i != handles_to_close_.end(); ++i) { 71 size_t bytes_entry = offsetof(HandleListEntry, handle_type) + 72 (i->first.size() + 1) * sizeof(base::char16); 73 for (HandleMap::mapped_type::iterator j = i->second.begin(); 74 j != i->second.end(); ++j) { 75 bytes_entry += ((*j).size() + 1) * sizeof(base::char16); 76 } 77 78 // Round up to the nearest multiple of word size. 79 bytes_entry = RoundUpToWordSize(bytes_entry); 80 bytes_total += bytes_entry; 81 } 82 83 return bytes_total; 84} 85 86bool HandleCloser::InitializeTargetHandles(TargetProcess* target) { 87 // Do nothing on an empty list (global pointer already initialized to NULL). 88 if (handles_to_close_.empty()) 89 return true; 90 91 size_t bytes_needed = GetBufferSize(); 92 scoped_ptr<size_t[]> local_buffer( 93 new size_t[bytes_needed / sizeof(size_t)]); 94 95 if (!SetupHandleList(local_buffer.get(), bytes_needed)) 96 return false; 97 98 HANDLE child = target->Process(); 99 100 // Allocate memory in the target process without specifying the address 101 void* remote_data = ::VirtualAllocEx(child, NULL, bytes_needed, 102 MEM_COMMIT, PAGE_READWRITE); 103 if (NULL == remote_data) 104 return false; 105 106 // Copy the handle buffer over. 107 SIZE_T bytes_written; 108 BOOL result = ::WriteProcessMemory(child, remote_data, local_buffer.get(), 109 bytes_needed, &bytes_written); 110 if (!result || bytes_written != bytes_needed) { 111 ::VirtualFreeEx(child, remote_data, 0, MEM_RELEASE); 112 return false; 113 } 114 115 g_handles_to_close = reinterpret_cast<HandleCloserInfo*>(remote_data); 116 117 ResultCode rc = target->TransferVariable("g_handles_to_close", 118 &g_handles_to_close, 119 sizeof(g_handles_to_close)); 120 121 return (SBOX_ALL_OK == rc); 122} 123 124bool HandleCloser::SetupHandleList(void* buffer, size_t buffer_bytes) { 125 ::ZeroMemory(buffer, buffer_bytes); 126 HandleCloserInfo* handle_info = reinterpret_cast<HandleCloserInfo*>(buffer); 127 handle_info->record_bytes = buffer_bytes; 128 handle_info->num_handle_types = handles_to_close_.size(); 129 130 base::char16* output = reinterpret_cast<base::char16*>( 131 &handle_info->handle_entries[0]); 132 base::char16* end = reinterpret_cast<base::char16*>( 133 reinterpret_cast<char*>(buffer) + buffer_bytes); 134 for (HandleMap::iterator i = handles_to_close_.begin(); 135 i != handles_to_close_.end(); ++i) { 136 if (output >= end) 137 return false; 138 HandleListEntry* list_entry = reinterpret_cast<HandleListEntry*>(output); 139 output = &list_entry->handle_type[0]; 140 141 // Copy the typename and set the offset and count. 142 i->first._Copy_s(output, i->first.size(), i->first.size()); 143 *(output += i->first.size()) = L'\0'; 144 output++; 145 list_entry->offset_to_names = reinterpret_cast<char*>(output) - 146 reinterpret_cast<char*>(list_entry); 147 list_entry->name_count = i->second.size(); 148 149 // Copy the handle names. 150 for (HandleMap::mapped_type::iterator j = i->second.begin(); 151 j != i->second.end(); ++j) { 152 output = std::copy((*j).begin(), (*j).end(), output) + 1; 153 } 154 155 // Round up to the nearest multiple of sizeof(size_t). 156 output = RoundUpToWordSize(output); 157 list_entry->record_bytes = reinterpret_cast<char*>(output) - 158 reinterpret_cast<char*>(list_entry); 159 } 160 161 DCHECK_EQ(reinterpret_cast<size_t>(output), reinterpret_cast<size_t>(end)); 162 return output <= end; 163} 164 165bool GetHandleName(HANDLE handle, base::string16* handle_name) { 166 static NtQueryObject QueryObject = NULL; 167 if (!QueryObject) 168 ResolveNTFunctionPtr("NtQueryObject", &QueryObject); 169 170 ULONG size = MAX_PATH; 171 scoped_ptr<UNICODE_STRING, base::FreeDeleter> name; 172 NTSTATUS result; 173 174 do { 175 name.reset(static_cast<UNICODE_STRING*>(malloc(size))); 176 DCHECK(name.get()); 177 result = QueryObject(handle, ObjectNameInformation, name.get(), 178 size, &size); 179 } while (result == STATUS_INFO_LENGTH_MISMATCH || 180 result == STATUS_BUFFER_OVERFLOW); 181 182 if (NT_SUCCESS(result) && name->Buffer && name->Length) 183 handle_name->assign(name->Buffer, name->Length / sizeof(wchar_t)); 184 else 185 handle_name->clear(); 186 187 return NT_SUCCESS(result); 188} 189 190} // namespace sandbox 191