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

Unified Diff: sandbox/win/src/broker_services.cc

Issue 1228373003: Sandbox: Remove ::CloseHandle from BrokerServices. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rename and improve comments. Created 5 years, 5 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « sandbox/win/src/broker_services.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: sandbox/win/src/broker_services.cc
diff --git a/sandbox/win/src/broker_services.cc b/sandbox/win/src/broker_services.cc
index 68d68d829325d4b95ce6406d6638e3198eb96761..4baa20bf08b63a33d4f3d1a34de6e2caa8f21409 100644
--- a/sandbox/win/src/broker_services.cc
+++ b/sandbox/win/src/broker_services.cc
@@ -8,6 +8,7 @@
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
+#include "base/stl_util.h"
#include "base/threading/platform_thread.h"
#include "base/win/scoped_handle.h"
#include "base/win/scoped_process_information.h"
@@ -55,22 +56,47 @@ enum {
// Helper structure that allows the Broker to associate a job notification
// with a job object and with a policy.
struct JobTracker {
- HANDLE job;
- sandbox::PolicyBase* policy;
- JobTracker(HANDLE cjob, sandbox::PolicyBase* cpolicy)
- : job(cjob), policy(cpolicy) {
+ JobTracker(base::win::ScopedHandle job, sandbox::PolicyBase* policy)
+ : job(job.Pass()), policy(policy) {
+ }
+ ~JobTracker() {
+ FreeResources();
}
+
+ // Releases the Job and notifies the associated Policy object to release its
+ // resources as well.
+ void FreeResources();
+
+ base::win::ScopedHandle job;
+ sandbox::PolicyBase* policy;
};
+void JobTracker::FreeResources() {
+ if (policy) {
+ BOOL res = ::TerminateJobObject(job.Get(), sandbox::SBOX_ALL_OK);
+ DCHECK(res);
+ // Closing the job causes the target process to be destroyed so this needs
+ // to happen before calling OnJobEmpty().
+ HANDLE stale_job_handle = job.Get();
+ job.Close();
+
+ // In OnJobEmpty() we don't actually use the job handle directly.
+ policy->OnJobEmpty(stale_job_handle);
+ policy->Release();
+ policy = NULL;
+ }
+}
+
// Helper structure that allows the broker to track peer processes
struct PeerTracker {
+ PeerTracker(DWORD process_id, HANDLE broker_job_port)
+ : wait_object(NULL), id(process_id), job_port(broker_job_port) {
+ }
+
HANDLE wait_object;
base::win::ScopedHandle process;
DWORD id;
HANDLE job_port;
- PeerTracker(DWORD process_id, HANDLE broker_job_port)
- : wait_object(NULL), id(process_id), job_port(broker_job_port) {
- }
};
void DeregisterPeerTracker(PeerTracker* peer) {
@@ -124,30 +150,38 @@ uint32_t GenerateTokenCacheKey(const sandbox::PolicyBase* policy) {
namespace sandbox {
-BrokerServicesBase::BrokerServicesBase()
- : job_port_(NULL),
- no_targets_(NULL),
- job_thread_(NULL),
- thread_pool_(NULL) {
+// TODO(rvargas): Replace this structure with a std::pair of ScopedHandles.
+struct BrokerServicesBase::TokenPair {
+ TokenPair(base::win::ScopedHandle initial_token,
+ base::win::ScopedHandle lockdown_token)
+ : initial(initial_token.Pass()),
+ lockdown(lockdown_token.Pass()) {
+ }
+
+ base::win::ScopedHandle initial;
+ base::win::ScopedHandle lockdown;
+};
+
+BrokerServicesBase::BrokerServicesBase() : thread_pool_(NULL) {
}
// The broker uses a dedicated worker thread that services the job completion
// port to perform policy notifications and associated cleanup tasks.
ResultCode BrokerServicesBase::Init() {
- if ((NULL != job_port_) || (NULL != thread_pool_))
+ if (job_port_.IsValid() || (NULL != thread_pool_))
return SBOX_ERROR_UNEXPECTED_CALL;
::InitializeCriticalSection(&lock_);
- job_port_ = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
- if (NULL == job_port_)
+ job_port_.Set(::CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0));
+ if (!job_port_.IsValid())
return SBOX_ERROR_GENERIC;
- no_targets_ = ::CreateEventW(NULL, TRUE, FALSE, NULL);
+ no_targets_.Set(::CreateEventW(NULL, TRUE, FALSE, NULL));
- job_thread_ = ::CreateThread(NULL, 0, // Default security and stack.
- TargetEventsThread, this, NULL, NULL);
- if (NULL == job_thread_)
+ job_thread_.Set(::CreateThread(NULL, 0, // Default security and stack.
+ TargetEventsThread, this, NULL, NULL));
+ if (!job_thread_.IsValid())
return SBOX_ERROR_GENERIC;
return SBOX_ALL_OK;
@@ -160,31 +194,24 @@ ResultCode BrokerServicesBase::Init() {
// wait for threads here.
BrokerServicesBase::~BrokerServicesBase() {
// If there is no port Init() was never called successfully.
- if (!job_port_)
+ if (!job_port_.IsValid())
return;
// Closing the port causes, that no more Job notifications are delivered to
// the worker thread and also causes the thread to exit. This is what we
// want to do since we are going to close all outstanding Jobs and notifying
// the policy objects ourselves.
- ::PostQueuedCompletionStatus(job_port_, 0, THREAD_CTRL_QUIT, FALSE);
- ::CloseHandle(job_port_);
+ ::PostQueuedCompletionStatus(job_port_.Get(), 0, THREAD_CTRL_QUIT, FALSE);
- if (WAIT_TIMEOUT == ::WaitForSingleObject(job_thread_, 1000)) {
+ if (job_thread_.IsValid() &&
+ WAIT_TIMEOUT == ::WaitForSingleObject(job_thread_.Get(), 1000)) {
// Cannot clean broker services.
NOTREACHED();
return;
}
- JobTrackerList::iterator it;
- for (it = tracker_list_.begin(); it != tracker_list_.end(); ++it) {
- JobTracker* tracker = (*it);
- FreeResources(tracker);
- delete tracker;
- }
- ::CloseHandle(job_thread_);
+ STLDeleteElements(&tracker_list_);
delete thread_pool_;
- ::CloseHandle(no_targets_);
// Cancel the wait events and delete remaining peer trackers.
for (PeerTrackerMap::iterator it = peer_map_.begin();
@@ -192,16 +219,10 @@ BrokerServicesBase::~BrokerServicesBase() {
DeregisterPeerTracker(it->second);
}
- // If job_port_ isn't NULL, assumes that the lock has been initialized.
- if (job_port_)
- ::DeleteCriticalSection(&lock_);
+ ::DeleteCriticalSection(&lock_);
// Close any token in the cache.
- for (TokenCacheMap::iterator it = token_cache_.begin();
- it != token_cache_.end(); ++it) {
- ::CloseHandle(it->second.first);
- ::CloseHandle(it->second.second);
- }
+ STLDeleteValues(&token_cache_);
}
TargetPolicy* BrokerServicesBase::CreatePolicy() {
@@ -210,21 +231,6 @@ TargetPolicy* BrokerServicesBase::CreatePolicy() {
return new PolicyBase;
}
-void BrokerServicesBase::FreeResources(JobTracker* tracker) {
- if (NULL != tracker->policy) {
- BOOL res = ::TerminateJobObject(tracker->job, SBOX_ALL_OK);
- DCHECK(res);
- // Closing the job causes the target process to be destroyed so this
- // needs to happen before calling OnJobEmpty().
- res = ::CloseHandle(tracker->job);
- DCHECK(res);
- // In OnJobEmpty() we don't actually use the job handle directly.
- tracker->policy->OnJobEmpty(tracker->job);
- tracker->policy->Release();
- tracker->policy = NULL;
- }
-}
-
// The worker thread stays in a loop waiting for asynchronous notifications
// from the job objects. Right now we only care about knowing when the last
// process on a job terminates, but in general this is the place to tell
@@ -236,8 +242,8 @@ DWORD WINAPI BrokerServicesBase::TargetEventsThread(PVOID param) {
base::PlatformThread::SetName("BrokerEvent");
BrokerServicesBase* broker = reinterpret_cast<BrokerServicesBase*>(param);
- HANDLE port = broker->job_port_;
- HANDLE no_targets = broker->no_targets_;
+ HANDLE port = broker->job_port_.Get();
+ HANDLE no_targets = broker->no_targets_.Get();
int target_counter = 0;
::ResetEvent(no_targets);
@@ -247,11 +253,12 @@ DWORD WINAPI BrokerServicesBase::TargetEventsThread(PVOID param) {
ULONG_PTR key = 0;
LPOVERLAPPED ovl = NULL;
- if (!::GetQueuedCompletionStatus(port, &events, &key, &ovl, INFINITE))
+ if (!::GetQueuedCompletionStatus(port, &events, &key, &ovl, INFINITE)) {
// this call fails if the port has been closed before we have a
// chance to service the last packet which is 'exit' anyway so
// this is not an error.
return 1;
+ }
if (key > THREAD_CTRL_LAST) {
// The notification comes from a job object. There are nine notifications
@@ -265,7 +272,7 @@ DWORD WINAPI BrokerServicesBase::TargetEventsThread(PVOID param) {
// to appear out of thin air in this job, it safe to assume that
// we can tell the policy to destroy the target object, and for
// us to release our reference to the policy object.
- FreeResources(tracker);
+ tracker->FreeResources();
break;
}
@@ -297,7 +304,7 @@ DWORD WINAPI BrokerServicesBase::TargetEventsThread(PVOID param) {
}
case JOB_OBJECT_MSG_PROCESS_MEMORY_LIMIT: {
- BOOL res = ::TerminateJobObject(tracker->job,
+ BOOL res = ::TerminateJobObject(tracker->job.Get(),
SBOX_FATAL_MEMORY_EXCEEDED);
DCHECK(res);
break;
@@ -367,33 +374,31 @@ ResultCode BrokerServicesBase::SpawnTarget(const wchar_t* exe_path,
// process launch.
uint32_t token_key = GenerateTokenCacheKey(policy_base);
TokenCacheMap::iterator it = token_cache_.find(token_key);
- HANDLE initial_token_temp;
- HANDLE lockdown_token_temp;
+ TokenPair* tokens;
if (it != token_cache_.end()) {
- initial_token_temp = it->second.first;
- lockdown_token_temp = it->second.second;
+ tokens = it->second;
} else {
result = policy_base->MakeTokens(&initial_token, &lockdown_token);
if (SBOX_ALL_OK != result)
return result;
- token_cache_[token_key] =
- std::make_pair(initial_token.Get(), lockdown_token.Get());
- initial_token_temp = initial_token.Take();
- lockdown_token_temp = lockdown_token.Take();
+
+ tokens = new TokenPair(initial_token.Pass(), lockdown_token.Pass());
+ token_cache_[token_key] = tokens;
}
- if (!::DuplicateToken(initial_token_temp, SecurityImpersonation,
- &initial_token_temp)) {
+ HANDLE temp_token;
+ if (!::DuplicateToken(tokens->initial.Get(), SecurityImpersonation,
+ &temp_token)) {
return SBOX_ERROR_GENERIC;
}
- initial_token.Set(initial_token_temp);
+ initial_token.Set(temp_token);
- if (!::DuplicateTokenEx(lockdown_token_temp, TOKEN_ALL_ACCESS, 0,
+ if (!::DuplicateTokenEx(tokens->lockdown.Get(), TOKEN_ALL_ACCESS, 0,
SecurityIdentification, TokenPrimary,
- &lockdown_token_temp)) {
+ &temp_token)) {
return SBOX_ERROR_GENERIC;
}
- lockdown_token.Set(lockdown_token_temp);
+ lockdown_token.Set(temp_token);
} else {
result = policy_base->MakeTokens(&initial_token, &lockdown_token);
if (SBOX_ALL_OK != result)
@@ -523,11 +528,12 @@ ResultCode BrokerServicesBase::SpawnTarget(const wchar_t* exe_path,
// the job object generates notifications using the completion port.
policy_base->AddRef();
if (job.IsValid()) {
- scoped_ptr<JobTracker> tracker(new JobTracker(job.Take(), policy_base));
+ scoped_ptr<JobTracker> tracker(new JobTracker(job.Pass(), policy_base));
// There is no obvious recovery after failure here. Previous version with
// SpawnCleanup() caused deletion of TargetProcess twice. crbug.com/480639
- CHECK(AssociateCompletionPort(tracker->job, job_port_, tracker.get()));
+ CHECK(AssociateCompletionPort(tracker->job.Get(), job_port_.Get(),
+ tracker.get()));
// Save the tracker because in cleanup we might need to force closing
// the Jobs.
@@ -538,7 +544,7 @@ ResultCode BrokerServicesBase::SpawnTarget(const wchar_t* exe_path,
// never get a message that this target is being terminated thus we should
// not block WaitForAllTargets until we have at least one target with job.
if (child_process_ids_.empty())
- ::SetEvent(no_targets_);
+ ::SetEvent(no_targets_.Get());
// We can not track the life time of such processes and it is responsibility
// of the host application to make sure that spawned targets without jobs
// are terminated when the main application don't need them anymore.
@@ -553,7 +559,7 @@ ResultCode BrokerServicesBase::SpawnTarget(const wchar_t* exe_path,
ResultCode BrokerServicesBase::WaitForAllTargets() {
- ::WaitForSingleObject(no_targets_, INFINITE);
+ ::WaitForSingleObject(no_targets_.Get(), INFINITE);
return SBOX_ALL_OK;
}
@@ -573,7 +579,7 @@ VOID CALLBACK BrokerServicesBase::RemovePeer(PVOID parameter, BOOLEAN timeout) {
ResultCode BrokerServicesBase::AddTargetPeer(HANDLE peer_process) {
scoped_ptr<PeerTracker> peer(new PeerTracker(::GetProcessId(peer_process),
- job_port_));
+ job_port_.Get()));
if (!peer->id)
return SBOX_ERROR_GENERIC;
« no previous file with comments | « sandbox/win/src/broker_services.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698