| Index: sandbox/src/broker_services.cc
|
| ===================================================================
|
| --- sandbox/src/broker_services.cc (revision 132034)
|
| +++ sandbox/src/broker_services.cc (working copy)
|
| @@ -41,12 +41,34 @@
|
| // executes TargetEventsThread().
|
| enum {
|
| THREAD_CTRL_NONE,
|
| + THREAD_CTRL_REMOVE_PEER,
|
| THREAD_CTRL_QUIT,
|
| - THREAD_CTRL_LAST
|
| + THREAD_CTRL_LAST,
|
| };
|
|
|
| -}
|
| +// 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) {
|
| + }
|
| +};
|
|
|
| +// Helper structure that allows the broker to track peer processes
|
| +struct PeerTracker {
|
| + 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) {
|
| + }
|
| +};
|
| +
|
| +} // namespace
|
| +
|
| namespace sandbox {
|
|
|
| BrokerServicesBase::BrokerServicesBase()
|
| @@ -85,6 +107,7 @@
|
| // If there is no port Init() was never called successfully.
|
| if (!job_port_)
|
| 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
|
| @@ -107,6 +130,18 @@
|
| ::CloseHandle(job_thread_);
|
| delete thread_pool_;
|
| ::CloseHandle(no_targets_);
|
| +
|
| + // Cancel the wait events and delete remaining peer trackers.
|
| + for (PeerTrackerMap::iterator it = peer_map_.begin();
|
| + it != peer_map_.end(); ++it) {
|
| + // Deregistration shouldn't fail, but we leak rather than crash if it does.
|
| + if (::UnregisterWaitEx(it->second->wait_object, INVALID_HANDLE_VALUE)) {
|
| + delete it->second;
|
| + } else {
|
| + NOTREACHED();
|
| + }
|
| + }
|
| +
|
| // If job_port_ isn't NULL, assumes that the lock has been initialized.
|
| if (job_port_)
|
| ::DeleteCriticalSection(&lock_);
|
| @@ -209,9 +244,23 @@
|
| }
|
| }
|
|
|
| + } else if (THREAD_CTRL_REMOVE_PEER == key) {
|
| + // Remove a process from our list of peers.
|
| + AutoLock lock(&broker->lock_);
|
| + PeerTrackerMap::iterator it =
|
| + broker->peer_map_.find(reinterpret_cast<DWORD>(ovl));
|
| + // This shouldn't fail, but if it does leak the memory rather than crash.
|
| + if (::UnregisterWaitEx(it->second->wait_object, INVALID_HANDLE_VALUE)) {
|
| + delete it->second;
|
| + broker->peer_map_.erase(it);
|
| + } else {
|
| + NOTREACHED();
|
| + }
|
| +
|
| } else if (THREAD_CTRL_QUIT == key) {
|
| // The broker object is being destroyed so the thread needs to exit.
|
| return 0;
|
| +
|
| } else {
|
| // We have not implemented more commands.
|
| NOTREACHED();
|
| @@ -312,7 +361,44 @@
|
|
|
| bool BrokerServicesBase::IsActiveTarget(DWORD process_id) {
|
| AutoLock lock(&lock_);
|
| - return child_process_ids_.find(process_id) != child_process_ids_.end();
|
| + return child_process_ids_.find(process_id) != child_process_ids_.end() ||
|
| + peer_map_.find(process_id) != peer_map_.end();
|
| }
|
|
|
| +VOID CALLBACK BrokerServicesBase::RemovePeer(PVOID parameter, BOOLEAN) {
|
| + PeerTracker* peer = reinterpret_cast<PeerTracker*>(parameter);
|
| + // Don't check the return code because we this may fail (safely) at shutdown.
|
| + ::PostQueuedCompletionStatus(peer->job_port, 0, THREAD_CTRL_REMOVE_PEER,
|
| + reinterpret_cast<LPOVERLAPPED>(peer->id));
|
| +}
|
| +
|
| +ResultCode BrokerServicesBase::AddTargetPeer(HANDLE peer_process) {
|
| + scoped_ptr<PeerTracker> peer(new PeerTracker(::GetProcessId(peer_process),
|
| + job_port_));
|
| + if (!peer->id)
|
| + return SBOX_ERROR_GENERIC;
|
| +
|
| + if (!::DuplicateHandle(::GetCurrentProcess(), peer_process,
|
| + ::GetCurrentProcess(), peer->process.Receive(),
|
| + SYNCHRONIZE, FALSE, 0)) {
|
| + return SBOX_ERROR_GENERIC;
|
| + }
|
| +
|
| + AutoLock lock(&lock_);
|
| + if (!peer_map_.insert(std::make_pair(peer->id, peer.get())).second)
|
| + return SBOX_ERROR_BAD_PARAMS;
|
| +
|
| + if (!::RegisterWaitForSingleObject(&peer->wait_object,
|
| + peer->process, RemovePeer,
|
| + peer.get(), INFINITE, WT_EXECUTEONLYONCE |
|
| + WT_EXECUTEINWAITTHREAD)) {
|
| + peer_map_.erase(peer->id);
|
| + return SBOX_ERROR_GENERIC;
|
| + }
|
| +
|
| + // Leak the pointer since it will be cleaned up by the callback.
|
| + peer.release();
|
| + return SBOX_ALL_OK;
|
| +}
|
| +
|
| } // namespace sandbox
|
|
|