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