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

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

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

Powered by Google App Engine
This is Rietveld 408576698