Index: sandbox/src/broker_services.cc |
=================================================================== |
--- sandbox/src/broker_services.cc (revision 131361) |
+++ sandbox/src/broker_services.cc (working copy) |
@@ -92,6 +92,16 @@ |
::PostQueuedCompletionStatus(job_port_, 0, THREAD_CTRL_QUIT, FALSE); |
::CloseHandle(job_port_); |
+ { // Cancel the wait events for all the peers. |
+ AutoLock lock(&lock_); |
+ for (PeerTrackerMap::iterator it = peer_map_.begin(); |
+ it != peer_map_.end(); ++it) { |
+ // This call terminates any running handlers. |
+ ::UnregisterWaitEx(it->second->wait_object_, NULL); |
+ delete it->second; |
+ } |
+ } |
+ |
if (WAIT_TIMEOUT == ::WaitForSingleObject(job_thread_, 1000)) { |
// Cannot clean broker services. |
NOTREACHED(); |
@@ -312,7 +322,56 @@ |
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::RemovePeerData(PVOID parameter, BOOLEAN) { |
+ DWORD process_id = reinterpret_cast<DWORD>(parameter); |
+ BrokerServicesBase* broker = BrokerServicesBase::GetInstance(); |
+ PeerTracker* peer_data; |
+ |
+ { // Hold the lock only during removal (since UregisterWaitEx can block). |
+ AutoLock lock(&broker->lock_); |
+ PeerTrackerMap::iterator it = broker->peer_map_.find(process_id); |
+ peer_data = it->second; |
+ broker->peer_map_.erase(it); |
+ } |
+ |
+ HANDLE wait_object = peer_data->wait_object_; |
+ delete peer_data; |
+ // This prevents us from terminating our own running handler. |
+ ::UnregisterWaitEx(wait_object, INVALID_HANDLE_VALUE); |
+} |
+ |
+ResultCode BrokerServicesBase::AddTargetPeer(HANDLE peer_process) { |
+ DWORD process_id = ::GetProcessId(peer_process); |
+ if (!process_id) |
+ return SBOX_ERROR_GENERIC; |
+ |
+ scoped_ptr<PeerTracker> peer(new PeerTracker); |
+ 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(process_id, peer.get())).second) |
+ return SBOX_ERROR_BAD_PARAMS; |
+ |
+ if (!::RegisterWaitForSingleObject(&peer->wait_object_, |
+ peer->process_, RemovePeerData, |
+ reinterpret_cast<void*>(process_id), |
+ INFINITE, WT_EXECUTEINWAITTHREAD | |
+ WT_EXECUTEONLYONCE)) { |
+ peer_map_.erase(process_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 |