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/win/src/broker_services.h" | 5 #include "sandbox/win/src/broker_services.h" |
6 | 6 |
7 #include <AclAPI.h> | 7 #include <AclAPI.h> |
8 | 8 |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/memory/scoped_ptr.h" | 10 #include "base/memory/scoped_ptr.h" |
| 11 #include "base/stl_util.h" |
11 #include "base/threading/platform_thread.h" | 12 #include "base/threading/platform_thread.h" |
12 #include "base/win/scoped_handle.h" | 13 #include "base/win/scoped_handle.h" |
13 #include "base/win/scoped_process_information.h" | 14 #include "base/win/scoped_process_information.h" |
14 #include "base/win/startup_information.h" | 15 #include "base/win/startup_information.h" |
15 #include "base/win/windows_version.h" | 16 #include "base/win/windows_version.h" |
16 #include "sandbox/win/src/app_container.h" | 17 #include "sandbox/win/src/app_container.h" |
17 #include "sandbox/win/src/process_mitigations.h" | 18 #include "sandbox/win/src/process_mitigations.h" |
18 #include "sandbox/win/src/sandbox_policy_base.h" | 19 #include "sandbox/win/src/sandbox_policy_base.h" |
19 #include "sandbox/win/src/sandbox.h" | 20 #include "sandbox/win/src/sandbox.h" |
20 #include "sandbox/win/src/target_process.h" | 21 #include "sandbox/win/src/target_process.h" |
(...skipping 27 matching lines...) Expand all Loading... |
48 enum { | 49 enum { |
49 THREAD_CTRL_NONE, | 50 THREAD_CTRL_NONE, |
50 THREAD_CTRL_REMOVE_PEER, | 51 THREAD_CTRL_REMOVE_PEER, |
51 THREAD_CTRL_QUIT, | 52 THREAD_CTRL_QUIT, |
52 THREAD_CTRL_LAST, | 53 THREAD_CTRL_LAST, |
53 }; | 54 }; |
54 | 55 |
55 // Helper structure that allows the Broker to associate a job notification | 56 // Helper structure that allows the Broker to associate a job notification |
56 // with a job object and with a policy. | 57 // with a job object and with a policy. |
57 struct JobTracker { | 58 struct JobTracker { |
58 HANDLE job; | 59 JobTracker(base::win::ScopedHandle job, sandbox::PolicyBase* policy) |
| 60 : job(job.Pass()), policy(policy) { |
| 61 } |
| 62 ~JobTracker() { |
| 63 FreeResources(); |
| 64 } |
| 65 |
| 66 // Releases the Job and notifies the associated Policy object to release its |
| 67 // resources as well. |
| 68 void FreeResources(); |
| 69 |
| 70 base::win::ScopedHandle job; |
59 sandbox::PolicyBase* policy; | 71 sandbox::PolicyBase* policy; |
60 JobTracker(HANDLE cjob, sandbox::PolicyBase* cpolicy) | 72 }; |
61 : job(cjob), policy(cpolicy) { | 73 |
| 74 void JobTracker::FreeResources() { |
| 75 if (policy) { |
| 76 BOOL res = ::TerminateJobObject(job.Get(), sandbox::SBOX_ALL_OK); |
| 77 DCHECK(res); |
| 78 // Closing the job causes the target process to be destroyed so this needs |
| 79 // to happen before calling OnJobEmpty(). |
| 80 HANDLE stale_job_handle = job.Get(); |
| 81 job.Close(); |
| 82 |
| 83 // In OnJobEmpty() we don't actually use the job handle directly. |
| 84 policy->OnJobEmpty(stale_job_handle); |
| 85 policy->Release(); |
| 86 policy = NULL; |
62 } | 87 } |
63 }; | 88 } |
64 | 89 |
65 // Helper structure that allows the broker to track peer processes | 90 // Helper structure that allows the broker to track peer processes |
66 struct PeerTracker { | 91 struct PeerTracker { |
| 92 PeerTracker(DWORD process_id, HANDLE broker_job_port) |
| 93 : wait_object(NULL), id(process_id), job_port(broker_job_port) { |
| 94 } |
| 95 |
67 HANDLE wait_object; | 96 HANDLE wait_object; |
68 base::win::ScopedHandle process; | 97 base::win::ScopedHandle process; |
69 DWORD id; | 98 DWORD id; |
70 HANDLE job_port; | 99 HANDLE job_port; |
71 PeerTracker(DWORD process_id, HANDLE broker_job_port) | |
72 : wait_object(NULL), id(process_id), job_port(broker_job_port) { | |
73 } | |
74 }; | 100 }; |
75 | 101 |
76 void DeregisterPeerTracker(PeerTracker* peer) { | 102 void DeregisterPeerTracker(PeerTracker* peer) { |
77 // Deregistration shouldn't fail, but we leak rather than crash if it does. | 103 // Deregistration shouldn't fail, but we leak rather than crash if it does. |
78 if (::UnregisterWaitEx(peer->wait_object, INVALID_HANDLE_VALUE)) { | 104 if (::UnregisterWaitEx(peer->wait_object, INVALID_HANDLE_VALUE)) { |
79 delete peer; | 105 delete peer; |
80 } else { | 106 } else { |
81 NOTREACHED(); | 107 NOTREACHED(); |
82 } | 108 } |
83 } | 109 } |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
117 key <<= kTokenShift; | 143 key <<= kTokenShift; |
118 key |= policy->GetIntegrityLevel(); | 144 key |= policy->GetIntegrityLevel(); |
119 | 145 |
120 return key; | 146 return key; |
121 } | 147 } |
122 | 148 |
123 } // namespace | 149 } // namespace |
124 | 150 |
125 namespace sandbox { | 151 namespace sandbox { |
126 | 152 |
127 BrokerServicesBase::BrokerServicesBase() | 153 // TODO(rvargas): Replace this structure with a std::pair of ScopedHandles. |
128 : job_port_(NULL), | 154 struct BrokerServicesBase::TokenPair { |
129 no_targets_(NULL), | 155 TokenPair(base::win::ScopedHandle initial_token, |
130 job_thread_(NULL), | 156 base::win::ScopedHandle lockdown_token) |
131 thread_pool_(NULL) { | 157 : initial(initial_token.Pass()), |
| 158 lockdown(lockdown_token.Pass()) { |
| 159 } |
| 160 |
| 161 base::win::ScopedHandle initial; |
| 162 base::win::ScopedHandle lockdown; |
| 163 }; |
| 164 |
| 165 BrokerServicesBase::BrokerServicesBase() : thread_pool_(NULL) { |
132 } | 166 } |
133 | 167 |
134 // The broker uses a dedicated worker thread that services the job completion | 168 // The broker uses a dedicated worker thread that services the job completion |
135 // port to perform policy notifications and associated cleanup tasks. | 169 // port to perform policy notifications and associated cleanup tasks. |
136 ResultCode BrokerServicesBase::Init() { | 170 ResultCode BrokerServicesBase::Init() { |
137 if ((NULL != job_port_) || (NULL != thread_pool_)) | 171 if (job_port_.IsValid() || (NULL != thread_pool_)) |
138 return SBOX_ERROR_UNEXPECTED_CALL; | 172 return SBOX_ERROR_UNEXPECTED_CALL; |
139 | 173 |
140 ::InitializeCriticalSection(&lock_); | 174 ::InitializeCriticalSection(&lock_); |
141 | 175 |
142 job_port_ = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0); | 176 job_port_.Set(::CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0)); |
143 if (NULL == job_port_) | 177 if (!job_port_.IsValid()) |
144 return SBOX_ERROR_GENERIC; | 178 return SBOX_ERROR_GENERIC; |
145 | 179 |
146 no_targets_ = ::CreateEventW(NULL, TRUE, FALSE, NULL); | 180 no_targets_.Set(::CreateEventW(NULL, TRUE, FALSE, NULL)); |
147 | 181 |
148 job_thread_ = ::CreateThread(NULL, 0, // Default security and stack. | 182 job_thread_.Set(::CreateThread(NULL, 0, // Default security and stack. |
149 TargetEventsThread, this, NULL, NULL); | 183 TargetEventsThread, this, NULL, NULL)); |
150 if (NULL == job_thread_) | 184 if (!job_thread_.IsValid()) |
151 return SBOX_ERROR_GENERIC; | 185 return SBOX_ERROR_GENERIC; |
152 | 186 |
153 return SBOX_ALL_OK; | 187 return SBOX_ALL_OK; |
154 } | 188 } |
155 | 189 |
156 // The destructor should only be called when the Broker process is terminating. | 190 // The destructor should only be called when the Broker process is terminating. |
157 // Since BrokerServicesBase is a singleton, this is called from the CRT | 191 // Since BrokerServicesBase is a singleton, this is called from the CRT |
158 // termination handlers, if this code lives on a DLL it is called during | 192 // termination handlers, if this code lives on a DLL it is called during |
159 // DLL_PROCESS_DETACH in other words, holding the loader lock, so we cannot | 193 // DLL_PROCESS_DETACH in other words, holding the loader lock, so we cannot |
160 // wait for threads here. | 194 // wait for threads here. |
161 BrokerServicesBase::~BrokerServicesBase() { | 195 BrokerServicesBase::~BrokerServicesBase() { |
162 // If there is no port Init() was never called successfully. | 196 // If there is no port Init() was never called successfully. |
163 if (!job_port_) | 197 if (!job_port_.IsValid()) |
164 return; | 198 return; |
165 | 199 |
166 // Closing the port causes, that no more Job notifications are delivered to | 200 // Closing the port causes, that no more Job notifications are delivered to |
167 // the worker thread and also causes the thread to exit. This is what we | 201 // the worker thread and also causes the thread to exit. This is what we |
168 // want to do since we are going to close all outstanding Jobs and notifying | 202 // want to do since we are going to close all outstanding Jobs and notifying |
169 // the policy objects ourselves. | 203 // the policy objects ourselves. |
170 ::PostQueuedCompletionStatus(job_port_, 0, THREAD_CTRL_QUIT, FALSE); | 204 ::PostQueuedCompletionStatus(job_port_.Get(), 0, THREAD_CTRL_QUIT, FALSE); |
171 ::CloseHandle(job_port_); | |
172 | 205 |
173 if (WAIT_TIMEOUT == ::WaitForSingleObject(job_thread_, 1000)) { | 206 if (job_thread_.IsValid() && |
| 207 WAIT_TIMEOUT == ::WaitForSingleObject(job_thread_.Get(), 1000)) { |
174 // Cannot clean broker services. | 208 // Cannot clean broker services. |
175 NOTREACHED(); | 209 NOTREACHED(); |
176 return; | 210 return; |
177 } | 211 } |
178 | 212 |
179 JobTrackerList::iterator it; | 213 STLDeleteElements(&tracker_list_); |
180 for (it = tracker_list_.begin(); it != tracker_list_.end(); ++it) { | |
181 JobTracker* tracker = (*it); | |
182 FreeResources(tracker); | |
183 delete tracker; | |
184 } | |
185 ::CloseHandle(job_thread_); | |
186 delete thread_pool_; | 214 delete thread_pool_; |
187 ::CloseHandle(no_targets_); | |
188 | 215 |
189 // Cancel the wait events and delete remaining peer trackers. | 216 // Cancel the wait events and delete remaining peer trackers. |
190 for (PeerTrackerMap::iterator it = peer_map_.begin(); | 217 for (PeerTrackerMap::iterator it = peer_map_.begin(); |
191 it != peer_map_.end(); ++it) { | 218 it != peer_map_.end(); ++it) { |
192 DeregisterPeerTracker(it->second); | 219 DeregisterPeerTracker(it->second); |
193 } | 220 } |
194 | 221 |
195 // If job_port_ isn't NULL, assumes that the lock has been initialized. | 222 ::DeleteCriticalSection(&lock_); |
196 if (job_port_) | |
197 ::DeleteCriticalSection(&lock_); | |
198 | 223 |
199 // Close any token in the cache. | 224 // Close any token in the cache. |
200 for (TokenCacheMap::iterator it = token_cache_.begin(); | 225 STLDeleteValues(&token_cache_); |
201 it != token_cache_.end(); ++it) { | |
202 ::CloseHandle(it->second.first); | |
203 ::CloseHandle(it->second.second); | |
204 } | |
205 } | 226 } |
206 | 227 |
207 TargetPolicy* BrokerServicesBase::CreatePolicy() { | 228 TargetPolicy* BrokerServicesBase::CreatePolicy() { |
208 // If you change the type of the object being created here you must also | 229 // If you change the type of the object being created here you must also |
209 // change the downcast to it in SpawnTarget(). | 230 // change the downcast to it in SpawnTarget(). |
210 return new PolicyBase; | 231 return new PolicyBase; |
211 } | 232 } |
212 | 233 |
213 void BrokerServicesBase::FreeResources(JobTracker* tracker) { | |
214 if (NULL != tracker->policy) { | |
215 BOOL res = ::TerminateJobObject(tracker->job, SBOX_ALL_OK); | |
216 DCHECK(res); | |
217 // Closing the job causes the target process to be destroyed so this | |
218 // needs to happen before calling OnJobEmpty(). | |
219 res = ::CloseHandle(tracker->job); | |
220 DCHECK(res); | |
221 // In OnJobEmpty() we don't actually use the job handle directly. | |
222 tracker->policy->OnJobEmpty(tracker->job); | |
223 tracker->policy->Release(); | |
224 tracker->policy = NULL; | |
225 } | |
226 } | |
227 | |
228 // The worker thread stays in a loop waiting for asynchronous notifications | 234 // The worker thread stays in a loop waiting for asynchronous notifications |
229 // from the job objects. Right now we only care about knowing when the last | 235 // from the job objects. Right now we only care about knowing when the last |
230 // process on a job terminates, but in general this is the place to tell | 236 // process on a job terminates, but in general this is the place to tell |
231 // the policy about events. | 237 // the policy about events. |
232 DWORD WINAPI BrokerServicesBase::TargetEventsThread(PVOID param) { | 238 DWORD WINAPI BrokerServicesBase::TargetEventsThread(PVOID param) { |
233 if (NULL == param) | 239 if (NULL == param) |
234 return 1; | 240 return 1; |
235 | 241 |
236 base::PlatformThread::SetName("BrokerEvent"); | 242 base::PlatformThread::SetName("BrokerEvent"); |
237 | 243 |
238 BrokerServicesBase* broker = reinterpret_cast<BrokerServicesBase*>(param); | 244 BrokerServicesBase* broker = reinterpret_cast<BrokerServicesBase*>(param); |
239 HANDLE port = broker->job_port_; | 245 HANDLE port = broker->job_port_.Get(); |
240 HANDLE no_targets = broker->no_targets_; | 246 HANDLE no_targets = broker->no_targets_.Get(); |
241 | 247 |
242 int target_counter = 0; | 248 int target_counter = 0; |
243 ::ResetEvent(no_targets); | 249 ::ResetEvent(no_targets); |
244 | 250 |
245 while (true) { | 251 while (true) { |
246 DWORD events = 0; | 252 DWORD events = 0; |
247 ULONG_PTR key = 0; | 253 ULONG_PTR key = 0; |
248 LPOVERLAPPED ovl = NULL; | 254 LPOVERLAPPED ovl = NULL; |
249 | 255 |
250 if (!::GetQueuedCompletionStatus(port, &events, &key, &ovl, INFINITE)) | 256 if (!::GetQueuedCompletionStatus(port, &events, &key, &ovl, INFINITE)) { |
251 // this call fails if the port has been closed before we have a | 257 // this call fails if the port has been closed before we have a |
252 // chance to service the last packet which is 'exit' anyway so | 258 // chance to service the last packet which is 'exit' anyway so |
253 // this is not an error. | 259 // this is not an error. |
254 return 1; | 260 return 1; |
| 261 } |
255 | 262 |
256 if (key > THREAD_CTRL_LAST) { | 263 if (key > THREAD_CTRL_LAST) { |
257 // The notification comes from a job object. There are nine notifications | 264 // The notification comes from a job object. There are nine notifications |
258 // that jobs can send and some of them depend on the job attributes set. | 265 // that jobs can send and some of them depend on the job attributes set. |
259 JobTracker* tracker = reinterpret_cast<JobTracker*>(key); | 266 JobTracker* tracker = reinterpret_cast<JobTracker*>(key); |
260 | 267 |
261 switch (events) { | 268 switch (events) { |
262 case JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO: { | 269 case JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO: { |
263 // The job object has signaled that the last process associated | 270 // The job object has signaled that the last process associated |
264 // with it has terminated. Assuming there is no way for a process | 271 // with it has terminated. Assuming there is no way for a process |
265 // to appear out of thin air in this job, it safe to assume that | 272 // to appear out of thin air in this job, it safe to assume that |
266 // we can tell the policy to destroy the target object, and for | 273 // we can tell the policy to destroy the target object, and for |
267 // us to release our reference to the policy object. | 274 // us to release our reference to the policy object. |
268 FreeResources(tracker); | 275 tracker->FreeResources(); |
269 break; | 276 break; |
270 } | 277 } |
271 | 278 |
272 case JOB_OBJECT_MSG_NEW_PROCESS: { | 279 case JOB_OBJECT_MSG_NEW_PROCESS: { |
273 ++target_counter; | 280 ++target_counter; |
274 if (1 == target_counter) { | 281 if (1 == target_counter) { |
275 ::ResetEvent(no_targets); | 282 ::ResetEvent(no_targets); |
276 } | 283 } |
277 break; | 284 break; |
278 } | 285 } |
(...skipping 11 matching lines...) Expand all Loading... |
290 | 297 |
291 DCHECK(target_counter >= 0); | 298 DCHECK(target_counter >= 0); |
292 break; | 299 break; |
293 } | 300 } |
294 | 301 |
295 case JOB_OBJECT_MSG_ACTIVE_PROCESS_LIMIT: { | 302 case JOB_OBJECT_MSG_ACTIVE_PROCESS_LIMIT: { |
296 break; | 303 break; |
297 } | 304 } |
298 | 305 |
299 case JOB_OBJECT_MSG_PROCESS_MEMORY_LIMIT: { | 306 case JOB_OBJECT_MSG_PROCESS_MEMORY_LIMIT: { |
300 BOOL res = ::TerminateJobObject(tracker->job, | 307 BOOL res = ::TerminateJobObject(tracker->job.Get(), |
301 SBOX_FATAL_MEMORY_EXCEEDED); | 308 SBOX_FATAL_MEMORY_EXCEEDED); |
302 DCHECK(res); | 309 DCHECK(res); |
303 break; | 310 break; |
304 } | 311 } |
305 | 312 |
306 default: { | 313 default: { |
307 NOTREACHED(); | 314 NOTREACHED(); |
308 break; | 315 break; |
309 } | 316 } |
310 } | 317 } |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
360 base::win::ScopedHandle initial_token; | 367 base::win::ScopedHandle initial_token; |
361 base::win::ScopedHandle lockdown_token; | 368 base::win::ScopedHandle lockdown_token; |
362 ResultCode result = SBOX_ALL_OK; | 369 ResultCode result = SBOX_ALL_OK; |
363 | 370 |
364 if (IsTokenCacheable(policy_base)) { | 371 if (IsTokenCacheable(policy_base)) { |
365 // Create the master tokens only once and save them in a cache. That way | 372 // Create the master tokens only once and save them in a cache. That way |
366 // can just duplicate them to avoid hammering LSASS on every sandboxed | 373 // can just duplicate them to avoid hammering LSASS on every sandboxed |
367 // process launch. | 374 // process launch. |
368 uint32_t token_key = GenerateTokenCacheKey(policy_base); | 375 uint32_t token_key = GenerateTokenCacheKey(policy_base); |
369 TokenCacheMap::iterator it = token_cache_.find(token_key); | 376 TokenCacheMap::iterator it = token_cache_.find(token_key); |
370 HANDLE initial_token_temp; | 377 TokenPair* tokens; |
371 HANDLE lockdown_token_temp; | |
372 if (it != token_cache_.end()) { | 378 if (it != token_cache_.end()) { |
373 initial_token_temp = it->second.first; | 379 tokens = it->second; |
374 lockdown_token_temp = it->second.second; | |
375 } else { | 380 } else { |
376 result = policy_base->MakeTokens(&initial_token, &lockdown_token); | 381 result = policy_base->MakeTokens(&initial_token, &lockdown_token); |
377 if (SBOX_ALL_OK != result) | 382 if (SBOX_ALL_OK != result) |
378 return result; | 383 return result; |
379 token_cache_[token_key] = | 384 |
380 std::make_pair(initial_token.Get(), lockdown_token.Get()); | 385 tokens = new TokenPair(initial_token.Pass(), lockdown_token.Pass()); |
381 initial_token_temp = initial_token.Take(); | 386 token_cache_[token_key] = tokens; |
382 lockdown_token_temp = lockdown_token.Take(); | |
383 } | 387 } |
384 | 388 |
385 if (!::DuplicateToken(initial_token_temp, SecurityImpersonation, | 389 HANDLE temp_token; |
386 &initial_token_temp)) { | 390 if (!::DuplicateToken(tokens->initial.Get(), SecurityImpersonation, |
| 391 &temp_token)) { |
387 return SBOX_ERROR_GENERIC; | 392 return SBOX_ERROR_GENERIC; |
388 } | 393 } |
389 initial_token.Set(initial_token_temp); | 394 initial_token.Set(temp_token); |
390 | 395 |
391 if (!::DuplicateTokenEx(lockdown_token_temp, TOKEN_ALL_ACCESS, 0, | 396 if (!::DuplicateTokenEx(tokens->lockdown.Get(), TOKEN_ALL_ACCESS, 0, |
392 SecurityIdentification, TokenPrimary, | 397 SecurityIdentification, TokenPrimary, |
393 &lockdown_token_temp)) { | 398 &temp_token)) { |
394 return SBOX_ERROR_GENERIC; | 399 return SBOX_ERROR_GENERIC; |
395 } | 400 } |
396 lockdown_token.Set(lockdown_token_temp); | 401 lockdown_token.Set(temp_token); |
397 } else { | 402 } else { |
398 result = policy_base->MakeTokens(&initial_token, &lockdown_token); | 403 result = policy_base->MakeTokens(&initial_token, &lockdown_token); |
399 if (SBOX_ALL_OK != result) | 404 if (SBOX_ALL_OK != result) |
400 return result; | 405 return result; |
401 } | 406 } |
402 | 407 |
403 HANDLE job_temp; | 408 HANDLE job_temp; |
404 result = policy_base->MakeJobObject(&job_temp); | 409 result = policy_base->MakeJobObject(&job_temp); |
405 if (SBOX_ALL_OK != result) | 410 if (SBOX_ALL_OK != result) |
406 return result; | 411 return result; |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
516 | 521 |
517 // Now the policy is the owner of the target. | 522 // Now the policy is the owner of the target. |
518 if (!policy_base->AddTarget(target)) { | 523 if (!policy_base->AddTarget(target)) { |
519 return SpawnCleanup(target, 0); | 524 return SpawnCleanup(target, 0); |
520 } | 525 } |
521 | 526 |
522 // We are going to keep a pointer to the policy because we'll call it when | 527 // We are going to keep a pointer to the policy because we'll call it when |
523 // the job object generates notifications using the completion port. | 528 // the job object generates notifications using the completion port. |
524 policy_base->AddRef(); | 529 policy_base->AddRef(); |
525 if (job.IsValid()) { | 530 if (job.IsValid()) { |
526 scoped_ptr<JobTracker> tracker(new JobTracker(job.Take(), policy_base)); | 531 scoped_ptr<JobTracker> tracker(new JobTracker(job.Pass(), policy_base)); |
527 | 532 |
528 // There is no obvious recovery after failure here. Previous version with | 533 // There is no obvious recovery after failure here. Previous version with |
529 // SpawnCleanup() caused deletion of TargetProcess twice. crbug.com/480639 | 534 // SpawnCleanup() caused deletion of TargetProcess twice. crbug.com/480639 |
530 CHECK(AssociateCompletionPort(tracker->job, job_port_, tracker.get())); | 535 CHECK(AssociateCompletionPort(tracker->job.Get(), job_port_.Get(), |
| 536 tracker.get())); |
531 | 537 |
532 // Save the tracker because in cleanup we might need to force closing | 538 // Save the tracker because in cleanup we might need to force closing |
533 // the Jobs. | 539 // the Jobs. |
534 tracker_list_.push_back(tracker.release()); | 540 tracker_list_.push_back(tracker.release()); |
535 child_process_ids_.insert(process_info.process_id()); | 541 child_process_ids_.insert(process_info.process_id()); |
536 } else { | 542 } else { |
537 // We have to signal the event once here because the completion port will | 543 // We have to signal the event once here because the completion port will |
538 // never get a message that this target is being terminated thus we should | 544 // never get a message that this target is being terminated thus we should |
539 // not block WaitForAllTargets until we have at least one target with job. | 545 // not block WaitForAllTargets until we have at least one target with job. |
540 if (child_process_ids_.empty()) | 546 if (child_process_ids_.empty()) |
541 ::SetEvent(no_targets_); | 547 ::SetEvent(no_targets_.Get()); |
542 // We can not track the life time of such processes and it is responsibility | 548 // We can not track the life time of such processes and it is responsibility |
543 // of the host application to make sure that spawned targets without jobs | 549 // of the host application to make sure that spawned targets without jobs |
544 // are terminated when the main application don't need them anymore. | 550 // are terminated when the main application don't need them anymore. |
545 // Sandbox policy engine needs to know that these processes are valid | 551 // Sandbox policy engine needs to know that these processes are valid |
546 // targets for e.g. BrokerDuplicateHandle so track them as peer processes. | 552 // targets for e.g. BrokerDuplicateHandle so track them as peer processes. |
547 AddTargetPeer(process_info.process_handle()); | 553 AddTargetPeer(process_info.process_handle()); |
548 } | 554 } |
549 | 555 |
550 *target_info = process_info.Take(); | 556 *target_info = process_info.Take(); |
551 return SBOX_ALL_OK; | 557 return SBOX_ALL_OK; |
552 } | 558 } |
553 | 559 |
554 | 560 |
555 ResultCode BrokerServicesBase::WaitForAllTargets() { | 561 ResultCode BrokerServicesBase::WaitForAllTargets() { |
556 ::WaitForSingleObject(no_targets_, INFINITE); | 562 ::WaitForSingleObject(no_targets_.Get(), INFINITE); |
557 return SBOX_ALL_OK; | 563 return SBOX_ALL_OK; |
558 } | 564 } |
559 | 565 |
560 bool BrokerServicesBase::IsActiveTarget(DWORD process_id) { | 566 bool BrokerServicesBase::IsActiveTarget(DWORD process_id) { |
561 AutoLock lock(&lock_); | 567 AutoLock lock(&lock_); |
562 return child_process_ids_.find(process_id) != child_process_ids_.end() || | 568 return child_process_ids_.find(process_id) != child_process_ids_.end() || |
563 peer_map_.find(process_id) != peer_map_.end(); | 569 peer_map_.find(process_id) != peer_map_.end(); |
564 } | 570 } |
565 | 571 |
566 VOID CALLBACK BrokerServicesBase::RemovePeer(PVOID parameter, BOOLEAN timeout) { | 572 VOID CALLBACK BrokerServicesBase::RemovePeer(PVOID parameter, BOOLEAN timeout) { |
567 PeerTracker* peer = reinterpret_cast<PeerTracker*>(parameter); | 573 PeerTracker* peer = reinterpret_cast<PeerTracker*>(parameter); |
568 // Don't check the return code because we this may fail (safely) at shutdown. | 574 // Don't check the return code because we this may fail (safely) at shutdown. |
569 ::PostQueuedCompletionStatus( | 575 ::PostQueuedCompletionStatus( |
570 peer->job_port, 0, THREAD_CTRL_REMOVE_PEER, | 576 peer->job_port, 0, THREAD_CTRL_REMOVE_PEER, |
571 reinterpret_cast<LPOVERLAPPED>(static_cast<uintptr_t>(peer->id))); | 577 reinterpret_cast<LPOVERLAPPED>(static_cast<uintptr_t>(peer->id))); |
572 } | 578 } |
573 | 579 |
574 ResultCode BrokerServicesBase::AddTargetPeer(HANDLE peer_process) { | 580 ResultCode BrokerServicesBase::AddTargetPeer(HANDLE peer_process) { |
575 scoped_ptr<PeerTracker> peer(new PeerTracker(::GetProcessId(peer_process), | 581 scoped_ptr<PeerTracker> peer(new PeerTracker(::GetProcessId(peer_process), |
576 job_port_)); | 582 job_port_.Get())); |
577 if (!peer->id) | 583 if (!peer->id) |
578 return SBOX_ERROR_GENERIC; | 584 return SBOX_ERROR_GENERIC; |
579 | 585 |
580 HANDLE process_handle; | 586 HANDLE process_handle; |
581 if (!::DuplicateHandle(::GetCurrentProcess(), peer_process, | 587 if (!::DuplicateHandle(::GetCurrentProcess(), peer_process, |
582 ::GetCurrentProcess(), &process_handle, | 588 ::GetCurrentProcess(), &process_handle, |
583 SYNCHRONIZE, FALSE, 0)) { | 589 SYNCHRONIZE, FALSE, 0)) { |
584 return SBOX_ERROR_GENERIC; | 590 return SBOX_ERROR_GENERIC; |
585 } | 591 } |
586 peer->process.Set(process_handle); | 592 peer->process.Set(process_handle); |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
621 return SBOX_ERROR_UNSUPPORTED; | 627 return SBOX_ERROR_UNSUPPORTED; |
622 | 628 |
623 base::string16 name = LookupAppContainer(sid); | 629 base::string16 name = LookupAppContainer(sid); |
624 if (name.empty()) | 630 if (name.empty()) |
625 return SBOX_ERROR_INVALID_APP_CONTAINER; | 631 return SBOX_ERROR_INVALID_APP_CONTAINER; |
626 | 632 |
627 return DeleteAppContainer(sid); | 633 return DeleteAppContainer(sid); |
628 } | 634 } |
629 | 635 |
630 } // namespace sandbox | 636 } // namespace sandbox |
OLD | NEW |