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

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

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