security/sandbox/win/src/broker_services.cc

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
michael@0 2 // Use of this source code is governed by a BSD-style license that can be
michael@0 3 // found in the LICENSE file.
michael@0 4
michael@0 5 #include "sandbox/win/src/broker_services.h"
michael@0 6
michael@0 7 #include "base/logging.h"
michael@0 8 #include "base/memory/scoped_ptr.h"
michael@0 9 #include "base/threading/platform_thread.h"
michael@0 10 #include "base/win/scoped_handle.h"
michael@0 11 #include "base/win/scoped_process_information.h"
michael@0 12 #include "base/win/startup_information.h"
michael@0 13 #include "base/win/windows_version.h"
michael@0 14 #include "sandbox/win/src/app_container.h"
michael@0 15 #include "sandbox/win/src/process_mitigations.h"
michael@0 16 #include "sandbox/win/src/sandbox_policy_base.h"
michael@0 17 #include "sandbox/win/src/sandbox.h"
michael@0 18 #include "sandbox/win/src/target_process.h"
michael@0 19 #include "sandbox/win/src/win2k_threadpool.h"
michael@0 20 #include "sandbox/win/src/win_utils.h"
michael@0 21
michael@0 22 namespace {
michael@0 23
michael@0 24 // Utility function to associate a completion port to a job object.
michael@0 25 bool AssociateCompletionPort(HANDLE job, HANDLE port, void* key) {
michael@0 26 JOBOBJECT_ASSOCIATE_COMPLETION_PORT job_acp = { key, port };
michael@0 27 return ::SetInformationJobObject(job,
michael@0 28 JobObjectAssociateCompletionPortInformation,
michael@0 29 &job_acp, sizeof(job_acp))? true : false;
michael@0 30 }
michael@0 31
michael@0 32 // Utility function to do the cleanup necessary when something goes wrong
michael@0 33 // while in SpawnTarget and we must terminate the target process.
michael@0 34 sandbox::ResultCode SpawnCleanup(sandbox::TargetProcess* target, DWORD error) {
michael@0 35 if (0 == error)
michael@0 36 error = ::GetLastError();
michael@0 37
michael@0 38 target->Terminate();
michael@0 39 delete target;
michael@0 40 ::SetLastError(error);
michael@0 41 return sandbox::SBOX_ERROR_GENERIC;
michael@0 42 }
michael@0 43
michael@0 44 // the different commands that you can send to the worker thread that
michael@0 45 // executes TargetEventsThread().
michael@0 46 enum {
michael@0 47 THREAD_CTRL_NONE,
michael@0 48 THREAD_CTRL_REMOVE_PEER,
michael@0 49 THREAD_CTRL_QUIT,
michael@0 50 THREAD_CTRL_LAST,
michael@0 51 };
michael@0 52
michael@0 53 // Helper structure that allows the Broker to associate a job notification
michael@0 54 // with a job object and with a policy.
michael@0 55 struct JobTracker {
michael@0 56 HANDLE job;
michael@0 57 sandbox::PolicyBase* policy;
michael@0 58 JobTracker(HANDLE cjob, sandbox::PolicyBase* cpolicy)
michael@0 59 : job(cjob), policy(cpolicy) {
michael@0 60 }
michael@0 61 };
michael@0 62
michael@0 63 // Helper structure that allows the broker to track peer processes
michael@0 64 struct PeerTracker {
michael@0 65 HANDLE wait_object;
michael@0 66 base::win::ScopedHandle process;
michael@0 67 DWORD id;
michael@0 68 HANDLE job_port;
michael@0 69 PeerTracker(DWORD process_id, HANDLE broker_job_port)
michael@0 70 : wait_object(NULL), id(process_id), job_port(broker_job_port) {
michael@0 71 }
michael@0 72 };
michael@0 73
michael@0 74 void DeregisterPeerTracker(PeerTracker* peer) {
michael@0 75 // Deregistration shouldn't fail, but we leak rather than crash if it does.
michael@0 76 if (::UnregisterWaitEx(peer->wait_object, INVALID_HANDLE_VALUE)) {
michael@0 77 delete peer;
michael@0 78 } else {
michael@0 79 NOTREACHED();
michael@0 80 }
michael@0 81 }
michael@0 82
michael@0 83 } // namespace
michael@0 84
michael@0 85 namespace sandbox {
michael@0 86
michael@0 87 BrokerServicesBase::BrokerServicesBase()
michael@0 88 : thread_pool_(NULL), job_port_(NULL), no_targets_(NULL),
michael@0 89 job_thread_(NULL) {
michael@0 90 }
michael@0 91
michael@0 92 // The broker uses a dedicated worker thread that services the job completion
michael@0 93 // port to perform policy notifications and associated cleanup tasks.
michael@0 94 ResultCode BrokerServicesBase::Init() {
michael@0 95 if ((NULL != job_port_) || (NULL != thread_pool_))
michael@0 96 return SBOX_ERROR_UNEXPECTED_CALL;
michael@0 97
michael@0 98 ::InitializeCriticalSection(&lock_);
michael@0 99
michael@0 100 job_port_ = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
michael@0 101 if (NULL == job_port_)
michael@0 102 return SBOX_ERROR_GENERIC;
michael@0 103
michael@0 104 no_targets_ = ::CreateEventW(NULL, TRUE, FALSE, NULL);
michael@0 105
michael@0 106 job_thread_ = ::CreateThread(NULL, 0, // Default security and stack.
michael@0 107 TargetEventsThread, this, NULL, NULL);
michael@0 108 if (NULL == job_thread_)
michael@0 109 return SBOX_ERROR_GENERIC;
michael@0 110
michael@0 111 return SBOX_ALL_OK;
michael@0 112 }
michael@0 113
michael@0 114 // The destructor should only be called when the Broker process is terminating.
michael@0 115 // Since BrokerServicesBase is a singleton, this is called from the CRT
michael@0 116 // termination handlers, if this code lives on a DLL it is called during
michael@0 117 // DLL_PROCESS_DETACH in other words, holding the loader lock, so we cannot
michael@0 118 // wait for threads here.
michael@0 119 BrokerServicesBase::~BrokerServicesBase() {
michael@0 120 // If there is no port Init() was never called successfully.
michael@0 121 if (!job_port_)
michael@0 122 return;
michael@0 123
michael@0 124 // Closing the port causes, that no more Job notifications are delivered to
michael@0 125 // the worker thread and also causes the thread to exit. This is what we
michael@0 126 // want to do since we are going to close all outstanding Jobs and notifying
michael@0 127 // the policy objects ourselves.
michael@0 128 ::PostQueuedCompletionStatus(job_port_, 0, THREAD_CTRL_QUIT, FALSE);
michael@0 129 ::CloseHandle(job_port_);
michael@0 130
michael@0 131 if (WAIT_TIMEOUT == ::WaitForSingleObject(job_thread_, 1000)) {
michael@0 132 // Cannot clean broker services.
michael@0 133 NOTREACHED();
michael@0 134 return;
michael@0 135 }
michael@0 136
michael@0 137 JobTrackerList::iterator it;
michael@0 138 for (it = tracker_list_.begin(); it != tracker_list_.end(); ++it) {
michael@0 139 JobTracker* tracker = (*it);
michael@0 140 FreeResources(tracker);
michael@0 141 delete tracker;
michael@0 142 }
michael@0 143 ::CloseHandle(job_thread_);
michael@0 144 delete thread_pool_;
michael@0 145 ::CloseHandle(no_targets_);
michael@0 146
michael@0 147 // Cancel the wait events and delete remaining peer trackers.
michael@0 148 for (PeerTrackerMap::iterator it = peer_map_.begin();
michael@0 149 it != peer_map_.end(); ++it) {
michael@0 150 DeregisterPeerTracker(it->second);
michael@0 151 }
michael@0 152
michael@0 153 // If job_port_ isn't NULL, assumes that the lock has been initialized.
michael@0 154 if (job_port_)
michael@0 155 ::DeleteCriticalSection(&lock_);
michael@0 156 }
michael@0 157
michael@0 158 TargetPolicy* BrokerServicesBase::CreatePolicy() {
michael@0 159 // If you change the type of the object being created here you must also
michael@0 160 // change the downcast to it in SpawnTarget().
michael@0 161 return new PolicyBase;
michael@0 162 }
michael@0 163
michael@0 164 void BrokerServicesBase::FreeResources(JobTracker* tracker) {
michael@0 165 if (NULL != tracker->policy) {
michael@0 166 BOOL res = ::TerminateJobObject(tracker->job, SBOX_ALL_OK);
michael@0 167 DCHECK(res);
michael@0 168 // Closing the job causes the target process to be destroyed so this
michael@0 169 // needs to happen before calling OnJobEmpty().
michael@0 170 res = ::CloseHandle(tracker->job);
michael@0 171 DCHECK(res);
michael@0 172 // In OnJobEmpty() we don't actually use the job handle directly.
michael@0 173 tracker->policy->OnJobEmpty(tracker->job);
michael@0 174 tracker->policy->Release();
michael@0 175 tracker->policy = NULL;
michael@0 176 }
michael@0 177 }
michael@0 178
michael@0 179 // The worker thread stays in a loop waiting for asynchronous notifications
michael@0 180 // from the job objects. Right now we only care about knowing when the last
michael@0 181 // process on a job terminates, but in general this is the place to tell
michael@0 182 // the policy about events.
michael@0 183 DWORD WINAPI BrokerServicesBase::TargetEventsThread(PVOID param) {
michael@0 184 if (NULL == param)
michael@0 185 return 1;
michael@0 186
michael@0 187 base::PlatformThread::SetName("BrokerEvent");
michael@0 188
michael@0 189 BrokerServicesBase* broker = reinterpret_cast<BrokerServicesBase*>(param);
michael@0 190 HANDLE port = broker->job_port_;
michael@0 191 HANDLE no_targets = broker->no_targets_;
michael@0 192
michael@0 193 int target_counter = 0;
michael@0 194 ::ResetEvent(no_targets);
michael@0 195
michael@0 196 while (true) {
michael@0 197 DWORD events = 0;
michael@0 198 ULONG_PTR key = 0;
michael@0 199 LPOVERLAPPED ovl = NULL;
michael@0 200
michael@0 201 if (!::GetQueuedCompletionStatus(port, &events, &key, &ovl, INFINITE))
michael@0 202 // this call fails if the port has been closed before we have a
michael@0 203 // chance to service the last packet which is 'exit' anyway so
michael@0 204 // this is not an error.
michael@0 205 return 1;
michael@0 206
michael@0 207 if (key > THREAD_CTRL_LAST) {
michael@0 208 // The notification comes from a job object. There are nine notifications
michael@0 209 // that jobs can send and some of them depend on the job attributes set.
michael@0 210 JobTracker* tracker = reinterpret_cast<JobTracker*>(key);
michael@0 211
michael@0 212 switch (events) {
michael@0 213 case JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO: {
michael@0 214 // The job object has signaled that the last process associated
michael@0 215 // with it has terminated. Assuming there is no way for a process
michael@0 216 // to appear out of thin air in this job, it safe to assume that
michael@0 217 // we can tell the policy to destroy the target object, and for
michael@0 218 // us to release our reference to the policy object.
michael@0 219 FreeResources(tracker);
michael@0 220 break;
michael@0 221 }
michael@0 222
michael@0 223 case JOB_OBJECT_MSG_NEW_PROCESS: {
michael@0 224 ++target_counter;
michael@0 225 if (1 == target_counter) {
michael@0 226 ::ResetEvent(no_targets);
michael@0 227 }
michael@0 228 break;
michael@0 229 }
michael@0 230
michael@0 231 case JOB_OBJECT_MSG_EXIT_PROCESS:
michael@0 232 case JOB_OBJECT_MSG_ABNORMAL_EXIT_PROCESS: {
michael@0 233 {
michael@0 234 AutoLock lock(&broker->lock_);
michael@0 235 broker->child_process_ids_.erase(reinterpret_cast<DWORD>(ovl));
michael@0 236 }
michael@0 237 --target_counter;
michael@0 238 if (0 == target_counter)
michael@0 239 ::SetEvent(no_targets);
michael@0 240
michael@0 241 DCHECK(target_counter >= 0);
michael@0 242 break;
michael@0 243 }
michael@0 244
michael@0 245 case JOB_OBJECT_MSG_ACTIVE_PROCESS_LIMIT: {
michael@0 246 break;
michael@0 247 }
michael@0 248
michael@0 249 default: {
michael@0 250 NOTREACHED();
michael@0 251 break;
michael@0 252 }
michael@0 253 }
michael@0 254 } else if (THREAD_CTRL_REMOVE_PEER == key) {
michael@0 255 // Remove a process from our list of peers.
michael@0 256 AutoLock lock(&broker->lock_);
michael@0 257 PeerTrackerMap::iterator it =
michael@0 258 broker->peer_map_.find(reinterpret_cast<DWORD>(ovl));
michael@0 259 DeregisterPeerTracker(it->second);
michael@0 260 broker->peer_map_.erase(it);
michael@0 261 } else if (THREAD_CTRL_QUIT == key) {
michael@0 262 // The broker object is being destroyed so the thread needs to exit.
michael@0 263 return 0;
michael@0 264 } else {
michael@0 265 // We have not implemented more commands.
michael@0 266 NOTREACHED();
michael@0 267 }
michael@0 268 }
michael@0 269
michael@0 270 NOTREACHED();
michael@0 271 return 0;
michael@0 272 }
michael@0 273
michael@0 274 // SpawnTarget does all the interesting sandbox setup and creates the target
michael@0 275 // process inside the sandbox.
michael@0 276 ResultCode BrokerServicesBase::SpawnTarget(const wchar_t* exe_path,
michael@0 277 const wchar_t* command_line,
michael@0 278 TargetPolicy* policy,
michael@0 279 PROCESS_INFORMATION* target_info) {
michael@0 280 if (!exe_path)
michael@0 281 return SBOX_ERROR_BAD_PARAMS;
michael@0 282
michael@0 283 if (!policy)
michael@0 284 return SBOX_ERROR_BAD_PARAMS;
michael@0 285
michael@0 286 // Even though the resources touched by SpawnTarget can be accessed in
michael@0 287 // multiple threads, the method itself cannot be called from more than
michael@0 288 // 1 thread. This is to protect the global variables used while setting up
michael@0 289 // the child process.
michael@0 290 static DWORD thread_id = ::GetCurrentThreadId();
michael@0 291 DCHECK(thread_id == ::GetCurrentThreadId());
michael@0 292
michael@0 293 AutoLock lock(&lock_);
michael@0 294
michael@0 295 // This downcast is safe as long as we control CreatePolicy()
michael@0 296 PolicyBase* policy_base = static_cast<PolicyBase*>(policy);
michael@0 297
michael@0 298 // Construct the tokens and the job object that we are going to associate
michael@0 299 // with the soon to be created target process.
michael@0 300 HANDLE initial_token_temp;
michael@0 301 HANDLE lockdown_token_temp;
michael@0 302 ResultCode result = policy_base->MakeTokens(&initial_token_temp,
michael@0 303 &lockdown_token_temp);
michael@0 304 if (SBOX_ALL_OK != result)
michael@0 305 return result;
michael@0 306
michael@0 307 base::win::ScopedHandle initial_token(initial_token_temp);
michael@0 308 base::win::ScopedHandle lockdown_token(lockdown_token_temp);
michael@0 309
michael@0 310 HANDLE job_temp;
michael@0 311 result = policy_base->MakeJobObject(&job_temp);
michael@0 312 if (SBOX_ALL_OK != result)
michael@0 313 return result;
michael@0 314
michael@0 315 base::win::ScopedHandle job(job_temp);
michael@0 316
michael@0 317 // Initialize the startup information from the policy.
michael@0 318 base::win::StartupInformation startup_info;
michael@0 319 string16 desktop = policy_base->GetAlternateDesktop();
michael@0 320 if (!desktop.empty()) {
michael@0 321 startup_info.startup_info()->lpDesktop =
michael@0 322 const_cast<wchar_t*>(desktop.c_str());
michael@0 323 }
michael@0 324
michael@0 325 bool inherit_handles = false;
michael@0 326 if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
michael@0 327 int attribute_count = 0;
michael@0 328 const AppContainerAttributes* app_container =
michael@0 329 policy_base->GetAppContainer();
michael@0 330 if (app_container)
michael@0 331 ++attribute_count;
michael@0 332
michael@0 333 DWORD64 mitigations;
michael@0 334 size_t mitigations_size;
michael@0 335 ConvertProcessMitigationsToPolicy(policy->GetProcessMitigations(),
michael@0 336 &mitigations, &mitigations_size);
michael@0 337 if (mitigations)
michael@0 338 ++attribute_count;
michael@0 339
michael@0 340 HANDLE stdout_handle = policy_base->GetStdoutHandle();
michael@0 341 HANDLE stderr_handle = policy_base->GetStderrHandle();
michael@0 342 HANDLE inherit_handle_list[2];
michael@0 343 int inherit_handle_count = 0;
michael@0 344 if (stdout_handle != INVALID_HANDLE_VALUE)
michael@0 345 inherit_handle_list[inherit_handle_count++] = stdout_handle;
michael@0 346 // Handles in the list must be unique.
michael@0 347 if (stderr_handle != stdout_handle && stderr_handle != INVALID_HANDLE_VALUE)
michael@0 348 inherit_handle_list[inherit_handle_count++] = stderr_handle;
michael@0 349 if (inherit_handle_count)
michael@0 350 ++attribute_count;
michael@0 351
michael@0 352 if (!startup_info.InitializeProcThreadAttributeList(attribute_count))
michael@0 353 return SBOX_ERROR_PROC_THREAD_ATTRIBUTES;
michael@0 354
michael@0 355 if (app_container) {
michael@0 356 result = app_container->ShareForStartup(&startup_info);
michael@0 357 if (SBOX_ALL_OK != result)
michael@0 358 return result;
michael@0 359 }
michael@0 360
michael@0 361 if (mitigations) {
michael@0 362 if (!startup_info.UpdateProcThreadAttribute(
michael@0 363 PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY, &mitigations,
michael@0 364 mitigations_size)) {
michael@0 365 return SBOX_ERROR_PROC_THREAD_ATTRIBUTES;
michael@0 366 }
michael@0 367 }
michael@0 368
michael@0 369 if (inherit_handle_count) {
michael@0 370 if (!startup_info.UpdateProcThreadAttribute(
michael@0 371 PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
michael@0 372 inherit_handle_list,
michael@0 373 sizeof(inherit_handle_list[0]) * inherit_handle_count)) {
michael@0 374 return SBOX_ERROR_PROC_THREAD_ATTRIBUTES;
michael@0 375 }
michael@0 376 startup_info.startup_info()->dwFlags |= STARTF_USESTDHANDLES;
michael@0 377 startup_info.startup_info()->hStdInput = INVALID_HANDLE_VALUE;
michael@0 378 startup_info.startup_info()->hStdOutput = stdout_handle;
michael@0 379 startup_info.startup_info()->hStdError = stderr_handle;
michael@0 380 // Allowing inheritance of handles is only secure now that we
michael@0 381 // have limited which handles will be inherited.
michael@0 382 inherit_handles = true;
michael@0 383 }
michael@0 384 }
michael@0 385
michael@0 386 // Construct the thread pool here in case it is expensive.
michael@0 387 // The thread pool is shared by all the targets
michael@0 388 if (NULL == thread_pool_)
michael@0 389 thread_pool_ = new Win2kThreadPool();
michael@0 390
michael@0 391 // Create the TargetProces object and spawn the target suspended. Note that
michael@0 392 // Brokerservices does not own the target object. It is owned by the Policy.
michael@0 393 base::win::ScopedProcessInformation process_info;
michael@0 394 TargetProcess* target = new TargetProcess(initial_token.Take(),
michael@0 395 lockdown_token.Take(),
michael@0 396 job,
michael@0 397 thread_pool_);
michael@0 398
michael@0 399 DWORD win_result = target->Create(exe_path, command_line, inherit_handles,
michael@0 400 startup_info, &process_info);
michael@0 401 if (ERROR_SUCCESS != win_result)
michael@0 402 return SpawnCleanup(target, win_result);
michael@0 403
michael@0 404 // Now the policy is the owner of the target.
michael@0 405 if (!policy_base->AddTarget(target)) {
michael@0 406 return SpawnCleanup(target, 0);
michael@0 407 }
michael@0 408
michael@0 409 // We are going to keep a pointer to the policy because we'll call it when
michael@0 410 // the job object generates notifications using the completion port.
michael@0 411 policy_base->AddRef();
michael@0 412 if (job.IsValid()) {
michael@0 413 scoped_ptr<JobTracker> tracker(new JobTracker(job.Take(), policy_base));
michael@0 414 if (!AssociateCompletionPort(tracker->job, job_port_, tracker.get()))
michael@0 415 return SpawnCleanup(target, 0);
michael@0 416 // Save the tracker because in cleanup we might need to force closing
michael@0 417 // the Jobs.
michael@0 418 tracker_list_.push_back(tracker.release());
michael@0 419 child_process_ids_.insert(process_info.process_id());
michael@0 420 } else {
michael@0 421 // We have to signal the event once here because the completion port will
michael@0 422 // never get a message that this target is being terminated thus we should
michael@0 423 // not block WaitForAllTargets until we have at least one target with job.
michael@0 424 if (child_process_ids_.empty())
michael@0 425 ::SetEvent(no_targets_);
michael@0 426 // We can not track the life time of such processes and it is responsibility
michael@0 427 // of the host application to make sure that spawned targets without jobs
michael@0 428 // are terminated when the main application don't need them anymore.
michael@0 429 }
michael@0 430
michael@0 431 *target_info = process_info.Take();
michael@0 432 return SBOX_ALL_OK;
michael@0 433 }
michael@0 434
michael@0 435
michael@0 436 ResultCode BrokerServicesBase::WaitForAllTargets() {
michael@0 437 ::WaitForSingleObject(no_targets_, INFINITE);
michael@0 438 return SBOX_ALL_OK;
michael@0 439 }
michael@0 440
michael@0 441 bool BrokerServicesBase::IsActiveTarget(DWORD process_id) {
michael@0 442 AutoLock lock(&lock_);
michael@0 443 return child_process_ids_.find(process_id) != child_process_ids_.end() ||
michael@0 444 peer_map_.find(process_id) != peer_map_.end();
michael@0 445 }
michael@0 446
michael@0 447 VOID CALLBACK BrokerServicesBase::RemovePeer(PVOID parameter, BOOLEAN timeout) {
michael@0 448 PeerTracker* peer = reinterpret_cast<PeerTracker*>(parameter);
michael@0 449 // Don't check the return code because we this may fail (safely) at shutdown.
michael@0 450 ::PostQueuedCompletionStatus(peer->job_port, 0, THREAD_CTRL_REMOVE_PEER,
michael@0 451 reinterpret_cast<LPOVERLAPPED>(peer->id));
michael@0 452 }
michael@0 453
michael@0 454 ResultCode BrokerServicesBase::AddTargetPeer(HANDLE peer_process) {
michael@0 455 scoped_ptr<PeerTracker> peer(new PeerTracker(::GetProcessId(peer_process),
michael@0 456 job_port_));
michael@0 457 if (!peer->id)
michael@0 458 return SBOX_ERROR_GENERIC;
michael@0 459
michael@0 460 HANDLE process_handle;
michael@0 461 if (!::DuplicateHandle(::GetCurrentProcess(), peer_process,
michael@0 462 ::GetCurrentProcess(), &process_handle,
michael@0 463 SYNCHRONIZE, FALSE, 0)) {
michael@0 464 return SBOX_ERROR_GENERIC;
michael@0 465 }
michael@0 466 peer->process.Set(process_handle);
michael@0 467
michael@0 468 AutoLock lock(&lock_);
michael@0 469 if (!peer_map_.insert(std::make_pair(peer->id, peer.get())).second)
michael@0 470 return SBOX_ERROR_BAD_PARAMS;
michael@0 471
michael@0 472 if (!::RegisterWaitForSingleObject(
michael@0 473 &peer->wait_object, peer->process, RemovePeer, peer.get(), INFINITE,
michael@0 474 WT_EXECUTEONLYONCE | WT_EXECUTEINWAITTHREAD)) {
michael@0 475 peer_map_.erase(peer->id);
michael@0 476 return SBOX_ERROR_GENERIC;
michael@0 477 }
michael@0 478
michael@0 479 // Release the pointer since it will be cleaned up by the callback.
michael@0 480 peer.release();
michael@0 481 return SBOX_ALL_OK;
michael@0 482 }
michael@0 483
michael@0 484 ResultCode BrokerServicesBase::InstallAppContainer(const wchar_t* sid,
michael@0 485 const wchar_t* name) {
michael@0 486 if (base::win::OSInfo::GetInstance()->version() < base::win::VERSION_WIN8)
michael@0 487 return SBOX_ERROR_UNSUPPORTED;
michael@0 488
michael@0 489 string16 old_name = LookupAppContainer(sid);
michael@0 490 if (old_name.empty())
michael@0 491 return CreateAppContainer(sid, name);
michael@0 492
michael@0 493 if (old_name != name)
michael@0 494 return SBOX_ERROR_INVALID_APP_CONTAINER;
michael@0 495
michael@0 496 return SBOX_ALL_OK;
michael@0 497 }
michael@0 498
michael@0 499 ResultCode BrokerServicesBase::UninstallAppContainer(const wchar_t* sid) {
michael@0 500 if (base::win::OSInfo::GetInstance()->version() < base::win::VERSION_WIN8)
michael@0 501 return SBOX_ERROR_UNSUPPORTED;
michael@0 502
michael@0 503 string16 name = LookupAppContainer(sid);
michael@0 504 if (name.empty())
michael@0 505 return SBOX_ERROR_INVALID_APP_CONTAINER;
michael@0 506
michael@0 507 return DeleteAppContainer(sid);
michael@0 508 }
michael@0 509
michael@0 510 } // namespace sandbox

mercurial