| 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 <vector> | 8 #include <vector> |
| 9 | 9 |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| 11 #include "base/macros.h" | 11 #include "base/macros.h" |
| 12 #include "base/memory/ref_counted.h" |
| 12 #include "base/memory/scoped_ptr.h" | 13 #include "base/memory/scoped_ptr.h" |
| 13 #include "base/stl_util.h" | 14 #include "base/stl_util.h" |
| 14 #include "base/threading/platform_thread.h" | 15 #include "base/threading/platform_thread.h" |
| 15 #include "base/win/scoped_handle.h" | 16 #include "base/win/scoped_handle.h" |
| 16 #include "base/win/scoped_process_information.h" | 17 #include "base/win/scoped_process_information.h" |
| 17 #include "base/win/startup_information.h" | 18 #include "base/win/startup_information.h" |
| 18 #include "base/win/windows_version.h" | 19 #include "base/win/windows_version.h" |
| 19 #include "sandbox/win/src/app_container.h" | 20 #include "sandbox/win/src/app_container.h" |
| 20 #include "sandbox/win/src/process_mitigations.h" | 21 #include "sandbox/win/src/process_mitigations.h" |
| 21 #include "sandbox/win/src/sandbox.h" | 22 #include "sandbox/win/src/sandbox.h" |
| (...skipping 29 matching lines...) Expand all Loading... |
| 51 enum { | 52 enum { |
| 52 THREAD_CTRL_NONE, | 53 THREAD_CTRL_NONE, |
| 53 THREAD_CTRL_REMOVE_PEER, | 54 THREAD_CTRL_REMOVE_PEER, |
| 54 THREAD_CTRL_QUIT, | 55 THREAD_CTRL_QUIT, |
| 55 THREAD_CTRL_LAST, | 56 THREAD_CTRL_LAST, |
| 56 }; | 57 }; |
| 57 | 58 |
| 58 // Helper structure that allows the Broker to associate a job notification | 59 // Helper structure that allows the Broker to associate a job notification |
| 59 // with a job object and with a policy. | 60 // with a job object and with a policy. |
| 60 struct JobTracker { | 61 struct JobTracker { |
| 61 JobTracker(base::win::ScopedHandle job, sandbox::TargetPolicy* policy) | 62 JobTracker(base::win::ScopedHandle job, |
| 62 : job(job.Pass()), policy(policy) { | 63 scoped_refptr<sandbox::TargetPolicy> policy) |
| 63 } | 64 : job(job.Pass()), policy(policy.Pass()) {} |
| 64 ~JobTracker() { | 65 ~JobTracker() { FreeResources(); } |
| 65 FreeResources(); | |
| 66 } | |
| 67 | 66 |
| 68 // Releases the Job and notifies the associated Policy object to release its | 67 // Releases the Job and notifies the associated Policy object to release its |
| 69 // resources as well. | 68 // resources as well. |
| 70 void FreeResources(); | 69 void FreeResources(); |
| 71 | 70 |
| 72 base::win::ScopedHandle job; | 71 base::win::ScopedHandle job; |
| 73 sandbox::TargetPolicy* policy; | 72 scoped_refptr<sandbox::TargetPolicy> policy; |
| 74 }; | 73 }; |
| 75 | 74 |
| 76 void JobTracker::FreeResources() { | 75 void JobTracker::FreeResources() { |
| 77 if (policy) { | 76 if (policy) { |
| 78 BOOL res = ::TerminateJobObject(job.Get(), sandbox::SBOX_ALL_OK); | 77 BOOL res = ::TerminateJobObject(job.Get(), sandbox::SBOX_ALL_OK); |
| 79 DCHECK(res); | 78 DCHECK(res); |
| 80 // Closing the job causes the target process to be destroyed so this needs | 79 // Closing the job causes the target process to be destroyed so this needs |
| 81 // to happen before calling OnJobEmpty(). | 80 // to happen before calling OnJobEmpty(). |
| 82 HANDLE stale_job_handle = job.Get(); | 81 HANDLE stale_job_handle = job.Get(); |
| 83 job.Close(); | 82 job.Close(); |
| 84 | 83 |
| 85 // In OnJobEmpty() we don't actually use the job handle directly. | 84 // In OnJobEmpty() we don't actually use the job handle directly. |
| 86 policy->OnJobEmpty(stale_job_handle); | 85 policy->OnJobEmpty(stale_job_handle); |
| 87 policy->Release(); | |
| 88 policy = NULL; | 86 policy = NULL; |
| 89 } | 87 } |
| 90 } | 88 } |
| 91 | 89 |
| 92 // Helper structure that allows the broker to track peer processes | 90 // Helper structure that allows the broker to track peer processes |
| 93 struct PeerTracker { | 91 struct PeerTracker { |
| 94 PeerTracker(DWORD process_id, HANDLE broker_job_port) | 92 PeerTracker(DWORD process_id, HANDLE broker_job_port) |
| 95 : wait_object(NULL), id(process_id), job_port(broker_job_port) { | 93 : wait_object(NULL), id(process_id), job_port(broker_job_port) { |
| 96 } | 94 } |
| 97 | 95 |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 167 | 165 |
| 168 // Cancel the wait events and delete remaining peer trackers. | 166 // Cancel the wait events and delete remaining peer trackers. |
| 169 for (PeerTrackerMap::iterator it = peer_map_.begin(); | 167 for (PeerTrackerMap::iterator it = peer_map_.begin(); |
| 170 it != peer_map_.end(); ++it) { | 168 it != peer_map_.end(); ++it) { |
| 171 DeregisterPeerTracker(it->second); | 169 DeregisterPeerTracker(it->second); |
| 172 } | 170 } |
| 173 | 171 |
| 174 ::DeleteCriticalSection(&lock_); | 172 ::DeleteCriticalSection(&lock_); |
| 175 } | 173 } |
| 176 | 174 |
| 177 TargetPolicy* BrokerServicesBase::CreatePolicy() { | 175 scoped_refptr<TargetPolicy> BrokerServicesBase::CreatePolicy() { |
| 178 return new TargetPolicy; | 176 return make_scoped_refptr(new TargetPolicy); |
| 179 } | 177 } |
| 180 | 178 |
| 181 // The worker thread stays in a loop waiting for asynchronous notifications | 179 // The worker thread stays in a loop waiting for asynchronous notifications |
| 182 // from the job objects. Right now we only care about knowing when the last | 180 // from the job objects. Right now we only care about knowing when the last |
| 183 // process on a job terminates, but in general this is the place to tell | 181 // process on a job terminates, but in general this is the place to tell |
| 184 // the policy about events. | 182 // the policy about events. |
| 185 DWORD WINAPI BrokerServicesBase::TargetEventsThread(PVOID param) { | 183 DWORD WINAPI BrokerServicesBase::TargetEventsThread(PVOID param) { |
| 186 if (NULL == param) | 184 if (NULL == param) |
| 187 return 1; | 185 return 1; |
| 188 | 186 |
| (...skipping 23 matching lines...) Expand all Loading... |
| 212 // that jobs can send and some of them depend on the job attributes set. | 210 // that jobs can send and some of them depend on the job attributes set. |
| 213 JobTracker* tracker = reinterpret_cast<JobTracker*>(key); | 211 JobTracker* tracker = reinterpret_cast<JobTracker*>(key); |
| 214 | 212 |
| 215 switch (events) { | 213 switch (events) { |
| 216 case JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO: { | 214 case JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO: { |
| 217 // The job object has signaled that the last process associated | 215 // The job object has signaled that the last process associated |
| 218 // with it has terminated. Assuming there is no way for a process | 216 // with it has terminated. Assuming there is no way for a process |
| 219 // to appear out of thin air in this job, it safe to assume that | 217 // to appear out of thin air in this job, it safe to assume that |
| 220 // we can tell the policy to destroy the target object, and for | 218 // we can tell the policy to destroy the target object, and for |
| 221 // us to release our reference to the policy object. | 219 // us to release our reference to the policy object. |
| 220 // TODO(rickyz): Is tracker removed from tracker_list_ or destroyed? |
| 222 tracker->FreeResources(); | 221 tracker->FreeResources(); |
| 223 break; | 222 break; |
| 224 } | 223 } |
| 225 | 224 |
| 226 case JOB_OBJECT_MSG_NEW_PROCESS: { | 225 case JOB_OBJECT_MSG_NEW_PROCESS: { |
| 227 ++target_counter; | 226 ++target_counter; |
| 228 if (1 == target_counter) { | 227 if (1 == target_counter) { |
| 229 ::ResetEvent(no_targets); | 228 ::ResetEvent(no_targets); |
| 230 } | 229 } |
| 231 break; | 230 break; |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 279 } | 278 } |
| 280 | 279 |
| 281 NOTREACHED(); | 280 NOTREACHED(); |
| 282 return 0; | 281 return 0; |
| 283 } | 282 } |
| 284 | 283 |
| 285 // SpawnTarget does all the interesting sandbox setup and creates the target | 284 // SpawnTarget does all the interesting sandbox setup and creates the target |
| 286 // process inside the sandbox. | 285 // process inside the sandbox. |
| 287 ResultCode BrokerServicesBase::SpawnTarget(const wchar_t* exe_path, | 286 ResultCode BrokerServicesBase::SpawnTarget(const wchar_t* exe_path, |
| 288 const wchar_t* command_line, | 287 const wchar_t* command_line, |
| 289 TargetPolicy* policy, | 288 scoped_refptr<TargetPolicy> policy, |
| 290 PROCESS_INFORMATION* target_info) { | 289 PROCESS_INFORMATION* target_info) { |
| 291 if (!exe_path) | 290 if (!exe_path) |
| 292 return SBOX_ERROR_BAD_PARAMS; | 291 return SBOX_ERROR_BAD_PARAMS; |
| 293 | 292 |
| 294 if (!policy) | 293 if (!policy) |
| 295 return SBOX_ERROR_BAD_PARAMS; | 294 return SBOX_ERROR_BAD_PARAMS; |
| 296 | 295 |
| 297 // Even though the resources touched by SpawnTarget can be accessed in | 296 // Even though the resources touched by SpawnTarget can be accessed in |
| 298 // multiple threads, the method itself cannot be called from more than | 297 // multiple threads, the method itself cannot be called from more than |
| 299 // 1 thread. This is to protect the global variables used while setting up | 298 // 1 thread. This is to protect the global variables used while setting up |
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 424 if (ERROR_SUCCESS != win_result) { | 423 if (ERROR_SUCCESS != win_result) { |
| 425 SpawnCleanup(target, win_result); | 424 SpawnCleanup(target, win_result); |
| 426 return SBOX_ERROR_CREATE_PROCESS; | 425 return SBOX_ERROR_CREATE_PROCESS; |
| 427 } | 426 } |
| 428 | 427 |
| 429 // Now the policy is the owner of the target. | 428 // Now the policy is the owner of the target. |
| 430 if (!policy->AddTarget(target)) { | 429 if (!policy->AddTarget(target)) { |
| 431 return SpawnCleanup(target, 0); | 430 return SpawnCleanup(target, 0); |
| 432 } | 431 } |
| 433 | 432 |
| 434 // We are going to keep a pointer to the policy because we'll call it when | |
| 435 // the job object generates notifications using the completion port. | |
| 436 policy->AddRef(); | |
| 437 if (job.IsValid()) { | 433 if (job.IsValid()) { |
| 438 scoped_ptr<JobTracker> tracker(new JobTracker(job.Pass(), policy)); | 434 scoped_ptr<JobTracker> tracker(new JobTracker(job.Pass(), policy.Pass())); |
| 439 | 435 |
| 440 // There is no obvious recovery after failure here. Previous version with | 436 // There is no obvious recovery after failure here. Previous version with |
| 441 // SpawnCleanup() caused deletion of TargetProcess twice. crbug.com/480639 | 437 // SpawnCleanup() caused deletion of TargetProcess twice. crbug.com/480639 |
| 442 CHECK(AssociateCompletionPort(tracker->job.Get(), job_port_.Get(), | 438 CHECK(AssociateCompletionPort(tracker->job.Get(), job_port_.Get(), |
| 443 tracker.get())); | 439 tracker.get())); |
| 444 | 440 |
| 445 // Save the tracker because in cleanup we might need to force closing | 441 // Save the tracker because in cleanup we might need to force closing |
| 446 // the Jobs. | 442 // the Jobs. |
| 447 tracker_list_.push_back(tracker.release()); | 443 tracker_list_.push_back(tracker.release()); |
| 448 child_process_ids_.insert(process_info.process_id()); | 444 child_process_ids_.insert(process_info.process_id()); |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 534 return SBOX_ERROR_UNSUPPORTED; | 530 return SBOX_ERROR_UNSUPPORTED; |
| 535 | 531 |
| 536 base::string16 name = LookupAppContainer(sid); | 532 base::string16 name = LookupAppContainer(sid); |
| 537 if (name.empty()) | 533 if (name.empty()) |
| 538 return SBOX_ERROR_INVALID_APP_CONTAINER; | 534 return SBOX_ERROR_INVALID_APP_CONTAINER; |
| 539 | 535 |
| 540 return DeleteAppContainer(sid); | 536 return DeleteAppContainer(sid); |
| 541 } | 537 } |
| 542 | 538 |
| 543 } // namespace sandbox | 539 } // namespace sandbox |
| OLD | NEW |