Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(59)

Side by Side Diff: sandbox/win/src/broker_services.cc

Issue 2646043002: Reland "Fix sandbox::PolicyBase leak" (Closed)
Patch Set: Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 <utility> 10 #include <utility>
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
46 // executes TargetEventsThread(). 46 // executes TargetEventsThread().
47 enum { 47 enum {
48 THREAD_CTRL_NONE, 48 THREAD_CTRL_NONE,
49 THREAD_CTRL_QUIT, 49 THREAD_CTRL_QUIT,
50 THREAD_CTRL_LAST, 50 THREAD_CTRL_LAST,
51 }; 51 };
52 52
53 // Helper structure that allows the Broker to associate a job notification 53 // Helper structure that allows the Broker to associate a job notification
54 // with a job object and with a policy. 54 // with a job object and with a policy.
55 struct JobTracker { 55 struct JobTracker {
56 JobTracker(base::win::ScopedHandle job, sandbox::PolicyBase* policy) 56 JobTracker(base::win::ScopedHandle job,
57 scoped_refptr<sandbox::PolicyBase> policy)
57 : job(std::move(job)), policy(policy) {} 58 : job(std::move(job)), policy(policy) {}
58 ~JobTracker() { 59 ~JobTracker() {
59 FreeResources(); 60 FreeResources();
60 } 61 }
61 62
62 // Releases the Job and notifies the associated Policy object to release its 63 // Releases the Job and notifies the associated Policy object to release its
63 // resources as well. 64 // resources as well.
64 void FreeResources(); 65 void FreeResources();
65 66
66 base::win::ScopedHandle job; 67 base::win::ScopedHandle job;
67 sandbox::PolicyBase* policy; 68 scoped_refptr<sandbox::PolicyBase> policy;
68 }; 69 };
69 70
70 void JobTracker::FreeResources() { 71 void JobTracker::FreeResources() {
71 if (policy) { 72 if (policy) {
72 BOOL res = ::TerminateJobObject(job.Get(), sandbox::SBOX_ALL_OK); 73 BOOL res = ::TerminateJobObject(job.Get(), sandbox::SBOX_ALL_OK);
73 DCHECK(res); 74 DCHECK(res);
74 // Closing the job causes the target process to be destroyed so this needs 75 // Closing the job causes the target process to be destroyed so this needs
75 // to happen before calling OnJobEmpty(). 76 // to happen before calling OnJobEmpty().
76 HANDLE stale_job_handle = job.Get(); 77 HANDLE stale_job_handle = job.Get();
77 job.Close(); 78 job.Close();
78 79
79 // In OnJobEmpty() we don't actually use the job handle directly. 80 // In OnJobEmpty() we don't actually use the job handle directly.
80 policy->OnJobEmpty(stale_job_handle); 81 policy->OnJobEmpty(stale_job_handle);
81 policy->Release(); 82 policy = nullptr;
82 policy = NULL;
83 } 83 }
84 } 84 }
85 85
86 } // namespace 86 } // namespace
87 87
88 namespace sandbox { 88 namespace sandbox {
89 89
90 BrokerServicesBase::BrokerServicesBase() {} 90 BrokerServicesBase::BrokerServicesBase() {}
91 91
92 // The broker uses a dedicated worker thread that services the job completion 92 // The broker uses a dedicated worker thread that services the job completion
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
133 NOTREACHED(); 133 NOTREACHED();
134 return; 134 return;
135 } 135 }
136 136
137 tracker_list_.clear(); 137 tracker_list_.clear();
138 thread_pool_.reset(); 138 thread_pool_.reset();
139 139
140 ::DeleteCriticalSection(&lock_); 140 ::DeleteCriticalSection(&lock_);
141 } 141 }
142 142
143 TargetPolicy* BrokerServicesBase::CreatePolicy() { 143 scoped_refptr<TargetPolicy> BrokerServicesBase::CreatePolicy() {
144 // If you change the type of the object being created here you must also 144 // If you change the type of the object being created here you must also
145 // change the downcast to it in SpawnTarget(). 145 // change the downcast to it in SpawnTarget().
146 return new PolicyBase; 146 scoped_refptr<TargetPolicy> policy(new PolicyBase);
147 // PolicyBase starts with refcount 1.
148 policy->Release();
149 return policy;
147 } 150 }
148 151
149 // The worker thread stays in a loop waiting for asynchronous notifications 152 // The worker thread stays in a loop waiting for asynchronous notifications
150 // from the job objects. Right now we only care about knowing when the last 153 // from the job objects. Right now we only care about knowing when the last
151 // process on a job terminates, but in general this is the place to tell 154 // process on a job terminates, but in general this is the place to tell
152 // the policy about events. 155 // the policy about events.
153 DWORD WINAPI BrokerServicesBase::TargetEventsThread(PVOID param) { 156 DWORD WINAPI BrokerServicesBase::TargetEventsThread(PVOID param) {
154 if (NULL == param) 157 if (NULL == param)
155 return 1; 158 return 1;
156 159
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after
259 } 262 }
260 263
261 NOTREACHED(); 264 NOTREACHED();
262 return 0; 265 return 0;
263 } 266 }
264 267
265 // SpawnTarget does all the interesting sandbox setup and creates the target 268 // SpawnTarget does all the interesting sandbox setup and creates the target
266 // process inside the sandbox. 269 // process inside the sandbox.
267 ResultCode BrokerServicesBase::SpawnTarget(const wchar_t* exe_path, 270 ResultCode BrokerServicesBase::SpawnTarget(const wchar_t* exe_path,
268 const wchar_t* command_line, 271 const wchar_t* command_line,
269 TargetPolicy* policy, 272 scoped_refptr<TargetPolicy> policy,
270 ResultCode* last_warning, 273 ResultCode* last_warning,
271 DWORD* last_error, 274 DWORD* last_error,
272 PROCESS_INFORMATION* target_info) { 275 PROCESS_INFORMATION* target_info) {
273 if (!exe_path) 276 if (!exe_path)
274 return SBOX_ERROR_BAD_PARAMS; 277 return SBOX_ERROR_BAD_PARAMS;
275 278
276 if (!policy) 279 if (!policy)
277 return SBOX_ERROR_BAD_PARAMS; 280 return SBOX_ERROR_BAD_PARAMS;
278 281
279 // Even though the resources touched by SpawnTarget can be accessed in 282 // Even though the resources touched by SpawnTarget can be accessed in
280 // multiple threads, the method itself cannot be called from more than 283 // multiple threads, the method itself cannot be called from more than
281 // 1 thread. This is to protect the global variables used while setting up 284 // 1 thread. This is to protect the global variables used while setting up
282 // the child process. 285 // the child process.
283 static DWORD thread_id = ::GetCurrentThreadId(); 286 static DWORD thread_id = ::GetCurrentThreadId();
284 DCHECK(thread_id == ::GetCurrentThreadId()); 287 DCHECK(thread_id == ::GetCurrentThreadId());
285 *last_warning = SBOX_ALL_OK; 288 *last_warning = SBOX_ALL_OK;
286 289
287 AutoLock lock(&lock_); 290 AutoLock lock(&lock_);
288 291
289 // This downcast is safe as long as we control CreatePolicy() 292 // This downcast is safe as long as we control CreatePolicy()
290 PolicyBase* policy_base = static_cast<PolicyBase*>(policy); 293 scoped_refptr<PolicyBase> policy_base(static_cast<PolicyBase*>(policy.get()));
291 294
292 // Construct the tokens and the job object that we are going to associate 295 // Construct the tokens and the job object that we are going to associate
293 // with the soon to be created target process. 296 // with the soon to be created target process.
294 base::win::ScopedHandle initial_token; 297 base::win::ScopedHandle initial_token;
295 base::win::ScopedHandle lockdown_token; 298 base::win::ScopedHandle lockdown_token;
296 base::win::ScopedHandle lowbox_token; 299 base::win::ScopedHandle lowbox_token;
297 ResultCode result = SBOX_ALL_OK; 300 ResultCode result = SBOX_ALL_OK;
298 301
299 result = 302 result =
300 policy_base->MakeTokens(&initial_token, &lockdown_token, &lowbox_token); 303 policy_base->MakeTokens(&initial_token, &lockdown_token, &lowbox_token);
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after
432 result = policy_base->AddTarget(target); 435 result = policy_base->AddTarget(target);
433 436
434 if (result != SBOX_ALL_OK) { 437 if (result != SBOX_ALL_OK) {
435 *last_error = ::GetLastError(); 438 *last_error = ::GetLastError();
436 SpawnCleanup(target); 439 SpawnCleanup(target);
437 return result; 440 return result;
438 } 441 }
439 442
440 // We are going to keep a pointer to the policy because we'll call it when 443 // 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. 444 // the job object generates notifications using the completion port.
442 policy_base->AddRef();
443 if (job.IsValid()) { 445 if (job.IsValid()) {
444 std::unique_ptr<JobTracker> tracker = 446 std::unique_ptr<JobTracker> tracker =
445 base::MakeUnique<JobTracker>(std::move(job), policy_base); 447 base::MakeUnique<JobTracker>(std::move(job), policy_base);
446 448
447 // There is no obvious recovery after failure here. Previous version with 449 // There is no obvious recovery after failure here. Previous version with
448 // SpawnCleanup() caused deletion of TargetProcess twice. crbug.com/480639 450 // SpawnCleanup() caused deletion of TargetProcess twice. crbug.com/480639
449 CHECK(AssociateCompletionPort(tracker->job.Get(), job_port_.Get(), 451 CHECK(AssociateCompletionPort(tracker->job.Get(), job_port_.Get(),
450 tracker.get())); 452 tracker.get()));
451 453
452 // Save the tracker because in cleanup we might need to force closing 454 // Save the tracker because in cleanup we might need to force closing
453 // the Jobs. 455 // the Jobs.
454 tracker_list_.push_back(std::move(tracker)); 456 tracker_list_.push_back(std::move(tracker));
455 child_process_ids_.insert(process_info.process_id()); 457 child_process_ids_.insert(process_info.process_id());
456 } else { 458 } else {
459 // Leak policy_base. This needs to outlive the child process, but there's
460 // nothing that tracks that lifetime properly if there's no job object.
461 // TODO(wfh): Find a way to make this have the correct lifetime.
462 policy_base->AddRef();
Will Harris 2017/01/24 19:47:32 note: new change
463
457 // We have to signal the event once here because the completion port will 464 // We have to signal the event once here because the completion port will
458 // never get a message that this target is being terminated thus we should 465 // never get a message that this target is being terminated thus we should
459 // not block WaitForAllTargets until we have at least one target with job. 466 // not block WaitForAllTargets until we have at least one target with job.
460 if (child_process_ids_.empty()) 467 if (child_process_ids_.empty())
461 ::SetEvent(no_targets_.Get()); 468 ::SetEvent(no_targets_.Get());
462 } 469 }
463 470
464 *target_info = process_info.Take(); 471 *target_info = process_info.Take();
465 return result; 472 return result;
466 } 473 }
467 474
468 475
469 ResultCode BrokerServicesBase::WaitForAllTargets() { 476 ResultCode BrokerServicesBase::WaitForAllTargets() {
470 ::WaitForSingleObject(no_targets_.Get(), INFINITE); 477 ::WaitForSingleObject(no_targets_.Get(), INFINITE);
471 return SBOX_ALL_OK; 478 return SBOX_ALL_OK;
472 } 479 }
473 480
474 bool BrokerServicesBase::IsActiveTarget(DWORD process_id) { 481 bool BrokerServicesBase::IsActiveTarget(DWORD process_id) {
475 AutoLock lock(&lock_); 482 AutoLock lock(&lock_);
476 return child_process_ids_.find(process_id) != child_process_ids_.end(); 483 return child_process_ids_.find(process_id) != child_process_ids_.end();
477 } 484 }
478 485
479 } // namespace sandbox 486 } // namespace sandbox
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698