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

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, 5 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 "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.
115 shared_section_.Take();
116 SharedMemIPCServer* server = ipc_server_.release();
117 sandbox_process_info_.TakeProcessHandle();
127 return; 118 return;
128 } 119 }
129 120
130 delete ipc_server_; 121 // ipc_server_ references our process handle, so make sure the former is shut
131 122 // down before the latter is closed (by ScopedProcessInformation).
132 ::CloseHandle(lockdown_token_); 123 ipc_server_.reset();
133 ::CloseHandle(initial_token_);
134 ::CloseHandle(sandbox_process_);
135 if (shared_section_)
136 ::CloseHandle(shared_section_);
137 free(exe_name_);
138 } 124 }
139 125
140 // Creates the target (child) process suspended and assigns it to the job 126 // Creates the target (child) process suspended and assigns it to the job
141 // object. 127 // object.
142 DWORD TargetProcess::Create(const wchar_t* exe_path, 128 DWORD TargetProcess::Create(const wchar_t* exe_path,
143 const wchar_t* command_line, 129 const wchar_t* command_line,
144 const wchar_t* desktop, 130 const wchar_t* desktop,
145 PROCESS_INFORMATION* target_info) { 131 base::win::ScopedProcessInformation* target_info) {
146 exe_name_ = _wcsdup(exe_path); 132 exe_name_.reset(_wcsdup(exe_path));
147 133
148 // the command line needs to be writable by CreateProcess(). 134 // the command line needs to be writable by CreateProcess().
149 scoped_ptr_malloc<wchar_t> cmd_line(_wcsdup(command_line)); 135 scoped_ptr_malloc<wchar_t> cmd_line(_wcsdup(command_line));
150 scoped_ptr_malloc<wchar_t> desktop_name(desktop ? _wcsdup(desktop) : NULL); 136 scoped_ptr_malloc<wchar_t> desktop_name(desktop ? _wcsdup(desktop) : NULL);
151 137
152 // Start the target process suspended. 138 // Start the target process suspended.
153 DWORD flags = 139 DWORD flags =
154 CREATE_SUSPENDED | CREATE_UNICODE_ENVIRONMENT | DETACHED_PROCESS; 140 CREATE_SUSPENDED | CREATE_UNICODE_ENVIRONMENT | DETACHED_PROCESS;
155 141
156 if (base::win::GetVersion() < base::win::VERSION_WIN8) { 142 if (base::win::GetVersion() < base::win::VERSION_WIN8) {
157 // Windows 8 implements nested jobs, but for older systems we need to 143 // 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. 144 // break out of any job we're in to enforce our restrictions.
159 flags |= CREATE_BREAKAWAY_FROM_JOB; 145 flags |= CREATE_BREAKAWAY_FROM_JOB;
160 } 146 }
161 147
162 STARTUPINFO startup_info = {sizeof(STARTUPINFO)}; 148 STARTUPINFO startup_info = {sizeof(STARTUPINFO)};
163 if (desktop) { 149 if (desktop) {
164 startup_info.lpDesktop = desktop_name.get(); 150 startup_info.lpDesktop = desktop_name.get();
165 } 151 }
166 152
167 PROCESS_INFORMATION process_info = {0}; 153 base::win::ScopedProcessInformation process_info;
168 154
169 if (!::CreateProcessAsUserW(lockdown_token_, 155 if (!::CreateProcessAsUserW(lockdown_token_,
170 exe_path, 156 exe_path,
171 cmd_line.get(), 157 cmd_line.get(),
172 NULL, // No security attribute. 158 NULL, // No security attribute.
173 NULL, // No thread attribute. 159 NULL, // No thread attribute.
174 FALSE, // Do not inherit handles. 160 FALSE, // Do not inherit handles.
175 flags, 161 flags,
176 NULL, // Use the environment of the caller. 162 NULL, // Use the environment of the caller.
177 NULL, // Use current directory of the caller. 163 NULL, // Use current directory of the caller.
178 &startup_info, 164 &startup_info,
179 &process_info)) { 165 process_info.Receive())) {
180 return ::GetLastError(); 166 return ::GetLastError();
181 } 167 }
168 lockdown_token_.Close();
182 169
183 PoisonLowerAddressRange(process_info.hProcess); 170 PoisonLowerAddressRange(process_info.process_handle());
184 171
185 DWORD win_result = ERROR_SUCCESS; 172 DWORD win_result = ERROR_SUCCESS;
186 173
187 // Assign the suspended target to the windows job object 174 // Assign the suspended target to the windows job object
188 if (!::AssignProcessToJobObject(job_, process_info.hProcess)) { 175 if (!::AssignProcessToJobObject(job_, process_info.process_handle())) {
189 win_result = ::GetLastError(); 176 win_result = ::GetLastError();
190 // It might be a security breach if we let the target run outside the job 177 // It might be a security breach if we let the target run outside the job
191 // so kill it before it causes damage 178 // so kill it before it causes damage
192 TerminateTarget(&process_info); 179 ::TerminateProcess(process_info.process_handle(), 0);
193 return win_result; 180 return win_result;
194 } 181 }
195 182
196 // Change the token of the main thread of the new process for the 183 // 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; 184 // impersonation token with more rights. This allows the target to start;
198 // otherwise it will crash too early for us to help. 185 // otherwise it will crash too early for us to help.
199 if (!SetThreadToken(&process_info.hThread, initial_token_)) { 186 {
200 win_result = ::GetLastError(); 187 HANDLE temp_thread = process_info.thread_handle();
201 TerminateTarget(&process_info); 188 if (!::SetThreadToken(&temp_thread, initial_token_)) {
202 return win_result; 189 win_result = ::GetLastError();
190 ::TerminateProcess(process_info.process_handle(), 0);
191 return win_result;
192 }
193 initial_token_.Close();
203 } 194 }
204 195
205 CONTEXT context; 196 CONTEXT context;
206 context.ContextFlags = CONTEXT_ALL; 197 context.ContextFlags = CONTEXT_ALL;
207 if (!::GetThreadContext(process_info.hThread, &context)) { 198 if (!::GetThreadContext(process_info.thread_handle(), &context)) {
208 win_result = ::GetLastError(); 199 win_result = ::GetLastError();
209 TerminateTarget(&process_info); 200 ::TerminateProcess(process_info.process_handle(), 0);
210 return win_result; 201 return win_result;
211 } 202 }
212 203
213 sandbox_process_ = process_info.hProcess;
214 sandbox_thread_ = process_info.hThread;
215 sandbox_process_id_ = process_info.dwProcessId;
216
217 #if defined(_WIN64) 204 #if defined(_WIN64)
218 void* entry_point = reinterpret_cast<void*>(context.Rcx); 205 void* entry_point = reinterpret_cast<void*>(context.Rcx);
219 #else 206 #else
220 #pragma warning(push) 207 #pragma warning(push)
221 #pragma warning(disable: 4312) 208 #pragma warning(disable: 4312)
222 // This cast generates a warning because it is 32 bit specific. 209 // This cast generates a warning because it is 32 bit specific.
223 void* entry_point = reinterpret_cast<void*>(context.Eax); 210 void* entry_point = reinterpret_cast<void*>(context.Eax);
224 #pragma warning(pop) 211 #pragma warning(pop)
225 #endif // _WIN64 212 #endif // _WIN64
213
214 if (!target_info->DuplicateFrom(process_info)) {
215 win_result = ::GetLastError(); // This may or may not be correct.
216 ::TerminateProcess(process_info.process_handle(), 0);
217 return win_result;
218 }
219
226 base_address_ = GetBaseAddress(exe_path, entry_point); 220 base_address_ = GetBaseAddress(exe_path, entry_point);
227 *target_info = process_info; 221 sandbox_process_info_.Swap(&process_info);
228 return win_result; 222 return win_result;
229 } 223 }
230 224
231 ResultCode TargetProcess::TransferVariable(const char* name, void* address, 225 ResultCode TargetProcess::TransferVariable(const char* name, void* address,
232 size_t size) { 226 size_t size) {
233 if (NULL == sandbox_process_) 227 if (!sandbox_process_info_.IsValid())
234 return SBOX_ERROR_UNEXPECTED_CALL; 228 return SBOX_ERROR_UNEXPECTED_CALL;
235 229
236 void* child_var = address; 230 void* child_var = address;
237 231
238 #if SANDBOX_EXPORTS 232 #if SANDBOX_EXPORTS
239 HMODULE module = ::LoadLibrary(exe_name_); 233 HMODULE module = ::LoadLibrary(exe_name_.get());
240 if (NULL == module) 234 if (NULL == module)
241 return SBOX_ERROR_GENERIC; 235 return SBOX_ERROR_GENERIC;
242 236
243 child_var = ::GetProcAddress(module, name); 237 child_var = ::GetProcAddress(module, name);
244 ::FreeLibrary(module); 238 ::FreeLibrary(module);
245 239
246 if (NULL == child_var) 240 if (NULL == child_var)
247 return SBOX_ERROR_GENERIC; 241 return SBOX_ERROR_GENERIC;
248 242
249 size_t offset = reinterpret_cast<char*>(child_var) - 243 size_t offset = reinterpret_cast<char*>(child_var) -
250 reinterpret_cast<char*>(module); 244 reinterpret_cast<char*>(module);
251 child_var = reinterpret_cast<char*>(MainModule()) + offset; 245 child_var = reinterpret_cast<char*>(MainModule()) + offset;
252 #else 246 #else
253 UNREFERENCED_PARAMETER(name); 247 UNREFERENCED_PARAMETER(name);
254 #endif 248 #endif
255 249
256 SIZE_T written; 250 SIZE_T written;
257 if (!::WriteProcessMemory(sandbox_process_, child_var, address, size, 251 if (!::WriteProcessMemory(sandbox_process_info_.process_handle(),
258 &written)) 252 child_var, address, size, &written))
259 return SBOX_ERROR_GENERIC; 253 return SBOX_ERROR_GENERIC;
260 254
261 if (written != size) 255 if (written != size)
262 return SBOX_ERROR_GENERIC; 256 return SBOX_ERROR_GENERIC;
263 257
264 return SBOX_ALL_OK; 258 return SBOX_ALL_OK;
265 } 259 }
266 260
267 // Construct the IPC server and the IPC dispatcher. When the target does 261 // Construct the IPC server and the IPC dispatcher. When the target does
268 // an IPC it will eventually call the dispatcher. 262 // an IPC it will eventually call the dispatcher.
269 DWORD TargetProcess::Init(Dispatcher* ipc_dispatcher, void* policy, 263 DWORD TargetProcess::Init(Dispatcher* ipc_dispatcher, void* policy,
270 uint32 shared_IPC_size, uint32 shared_policy_size) { 264 uint32 shared_IPC_size, uint32 shared_policy_size) {
271 // We need to map the shared memory on the target. This is necessary for 265 // 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 266 // 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 267 // 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 268 // the handle to the shared section. The target on the first IPC must do
275 // the rest, which boils down to calling MapViewofFile() 269 // the rest, which boils down to calling MapViewofFile()
276 270
277 // We use this single memory pool for IPC and for policy. 271 // We use this single memory pool for IPC and for policy.
278 DWORD shared_mem_size = static_cast<DWORD>(shared_IPC_size + 272 DWORD shared_mem_size = static_cast<DWORD>(shared_IPC_size +
279 shared_policy_size); 273 shared_policy_size);
280 shared_section_ = ::CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, 274 shared_section_.Set(::CreateFileMappingW(INVALID_HANDLE_VALUE, NULL,
281 PAGE_READWRITE | SEC_COMMIT, 275 PAGE_READWRITE | SEC_COMMIT,
282 0, shared_mem_size, NULL); 276 0, shared_mem_size, NULL));
283 if (NULL == shared_section_) { 277 if (!shared_section_.IsValid()) {
284 return ::GetLastError(); 278 return ::GetLastError();
285 } 279 }
286 280
287 DWORD access = FILE_MAP_READ | FILE_MAP_WRITE; 281 DWORD access = FILE_MAP_READ | FILE_MAP_WRITE;
288 HANDLE target_shared_section = NULL; 282 HANDLE target_shared_section;
289 if (!::DuplicateHandle(::GetCurrentProcess(), shared_section_, 283 if (!::DuplicateHandle(::GetCurrentProcess(), shared_section_,
290 sandbox_process_, &target_shared_section, 284 sandbox_process_info_.process_handle(),
291 access, FALSE, 0)) { 285 &target_shared_section, access, FALSE, 0)) {
292 return ::GetLastError(); 286 return ::GetLastError();
293 } 287 }
294 288
295 void* shared_memory = ::MapViewOfFile(shared_section_, 289 void* shared_memory = ::MapViewOfFile(shared_section_,
296 FILE_MAP_WRITE|FILE_MAP_READ, 290 FILE_MAP_WRITE|FILE_MAP_READ,
297 0, 0, 0); 291 0, 0, 0);
298 if (NULL == shared_memory) { 292 if (NULL == shared_memory) {
299 return ::GetLastError(); 293 return ::GetLastError();
300 } 294 }
301 295
(...skipping 20 matching lines...) Expand all
322 } 316 }
323 g_shared_policy_size = shared_policy_size; 317 g_shared_policy_size = shared_policy_size;
324 ret = TransferVariable("g_shared_policy_size", &g_shared_policy_size, 318 ret = TransferVariable("g_shared_policy_size", &g_shared_policy_size,
325 sizeof(g_shared_policy_size)); 319 sizeof(g_shared_policy_size));
326 g_shared_policy_size = 0; 320 g_shared_policy_size = 0;
327 if (SBOX_ALL_OK != ret) { 321 if (SBOX_ALL_OK != ret) {
328 return (SBOX_ERROR_GENERIC == ret) ? 322 return (SBOX_ERROR_GENERIC == ret) ?
329 ::GetLastError() : ERROR_INVALID_FUNCTION; 323 ::GetLastError() : ERROR_INVALID_FUNCTION;
330 } 324 }
331 325
332 ipc_server_ = new SharedMemIPCServer(sandbox_process_, sandbox_process_id_, 326 ipc_server_.reset(
333 job_, thread_pool_, ipc_dispatcher); 327 new SharedMemIPCServer(sandbox_process_info_.process_handle(),
328 sandbox_process_info_.process_id(),
329 job_, thread_pool_, ipc_dispatcher));
334 330
335 if (!ipc_server_->Init(shared_memory, shared_IPC_size, kIPCChannelSize)) 331 if (!ipc_server_->Init(shared_memory, shared_IPC_size, kIPCChannelSize))
336 return ERROR_NOT_ENOUGH_MEMORY; 332 return ERROR_NOT_ENOUGH_MEMORY;
337 333
338 // After this point we cannot use this handle anymore. 334 // After this point we cannot use this handle anymore.
339 sandbox_thread_ = NULL; 335 ::CloseHandle(sandbox_process_info_.TakeThreadHandle());
340 336
341 return ERROR_SUCCESS; 337 return ERROR_SUCCESS;
342 } 338 }
343 339
344 void TargetProcess::Terminate() { 340 void TargetProcess::Terminate() {
345 if (NULL == sandbox_process_) 341 if (!sandbox_process_info_.IsValid())
346 return; 342 return;
347 343
348 ::TerminateProcess(sandbox_process_, 0); 344 ::TerminateProcess(sandbox_process_info_.process_handle(), 0);
349 } 345 }
350 346
351 347
352 TargetProcess* MakeTestTargetProcess(HANDLE process, HMODULE base_address) { 348 TargetProcess* MakeTestTargetProcess(HANDLE process, HMODULE base_address) {
353 TargetProcess* target = new TargetProcess(NULL, NULL, NULL, NULL); 349 TargetProcess* target = new TargetProcess(NULL, NULL, NULL, NULL);
354 target->sandbox_process_ = process; 350 target->sandbox_process_info_.Receive()->hProcess = process;
355 target->base_address_ = base_address; 351 target->base_address_ = base_address;
356 return target; 352 return target;
357 } 353 }
358 354
359 } // namespace sandbox 355 } // 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