| 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/win/src/broker_services.h" | 5 #include "sandbox/win/src/broker_services.h" |
| 6 | 6 |
| 7 #include <AclAPI.h> | 7 #include <AclAPI.h> |
| 8 | 8 |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "base/memory/scoped_ptr.h" | 10 #include "base/memory/scoped_ptr.h" |
| 11 #include "base/stl_util.h" |
| 11 #include "base/threading/platform_thread.h" | 12 #include "base/threading/platform_thread.h" |
| 12 #include "base/win/scoped_handle.h" | 13 #include "base/win/scoped_handle.h" |
| 13 #include "base/win/scoped_process_information.h" | 14 #include "base/win/scoped_process_information.h" |
| 14 #include "base/win/startup_information.h" | 15 #include "base/win/startup_information.h" |
| 15 #include "base/win/windows_version.h" | 16 #include "base/win/windows_version.h" |
| 16 #include "sandbox/win/src/app_container.h" | 17 #include "sandbox/win/src/app_container.h" |
| 17 #include "sandbox/win/src/process_mitigations.h" | 18 #include "sandbox/win/src/process_mitigations.h" |
| 18 #include "sandbox/win/src/sandbox_policy_base.h" | 19 #include "sandbox/win/src/sandbox_policy_base.h" |
| 19 #include "sandbox/win/src/sandbox.h" | 20 #include "sandbox/win/src/sandbox.h" |
| 20 #include "sandbox/win/src/target_process.h" | 21 #include "sandbox/win/src/target_process.h" |
| (...skipping 27 matching lines...) Expand all Loading... |
| 48 enum { | 49 enum { |
| 49 THREAD_CTRL_NONE, | 50 THREAD_CTRL_NONE, |
| 50 THREAD_CTRL_REMOVE_PEER, | 51 THREAD_CTRL_REMOVE_PEER, |
| 51 THREAD_CTRL_QUIT, | 52 THREAD_CTRL_QUIT, |
| 52 THREAD_CTRL_LAST, | 53 THREAD_CTRL_LAST, |
| 53 }; | 54 }; |
| 54 | 55 |
| 55 // Helper structure that allows the Broker to associate a job notification | 56 // Helper structure that allows the Broker to associate a job notification |
| 56 // with a job object and with a policy. | 57 // with a job object and with a policy. |
| 57 struct JobTracker { | 58 struct JobTracker { |
| 58 HANDLE job; | 59 JobTracker(base::win::ScopedHandle job, sandbox::PolicyBase* policy) |
| 60 : job(job.Pass()), policy(policy) { |
| 61 } |
| 62 ~JobTracker() { |
| 63 FreeResources(); |
| 64 } |
| 65 |
| 66 // Releases the Job and notifies the associated Policy object to release its |
| 67 // resources as well. |
| 68 void FreeResources(); |
| 69 |
| 70 base::win::ScopedHandle job; |
| 59 sandbox::PolicyBase* policy; | 71 sandbox::PolicyBase* policy; |
| 60 JobTracker(HANDLE cjob, sandbox::PolicyBase* cpolicy) | 72 }; |
| 61 : job(cjob), policy(cpolicy) { | 73 |
| 74 void JobTracker::FreeResources() { |
| 75 if (policy) { |
| 76 BOOL res = ::TerminateJobObject(job.Get(), sandbox::SBOX_ALL_OK); |
| 77 DCHECK(res); |
| 78 // Closing the job causes the target process to be destroyed so this needs |
| 79 // to happen before calling OnJobEmpty(). |
| 80 HANDLE stale_job_handle = job.Get(); |
| 81 job.Close(); |
| 82 |
| 83 // In OnJobEmpty() we don't actually use the job handle directly. |
| 84 policy->OnJobEmpty(stale_job_handle); |
| 85 policy->Release(); |
| 86 policy = NULL; |
| 62 } | 87 } |
| 63 }; | 88 } |
| 64 | 89 |
| 65 // Helper structure that allows the broker to track peer processes | 90 // Helper structure that allows the broker to track peer processes |
| 66 struct PeerTracker { | 91 struct PeerTracker { |
| 92 PeerTracker(DWORD process_id, HANDLE broker_job_port) |
| 93 : wait_object(NULL), id(process_id), job_port(broker_job_port) { |
| 94 } |
| 95 |
| 67 HANDLE wait_object; | 96 HANDLE wait_object; |
| 68 base::win::ScopedHandle process; | 97 base::win::ScopedHandle process; |
| 69 DWORD id; | 98 DWORD id; |
| 70 HANDLE job_port; | 99 HANDLE job_port; |
| 71 PeerTracker(DWORD process_id, HANDLE broker_job_port) | |
| 72 : wait_object(NULL), id(process_id), job_port(broker_job_port) { | |
| 73 } | |
| 74 }; | 100 }; |
| 75 | 101 |
| 76 void DeregisterPeerTracker(PeerTracker* peer) { | 102 void DeregisterPeerTracker(PeerTracker* peer) { |
| 77 // Deregistration shouldn't fail, but we leak rather than crash if it does. | 103 // Deregistration shouldn't fail, but we leak rather than crash if it does. |
| 78 if (::UnregisterWaitEx(peer->wait_object, INVALID_HANDLE_VALUE)) { | 104 if (::UnregisterWaitEx(peer->wait_object, INVALID_HANDLE_VALUE)) { |
| 79 delete peer; | 105 delete peer; |
| 80 } else { | 106 } else { |
| 81 NOTREACHED(); | 107 NOTREACHED(); |
| 82 } | 108 } |
| 83 } | 109 } |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 117 key <<= kTokenShift; | 143 key <<= kTokenShift; |
| 118 key |= policy->GetIntegrityLevel(); | 144 key |= policy->GetIntegrityLevel(); |
| 119 | 145 |
| 120 return key; | 146 return key; |
| 121 } | 147 } |
| 122 | 148 |
| 123 } // namespace | 149 } // namespace |
| 124 | 150 |
| 125 namespace sandbox { | 151 namespace sandbox { |
| 126 | 152 |
| 127 BrokerServicesBase::BrokerServicesBase() | 153 // TODO(rvargas): Replace this structure with a std::pair of ScopedHandles. |
| 128 : job_port_(NULL), | 154 struct BrokerServicesBase::TokenPair { |
| 129 no_targets_(NULL), | 155 TokenPair(base::win::ScopedHandle initial_token, |
| 130 job_thread_(NULL), | 156 base::win::ScopedHandle lockdown_token) |
| 131 thread_pool_(NULL) { | 157 : initial(initial_token.Pass()), |
| 158 lockdown(lockdown_token.Pass()) { |
| 159 } |
| 160 |
| 161 base::win::ScopedHandle initial; |
| 162 base::win::ScopedHandle lockdown; |
| 163 }; |
| 164 |
| 165 BrokerServicesBase::BrokerServicesBase() : thread_pool_(NULL) { |
| 132 } | 166 } |
| 133 | 167 |
| 134 // The broker uses a dedicated worker thread that services the job completion | 168 // The broker uses a dedicated worker thread that services the job completion |
| 135 // port to perform policy notifications and associated cleanup tasks. | 169 // port to perform policy notifications and associated cleanup tasks. |
| 136 ResultCode BrokerServicesBase::Init() { | 170 ResultCode BrokerServicesBase::Init() { |
| 137 if ((NULL != job_port_) || (NULL != thread_pool_)) | 171 if (job_port_.IsValid() || (NULL != thread_pool_)) |
| 138 return SBOX_ERROR_UNEXPECTED_CALL; | 172 return SBOX_ERROR_UNEXPECTED_CALL; |
| 139 | 173 |
| 140 ::InitializeCriticalSection(&lock_); | 174 ::InitializeCriticalSection(&lock_); |
| 141 | 175 |
| 142 job_port_ = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0); | 176 job_port_.Set(::CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0)); |
| 143 if (NULL == job_port_) | 177 if (!job_port_.IsValid()) |
| 144 return SBOX_ERROR_GENERIC; | 178 return SBOX_ERROR_GENERIC; |
| 145 | 179 |
| 146 no_targets_ = ::CreateEventW(NULL, TRUE, FALSE, NULL); | 180 no_targets_.Set(::CreateEventW(NULL, TRUE, FALSE, NULL)); |
| 147 | 181 |
| 148 job_thread_ = ::CreateThread(NULL, 0, // Default security and stack. | 182 job_thread_.Set(::CreateThread(NULL, 0, // Default security and stack. |
| 149 TargetEventsThread, this, NULL, NULL); | 183 TargetEventsThread, this, NULL, NULL)); |
| 150 if (NULL == job_thread_) | 184 if (!job_thread_.IsValid()) |
| 151 return SBOX_ERROR_GENERIC; | 185 return SBOX_ERROR_GENERIC; |
| 152 | 186 |
| 153 return SBOX_ALL_OK; | 187 return SBOX_ALL_OK; |
| 154 } | 188 } |
| 155 | 189 |
| 156 // The destructor should only be called when the Broker process is terminating. | 190 // The destructor should only be called when the Broker process is terminating. |
| 157 // Since BrokerServicesBase is a singleton, this is called from the CRT | 191 // Since BrokerServicesBase is a singleton, this is called from the CRT |
| 158 // termination handlers, if this code lives on a DLL it is called during | 192 // termination handlers, if this code lives on a DLL it is called during |
| 159 // DLL_PROCESS_DETACH in other words, holding the loader lock, so we cannot | 193 // DLL_PROCESS_DETACH in other words, holding the loader lock, so we cannot |
| 160 // wait for threads here. | 194 // wait for threads here. |
| 161 BrokerServicesBase::~BrokerServicesBase() { | 195 BrokerServicesBase::~BrokerServicesBase() { |
| 162 // If there is no port Init() was never called successfully. | 196 // If there is no port Init() was never called successfully. |
| 163 if (!job_port_) | 197 if (!job_port_.IsValid()) |
| 164 return; | 198 return; |
| 165 | 199 |
| 166 // Closing the port causes, that no more Job notifications are delivered to | 200 // Closing the port causes, that no more Job notifications are delivered to |
| 167 // the worker thread and also causes the thread to exit. This is what we | 201 // the worker thread and also causes the thread to exit. This is what we |
| 168 // want to do since we are going to close all outstanding Jobs and notifying | 202 // want to do since we are going to close all outstanding Jobs and notifying |
| 169 // the policy objects ourselves. | 203 // the policy objects ourselves. |
| 170 ::PostQueuedCompletionStatus(job_port_, 0, THREAD_CTRL_QUIT, FALSE); | 204 ::PostQueuedCompletionStatus(job_port_.Get(), 0, THREAD_CTRL_QUIT, FALSE); |
| 171 ::CloseHandle(job_port_); | |
| 172 | 205 |
| 173 if (WAIT_TIMEOUT == ::WaitForSingleObject(job_thread_, 1000)) { | 206 if (job_thread_.IsValid() && |
| 207 WAIT_TIMEOUT == ::WaitForSingleObject(job_thread_.Get(), 1000)) { |
| 174 // Cannot clean broker services. | 208 // Cannot clean broker services. |
| 175 NOTREACHED(); | 209 NOTREACHED(); |
| 176 return; | 210 return; |
| 177 } | 211 } |
| 178 | 212 |
| 179 JobTrackerList::iterator it; | 213 STLDeleteElements(&tracker_list_); |
| 180 for (it = tracker_list_.begin(); it != tracker_list_.end(); ++it) { | |
| 181 JobTracker* tracker = (*it); | |
| 182 FreeResources(tracker); | |
| 183 delete tracker; | |
| 184 } | |
| 185 ::CloseHandle(job_thread_); | |
| 186 delete thread_pool_; | 214 delete thread_pool_; |
| 187 ::CloseHandle(no_targets_); | |
| 188 | 215 |
| 189 // Cancel the wait events and delete remaining peer trackers. | 216 // Cancel the wait events and delete remaining peer trackers. |
| 190 for (PeerTrackerMap::iterator it = peer_map_.begin(); | 217 for (PeerTrackerMap::iterator it = peer_map_.begin(); |
| 191 it != peer_map_.end(); ++it) { | 218 it != peer_map_.end(); ++it) { |
| 192 DeregisterPeerTracker(it->second); | 219 DeregisterPeerTracker(it->second); |
| 193 } | 220 } |
| 194 | 221 |
| 195 // If job_port_ isn't NULL, assumes that the lock has been initialized. | 222 ::DeleteCriticalSection(&lock_); |
| 196 if (job_port_) | |
| 197 ::DeleteCriticalSection(&lock_); | |
| 198 | 223 |
| 199 // Close any token in the cache. | 224 // Close any token in the cache. |
| 200 for (TokenCacheMap::iterator it = token_cache_.begin(); | 225 STLDeleteValues(&token_cache_); |
| 201 it != token_cache_.end(); ++it) { | |
| 202 ::CloseHandle(it->second.first); | |
| 203 ::CloseHandle(it->second.second); | |
| 204 } | |
| 205 } | 226 } |
| 206 | 227 |
| 207 TargetPolicy* BrokerServicesBase::CreatePolicy() { | 228 TargetPolicy* BrokerServicesBase::CreatePolicy() { |
| 208 // If you change the type of the object being created here you must also | 229 // If you change the type of the object being created here you must also |
| 209 // change the downcast to it in SpawnTarget(). | 230 // change the downcast to it in SpawnTarget(). |
| 210 return new PolicyBase; | 231 return new PolicyBase; |
| 211 } | 232 } |
| 212 | 233 |
| 213 void BrokerServicesBase::FreeResources(JobTracker* tracker) { | |
| 214 if (NULL != tracker->policy) { | |
| 215 BOOL res = ::TerminateJobObject(tracker->job, SBOX_ALL_OK); | |
| 216 DCHECK(res); | |
| 217 // Closing the job causes the target process to be destroyed so this | |
| 218 // needs to happen before calling OnJobEmpty(). | |
| 219 res = ::CloseHandle(tracker->job); | |
| 220 DCHECK(res); | |
| 221 // In OnJobEmpty() we don't actually use the job handle directly. | |
| 222 tracker->policy->OnJobEmpty(tracker->job); | |
| 223 tracker->policy->Release(); | |
| 224 tracker->policy = NULL; | |
| 225 } | |
| 226 } | |
| 227 | |
| 228 // The worker thread stays in a loop waiting for asynchronous notifications | 234 // The worker thread stays in a loop waiting for asynchronous notifications |
| 229 // from the job objects. Right now we only care about knowing when the last | 235 // from the job objects. Right now we only care about knowing when the last |
| 230 // process on a job terminates, but in general this is the place to tell | 236 // process on a job terminates, but in general this is the place to tell |
| 231 // the policy about events. | 237 // the policy about events. |
| 232 DWORD WINAPI BrokerServicesBase::TargetEventsThread(PVOID param) { | 238 DWORD WINAPI BrokerServicesBase::TargetEventsThread(PVOID param) { |
| 233 if (NULL == param) | 239 if (NULL == param) |
| 234 return 1; | 240 return 1; |
| 235 | 241 |
| 236 base::PlatformThread::SetName("BrokerEvent"); | 242 base::PlatformThread::SetName("BrokerEvent"); |
| 237 | 243 |
| 238 BrokerServicesBase* broker = reinterpret_cast<BrokerServicesBase*>(param); | 244 BrokerServicesBase* broker = reinterpret_cast<BrokerServicesBase*>(param); |
| 239 HANDLE port = broker->job_port_; | 245 HANDLE port = broker->job_port_.Get(); |
| 240 HANDLE no_targets = broker->no_targets_; | 246 HANDLE no_targets = broker->no_targets_.Get(); |
| 241 | 247 |
| 242 int target_counter = 0; | 248 int target_counter = 0; |
| 243 ::ResetEvent(no_targets); | 249 ::ResetEvent(no_targets); |
| 244 | 250 |
| 245 while (true) { | 251 while (true) { |
| 246 DWORD events = 0; | 252 DWORD events = 0; |
| 247 ULONG_PTR key = 0; | 253 ULONG_PTR key = 0; |
| 248 LPOVERLAPPED ovl = NULL; | 254 LPOVERLAPPED ovl = NULL; |
| 249 | 255 |
| 250 if (!::GetQueuedCompletionStatus(port, &events, &key, &ovl, INFINITE)) | 256 if (!::GetQueuedCompletionStatus(port, &events, &key, &ovl, INFINITE)) { |
| 251 // this call fails if the port has been closed before we have a | 257 // this call fails if the port has been closed before we have a |
| 252 // chance to service the last packet which is 'exit' anyway so | 258 // chance to service the last packet which is 'exit' anyway so |
| 253 // this is not an error. | 259 // this is not an error. |
| 254 return 1; | 260 return 1; |
| 261 } |
| 255 | 262 |
| 256 if (key > THREAD_CTRL_LAST) { | 263 if (key > THREAD_CTRL_LAST) { |
| 257 // The notification comes from a job object. There are nine notifications | 264 // The notification comes from a job object. There are nine notifications |
| 258 // that jobs can send and some of them depend on the job attributes set. | 265 // that jobs can send and some of them depend on the job attributes set. |
| 259 JobTracker* tracker = reinterpret_cast<JobTracker*>(key); | 266 JobTracker* tracker = reinterpret_cast<JobTracker*>(key); |
| 260 | 267 |
| 261 switch (events) { | 268 switch (events) { |
| 262 case JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO: { | 269 case JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO: { |
| 263 // The job object has signaled that the last process associated | 270 // The job object has signaled that the last process associated |
| 264 // with it has terminated. Assuming there is no way for a process | 271 // with it has terminated. Assuming there is no way for a process |
| 265 // to appear out of thin air in this job, it safe to assume that | 272 // to appear out of thin air in this job, it safe to assume that |
| 266 // we can tell the policy to destroy the target object, and for | 273 // we can tell the policy to destroy the target object, and for |
| 267 // us to release our reference to the policy object. | 274 // us to release our reference to the policy object. |
| 268 FreeResources(tracker); | 275 tracker->FreeResources(); |
| 269 break; | 276 break; |
| 270 } | 277 } |
| 271 | 278 |
| 272 case JOB_OBJECT_MSG_NEW_PROCESS: { | 279 case JOB_OBJECT_MSG_NEW_PROCESS: { |
| 273 ++target_counter; | 280 ++target_counter; |
| 274 if (1 == target_counter) { | 281 if (1 == target_counter) { |
| 275 ::ResetEvent(no_targets); | 282 ::ResetEvent(no_targets); |
| 276 } | 283 } |
| 277 break; | 284 break; |
| 278 } | 285 } |
| (...skipping 11 matching lines...) Expand all Loading... |
| 290 | 297 |
| 291 DCHECK(target_counter >= 0); | 298 DCHECK(target_counter >= 0); |
| 292 break; | 299 break; |
| 293 } | 300 } |
| 294 | 301 |
| 295 case JOB_OBJECT_MSG_ACTIVE_PROCESS_LIMIT: { | 302 case JOB_OBJECT_MSG_ACTIVE_PROCESS_LIMIT: { |
| 296 break; | 303 break; |
| 297 } | 304 } |
| 298 | 305 |
| 299 case JOB_OBJECT_MSG_PROCESS_MEMORY_LIMIT: { | 306 case JOB_OBJECT_MSG_PROCESS_MEMORY_LIMIT: { |
| 300 BOOL res = ::TerminateJobObject(tracker->job, | 307 BOOL res = ::TerminateJobObject(tracker->job.Get(), |
| 301 SBOX_FATAL_MEMORY_EXCEEDED); | 308 SBOX_FATAL_MEMORY_EXCEEDED); |
| 302 DCHECK(res); | 309 DCHECK(res); |
| 303 break; | 310 break; |
| 304 } | 311 } |
| 305 | 312 |
| 306 default: { | 313 default: { |
| 307 NOTREACHED(); | 314 NOTREACHED(); |
| 308 break; | 315 break; |
| 309 } | 316 } |
| 310 } | 317 } |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 360 base::win::ScopedHandle initial_token; | 367 base::win::ScopedHandle initial_token; |
| 361 base::win::ScopedHandle lockdown_token; | 368 base::win::ScopedHandle lockdown_token; |
| 362 ResultCode result = SBOX_ALL_OK; | 369 ResultCode result = SBOX_ALL_OK; |
| 363 | 370 |
| 364 if (IsTokenCacheable(policy_base)) { | 371 if (IsTokenCacheable(policy_base)) { |
| 365 // Create the master tokens only once and save them in a cache. That way | 372 // Create the master tokens only once and save them in a cache. That way |
| 366 // can just duplicate them to avoid hammering LSASS on every sandboxed | 373 // can just duplicate them to avoid hammering LSASS on every sandboxed |
| 367 // process launch. | 374 // process launch. |
| 368 uint32_t token_key = GenerateTokenCacheKey(policy_base); | 375 uint32_t token_key = GenerateTokenCacheKey(policy_base); |
| 369 TokenCacheMap::iterator it = token_cache_.find(token_key); | 376 TokenCacheMap::iterator it = token_cache_.find(token_key); |
| 370 HANDLE initial_token_temp; | 377 TokenPair* tokens; |
| 371 HANDLE lockdown_token_temp; | |
| 372 if (it != token_cache_.end()) { | 378 if (it != token_cache_.end()) { |
| 373 initial_token_temp = it->second.first; | 379 tokens = it->second; |
| 374 lockdown_token_temp = it->second.second; | |
| 375 } else { | 380 } else { |
| 376 result = policy_base->MakeTokens(&initial_token, &lockdown_token); | 381 result = policy_base->MakeTokens(&initial_token, &lockdown_token); |
| 377 if (SBOX_ALL_OK != result) | 382 if (SBOX_ALL_OK != result) |
| 378 return result; | 383 return result; |
| 379 token_cache_[token_key] = | 384 |
| 380 std::make_pair(initial_token.Get(), lockdown_token.Get()); | 385 tokens = new TokenPair(initial_token.Pass(), lockdown_token.Pass()); |
| 381 initial_token_temp = initial_token.Take(); | 386 token_cache_[token_key] = tokens; |
| 382 lockdown_token_temp = lockdown_token.Take(); | |
| 383 } | 387 } |
| 384 | 388 |
| 385 if (!::DuplicateToken(initial_token_temp, SecurityImpersonation, | 389 HANDLE temp_token; |
| 386 &initial_token_temp)) { | 390 if (!::DuplicateToken(tokens->initial.Get(), SecurityImpersonation, |
| 391 &temp_token)) { |
| 387 return SBOX_ERROR_GENERIC; | 392 return SBOX_ERROR_GENERIC; |
| 388 } | 393 } |
| 389 initial_token.Set(initial_token_temp); | 394 initial_token.Set(temp_token); |
| 390 | 395 |
| 391 if (!::DuplicateTokenEx(lockdown_token_temp, TOKEN_ALL_ACCESS, 0, | 396 if (!::DuplicateTokenEx(tokens->lockdown.Get(), TOKEN_ALL_ACCESS, 0, |
| 392 SecurityIdentification, TokenPrimary, | 397 SecurityIdentification, TokenPrimary, |
| 393 &lockdown_token_temp)) { | 398 &temp_token)) { |
| 394 return SBOX_ERROR_GENERIC; | 399 return SBOX_ERROR_GENERIC; |
| 395 } | 400 } |
| 396 lockdown_token.Set(lockdown_token_temp); | 401 lockdown_token.Set(temp_token); |
| 397 } else { | 402 } else { |
| 398 result = policy_base->MakeTokens(&initial_token, &lockdown_token); | 403 result = policy_base->MakeTokens(&initial_token, &lockdown_token); |
| 399 if (SBOX_ALL_OK != result) | 404 if (SBOX_ALL_OK != result) |
| 400 return result; | 405 return result; |
| 401 } | 406 } |
| 402 | 407 |
| 403 HANDLE job_temp; | 408 HANDLE job_temp; |
| 404 result = policy_base->MakeJobObject(&job_temp); | 409 result = policy_base->MakeJobObject(&job_temp); |
| 405 if (SBOX_ALL_OK != result) | 410 if (SBOX_ALL_OK != result) |
| 406 return result; | 411 return result; |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 516 | 521 |
| 517 // Now the policy is the owner of the target. | 522 // Now the policy is the owner of the target. |
| 518 if (!policy_base->AddTarget(target)) { | 523 if (!policy_base->AddTarget(target)) { |
| 519 return SpawnCleanup(target, 0); | 524 return SpawnCleanup(target, 0); |
| 520 } | 525 } |
| 521 | 526 |
| 522 // We are going to keep a pointer to the policy because we'll call it when | 527 // We are going to keep a pointer to the policy because we'll call it when |
| 523 // the job object generates notifications using the completion port. | 528 // the job object generates notifications using the completion port. |
| 524 policy_base->AddRef(); | 529 policy_base->AddRef(); |
| 525 if (job.IsValid()) { | 530 if (job.IsValid()) { |
| 526 scoped_ptr<JobTracker> tracker(new JobTracker(job.Take(), policy_base)); | 531 scoped_ptr<JobTracker> tracker(new JobTracker(job.Pass(), policy_base)); |
| 527 | 532 |
| 528 // There is no obvious recovery after failure here. Previous version with | 533 // There is no obvious recovery after failure here. Previous version with |
| 529 // SpawnCleanup() caused deletion of TargetProcess twice. crbug.com/480639 | 534 // SpawnCleanup() caused deletion of TargetProcess twice. crbug.com/480639 |
| 530 CHECK(AssociateCompletionPort(tracker->job, job_port_, tracker.get())); | 535 CHECK(AssociateCompletionPort(tracker->job.Get(), job_port_.Get(), |
| 536 tracker.get())); |
| 531 | 537 |
| 532 // Save the tracker because in cleanup we might need to force closing | 538 // Save the tracker because in cleanup we might need to force closing |
| 533 // the Jobs. | 539 // the Jobs. |
| 534 tracker_list_.push_back(tracker.release()); | 540 tracker_list_.push_back(tracker.release()); |
| 535 child_process_ids_.insert(process_info.process_id()); | 541 child_process_ids_.insert(process_info.process_id()); |
| 536 } else { | 542 } else { |
| 537 // We have to signal the event once here because the completion port will | 543 // We have to signal the event once here because the completion port will |
| 538 // never get a message that this target is being terminated thus we should | 544 // never get a message that this target is being terminated thus we should |
| 539 // not block WaitForAllTargets until we have at least one target with job. | 545 // not block WaitForAllTargets until we have at least one target with job. |
| 540 if (child_process_ids_.empty()) | 546 if (child_process_ids_.empty()) |
| 541 ::SetEvent(no_targets_); | 547 ::SetEvent(no_targets_.Get()); |
| 542 // We can not track the life time of such processes and it is responsibility | 548 // We can not track the life time of such processes and it is responsibility |
| 543 // of the host application to make sure that spawned targets without jobs | 549 // of the host application to make sure that spawned targets without jobs |
| 544 // are terminated when the main application don't need them anymore. | 550 // are terminated when the main application don't need them anymore. |
| 545 // Sandbox policy engine needs to know that these processes are valid | 551 // Sandbox policy engine needs to know that these processes are valid |
| 546 // targets for e.g. BrokerDuplicateHandle so track them as peer processes. | 552 // targets for e.g. BrokerDuplicateHandle so track them as peer processes. |
| 547 AddTargetPeer(process_info.process_handle()); | 553 AddTargetPeer(process_info.process_handle()); |
| 548 } | 554 } |
| 549 | 555 |
| 550 *target_info = process_info.Take(); | 556 *target_info = process_info.Take(); |
| 551 return SBOX_ALL_OK; | 557 return SBOX_ALL_OK; |
| 552 } | 558 } |
| 553 | 559 |
| 554 | 560 |
| 555 ResultCode BrokerServicesBase::WaitForAllTargets() { | 561 ResultCode BrokerServicesBase::WaitForAllTargets() { |
| 556 ::WaitForSingleObject(no_targets_, INFINITE); | 562 ::WaitForSingleObject(no_targets_.Get(), INFINITE); |
| 557 return SBOX_ALL_OK; | 563 return SBOX_ALL_OK; |
| 558 } | 564 } |
| 559 | 565 |
| 560 bool BrokerServicesBase::IsActiveTarget(DWORD process_id) { | 566 bool BrokerServicesBase::IsActiveTarget(DWORD process_id) { |
| 561 AutoLock lock(&lock_); | 567 AutoLock lock(&lock_); |
| 562 return child_process_ids_.find(process_id) != child_process_ids_.end() || | 568 return child_process_ids_.find(process_id) != child_process_ids_.end() || |
| 563 peer_map_.find(process_id) != peer_map_.end(); | 569 peer_map_.find(process_id) != peer_map_.end(); |
| 564 } | 570 } |
| 565 | 571 |
| 566 VOID CALLBACK BrokerServicesBase::RemovePeer(PVOID parameter, BOOLEAN timeout) { | 572 VOID CALLBACK BrokerServicesBase::RemovePeer(PVOID parameter, BOOLEAN timeout) { |
| 567 PeerTracker* peer = reinterpret_cast<PeerTracker*>(parameter); | 573 PeerTracker* peer = reinterpret_cast<PeerTracker*>(parameter); |
| 568 // Don't check the return code because we this may fail (safely) at shutdown. | 574 // Don't check the return code because we this may fail (safely) at shutdown. |
| 569 ::PostQueuedCompletionStatus( | 575 ::PostQueuedCompletionStatus( |
| 570 peer->job_port, 0, THREAD_CTRL_REMOVE_PEER, | 576 peer->job_port, 0, THREAD_CTRL_REMOVE_PEER, |
| 571 reinterpret_cast<LPOVERLAPPED>(static_cast<uintptr_t>(peer->id))); | 577 reinterpret_cast<LPOVERLAPPED>(static_cast<uintptr_t>(peer->id))); |
| 572 } | 578 } |
| 573 | 579 |
| 574 ResultCode BrokerServicesBase::AddTargetPeer(HANDLE peer_process) { | 580 ResultCode BrokerServicesBase::AddTargetPeer(HANDLE peer_process) { |
| 575 scoped_ptr<PeerTracker> peer(new PeerTracker(::GetProcessId(peer_process), | 581 scoped_ptr<PeerTracker> peer(new PeerTracker(::GetProcessId(peer_process), |
| 576 job_port_)); | 582 job_port_.Get())); |
| 577 if (!peer->id) | 583 if (!peer->id) |
| 578 return SBOX_ERROR_GENERIC; | 584 return SBOX_ERROR_GENERIC; |
| 579 | 585 |
| 580 HANDLE process_handle; | 586 HANDLE process_handle; |
| 581 if (!::DuplicateHandle(::GetCurrentProcess(), peer_process, | 587 if (!::DuplicateHandle(::GetCurrentProcess(), peer_process, |
| 582 ::GetCurrentProcess(), &process_handle, | 588 ::GetCurrentProcess(), &process_handle, |
| 583 SYNCHRONIZE, FALSE, 0)) { | 589 SYNCHRONIZE, FALSE, 0)) { |
| 584 return SBOX_ERROR_GENERIC; | 590 return SBOX_ERROR_GENERIC; |
| 585 } | 591 } |
| 586 peer->process.Set(process_handle); | 592 peer->process.Set(process_handle); |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 621 return SBOX_ERROR_UNSUPPORTED; | 627 return SBOX_ERROR_UNSUPPORTED; |
| 622 | 628 |
| 623 base::string16 name = LookupAppContainer(sid); | 629 base::string16 name = LookupAppContainer(sid); |
| 624 if (name.empty()) | 630 if (name.empty()) |
| 625 return SBOX_ERROR_INVALID_APP_CONTAINER; | 631 return SBOX_ERROR_INVALID_APP_CONTAINER; |
| 626 | 632 |
| 627 return DeleteAppContainer(sid); | 633 return DeleteAppContainer(sid); |
| 628 } | 634 } |
| 629 | 635 |
| 630 } // namespace sandbox | 636 } // namespace sandbox |
| OLD | NEW |