| 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/src/broker_services.h" | 5 #include "sandbox/src/broker_services.h" |
| 6 | 6 |
| 7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "base/memory/scoped_ptr.h" | 8 #include "base/memory/scoped_ptr.h" |
| 9 #include "base/threading/platform_thread.h" | 9 #include "base/threading/platform_thread.h" |
| 10 #include "base/win/scoped_handle.h" | 10 #include "base/win/scoped_handle.h" |
| (...skipping 23 matching lines...) Expand all Loading... |
| 34 target->Terminate(); | 34 target->Terminate(); |
| 35 delete target; | 35 delete target; |
| 36 ::SetLastError(error); | 36 ::SetLastError(error); |
| 37 return sandbox::SBOX_ERROR_GENERIC; | 37 return sandbox::SBOX_ERROR_GENERIC; |
| 38 } | 38 } |
| 39 | 39 |
| 40 // the different commands that you can send to the worker thread that | 40 // the different commands that you can send to the worker thread that |
| 41 // executes TargetEventsThread(). | 41 // executes TargetEventsThread(). |
| 42 enum { | 42 enum { |
| 43 THREAD_CTRL_NONE, | 43 THREAD_CTRL_NONE, |
| 44 THREAD_CTRL_REMOVE_PEER, |
| 44 THREAD_CTRL_QUIT, | 45 THREAD_CTRL_QUIT, |
| 45 THREAD_CTRL_LAST | 46 THREAD_CTRL_LAST, |
| 46 }; | 47 }; |
| 47 | 48 |
| 48 } | 49 // Helper structure that allows the Broker to associate a job notification |
| 50 // with a job object and with a policy. |
| 51 struct JobTracker { |
| 52 HANDLE job; |
| 53 sandbox::PolicyBase* policy; |
| 54 JobTracker(HANDLE cjob, sandbox::PolicyBase* cpolicy) |
| 55 : job(cjob), policy(cpolicy) { |
| 56 } |
| 57 }; |
| 58 |
| 59 // Helper structure that allows the broker to track peer processes |
| 60 struct PeerTracker { |
| 61 HANDLE wait_object; |
| 62 base::win::ScopedHandle process; |
| 63 DWORD id; |
| 64 HANDLE job_port; |
| 65 PeerTracker(DWORD process_id, HANDLE broker_job_port) |
| 66 : wait_object(NULL), id(process_id), job_port(broker_job_port) { |
| 67 } |
| 68 }; |
| 69 |
| 70 } // namespace |
| 49 | 71 |
| 50 namespace sandbox { | 72 namespace sandbox { |
| 51 | 73 |
| 52 BrokerServicesBase::BrokerServicesBase() | 74 BrokerServicesBase::BrokerServicesBase() |
| 53 : thread_pool_(NULL), job_port_(NULL), no_targets_(NULL), | 75 : thread_pool_(NULL), job_port_(NULL), no_targets_(NULL), |
| 54 job_thread_(NULL) { | 76 job_thread_(NULL) { |
| 55 } | 77 } |
| 56 | 78 |
| 57 // The broker uses a dedicated worker thread that services the job completion | 79 // The broker uses a dedicated worker thread that services the job completion |
| 58 // port to perform policy notifications and associated cleanup tasks. | 80 // port to perform policy notifications and associated cleanup tasks. |
| (...skipping 19 matching lines...) Expand all Loading... |
| 78 | 100 |
| 79 // The destructor should only be called when the Broker process is terminating. | 101 // The destructor should only be called when the Broker process is terminating. |
| 80 // Since BrokerServicesBase is a singleton, this is called from the CRT | 102 // Since BrokerServicesBase is a singleton, this is called from the CRT |
| 81 // termination handlers, if this code lives on a DLL it is called during | 103 // termination handlers, if this code lives on a DLL it is called during |
| 82 // DLL_PROCESS_DETACH in other words, holding the loader lock, so we cannot | 104 // DLL_PROCESS_DETACH in other words, holding the loader lock, so we cannot |
| 83 // wait for threads here. | 105 // wait for threads here. |
| 84 BrokerServicesBase::~BrokerServicesBase() { | 106 BrokerServicesBase::~BrokerServicesBase() { |
| 85 // If there is no port Init() was never called successfully. | 107 // If there is no port Init() was never called successfully. |
| 86 if (!job_port_) | 108 if (!job_port_) |
| 87 return; | 109 return; |
| 110 |
| 88 // Closing the port causes, that no more Job notifications are delivered to | 111 // Closing the port causes, that no more Job notifications are delivered to |
| 89 // the worker thread and also causes the thread to exit. This is what we | 112 // the worker thread and also causes the thread to exit. This is what we |
| 90 // want to do since we are going to close all outstanding Jobs and notifying | 113 // want to do since we are going to close all outstanding Jobs and notifying |
| 91 // the policy objects ourselves. | 114 // the policy objects ourselves. |
| 92 ::PostQueuedCompletionStatus(job_port_, 0, THREAD_CTRL_QUIT, FALSE); | 115 ::PostQueuedCompletionStatus(job_port_, 0, THREAD_CTRL_QUIT, FALSE); |
| 93 ::CloseHandle(job_port_); | 116 ::CloseHandle(job_port_); |
| 94 | 117 |
| 95 if (WAIT_TIMEOUT == ::WaitForSingleObject(job_thread_, 1000)) { | 118 if (WAIT_TIMEOUT == ::WaitForSingleObject(job_thread_, 1000)) { |
| 96 // Cannot clean broker services. | 119 // Cannot clean broker services. |
| 97 NOTREACHED(); | 120 NOTREACHED(); |
| 98 return; | 121 return; |
| 99 } | 122 } |
| 100 | 123 |
| 101 JobTrackerList::iterator it; | 124 JobTrackerList::iterator it; |
| 102 for (it = tracker_list_.begin(); it != tracker_list_.end(); ++it) { | 125 for (it = tracker_list_.begin(); it != tracker_list_.end(); ++it) { |
| 103 JobTracker* tracker = (*it); | 126 JobTracker* tracker = (*it); |
| 104 FreeResources(tracker); | 127 FreeResources(tracker); |
| 105 delete tracker; | 128 delete tracker; |
| 106 } | 129 } |
| 107 ::CloseHandle(job_thread_); | 130 ::CloseHandle(job_thread_); |
| 108 delete thread_pool_; | 131 delete thread_pool_; |
| 109 ::CloseHandle(no_targets_); | 132 ::CloseHandle(no_targets_); |
| 133 |
| 134 // Cancel the wait events and delete remaining peer trackers. |
| 135 for (PeerTrackerMap::iterator it = peer_map_.begin(); |
| 136 it != peer_map_.end(); ++it) { |
| 137 // Deregistration shouldn't fail, but we leak rather than crash if it does. |
| 138 if (::UnregisterWaitEx(it->second->wait_object, INVALID_HANDLE_VALUE)) { |
| 139 delete it->second; |
| 140 } else { |
| 141 NOTREACHED(); |
| 142 } |
| 143 } |
| 144 |
| 110 // If job_port_ isn't NULL, assumes that the lock has been initialized. | 145 // If job_port_ isn't NULL, assumes that the lock has been initialized. |
| 111 if (job_port_) | 146 if (job_port_) |
| 112 ::DeleteCriticalSection(&lock_); | 147 ::DeleteCriticalSection(&lock_); |
| 113 } | 148 } |
| 114 | 149 |
| 115 TargetPolicy* BrokerServicesBase::CreatePolicy() { | 150 TargetPolicy* BrokerServicesBase::CreatePolicy() { |
| 116 // If you change the type of the object being created here you must also | 151 // If you change the type of the object being created here you must also |
| 117 // change the downcast to it in SpawnTarget(). | 152 // change the downcast to it in SpawnTarget(). |
| 118 return new PolicyBase; | 153 return new PolicyBase; |
| 119 } | 154 } |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 202 case JOB_OBJECT_MSG_ACTIVE_PROCESS_LIMIT: { | 237 case JOB_OBJECT_MSG_ACTIVE_PROCESS_LIMIT: { |
| 203 break; | 238 break; |
| 204 } | 239 } |
| 205 | 240 |
| 206 default: { | 241 default: { |
| 207 NOTREACHED(); | 242 NOTREACHED(); |
| 208 break; | 243 break; |
| 209 } | 244 } |
| 210 } | 245 } |
| 211 | 246 |
| 247 } else if (THREAD_CTRL_REMOVE_PEER == key) { |
| 248 // Remove a process from our list of peers. |
| 249 AutoLock lock(&broker->lock_); |
| 250 PeerTrackerMap::iterator it = |
| 251 broker->peer_map_.find(reinterpret_cast<DWORD>(ovl)); |
| 252 // This shouldn't fail, but if it does leak the memory rather than crash. |
| 253 if (::UnregisterWaitEx(it->second->wait_object, INVALID_HANDLE_VALUE)) { |
| 254 delete it->second; |
| 255 broker->peer_map_.erase(it); |
| 256 } else { |
| 257 NOTREACHED(); |
| 258 } |
| 259 |
| 212 } else if (THREAD_CTRL_QUIT == key) { | 260 } else if (THREAD_CTRL_QUIT == key) { |
| 213 // The broker object is being destroyed so the thread needs to exit. | 261 // The broker object is being destroyed so the thread needs to exit. |
| 214 return 0; | 262 return 0; |
| 263 |
| 215 } else { | 264 } else { |
| 216 // We have not implemented more commands. | 265 // We have not implemented more commands. |
| 217 NOTREACHED(); | 266 NOTREACHED(); |
| 218 } | 267 } |
| 219 } | 268 } |
| 220 | 269 |
| 221 NOTREACHED(); | 270 NOTREACHED(); |
| 222 return 0; | 271 return 0; |
| 223 } | 272 } |
| 224 | 273 |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 305 } | 354 } |
| 306 | 355 |
| 307 | 356 |
| 308 ResultCode BrokerServicesBase::WaitForAllTargets() { | 357 ResultCode BrokerServicesBase::WaitForAllTargets() { |
| 309 ::WaitForSingleObject(no_targets_, INFINITE); | 358 ::WaitForSingleObject(no_targets_, INFINITE); |
| 310 return SBOX_ALL_OK; | 359 return SBOX_ALL_OK; |
| 311 } | 360 } |
| 312 | 361 |
| 313 bool BrokerServicesBase::IsActiveTarget(DWORD process_id) { | 362 bool BrokerServicesBase::IsActiveTarget(DWORD process_id) { |
| 314 AutoLock lock(&lock_); | 363 AutoLock lock(&lock_); |
| 315 return child_process_ids_.find(process_id) != child_process_ids_.end(); | 364 return child_process_ids_.find(process_id) != child_process_ids_.end() || |
| 365 peer_map_.find(process_id) != peer_map_.end(); |
| 366 } |
| 367 |
| 368 VOID CALLBACK BrokerServicesBase::RemovePeer(PVOID parameter, BOOLEAN) { |
| 369 PeerTracker* peer = reinterpret_cast<PeerTracker*>(parameter); |
| 370 // Don't check the return code because we this may fail (safely) at shutdown. |
| 371 ::PostQueuedCompletionStatus(peer->job_port, 0, THREAD_CTRL_REMOVE_PEER, |
| 372 reinterpret_cast<LPOVERLAPPED>(peer->id)); |
| 373 } |
| 374 |
| 375 ResultCode BrokerServicesBase::AddTargetPeer(HANDLE peer_process) { |
| 376 scoped_ptr<PeerTracker> peer(new PeerTracker(::GetProcessId(peer_process), |
| 377 job_port_)); |
| 378 if (!peer->id) |
| 379 return SBOX_ERROR_GENERIC; |
| 380 |
| 381 if (!::DuplicateHandle(::GetCurrentProcess(), peer_process, |
| 382 ::GetCurrentProcess(), peer->process.Receive(), |
| 383 SYNCHRONIZE, FALSE, 0)) { |
| 384 return SBOX_ERROR_GENERIC; |
| 385 } |
| 386 |
| 387 AutoLock lock(&lock_); |
| 388 if (!peer_map_.insert(std::make_pair(peer->id, peer.get())).second) |
| 389 return SBOX_ERROR_BAD_PARAMS; |
| 390 |
| 391 if (!::RegisterWaitForSingleObject(&peer->wait_object, |
| 392 peer->process, RemovePeer, |
| 393 peer.get(), INFINITE, WT_EXECUTEONLYONCE | |
| 394 WT_EXECUTEINWAITTHREAD)) { |
| 395 peer_map_.erase(peer->id); |
| 396 return SBOX_ERROR_GENERIC; |
| 397 } |
| 398 |
| 399 // Leak the pointer since it will be cleaned up by the callback. |
| 400 peer.release(); |
| 401 return SBOX_ALL_OK; |
| 316 } | 402 } |
| 317 | 403 |
| 318 } // namespace sandbox | 404 } // namespace sandbox |
| OLD | NEW |