Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / sandbox / win / src / handle_closer.cc
blob2e3a78223bcf33ac6f286e621e0b97873fa72023
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.
5 #include "sandbox/win/src/handle_closer.h"
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"
16 namespace {
18 template<typename T> T RoundUpToWordSize(T v) {
19 if (size_t mod = v % sizeof(size_t))
20 v += sizeof(size_t) - mod;
21 return v;
24 template<typename T> T* RoundUpToWordSize(T* v) {
25 return reinterpret_cast<T*>(RoundUpToWordSize(reinterpret_cast<size_t>(v)));
28 } // namespace
30 namespace sandbox {
32 // Memory buffer mapped from the parent, with the list of handles.
33 SANDBOX_INTERCEPT HandleCloserInfo* g_handles_to_close;
35 HandleCloser::HandleCloser() {
38 HandleCloser::~HandleCloser() {
41 ResultCode HandleCloser::AddHandle(const base::char16* handle_type,
42 const base::char16* handle_name) {
43 if (!handle_type)
44 return SBOX_ERROR_BAD_PARAMS;
46 base::string16 resolved_name;
47 if (handle_name) {
48 resolved_name = handle_name;
49 if (handle_type == base::string16(L"Key"))
50 if (!ResolveRegistryName(resolved_name, &resolved_name))
51 return SBOX_ERROR_BAD_PARAMS;
54 HandleMap::iterator names = handles_to_close_.find(handle_type);
55 if (names == handles_to_close_.end()) { // We have no entries for this type.
56 std::pair<HandleMap::iterator, bool> result = handles_to_close_.insert(
57 HandleMap::value_type(handle_type, HandleMap::mapped_type()));
58 names = result.first;
59 if (handle_name)
60 names->second.insert(resolved_name);
61 } else if (!handle_name) { // Now we need to close all handles of this type.
62 names->second.clear();
63 } else if (!names->second.empty()) { // Add another name for this type.
64 names->second.insert(resolved_name);
65 } // If we're already closing all handles of type then we're done.
67 return SBOX_ALL_OK;
70 size_t HandleCloser::GetBufferSize() {
71 size_t bytes_total = offsetof(HandleCloserInfo, handle_entries);
73 for (HandleMap::iterator i = handles_to_close_.begin();
74 i != handles_to_close_.end(); ++i) {
75 size_t bytes_entry = offsetof(HandleListEntry, handle_type) +
76 (i->first.size() + 1) * sizeof(base::char16);
77 for (HandleMap::mapped_type::iterator j = i->second.begin();
78 j != i->second.end(); ++j) {
79 bytes_entry += ((*j).size() + 1) * sizeof(base::char16);
82 // Round up to the nearest multiple of word size.
83 bytes_entry = RoundUpToWordSize(bytes_entry);
84 bytes_total += bytes_entry;
87 return bytes_total;
90 bool HandleCloser::InitializeTargetHandles(TargetProcess* target) {
91 // Do nothing on an empty list (global pointer already initialized to NULL).
92 if (handles_to_close_.empty())
93 return true;
95 size_t bytes_needed = GetBufferSize();
96 scoped_ptr<size_t[]> local_buffer(
97 new size_t[bytes_needed / sizeof(size_t)]);
99 if (!SetupHandleList(local_buffer.get(), bytes_needed))
100 return false;
102 HANDLE child = target->Process();
104 // Allocate memory in the target process without specifying the address
105 void* remote_data = ::VirtualAllocEx(child, NULL, bytes_needed,
106 MEM_COMMIT, PAGE_READWRITE);
107 if (NULL == remote_data)
108 return false;
110 // Copy the handle buffer over.
111 SIZE_T bytes_written;
112 BOOL result = ::WriteProcessMemory(child, remote_data, local_buffer.get(),
113 bytes_needed, &bytes_written);
114 if (!result || bytes_written != bytes_needed) {
115 ::VirtualFreeEx(child, remote_data, 0, MEM_RELEASE);
116 return false;
119 g_handles_to_close = reinterpret_cast<HandleCloserInfo*>(remote_data);
121 ResultCode rc = target->TransferVariable("g_handles_to_close",
122 &g_handles_to_close,
123 sizeof(g_handles_to_close));
125 return (SBOX_ALL_OK == rc);
128 bool HandleCloser::SetupHandleList(void* buffer, size_t buffer_bytes) {
129 ::ZeroMemory(buffer, buffer_bytes);
130 HandleCloserInfo* handle_info = reinterpret_cast<HandleCloserInfo*>(buffer);
131 handle_info->record_bytes = buffer_bytes;
132 handle_info->num_handle_types = handles_to_close_.size();
134 base::char16* output = reinterpret_cast<base::char16*>(
135 &handle_info->handle_entries[0]);
136 base::char16* end = reinterpret_cast<base::char16*>(
137 reinterpret_cast<char*>(buffer) + buffer_bytes);
138 for (HandleMap::iterator i = handles_to_close_.begin();
139 i != handles_to_close_.end(); ++i) {
140 if (output >= end)
141 return false;
142 HandleListEntry* list_entry = reinterpret_cast<HandleListEntry*>(output);
143 output = &list_entry->handle_type[0];
145 // Copy the typename and set the offset and count.
146 i->first._Copy_s(output, i->first.size(), i->first.size());
147 *(output += i->first.size()) = L'\0';
148 output++;
149 list_entry->offset_to_names = reinterpret_cast<char*>(output) -
150 reinterpret_cast<char*>(list_entry);
151 list_entry->name_count = i->second.size();
153 // Copy the handle names.
154 for (HandleMap::mapped_type::iterator j = i->second.begin();
155 j != i->second.end(); ++j) {
156 output = std::copy((*j).begin(), (*j).end(), output) + 1;
159 // Round up to the nearest multiple of sizeof(size_t).
160 output = RoundUpToWordSize(output);
161 list_entry->record_bytes = reinterpret_cast<char*>(output) -
162 reinterpret_cast<char*>(list_entry);
165 DCHECK_EQ(reinterpret_cast<size_t>(output), reinterpret_cast<size_t>(end));
166 return output <= end;
169 bool GetHandleName(HANDLE handle, base::string16* handle_name) {
170 static NtQueryObject QueryObject = NULL;
171 if (!QueryObject)
172 ResolveNTFunctionPtr("NtQueryObject", &QueryObject);
174 ULONG size = MAX_PATH;
175 scoped_ptr<UNICODE_STRING, base::FreeDeleter> name;
176 NTSTATUS result;
178 do {
179 name.reset(static_cast<UNICODE_STRING*>(malloc(size)));
180 DCHECK(name.get());
181 result = QueryObject(handle, ObjectNameInformation, name.get(),
182 size, &size);
183 } while (result == STATUS_INFO_LENGTH_MISMATCH ||
184 result == STATUS_BUFFER_OVERFLOW);
186 if (NT_SUCCESS(result) && name->Buffer && name->Length)
187 handle_name->assign(name->Buffer, name->Length / sizeof(wchar_t));
188 else
189 handle_name->clear();
191 return NT_SUCCESS(result);
194 } // namespace sandbox