Chromium Code Reviews| 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 #include <stddef.h> | 8 #include <stddef.h> |
| 9 | 9 |
| 10 #include <memory> | 10 #include <memory> |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 47 // executes TargetEventsThread(). | 47 // executes TargetEventsThread(). |
| 48 enum { | 48 enum { |
| 49 THREAD_CTRL_NONE, | 49 THREAD_CTRL_NONE, |
| 50 THREAD_CTRL_QUIT, | 50 THREAD_CTRL_QUIT, |
| 51 THREAD_CTRL_LAST, | 51 THREAD_CTRL_LAST, |
| 52 }; | 52 }; |
| 53 | 53 |
| 54 // Helper structure that allows the Broker to associate a job notification | 54 // Helper structure that allows the Broker to associate a job notification |
| 55 // with a job object and with a policy. | 55 // with a job object and with a policy. |
| 56 struct JobTracker { | 56 struct JobTracker { |
| 57 JobTracker(base::win::ScopedHandle job, sandbox::PolicyBase* policy) | 57 JobTracker(base::win::ScopedHandle job, |
| 58 scoped_refptr<sandbox::PolicyBase> policy) | |
| 58 : job(std::move(job)), policy(policy) {} | 59 : job(std::move(job)), policy(policy) {} |
| 59 ~JobTracker() { | 60 ~JobTracker() { |
| 60 FreeResources(); | 61 FreeResources(); |
| 61 } | 62 } |
| 62 | 63 |
| 63 // Releases the Job and notifies the associated Policy object to release its | 64 // Releases the Job and notifies the associated Policy object to release its |
| 64 // resources as well. | 65 // resources as well. |
| 65 void FreeResources(); | 66 void FreeResources(); |
| 66 | 67 |
| 67 base::win::ScopedHandle job; | 68 base::win::ScopedHandle job; |
| 68 sandbox::PolicyBase* policy; | 69 scoped_refptr<sandbox::PolicyBase> policy; |
| 69 }; | 70 }; |
| 70 | 71 |
| 71 void JobTracker::FreeResources() { | 72 void JobTracker::FreeResources() { |
| 72 if (policy) { | 73 if (policy) { |
| 73 BOOL res = ::TerminateJobObject(job.Get(), sandbox::SBOX_ALL_OK); | 74 BOOL res = ::TerminateJobObject(job.Get(), sandbox::SBOX_ALL_OK); |
| 74 DCHECK(res); | 75 DCHECK(res); |
| 75 // Closing the job causes the target process to be destroyed so this needs | 76 // Closing the job causes the target process to be destroyed so this needs |
| 76 // to happen before calling OnJobEmpty(). | 77 // to happen before calling OnJobEmpty(). |
| 77 HANDLE stale_job_handle = job.Get(); | 78 HANDLE stale_job_handle = job.Get(); |
| 78 job.Close(); | 79 job.Close(); |
| 79 | 80 |
| 80 // In OnJobEmpty() we don't actually use the job handle directly. | 81 // In OnJobEmpty() we don't actually use the job handle directly. |
| 81 policy->OnJobEmpty(stale_job_handle); | 82 policy->OnJobEmpty(stale_job_handle); |
| 82 policy->Release(); | 83 policy = nullptr; |
| 83 policy = NULL; | |
| 84 } | 84 } |
| 85 } | 85 } |
| 86 | 86 |
| 87 } // namespace | 87 } // namespace |
| 88 | 88 |
| 89 namespace sandbox { | 89 namespace sandbox { |
| 90 | 90 |
| 91 BrokerServicesBase::BrokerServicesBase() : thread_pool_(NULL) { | 91 BrokerServicesBase::BrokerServicesBase() : thread_pool_(NULL) { |
| 92 } | 92 } |
| 93 | 93 |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 135 NOTREACHED(); | 135 NOTREACHED(); |
| 136 return; | 136 return; |
| 137 } | 137 } |
| 138 | 138 |
| 139 base::STLDeleteElements(&tracker_list_); | 139 base::STLDeleteElements(&tracker_list_); |
| 140 delete thread_pool_; | 140 delete thread_pool_; |
| 141 | 141 |
| 142 ::DeleteCriticalSection(&lock_); | 142 ::DeleteCriticalSection(&lock_); |
| 143 } | 143 } |
| 144 | 144 |
| 145 TargetPolicy* BrokerServicesBase::CreatePolicy() { | 145 scoped_refptr<TargetPolicy> BrokerServicesBase::CreatePolicy() { |
| 146 // If you change the type of the object being created here you must also | 146 // If you change the type of the object being created here you must also |
| 147 // change the downcast to it in SpawnTarget(). | 147 // change the downcast to it in SpawnTarget(). |
| 148 return new PolicyBase; | 148 scoped_refptr<TargetPolicy> policy(new PolicyBase); |
| 149 // PolicyBase starts with refcount 1. | |
|
piman
2016/09/13 22:29:07
nit: could we fix that?
| |
| 150 policy->Release(); | |
| 151 return policy; | |
| 149 } | 152 } |
| 150 | 153 |
| 151 // The worker thread stays in a loop waiting for asynchronous notifications | 154 // The worker thread stays in a loop waiting for asynchronous notifications |
| 152 // from the job objects. Right now we only care about knowing when the last | 155 // from the job objects. Right now we only care about knowing when the last |
| 153 // process on a job terminates, but in general this is the place to tell | 156 // process on a job terminates, but in general this is the place to tell |
| 154 // the policy about events. | 157 // the policy about events. |
| 155 DWORD WINAPI BrokerServicesBase::TargetEventsThread(PVOID param) { | 158 DWORD WINAPI BrokerServicesBase::TargetEventsThread(PVOID param) { |
| 156 if (NULL == param) | 159 if (NULL == param) |
| 157 return 1; | 160 return 1; |
| 158 | 161 |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 261 } | 264 } |
| 262 | 265 |
| 263 NOTREACHED(); | 266 NOTREACHED(); |
| 264 return 0; | 267 return 0; |
| 265 } | 268 } |
| 266 | 269 |
| 267 // SpawnTarget does all the interesting sandbox setup and creates the target | 270 // SpawnTarget does all the interesting sandbox setup and creates the target |
| 268 // process inside the sandbox. | 271 // process inside the sandbox. |
| 269 ResultCode BrokerServicesBase::SpawnTarget(const wchar_t* exe_path, | 272 ResultCode BrokerServicesBase::SpawnTarget(const wchar_t* exe_path, |
| 270 const wchar_t* command_line, | 273 const wchar_t* command_line, |
| 271 TargetPolicy* policy, | 274 scoped_refptr<TargetPolicy> policy, |
| 272 ResultCode* last_warning, | 275 ResultCode* last_warning, |
| 273 DWORD* last_error, | 276 DWORD* last_error, |
| 274 PROCESS_INFORMATION* target_info) { | 277 PROCESS_INFORMATION* target_info) { |
| 275 if (!exe_path) | 278 if (!exe_path) |
| 276 return SBOX_ERROR_BAD_PARAMS; | 279 return SBOX_ERROR_BAD_PARAMS; |
| 277 | 280 |
| 278 if (!policy) | 281 if (!policy) |
| 279 return SBOX_ERROR_BAD_PARAMS; | 282 return SBOX_ERROR_BAD_PARAMS; |
| 280 | 283 |
| 281 // Even though the resources touched by SpawnTarget can be accessed in | 284 // Even though the resources touched by SpawnTarget can be accessed in |
| 282 // multiple threads, the method itself cannot be called from more than | 285 // multiple threads, the method itself cannot be called from more than |
| 283 // 1 thread. This is to protect the global variables used while setting up | 286 // 1 thread. This is to protect the global variables used while setting up |
| 284 // the child process. | 287 // the child process. |
| 285 static DWORD thread_id = ::GetCurrentThreadId(); | 288 static DWORD thread_id = ::GetCurrentThreadId(); |
| 286 DCHECK(thread_id == ::GetCurrentThreadId()); | 289 DCHECK(thread_id == ::GetCurrentThreadId()); |
| 287 *last_warning = SBOX_ALL_OK; | 290 *last_warning = SBOX_ALL_OK; |
| 288 | 291 |
| 289 AutoLock lock(&lock_); | 292 AutoLock lock(&lock_); |
| 290 | 293 |
| 291 // This downcast is safe as long as we control CreatePolicy() | 294 // This downcast is safe as long as we control CreatePolicy() |
| 292 PolicyBase* policy_base = static_cast<PolicyBase*>(policy); | 295 scoped_refptr<PolicyBase> policy_base(static_cast<PolicyBase*>(policy.get())); |
| 293 | 296 |
| 294 // Construct the tokens and the job object that we are going to associate | 297 // Construct the tokens and the job object that we are going to associate |
| 295 // with the soon to be created target process. | 298 // with the soon to be created target process. |
| 296 base::win::ScopedHandle initial_token; | 299 base::win::ScopedHandle initial_token; |
| 297 base::win::ScopedHandle lockdown_token; | 300 base::win::ScopedHandle lockdown_token; |
| 298 base::win::ScopedHandle lowbox_token; | 301 base::win::ScopedHandle lowbox_token; |
| 299 ResultCode result = SBOX_ALL_OK; | 302 ResultCode result = SBOX_ALL_OK; |
| 300 | 303 |
| 301 result = | 304 result = |
| 302 policy_base->MakeTokens(&initial_token, &lockdown_token, &lowbox_token); | 305 policy_base->MakeTokens(&initial_token, &lockdown_token, &lowbox_token); |
| (...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 434 result = policy_base->AddTarget(target); | 437 result = policy_base->AddTarget(target); |
| 435 | 438 |
| 436 if (result != SBOX_ALL_OK) { | 439 if (result != SBOX_ALL_OK) { |
| 437 *last_error = ::GetLastError(); | 440 *last_error = ::GetLastError(); |
| 438 SpawnCleanup(target); | 441 SpawnCleanup(target); |
| 439 return result; | 442 return result; |
| 440 } | 443 } |
| 441 | 444 |
| 442 // We are going to keep a pointer to the policy because we'll call it when | 445 // We are going to keep a pointer to the policy because we'll call it when |
| 443 // the job object generates notifications using the completion port. | 446 // the job object generates notifications using the completion port. |
| 444 policy_base->AddRef(); | |
| 445 if (job.IsValid()) { | 447 if (job.IsValid()) { |
| 446 std::unique_ptr<JobTracker> tracker( | 448 std::unique_ptr<JobTracker> tracker( |
| 447 new JobTracker(std::move(job), policy_base)); | 449 new JobTracker(std::move(job), policy_base)); |
| 448 | 450 |
| 449 // There is no obvious recovery after failure here. Previous version with | 451 // There is no obvious recovery after failure here. Previous version with |
| 450 // SpawnCleanup() caused deletion of TargetProcess twice. crbug.com/480639 | 452 // SpawnCleanup() caused deletion of TargetProcess twice. crbug.com/480639 |
| 451 CHECK(AssociateCompletionPort(tracker->job.Get(), job_port_.Get(), | 453 CHECK(AssociateCompletionPort(tracker->job.Get(), job_port_.Get(), |
| 452 tracker.get())); | 454 tracker.get())); |
| 453 | 455 |
| 454 // Save the tracker because in cleanup we might need to force closing | 456 // Save the tracker because in cleanup we might need to force closing |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 472 ::WaitForSingleObject(no_targets_.Get(), INFINITE); | 474 ::WaitForSingleObject(no_targets_.Get(), INFINITE); |
| 473 return SBOX_ALL_OK; | 475 return SBOX_ALL_OK; |
| 474 } | 476 } |
| 475 | 477 |
| 476 bool BrokerServicesBase::IsActiveTarget(DWORD process_id) { | 478 bool BrokerServicesBase::IsActiveTarget(DWORD process_id) { |
| 477 AutoLock lock(&lock_); | 479 AutoLock lock(&lock_); |
| 478 return child_process_ids_.find(process_id) != child_process_ids_.end(); | 480 return child_process_ids_.find(process_id) != child_process_ids_.end(); |
| 479 } | 481 } |
| 480 | 482 |
| 481 } // namespace sandbox | 483 } // namespace sandbox |
| OLD | NEW |