| OLD | NEW |
| 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 Loading... |
| 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 |
| OLD | NEW |