| 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 | 9 |
| 9 #include "base/logging.h" | 10 #include "base/logging.h" |
| 10 #include "base/macros.h" | 11 #include "base/macros.h" |
| 11 #include "base/memory/scoped_ptr.h" | 12 #include "base/memory/scoped_ptr.h" |
| 12 #include "base/stl_util.h" | 13 #include "base/stl_util.h" |
| 13 #include "base/threading/platform_thread.h" | 14 #include "base/threading/platform_thread.h" |
| 14 #include "base/win/scoped_handle.h" | 15 #include "base/win/scoped_handle.h" |
| 15 #include "base/win/scoped_process_information.h" | 16 #include "base/win/scoped_process_information.h" |
| 16 #include "base/win/startup_information.h" | 17 #include "base/win/startup_information.h" |
| 17 #include "base/win/windows_version.h" | 18 #include "base/win/windows_version.h" |
| 18 #include "sandbox/win/src/app_container.h" | 19 #include "sandbox/win/src/app_container.h" |
| 19 #include "sandbox/win/src/process_mitigations.h" | 20 #include "sandbox/win/src/process_mitigations.h" |
| 20 #include "sandbox/win/src/sandbox_policy_base.h" | |
| 21 #include "sandbox/win/src/sandbox.h" | 21 #include "sandbox/win/src/sandbox.h" |
| 22 #include "sandbox/win/src/sandbox_policy.h" |
| 22 #include "sandbox/win/src/target_process.h" | 23 #include "sandbox/win/src/target_process.h" |
| 23 #include "sandbox/win/src/win2k_threadpool.h" | 24 #include "sandbox/win/src/win2k_threadpool.h" |
| 24 #include "sandbox/win/src/win_utils.h" | 25 #include "sandbox/win/src/win_utils.h" |
| 25 | 26 |
| 26 namespace { | 27 namespace { |
| 27 | 28 |
| 28 // Utility function to associate a completion port to a job object. | 29 // Utility function to associate a completion port to a job object. |
| 29 bool AssociateCompletionPort(HANDLE job, HANDLE port, void* key) { | 30 bool AssociateCompletionPort(HANDLE job, HANDLE port, void* key) { |
| 30 JOBOBJECT_ASSOCIATE_COMPLETION_PORT job_acp = { key, port }; | 31 JOBOBJECT_ASSOCIATE_COMPLETION_PORT job_acp = { key, port }; |
| 31 return ::SetInformationJobObject(job, | 32 return ::SetInformationJobObject(job, |
| (...skipping 18 matching lines...) Expand all Loading... |
| 50 enum { | 51 enum { |
| 51 THREAD_CTRL_NONE, | 52 THREAD_CTRL_NONE, |
| 52 THREAD_CTRL_REMOVE_PEER, | 53 THREAD_CTRL_REMOVE_PEER, |
| 53 THREAD_CTRL_QUIT, | 54 THREAD_CTRL_QUIT, |
| 54 THREAD_CTRL_LAST, | 55 THREAD_CTRL_LAST, |
| 55 }; | 56 }; |
| 56 | 57 |
| 57 // Helper structure that allows the Broker to associate a job notification | 58 // Helper structure that allows the Broker to associate a job notification |
| 58 // with a job object and with a policy. | 59 // with a job object and with a policy. |
| 59 struct JobTracker { | 60 struct JobTracker { |
| 60 JobTracker(base::win::ScopedHandle job, sandbox::PolicyBase* policy) | 61 JobTracker(base::win::ScopedHandle job, sandbox::TargetPolicy* policy) |
| 61 : job(job.Pass()), policy(policy) { | 62 : job(job.Pass()), policy(policy) { |
| 62 } | 63 } |
| 63 ~JobTracker() { | 64 ~JobTracker() { |
| 64 FreeResources(); | 65 FreeResources(); |
| 65 } | 66 } |
| 66 | 67 |
| 67 // Releases the Job and notifies the associated Policy object to release its | 68 // Releases the Job and notifies the associated Policy object to release its |
| 68 // resources as well. | 69 // resources as well. |
| 69 void FreeResources(); | 70 void FreeResources(); |
| 70 | 71 |
| 71 base::win::ScopedHandle job; | 72 base::win::ScopedHandle job; |
| 72 sandbox::PolicyBase* policy; | 73 sandbox::TargetPolicy* policy; |
| 73 }; | 74 }; |
| 74 | 75 |
| 75 void JobTracker::FreeResources() { | 76 void JobTracker::FreeResources() { |
| 76 if (policy) { | 77 if (policy) { |
| 77 BOOL res = ::TerminateJobObject(job.Get(), sandbox::SBOX_ALL_OK); | 78 BOOL res = ::TerminateJobObject(job.Get(), sandbox::SBOX_ALL_OK); |
| 78 DCHECK(res); | 79 DCHECK(res); |
| 79 // Closing the job causes the target process to be destroyed so this needs | 80 // Closing the job causes the target process to be destroyed so this needs |
| 80 // to happen before calling OnJobEmpty(). | 81 // to happen before calling OnJobEmpty(). |
| 81 HANDLE stale_job_handle = job.Get(); | 82 HANDLE stale_job_handle = job.Get(); |
| 82 job.Close(); | 83 job.Close(); |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 167 // Cancel the wait events and delete remaining peer trackers. | 168 // Cancel the wait events and delete remaining peer trackers. |
| 168 for (PeerTrackerMap::iterator it = peer_map_.begin(); | 169 for (PeerTrackerMap::iterator it = peer_map_.begin(); |
| 169 it != peer_map_.end(); ++it) { | 170 it != peer_map_.end(); ++it) { |
| 170 DeregisterPeerTracker(it->second); | 171 DeregisterPeerTracker(it->second); |
| 171 } | 172 } |
| 172 | 173 |
| 173 ::DeleteCriticalSection(&lock_); | 174 ::DeleteCriticalSection(&lock_); |
| 174 } | 175 } |
| 175 | 176 |
| 176 TargetPolicy* BrokerServicesBase::CreatePolicy() { | 177 TargetPolicy* BrokerServicesBase::CreatePolicy() { |
| 177 // If you change the type of the object being created here you must also | 178 return new TargetPolicy; |
| 178 // change the downcast to it in SpawnTarget(). | |
| 179 return new PolicyBase; | |
| 180 } | 179 } |
| 181 | 180 |
| 182 // The worker thread stays in a loop waiting for asynchronous notifications | 181 // The worker thread stays in a loop waiting for asynchronous notifications |
| 183 // from the job objects. Right now we only care about knowing when the last | 182 // from the job objects. Right now we only care about knowing when the last |
| 184 // process on a job terminates, but in general this is the place to tell | 183 // process on a job terminates, but in general this is the place to tell |
| 185 // the policy about events. | 184 // the policy about events. |
| 186 DWORD WINAPI BrokerServicesBase::TargetEventsThread(PVOID param) { | 185 DWORD WINAPI BrokerServicesBase::TargetEventsThread(PVOID param) { |
| 187 if (NULL == param) | 186 if (NULL == param) |
| 188 return 1; | 187 return 1; |
| 189 | 188 |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 297 | 296 |
| 298 // Even though the resources touched by SpawnTarget can be accessed in | 297 // Even though the resources touched by SpawnTarget can be accessed in |
| 299 // multiple threads, the method itself cannot be called from more than | 298 // multiple threads, the method itself cannot be called from more than |
| 300 // 1 thread. This is to protect the global variables used while setting up | 299 // 1 thread. This is to protect the global variables used while setting up |
| 301 // the child process. | 300 // the child process. |
| 302 static DWORD thread_id = ::GetCurrentThreadId(); | 301 static DWORD thread_id = ::GetCurrentThreadId(); |
| 303 DCHECK(thread_id == ::GetCurrentThreadId()); | 302 DCHECK(thread_id == ::GetCurrentThreadId()); |
| 304 | 303 |
| 305 AutoLock lock(&lock_); | 304 AutoLock lock(&lock_); |
| 306 | 305 |
| 307 // This downcast is safe as long as we control CreatePolicy() | 306 if (policy->GetAppContainer() && policy->GetLowBoxSid()) |
| 308 PolicyBase* policy_base = static_cast<PolicyBase*>(policy); | |
| 309 | |
| 310 if (policy_base->GetAppContainer() && policy_base->GetLowBoxSid()) | |
| 311 return SBOX_ERROR_BAD_PARAMS; | 307 return SBOX_ERROR_BAD_PARAMS; |
| 312 | 308 |
| 313 // Construct the tokens and the job object that we are going to associate | 309 // Construct the tokens and the job object that we are going to associate |
| 314 // with the soon to be created target process. | 310 // with the soon to be created target process. |
| 315 base::win::ScopedHandle initial_token; | 311 base::win::ScopedHandle initial_token; |
| 316 base::win::ScopedHandle lockdown_token; | 312 base::win::ScopedHandle lockdown_token; |
| 317 base::win::ScopedHandle lowbox_token; | 313 base::win::ScopedHandle lowbox_token; |
| 318 ResultCode result = SBOX_ALL_OK; | 314 ResultCode result = SBOX_ALL_OK; |
| 319 | 315 |
| 320 result = | 316 result = policy->MakeTokens(&initial_token, &lockdown_token, &lowbox_token); |
| 321 policy_base->MakeTokens(&initial_token, &lockdown_token, &lowbox_token); | |
| 322 if (SBOX_ALL_OK != result) | 317 if (SBOX_ALL_OK != result) |
| 323 return result; | 318 return result; |
| 324 | 319 |
| 325 base::win::ScopedHandle job; | 320 base::win::ScopedHandle job; |
| 326 result = policy_base->MakeJobObject(&job); | 321 result = policy->MakeJobObject(&job); |
| 327 if (SBOX_ALL_OK != result) | 322 if (SBOX_ALL_OK != result) |
| 328 return result; | 323 return result; |
| 329 | 324 |
| 330 // Initialize the startup information from the policy. | 325 // Initialize the startup information from the policy. |
| 331 base::win::StartupInformation startup_info; | 326 base::win::StartupInformation startup_info; |
| 332 // The liftime of |mitigations| and |inherit_handle_list| have to be at least | 327 // The liftime of |mitigations| and |inherit_handle_list| have to be at least |
| 333 // as long as |startup_info| because |UpdateProcThreadAttribute| requires that | 328 // as long as |startup_info| because |UpdateProcThreadAttribute| requires that |
| 334 // its |lpValue| parameter persist until |DeleteProcThreadAttributeList| is | 329 // its |lpValue| parameter persist until |DeleteProcThreadAttributeList| is |
| 335 // called; StartupInformation's destructor makes such a call. | 330 // called; StartupInformation's destructor makes such a call. |
| 336 DWORD64 mitigations; | 331 DWORD64 mitigations; |
| 337 | 332 |
| 338 std::vector<HANDLE> inherited_handle_list; | 333 std::vector<HANDLE> inherited_handle_list; |
| 339 | 334 |
| 340 base::string16 desktop = policy_base->GetAlternateDesktop(); | 335 base::string16 desktop = policy->GetAlternateDesktop(); |
| 341 if (!desktop.empty()) { | 336 if (!desktop.empty()) { |
| 342 startup_info.startup_info()->lpDesktop = | 337 startup_info.startup_info()->lpDesktop = |
| 343 const_cast<wchar_t*>(desktop.c_str()); | 338 const_cast<wchar_t*>(desktop.c_str()); |
| 344 } | 339 } |
| 345 | 340 |
| 346 bool inherit_handles = false; | 341 bool inherit_handles = false; |
| 347 | 342 |
| 348 if (base::win::GetVersion() >= base::win::VERSION_VISTA) { | 343 if (base::win::GetVersion() >= base::win::VERSION_VISTA) { |
| 349 int attribute_count = 0; | 344 int attribute_count = 0; |
| 350 const AppContainerAttributes* app_container = | 345 const AppContainerAttributes* app_container = policy->GetAppContainer(); |
| 351 policy_base->GetAppContainer(); | |
| 352 if (app_container) | 346 if (app_container) |
| 353 ++attribute_count; | 347 ++attribute_count; |
| 354 | 348 |
| 355 size_t mitigations_size; | 349 size_t mitigations_size; |
| 356 ConvertProcessMitigationsToPolicy(policy->GetProcessMitigations(), | 350 ConvertProcessMitigationsToPolicy(policy->GetProcessMitigations(), |
| 357 &mitigations, &mitigations_size); | 351 &mitigations, &mitigations_size); |
| 358 if (mitigations) | 352 if (mitigations) |
| 359 ++attribute_count; | 353 ++attribute_count; |
| 360 | 354 |
| 361 HANDLE stdout_handle = policy_base->GetStdoutHandle(); | 355 HANDLE stdout_handle = policy->GetStdoutHandle(); |
| 362 HANDLE stderr_handle = policy_base->GetStderrHandle(); | 356 HANDLE stderr_handle = policy->GetStderrHandle(); |
| 363 | 357 |
| 364 if (stdout_handle != INVALID_HANDLE_VALUE) | 358 if (stdout_handle != INVALID_HANDLE_VALUE) |
| 365 inherited_handle_list.push_back(stdout_handle); | 359 inherited_handle_list.push_back(stdout_handle); |
| 366 | 360 |
| 367 // Handles in the list must be unique. | 361 // Handles in the list must be unique. |
| 368 if (stderr_handle != stdout_handle && stderr_handle != INVALID_HANDLE_VALUE) | 362 if (stderr_handle != stdout_handle && stderr_handle != INVALID_HANDLE_VALUE) |
| 369 inherited_handle_list.push_back(stderr_handle); | 363 inherited_handle_list.push_back(stderr_handle); |
| 370 | 364 |
| 371 const HandleList& policy_handle_list = policy_base->GetHandlesBeingShared(); | 365 const HandleList& policy_handle_list = policy->GetHandlesBeingShared(); |
| 372 | 366 |
| 373 for (auto handle : policy_handle_list) | 367 for (auto handle : policy_handle_list) |
| 374 inherited_handle_list.push_back(handle->Get()); | 368 inherited_handle_list.push_back(handle->Get()); |
| 375 | 369 |
| 376 if (inherited_handle_list.size()) | 370 if (inherited_handle_list.size()) |
| 377 ++attribute_count; | 371 ++attribute_count; |
| 378 | 372 |
| 379 if (!startup_info.InitializeProcThreadAttributeList(attribute_count)) | 373 if (!startup_info.InitializeProcThreadAttributeList(attribute_count)) |
| 380 return SBOX_ERROR_PROC_THREAD_ATTRIBUTES; | 374 return SBOX_ERROR_PROC_THREAD_ATTRIBUTES; |
| 381 | 375 |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 418 // Create the TargetProces object and spawn the target suspended. Note that | 412 // Create the TargetProces object and spawn the target suspended. Note that |
| 419 // Brokerservices does not own the target object. It is owned by the Policy. | 413 // Brokerservices does not own the target object. It is owned by the Policy. |
| 420 base::win::ScopedProcessInformation process_info; | 414 base::win::ScopedProcessInformation process_info; |
| 421 TargetProcess* target = | 415 TargetProcess* target = |
| 422 new TargetProcess(initial_token.Pass(), lockdown_token.Pass(), | 416 new TargetProcess(initial_token.Pass(), lockdown_token.Pass(), |
| 423 lowbox_token.Pass(), job.Get(), thread_pool_); | 417 lowbox_token.Pass(), job.Get(), thread_pool_); |
| 424 | 418 |
| 425 DWORD win_result = target->Create(exe_path, command_line, inherit_handles, | 419 DWORD win_result = target->Create(exe_path, command_line, inherit_handles, |
| 426 startup_info, &process_info); | 420 startup_info, &process_info); |
| 427 | 421 |
| 428 policy_base->ClearSharedHandles(); | 422 policy->ClearSharedHandles(); |
| 429 | 423 |
| 430 if (ERROR_SUCCESS != win_result) { | 424 if (ERROR_SUCCESS != win_result) { |
| 431 SpawnCleanup(target, win_result); | 425 SpawnCleanup(target, win_result); |
| 432 return SBOX_ERROR_CREATE_PROCESS; | 426 return SBOX_ERROR_CREATE_PROCESS; |
| 433 } | 427 } |
| 434 | 428 |
| 435 // Now the policy is the owner of the target. | 429 // Now the policy is the owner of the target. |
| 436 if (!policy_base->AddTarget(target)) { | 430 if (!policy->AddTarget(target)) { |
| 437 return SpawnCleanup(target, 0); | 431 return SpawnCleanup(target, 0); |
| 438 } | 432 } |
| 439 | 433 |
| 440 // We are going to keep a pointer to the policy because we'll call it when | 434 // We are going to keep a pointer to the policy because we'll call it when |
| 441 // the job object generates notifications using the completion port. | 435 // the job object generates notifications using the completion port. |
| 442 policy_base->AddRef(); | 436 policy->AddRef(); |
| 443 if (job.IsValid()) { | 437 if (job.IsValid()) { |
| 444 scoped_ptr<JobTracker> tracker(new JobTracker(job.Pass(), policy_base)); | 438 scoped_ptr<JobTracker> tracker(new JobTracker(job.Pass(), policy)); |
| 445 | 439 |
| 446 // There is no obvious recovery after failure here. Previous version with | 440 // There is no obvious recovery after failure here. Previous version with |
| 447 // SpawnCleanup() caused deletion of TargetProcess twice. crbug.com/480639 | 441 // SpawnCleanup() caused deletion of TargetProcess twice. crbug.com/480639 |
| 448 CHECK(AssociateCompletionPort(tracker->job.Get(), job_port_.Get(), | 442 CHECK(AssociateCompletionPort(tracker->job.Get(), job_port_.Get(), |
| 449 tracker.get())); | 443 tracker.get())); |
| 450 | 444 |
| 451 // Save the tracker because in cleanup we might need to force closing | 445 // Save the tracker because in cleanup we might need to force closing |
| 452 // the Jobs. | 446 // the Jobs. |
| 453 tracker_list_.push_back(tracker.release()); | 447 tracker_list_.push_back(tracker.release()); |
| 454 child_process_ids_.insert(process_info.process_id()); | 448 child_process_ids_.insert(process_info.process_id()); |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 540 return SBOX_ERROR_UNSUPPORTED; | 534 return SBOX_ERROR_UNSUPPORTED; |
| 541 | 535 |
| 542 base::string16 name = LookupAppContainer(sid); | 536 base::string16 name = LookupAppContainer(sid); |
| 543 if (name.empty()) | 537 if (name.empty()) |
| 544 return SBOX_ERROR_INVALID_APP_CONTAINER; | 538 return SBOX_ERROR_INVALID_APP_CONTAINER; |
| 545 | 539 |
| 546 return DeleteAppContainer(sid); | 540 return DeleteAppContainer(sid); |
| 547 } | 541 } |
| 548 | 542 |
| 549 } // namespace sandbox | 543 } // namespace sandbox |
| OLD | NEW |