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