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 |