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 19 matching lines...) Expand all Loading... |
30 // Utility function to associate a completion port to a job object. | 30 // Utility function to associate a completion port to a job object. |
31 bool AssociateCompletionPort(HANDLE job, HANDLE port, void* key) { | 31 bool AssociateCompletionPort(HANDLE job, HANDLE port, void* key) { |
32 JOBOBJECT_ASSOCIATE_COMPLETION_PORT job_acp = { key, port }; | 32 JOBOBJECT_ASSOCIATE_COMPLETION_PORT job_acp = { key, port }; |
33 return ::SetInformationJobObject(job, | 33 return ::SetInformationJobObject(job, |
34 JobObjectAssociateCompletionPortInformation, | 34 JobObjectAssociateCompletionPortInformation, |
35 &job_acp, sizeof(job_acp))? true : false; | 35 &job_acp, sizeof(job_acp))? true : false; |
36 } | 36 } |
37 | 37 |
38 // Utility function to do the cleanup necessary when something goes wrong | 38 // Utility function to do the cleanup necessary when something goes wrong |
39 // while in SpawnTarget and we must terminate the target process. | 39 // while in SpawnTarget and we must terminate the target process. |
40 sandbox::ResultCode SpawnCleanup(sandbox::TargetProcess* target, DWORD error) { | 40 sandbox::ResultCode SpawnCleanup(sandbox::TargetProcess* target) { |
41 if (0 == error) | |
42 error = ::GetLastError(); | |
43 | |
44 target->Terminate(); | 41 target->Terminate(); |
45 delete target; | 42 delete target; |
46 ::SetLastError(error); | |
47 return sandbox::SBOX_ERROR_GENERIC; | 43 return sandbox::SBOX_ERROR_GENERIC; |
48 } | 44 } |
49 | 45 |
50 // the different commands that you can send to the worker thread that | 46 // the different commands that you can send to the worker thread that |
51 // executes TargetEventsThread(). | 47 // executes TargetEventsThread(). |
52 enum { | 48 enum { |
53 THREAD_CTRL_NONE, | 49 THREAD_CTRL_NONE, |
54 THREAD_CTRL_QUIT, | 50 THREAD_CTRL_QUIT, |
55 THREAD_CTRL_LAST, | 51 THREAD_CTRL_LAST, |
56 }; | 52 }; |
(...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
266 | 262 |
267 NOTREACHED(); | 263 NOTREACHED(); |
268 return 0; | 264 return 0; |
269 } | 265 } |
270 | 266 |
271 // SpawnTarget does all the interesting sandbox setup and creates the target | 267 // SpawnTarget does all the interesting sandbox setup and creates the target |
272 // process inside the sandbox. | 268 // process inside the sandbox. |
273 ResultCode BrokerServicesBase::SpawnTarget(const wchar_t* exe_path, | 269 ResultCode BrokerServicesBase::SpawnTarget(const wchar_t* exe_path, |
274 const wchar_t* command_line, | 270 const wchar_t* command_line, |
275 TargetPolicy* policy, | 271 TargetPolicy* policy, |
| 272 ResultCode* last_warning, |
| 273 DWORD* last_error, |
276 PROCESS_INFORMATION* target_info) { | 274 PROCESS_INFORMATION* target_info) { |
277 if (!exe_path) | 275 if (!exe_path) |
278 return SBOX_ERROR_BAD_PARAMS; | 276 return SBOX_ERROR_BAD_PARAMS; |
279 | 277 |
280 if (!policy) | 278 if (!policy) |
281 return SBOX_ERROR_BAD_PARAMS; | 279 return SBOX_ERROR_BAD_PARAMS; |
282 | 280 |
283 // Even though the resources touched by SpawnTarget can be accessed in | 281 // Even though the resources touched by SpawnTarget can be accessed in |
284 // multiple threads, the method itself cannot be called from more than | 282 // multiple threads, the method itself cannot be called from more than |
285 // 1 thread. This is to protect the global variables used while setting up | 283 // 1 thread. This is to protect the global variables used while setting up |
286 // the child process. | 284 // the child process. |
287 static DWORD thread_id = ::GetCurrentThreadId(); | 285 static DWORD thread_id = ::GetCurrentThreadId(); |
288 DCHECK(thread_id == ::GetCurrentThreadId()); | 286 DCHECK(thread_id == ::GetCurrentThreadId()); |
| 287 *last_warning = SBOX_ALL_OK; |
289 | 288 |
290 AutoLock lock(&lock_); | 289 AutoLock lock(&lock_); |
291 | 290 |
292 // This downcast is safe as long as we control CreatePolicy() | 291 // This downcast is safe as long as we control CreatePolicy() |
293 PolicyBase* policy_base = static_cast<PolicyBase*>(policy); | 292 PolicyBase* policy_base = static_cast<PolicyBase*>(policy); |
294 | 293 |
295 // Construct the tokens and the job object that we are going to associate | 294 // Construct the tokens and the job object that we are going to associate |
296 // with the soon to be created target process. | 295 // with the soon to be created target process. |
297 base::win::ScopedHandle initial_token; | 296 base::win::ScopedHandle initial_token; |
298 base::win::ScopedHandle lockdown_token; | 297 base::win::ScopedHandle lockdown_token; |
299 base::win::ScopedHandle lowbox_token; | 298 base::win::ScopedHandle lowbox_token; |
300 ResultCode result = SBOX_ALL_OK; | 299 ResultCode result = SBOX_ALL_OK; |
301 | 300 |
302 result = | 301 result = |
303 policy_base->MakeTokens(&initial_token, &lockdown_token, &lowbox_token); | 302 policy_base->MakeTokens(&initial_token, &lockdown_token, &lowbox_token); |
304 if (SBOX_ALL_OK != result) | 303 if (SBOX_ALL_OK != result) |
305 return result; | 304 return result; |
| 305 if (lowbox_token.IsValid() && |
| 306 base::win::GetVersion() < base::win::VERSION_WIN8) { |
| 307 // We don't allow lowbox_token below Windows 8. |
| 308 return SBOX_ERROR_BAD_PARAMS; |
| 309 } |
306 | 310 |
307 base::win::ScopedHandle job; | 311 base::win::ScopedHandle job; |
308 result = policy_base->MakeJobObject(&job); | 312 result = policy_base->MakeJobObject(&job); |
309 if (SBOX_ALL_OK != result) | 313 if (SBOX_ALL_OK != result) |
310 return result; | 314 return result; |
311 | 315 |
312 // Initialize the startup information from the policy. | 316 // Initialize the startup information from the policy. |
313 base::win::StartupInformation startup_info; | 317 base::win::StartupInformation startup_info; |
314 // The liftime of |mitigations|, |inherit_handle_list| and | 318 // The liftime of |mitigations|, |inherit_handle_list| and |
315 // |child_process_creation| have to be at least as long as | 319 // |child_process_creation| have to be at least as long as |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
400 // Construct the thread pool here in case it is expensive. | 404 // Construct the thread pool here in case it is expensive. |
401 // The thread pool is shared by all the targets | 405 // The thread pool is shared by all the targets |
402 if (NULL == thread_pool_) | 406 if (NULL == thread_pool_) |
403 thread_pool_ = new Win2kThreadPool(); | 407 thread_pool_ = new Win2kThreadPool(); |
404 | 408 |
405 // Create the TargetProcess object and spawn the target suspended. Note that | 409 // Create the TargetProcess object and spawn the target suspended. Note that |
406 // Brokerservices does not own the target object. It is owned by the Policy. | 410 // Brokerservices does not own the target object. It is owned by the Policy. |
407 base::win::ScopedProcessInformation process_info; | 411 base::win::ScopedProcessInformation process_info; |
408 TargetProcess* target = | 412 TargetProcess* target = |
409 new TargetProcess(std::move(initial_token), std::move(lockdown_token), | 413 new TargetProcess(std::move(initial_token), std::move(lockdown_token), |
410 std::move(lowbox_token), job.Get(), thread_pool_); | 414 job.Get(), thread_pool_); |
411 | 415 |
412 DWORD win_result; | |
413 result = target->Create(exe_path, command_line, inherit_handles, startup_info, | 416 result = target->Create(exe_path, command_line, inherit_handles, startup_info, |
414 &process_info, &win_result); | 417 &process_info, last_error); |
415 | 418 |
416 if (result != SBOX_ALL_OK) { | 419 if (result != SBOX_ALL_OK) { |
417 SpawnCleanup(target, win_result); | 420 SpawnCleanup(target); |
418 return result; | 421 return result; |
419 } | 422 } |
420 | 423 |
| 424 if (lowbox_token.IsValid()) { |
| 425 *last_warning = target->AssignLowBoxToken(lowbox_token); |
| 426 // If this fails we continue, but report the error as a warning. |
| 427 // This is due to certain configurations causing the setting of the |
| 428 // token to fail post creation, and we'd rather continue if possible. |
| 429 if (*last_warning != SBOX_ALL_OK) |
| 430 *last_error = ::GetLastError(); |
| 431 } |
| 432 |
421 // Now the policy is the owner of the target. | 433 // Now the policy is the owner of the target. |
422 result = policy_base->AddTarget(target); | 434 result = policy_base->AddTarget(target); |
423 | 435 |
424 if (result != SBOX_ALL_OK) { | 436 if (result != SBOX_ALL_OK) { |
425 SpawnCleanup(target, 0); | 437 *last_error = ::GetLastError(); |
| 438 SpawnCleanup(target); |
426 return result; | 439 return result; |
427 } | 440 } |
428 | 441 |
429 // We are going to keep a pointer to the policy because we'll call it when | 442 // We are going to keep a pointer to the policy because we'll call it when |
430 // the job object generates notifications using the completion port. | 443 // the job object generates notifications using the completion port. |
431 policy_base->AddRef(); | 444 policy_base->AddRef(); |
432 if (job.IsValid()) { | 445 if (job.IsValid()) { |
433 std::unique_ptr<JobTracker> tracker( | 446 std::unique_ptr<JobTracker> tracker( |
434 new JobTracker(std::move(job), policy_base)); | 447 new JobTracker(std::move(job), policy_base)); |
435 | 448 |
(...skipping 23 matching lines...) Expand all Loading... |
459 ::WaitForSingleObject(no_targets_.Get(), INFINITE); | 472 ::WaitForSingleObject(no_targets_.Get(), INFINITE); |
460 return SBOX_ALL_OK; | 473 return SBOX_ALL_OK; |
461 } | 474 } |
462 | 475 |
463 bool BrokerServicesBase::IsActiveTarget(DWORD process_id) { | 476 bool BrokerServicesBase::IsActiveTarget(DWORD process_id) { |
464 AutoLock lock(&lock_); | 477 AutoLock lock(&lock_); |
465 return child_process_ids_.find(process_id) != child_process_ids_.end(); | 478 return child_process_ids_.find(process_id) != child_process_ids_.end(); |
466 } | 479 } |
467 | 480 |
468 } // namespace sandbox | 481 } // namespace sandbox |
OLD | NEW |