security/sandbox/win/src/handle_closer.cc

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

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

mercurial