Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(156)

Side by Side Diff: sandbox/src/target_process.cc

Issue 9959018: Use ScopedProcessInformation and other RAII types in sandbox. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Update copyright years. Created 8 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « sandbox/src/target_process.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "sandbox/src/target_process.h" 5 #include "sandbox/src/target_process.h"
6 6
7 #include "base/basictypes.h" 7 #include "base/basictypes.h"
8 #include "base/memory/scoped_ptr.h" 8 #include "base/memory/scoped_ptr.h"
9 #include "base/win/pe_image.h" 9 #include "base/win/pe_image.h"
10 #include "sandbox/src/crosscall_server.h" 10 #include "sandbox/src/crosscall_server.h"
11 #include "sandbox/src/crosscall_client.h" 11 #include "sandbox/src/crosscall_client.h"
12 #include "sandbox/src/policy_low_level.h" 12 #include "sandbox/src/policy_low_level.h"
13 #include "sandbox/src/sandbox_types.h" 13 #include "sandbox/src/sandbox_types.h"
14 #include "sandbox/src/sharedmem_ipc_server.h" 14 #include "sandbox/src/sharedmem_ipc_server.h"
15 15
16 namespace { 16 namespace {
17 17
18 void TerminateTarget(PROCESS_INFORMATION* pi) {
19 ::CloseHandle(pi->hThread);
20 ::TerminateProcess(pi->hProcess, 0);
21 ::CloseHandle(pi->hProcess);
22 }
23
24 void CopyPolicyToTarget(const void* source, size_t size, void* dest) { 18 void CopyPolicyToTarget(const void* source, size_t size, void* dest) {
25 if (!source || !size) 19 if (!source || !size)
26 return; 20 return;
27 memcpy(dest, source, size); 21 memcpy(dest, source, size);
28 sandbox::PolicyGlobal* policy = 22 sandbox::PolicyGlobal* policy =
29 reinterpret_cast<sandbox::PolicyGlobal*>(dest); 23 reinterpret_cast<sandbox::PolicyGlobal*>(dest);
30 24
31 size_t offset = reinterpret_cast<size_t>(source); 25 size_t offset = reinterpret_cast<size_t>(source);
32 26
33 for (size_t i = 0; i < sandbox::kMaxServiceCount; i++) { 27 for (size_t i = 0; i < sandbox::kMaxServiceCount; i++) {
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
90 84
91 85
92 TargetProcess::TargetProcess(HANDLE initial_token, HANDLE lockdown_token, 86 TargetProcess::TargetProcess(HANDLE initial_token, HANDLE lockdown_token,
93 HANDLE job, ThreadProvider* thread_pool) 87 HANDLE job, ThreadProvider* thread_pool)
94 // This object owns everything initialized here except thread_pool and 88 // This object owns everything initialized here except thread_pool and
95 // the job_ handle. The Job handle is closed by BrokerServices and results 89 // the job_ handle. The Job handle is closed by BrokerServices and results
96 // eventually in a call to our dtor. 90 // eventually in a call to our dtor.
97 : lockdown_token_(lockdown_token), 91 : lockdown_token_(lockdown_token),
98 initial_token_(initial_token), 92 initial_token_(initial_token),
99 job_(job), 93 job_(job),
100 shared_section_(NULL),
101 ipc_server_(NULL),
102 thread_pool_(thread_pool), 94 thread_pool_(thread_pool),
103 base_address_(NULL), 95 base_address_(NULL) {
104 exe_name_(NULL),
105 sandbox_process_(NULL),
106 sandbox_thread_(NULL),
107 sandbox_process_id_(0) {
108 } 96 }
109 97
110 TargetProcess::~TargetProcess() { 98 TargetProcess::~TargetProcess() {
111 DWORD exit_code = 0; 99 DWORD exit_code = 0;
112 // Give a chance to the process to die. In most cases the JOB_KILL_ON_CLOSE 100 // Give a chance to the process to die. In most cases the JOB_KILL_ON_CLOSE
113 // will take effect only when the context changes. As far as the testing went, 101 // will take effect only when the context changes. As far as the testing went,
114 // this wait was enough to switch context and kill the processes in the job. 102 // this wait was enough to switch context and kill the processes in the job.
115 // If this process is already dead, the function will return without waiting. 103 // If this process is already dead, the function will return without waiting.
116 // TODO(nsylvain): If the process is still alive at the end, we should kill 104 // TODO(nsylvain): If the process is still alive at the end, we should kill
117 // it. http://b/893891 105 // it. http://b/893891
118 // For now, this wait is there only to do a best effort to prevent some leaks 106 // For now, this wait is there only to do a best effort to prevent some leaks
119 // from showing up in purify. 107 // from showing up in purify.
120 ::WaitForSingleObject(sandbox_process_, 50); 108 ::WaitForSingleObject(sandbox_process_info_.process_handle(), 50);
121 if (!::GetExitCodeProcess(sandbox_process_, &exit_code) || 109 if (!::GetExitCodeProcess(sandbox_process_info_.process_handle(),
122 (STILL_ACTIVE == exit_code)) { 110 &exit_code) || (STILL_ACTIVE == exit_code)) {
123 // It is an error to destroy this object while the target process is still 111 // It is an error to destroy this object while the target process is still
124 // alive because we need to destroy the IPC subsystem and cannot risk to 112 // alive because we need to destroy the IPC subsystem and cannot risk to
125 // have an IPC reach us after this point. 113 // have an IPC reach us after this point.
126 return; 114 return;
127 } 115 }
128 116
129 delete ipc_server_; 117 // ipc_server_ references our process handle, so make sure the former is shut
130 118 // down before the latter is closed (by ScopedProcessInformation).
131 ::CloseHandle(lockdown_token_); 119 ipc_server_.reset();
132 ::CloseHandle(initial_token_);
133 ::CloseHandle(sandbox_process_);
134 if (shared_section_)
135 ::CloseHandle(shared_section_);
136 free(exe_name_);
137 } 120 }
138 121
139 // Creates the target (child) process suspended and assigns it to the job 122 // Creates the target (child) process suspended and assigns it to the job
140 // object. 123 // object.
141 DWORD TargetProcess::Create(const wchar_t* exe_path, 124 DWORD TargetProcess::Create(const wchar_t* exe_path,
142 const wchar_t* command_line, 125 const wchar_t* command_line,
143 const wchar_t* desktop, 126 const wchar_t* desktop,
144 PROCESS_INFORMATION* target_info) { 127 base::win::ScopedProcessInformation* target_info) {
145 exe_name_ = _wcsdup(exe_path); 128 exe_name_.reset(_wcsdup(exe_path));
146 129
147 // the command line needs to be writable by CreateProcess(). 130 // the command line needs to be writable by CreateProcess().
148 scoped_ptr_malloc<wchar_t> cmd_line(_wcsdup(command_line)); 131 scoped_ptr_malloc<wchar_t> cmd_line(_wcsdup(command_line));
149 scoped_ptr_malloc<wchar_t> desktop_name(desktop ? _wcsdup(desktop) : NULL); 132 scoped_ptr_malloc<wchar_t> desktop_name(desktop ? _wcsdup(desktop) : NULL);
150 133
151 // Start the target process suspended. 134 // Start the target process suspended.
152 const DWORD flags = CREATE_SUSPENDED | CREATE_BREAKAWAY_FROM_JOB | 135 const DWORD flags = CREATE_SUSPENDED | CREATE_BREAKAWAY_FROM_JOB |
153 CREATE_UNICODE_ENVIRONMENT | DETACHED_PROCESS; 136 CREATE_UNICODE_ENVIRONMENT | DETACHED_PROCESS;
154 137
155 STARTUPINFO startup_info = {sizeof(STARTUPINFO)}; 138 STARTUPINFO startup_info = {sizeof(STARTUPINFO)};
156 if (desktop) { 139 if (desktop) {
157 startup_info.lpDesktop = desktop_name.get(); 140 startup_info.lpDesktop = desktop_name.get();
158 } 141 }
159 142
160 PROCESS_INFORMATION process_info = {0}; 143 base::win::ScopedProcessInformation process_info;
161 144
162 if (!::CreateProcessAsUserW(lockdown_token_, 145 if (!::CreateProcessAsUserW(lockdown_token_,
163 exe_path, 146 exe_path,
164 cmd_line.get(), 147 cmd_line.get(),
165 NULL, // No security attribute. 148 NULL, // No security attribute.
166 NULL, // No thread attribute. 149 NULL, // No thread attribute.
167 FALSE, // Do not inherit handles. 150 FALSE, // Do not inherit handles.
168 flags, 151 flags,
169 NULL, // Use the environment of the caller. 152 NULL, // Use the environment of the caller.
170 NULL, // Use current directory of the caller. 153 NULL, // Use current directory of the caller.
171 &startup_info, 154 &startup_info,
172 &process_info)) { 155 process_info.Receive())) {
173 return ::GetLastError(); 156 return ::GetLastError();
174 } 157 }
175 158
176 PoisonLowerAddressRange(process_info.hProcess); 159 PoisonLowerAddressRange(process_info.process_handle());
177 160
178 DWORD win_result = ERROR_SUCCESS; 161 DWORD win_result = ERROR_SUCCESS;
179 162
180 // Assign the suspended target to the windows job object 163 // Assign the suspended target to the windows job object
181 if (!::AssignProcessToJobObject(job_, process_info.hProcess)) { 164 if (!::AssignProcessToJobObject(job_, process_info.process_handle())) {
182 win_result = ::GetLastError(); 165 win_result = ::GetLastError();
183 // It might be a security breach if we let the target run outside the job 166 // It might be a security breach if we let the target run outside the job
184 // so kill it before it causes damage 167 // so kill it before it causes damage
185 TerminateTarget(&process_info); 168 ::TerminateProcess(process_info.process_handle(), 0);
186 return win_result; 169 return win_result;
187 } 170 }
188 171
189 // Change the token of the main thread of the new process for the 172 // Change the token of the main thread of the new process for the
190 // impersonation token with more rights. This allows the target to start; 173 // impersonation token with more rights. This allows the target to start;
191 // otherwise it will crash too early for us to help. 174 // otherwise it will crash too early for us to help.
192 if (!SetThreadToken(&process_info.hThread, initial_token_)) { 175 {
193 win_result = ::GetLastError(); 176 HANDLE temp_thread = process_info.thread_handle();
194 TerminateTarget(&process_info); 177 if (!::SetThreadToken(&temp_thread, initial_token_)) {
195 return win_result; 178 win_result = ::GetLastError();
179 ::TerminateProcess(process_info.process_handle(), 0);
180 return win_result;
181 }
196 } 182 }
197 183
198 CONTEXT context; 184 CONTEXT context;
199 context.ContextFlags = CONTEXT_ALL; 185 context.ContextFlags = CONTEXT_ALL;
200 if (!::GetThreadContext(process_info.hThread, &context)) { 186 if (!::GetThreadContext(process_info.thread_handle(), &context)) {
201 win_result = ::GetLastError(); 187 win_result = ::GetLastError();
202 TerminateTarget(&process_info); 188 ::TerminateProcess(process_info.process_handle(), 0);
203 return win_result; 189 return win_result;
204 } 190 }
205 191
206 sandbox_process_ = process_info.hProcess;
207 sandbox_thread_ = process_info.hThread;
208 sandbox_process_id_ = process_info.dwProcessId;
209
210 #if defined(_WIN64) 192 #if defined(_WIN64)
211 void* entry_point = reinterpret_cast<void*>(context.Rcx); 193 void* entry_point = reinterpret_cast<void*>(context.Rcx);
212 #else 194 #else
213 #pragma warning(push) 195 #pragma warning(push)
214 #pragma warning(disable: 4312) 196 #pragma warning(disable: 4312)
215 // This cast generates a warning because it is 32 bit specific. 197 // This cast generates a warning because it is 32 bit specific.
216 void* entry_point = reinterpret_cast<void*>(context.Eax); 198 void* entry_point = reinterpret_cast<void*>(context.Eax);
217 #pragma warning(pop) 199 #pragma warning(pop)
218 #endif // _WIN64 200 #endif // _WIN64
201
202 if (!target_info->DuplicateFrom(process_info)) {
203 ::TerminateProcess(process_info.process_handle(), 0);
204 return ERROR_INVALID_FUNCTION;
205 }
206
219 base_address_ = GetBaseAddress(exe_path, entry_point); 207 base_address_ = GetBaseAddress(exe_path, entry_point);
220 *target_info = process_info; 208 sandbox_process_info_.Swap(&process_info);
221 return win_result; 209 return win_result;
222 } 210 }
223 211
224 ResultCode TargetProcess::TransferVariable(char* name, void* address, 212 ResultCode TargetProcess::TransferVariable(char* name, void* address,
225 size_t size) { 213 size_t size) {
226 if (NULL == sandbox_process_) 214 if (!sandbox_process_info_.IsValid())
227 return SBOX_ERROR_UNEXPECTED_CALL; 215 return SBOX_ERROR_UNEXPECTED_CALL;
228 216
229 void* child_var = address; 217 void* child_var = address;
230 218
231 #if SANDBOX_EXPORTS 219 #if SANDBOX_EXPORTS
232 HMODULE module = ::LoadLibrary(exe_name_); 220 HMODULE module = ::LoadLibrary(exe_name_.get());
233 if (NULL == module) 221 if (NULL == module)
234 return SBOX_ERROR_GENERIC; 222 return SBOX_ERROR_GENERIC;
235 223
236 child_var = ::GetProcAddress(module, name); 224 child_var = ::GetProcAddress(module, name);
237 ::FreeLibrary(module); 225 ::FreeLibrary(module);
238 226
239 if (NULL == child_var) 227 if (NULL == child_var)
240 return SBOX_ERROR_GENERIC; 228 return SBOX_ERROR_GENERIC;
241 229
242 size_t offset = reinterpret_cast<char*>(child_var) - 230 size_t offset = reinterpret_cast<char*>(child_var) -
243 reinterpret_cast<char*>(module); 231 reinterpret_cast<char*>(module);
244 child_var = reinterpret_cast<char*>(MainModule()) + offset; 232 child_var = reinterpret_cast<char*>(MainModule()) + offset;
245 #else 233 #else
246 UNREFERENCED_PARAMETER(name); 234 UNREFERENCED_PARAMETER(name);
247 #endif 235 #endif
248 236
249 SIZE_T written; 237 SIZE_T written;
250 if (!::WriteProcessMemory(sandbox_process_, child_var, address, size, 238 if (!::WriteProcessMemory(sandbox_process_info_.process_handle(),
251 &written)) 239 child_var, address, size, &written))
252 return SBOX_ERROR_GENERIC; 240 return SBOX_ERROR_GENERIC;
253 241
254 if (written != size) 242 if (written != size)
255 return SBOX_ERROR_GENERIC; 243 return SBOX_ERROR_GENERIC;
256 244
257 return SBOX_ALL_OK; 245 return SBOX_ALL_OK;
258 } 246 }
259 247
260 // Construct the IPC server and the IPC dispatcher. When the target does 248 // Construct the IPC server and the IPC dispatcher. When the target does
261 // an IPC it will eventually call the dispatcher. 249 // an IPC it will eventually call the dispatcher.
262 DWORD TargetProcess::Init(Dispatcher* ipc_dispatcher, void* policy, 250 DWORD TargetProcess::Init(Dispatcher* ipc_dispatcher, void* policy,
263 size_t shared_IPC_size, size_t shared_policy_size) { 251 size_t shared_IPC_size, size_t shared_policy_size) {
264 // We need to map the shared memory on the target. This is necessary for 252 // We need to map the shared memory on the target. This is necessary for
265 // any IPC that needs to take place, even if the target has not yet hit 253 // any IPC that needs to take place, even if the target has not yet hit
266 // the main( ) function or even has initialized the CRT. So here we set 254 // the main( ) function or even has initialized the CRT. So here we set
267 // the handle to the shared section. The target on the first IPC must do 255 // the handle to the shared section. The target on the first IPC must do
268 // the rest, which boils down to calling MapViewofFile() 256 // the rest, which boils down to calling MapViewofFile()
269 257
270 // We use this single memory pool for IPC and for policy. 258 // We use this single memory pool for IPC and for policy.
271 DWORD shared_mem_size = static_cast<DWORD>(shared_IPC_size + 259 DWORD shared_mem_size = static_cast<DWORD>(shared_IPC_size +
272 shared_policy_size); 260 shared_policy_size);
273 shared_section_ = ::CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, 261 shared_section_.Set(::CreateFileMappingW(INVALID_HANDLE_VALUE, NULL,
274 PAGE_READWRITE | SEC_COMMIT, 262 PAGE_READWRITE | SEC_COMMIT,
275 0, shared_mem_size, NULL); 263 0, shared_mem_size, NULL));
276 if (NULL == shared_section_) { 264 if (!shared_section_.IsValid()) {
277 return ::GetLastError(); 265 return ::GetLastError();
278 } 266 }
279 267
280 DWORD access = FILE_MAP_READ | FILE_MAP_WRITE; 268 DWORD access = FILE_MAP_READ | FILE_MAP_WRITE;
281 HANDLE target_shared_section = NULL; 269 base::win::ScopedHandle target_shared_section;
282 if (!::DuplicateHandle(::GetCurrentProcess(), shared_section_, 270 if (!::DuplicateHandle(::GetCurrentProcess(), shared_section_,
283 sandbox_process_, &target_shared_section, 271 sandbox_process_info_.process_handle(),
284 access, FALSE, 0)) { 272 target_shared_section.Receive(), access, FALSE, 0)) {
285 return ::GetLastError(); 273 return ::GetLastError();
286 } 274 }
287 275
288 void* shared_memory = ::MapViewOfFile(shared_section_, 276 void* shared_memory = ::MapViewOfFile(shared_section_,
289 FILE_MAP_WRITE|FILE_MAP_READ, 277 FILE_MAP_WRITE|FILE_MAP_READ,
290 0, 0, 0); 278 0, 0, 0);
291 if (NULL == shared_memory) { 279 if (NULL == shared_memory) {
292 return ::GetLastError(); 280 return ::GetLastError();
293 } 281 }
294 282
295 CopyPolicyToTarget(policy, shared_policy_size, 283 CopyPolicyToTarget(policy, shared_policy_size,
296 reinterpret_cast<char*>(shared_memory) + shared_IPC_size); 284 reinterpret_cast<char*>(shared_memory) + shared_IPC_size);
297 285
298 ResultCode ret; 286 ResultCode ret;
299 // Set the global variables in the target. These are not used on the broker. 287 // Set the global variables in the target. These are not used on the broker.
300 g_shared_section = target_shared_section; 288 g_shared_section = target_shared_section.Take();
301 ret = TransferVariable("g_shared_section", &g_shared_section, 289 ret = TransferVariable("g_shared_section", &g_shared_section,
302 sizeof(g_shared_section)); 290 sizeof(g_shared_section));
303 g_shared_section = NULL; 291 g_shared_section = NULL;
304 if (SBOX_ALL_OK != ret) { 292 if (SBOX_ALL_OK != ret) {
305 return (SBOX_ERROR_GENERIC == ret)? 293 return (SBOX_ERROR_GENERIC == ret)?
306 ::GetLastError() : ERROR_INVALID_FUNCTION; 294 ::GetLastError() : ERROR_INVALID_FUNCTION;
307 } 295 }
308 g_shared_IPC_size = shared_IPC_size; 296 g_shared_IPC_size = shared_IPC_size;
309 ret = TransferVariable("g_shared_IPC_size", &g_shared_IPC_size, 297 ret = TransferVariable("g_shared_IPC_size", &g_shared_IPC_size,
310 sizeof(g_shared_IPC_size)); 298 sizeof(g_shared_IPC_size));
311 g_shared_IPC_size = 0; 299 g_shared_IPC_size = 0;
312 if (SBOX_ALL_OK != ret) { 300 if (SBOX_ALL_OK != ret) {
313 return (SBOX_ERROR_GENERIC == ret) ? 301 return (SBOX_ERROR_GENERIC == ret) ?
314 ::GetLastError() : ERROR_INVALID_FUNCTION; 302 ::GetLastError() : ERROR_INVALID_FUNCTION;
315 } 303 }
316 g_shared_policy_size = shared_policy_size; 304 g_shared_policy_size = shared_policy_size;
317 ret = TransferVariable("g_shared_policy_size", &g_shared_policy_size, 305 ret = TransferVariable("g_shared_policy_size", &g_shared_policy_size,
318 sizeof(g_shared_policy_size)); 306 sizeof(g_shared_policy_size));
319 g_shared_policy_size = 0; 307 g_shared_policy_size = 0;
320 if (SBOX_ALL_OK != ret) { 308 if (SBOX_ALL_OK != ret) {
321 return (SBOX_ERROR_GENERIC == ret) ? 309 return (SBOX_ERROR_GENERIC == ret) ?
322 ::GetLastError() : ERROR_INVALID_FUNCTION; 310 ::GetLastError() : ERROR_INVALID_FUNCTION;
323 } 311 }
324 312
325 ipc_server_ = new SharedMemIPCServer(sandbox_process_, sandbox_process_id_, 313 ipc_server_.reset(
326 job_, thread_pool_, ipc_dispatcher); 314 new SharedMemIPCServer(sandbox_process_info_.process_handle(),
315 sandbox_process_info_.process_id(),
316 job_, thread_pool_, ipc_dispatcher));
327 317
328 if (!ipc_server_->Init(shared_memory, shared_IPC_size, kIPCChannelSize)) 318 if (!ipc_server_->Init(shared_memory, shared_IPC_size, kIPCChannelSize))
329 return ERROR_NOT_ENOUGH_MEMORY; 319 return ERROR_NOT_ENOUGH_MEMORY;
330 320
331 // After this point we cannot use this handle anymore. 321 // After this point we cannot use this handle anymore.
332 sandbox_thread_ = NULL; 322 ::CloseHandle(sandbox_process_info_.TakeThreadHandle());
333 323
334 return ERROR_SUCCESS; 324 return ERROR_SUCCESS;
335 } 325 }
336 326
337 void TargetProcess::Terminate() { 327 void TargetProcess::Terminate() {
338 if (NULL == sandbox_process_) 328 if (!sandbox_process_info_.IsValid())
339 return; 329 return;
340 330
341 ::TerminateProcess(sandbox_process_, 0); 331 ::TerminateProcess(sandbox_process_info_.process_handle(), 0);
342 } 332 }
343 333
344 334
345 TargetProcess* MakeTestTargetProcess(HANDLE process, HMODULE base_address) { 335 TargetProcess* MakeTestTargetProcess(HANDLE process, HMODULE base_address) {
346 TargetProcess* target = new TargetProcess(NULL, NULL, NULL, NULL); 336 TargetProcess* target = new TargetProcess(NULL, NULL, NULL, NULL);
347 target->sandbox_process_ = process; 337 target->sandbox_process_info_.Receive()->hProcess = process;
348 target->base_address_ = base_address; 338 target->base_address_ = base_address;
349 return target; 339 return target;
350 } 340 }
351 341
352 } // namespace sandbox 342 } // namespace sandbox
OLDNEW
« no previous file with comments | « sandbox/src/target_process.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698