Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(113)

Unified Diff: sandbox/src/broker_services.cc

Issue 10689170: Move the Windows sandbox to sandbox/win (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase on top of tree (properly this time) Created 8 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « sandbox/src/broker_services.h ('k') | sandbox/src/crosscall_client.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: sandbox/src/broker_services.cc
diff --git a/sandbox/src/broker_services.cc b/sandbox/src/broker_services.cc
deleted file mode 100644
index 7f46abedeb9fc8bbf9ddad90a010569b70bd88a6..0000000000000000000000000000000000000000
--- a/sandbox/src/broker_services.cc
+++ /dev/null
@@ -1,405 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "sandbox/src/broker_services.h"
-
-#include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/threading/platform_thread.h"
-#include "base/win/scoped_handle.h"
-#include "base/win/scoped_process_information.h"
-#include "sandbox/src/sandbox_policy_base.h"
-#include "sandbox/src/sandbox.h"
-#include "sandbox/src/target_process.h"
-#include "sandbox/src/win2k_threadpool.h"
-#include "sandbox/src/win_utils.h"
-
-namespace {
-
-// Utility function to associate a completion port to a job object.
-bool AssociateCompletionPort(HANDLE job, HANDLE port, void* key) {
- JOBOBJECT_ASSOCIATE_COMPLETION_PORT job_acp = { key, port };
- return ::SetInformationJobObject(job,
- JobObjectAssociateCompletionPortInformation,
- &job_acp, sizeof(job_acp))? true : false;
-}
-
-// Utility function to do the cleanup necessary when something goes wrong
-// while in SpawnTarget and we must terminate the target process.
-sandbox::ResultCode SpawnCleanup(sandbox::TargetProcess* target, DWORD error) {
- if (0 == error)
- error = ::GetLastError();
-
- target->Terminate();
- delete target;
- ::SetLastError(error);
- return sandbox::SBOX_ERROR_GENERIC;
-}
-
-// the different commands that you can send to the worker thread that
-// executes TargetEventsThread().
-enum {
- THREAD_CTRL_NONE,
- THREAD_CTRL_REMOVE_PEER,
- THREAD_CTRL_QUIT,
- 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) {
- }
-};
-
-void DeregisterPeerTracker(PeerTracker* peer) {
- // Deregistration shouldn't fail, but we leak rather than crash if it does.
- if (::UnregisterWaitEx(peer->wait_object, INVALID_HANDLE_VALUE)) {
- delete peer;
- } else {
- NOTREACHED();
- }
-}
-
-} // namespace
-
-namespace sandbox {
-
-BrokerServicesBase::BrokerServicesBase()
- : thread_pool_(NULL), job_port_(NULL), no_targets_(NULL),
- job_thread_(NULL) {
-}
-
-// The broker uses a dedicated worker thread that services the job completion
-// port to perform policy notifications and associated cleanup tasks.
-ResultCode BrokerServicesBase::Init() {
- if ((NULL != job_port_) || (NULL != thread_pool_))
- return SBOX_ERROR_UNEXPECTED_CALL;
-
- ::InitializeCriticalSection(&lock_);
-
- job_port_ = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
- if (NULL == job_port_)
- return SBOX_ERROR_GENERIC;
-
- no_targets_ = ::CreateEventW(NULL, TRUE, FALSE, NULL);
-
- job_thread_ = ::CreateThread(NULL, 0, // Default security and stack.
- TargetEventsThread, this, NULL, NULL);
- if (NULL == job_thread_)
- return SBOX_ERROR_GENERIC;
-
- return SBOX_ALL_OK;
-}
-
-// The destructor should only be called when the Broker process is terminating.
-// Since BrokerServicesBase is a singleton, this is called from the CRT
-// termination handlers, if this code lives on a DLL it is called during
-// DLL_PROCESS_DETACH in other words, holding the loader lock, so we cannot
-// wait for threads here.
-BrokerServicesBase::~BrokerServicesBase() {
- // 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
- // the policy objects ourselves.
- ::PostQueuedCompletionStatus(job_port_, 0, THREAD_CTRL_QUIT, FALSE);
- ::CloseHandle(job_port_);
-
- if (WAIT_TIMEOUT == ::WaitForSingleObject(job_thread_, 1000)) {
- // Cannot clean broker services.
- NOTREACHED();
- return;
- }
-
- JobTrackerList::iterator it;
- for (it = tracker_list_.begin(); it != tracker_list_.end(); ++it) {
- JobTracker* tracker = (*it);
- FreeResources(tracker);
- delete tracker;
- }
- ::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) {
- DeregisterPeerTracker(it->second);
- }
-
- // If job_port_ isn't NULL, assumes that the lock has been initialized.
- if (job_port_)
- ::DeleteCriticalSection(&lock_);
-}
-
-TargetPolicy* BrokerServicesBase::CreatePolicy() {
- // If you change the type of the object being created here you must also
- // change the downcast to it in SpawnTarget().
- return new PolicyBase;
-}
-
-void BrokerServicesBase::FreeResources(JobTracker* tracker) {
- if (NULL != tracker->policy) {
- BOOL res = ::TerminateJobObject(tracker->job, SBOX_ALL_OK);
- DCHECK(res);
- // Closing the job causes the target process to be destroyed so this
- // needs to happen before calling OnJobEmpty().
- res = ::CloseHandle(tracker->job);
- DCHECK(res);
- // In OnJobEmpty() we don't actually use the job handle directly.
- tracker->policy->OnJobEmpty(tracker->job);
- tracker->policy->Release();
- tracker->policy = NULL;
- }
-}
-
-// The worker thread stays in a loop waiting for asynchronous notifications
-// from the job objects. Right now we only care about knowing when the last
-// process on a job terminates, but in general this is the place to tell
-// the policy about events.
-DWORD WINAPI BrokerServicesBase::TargetEventsThread(PVOID param) {
- if (NULL == param)
- return 1;
-
- base::PlatformThread::SetName("BrokerEvent");
-
- BrokerServicesBase* broker = reinterpret_cast<BrokerServicesBase*>(param);
- HANDLE port = broker->job_port_;
- HANDLE no_targets = broker->no_targets_;
-
- int target_counter = 0;
- ::ResetEvent(no_targets);
-
- while (true) {
- DWORD events = 0;
- ULONG_PTR key = 0;
- LPOVERLAPPED ovl = NULL;
-
- if (!::GetQueuedCompletionStatus(port, &events, &key, &ovl, INFINITE))
- // this call fails if the port has been closed before we have a
- // chance to service the last packet which is 'exit' anyway so
- // this is not an error.
- return 1;
-
- if (key > THREAD_CTRL_LAST) {
- // The notification comes from a job object. There are nine notifications
- // that jobs can send and some of them depend on the job attributes set.
- JobTracker* tracker = reinterpret_cast<JobTracker*>(key);
-
- switch (events) {
- case JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO: {
- // The job object has signaled that the last process associated
- // with it has terminated. Assuming there is no way for a process
- // to appear out of thin air in this job, it safe to assume that
- // we can tell the policy to destroy the target object, and for
- // us to release our reference to the policy object.
- FreeResources(tracker);
- break;
- }
-
- case JOB_OBJECT_MSG_NEW_PROCESS: {
- ++target_counter;
- if (1 == target_counter) {
- ::ResetEvent(no_targets);
- }
- break;
- }
-
- case JOB_OBJECT_MSG_EXIT_PROCESS:
- case JOB_OBJECT_MSG_ABNORMAL_EXIT_PROCESS: {
- {
- AutoLock lock(&broker->lock_);
- broker->child_process_ids_.erase(reinterpret_cast<DWORD>(ovl));
- }
- --target_counter;
- if (0 == target_counter)
- ::SetEvent(no_targets);
-
- DCHECK(target_counter >= 0);
- break;
- }
-
- case JOB_OBJECT_MSG_ACTIVE_PROCESS_LIMIT: {
- break;
- }
-
- default: {
- NOTREACHED();
- break;
- }
- }
- } 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));
- DeregisterPeerTracker(it->second);
- broker->peer_map_.erase(it);
- } 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();
- }
- }
-
- NOTREACHED();
- return 0;
-}
-
-// SpawnTarget does all the interesting sandbox setup and creates the target
-// process inside the sandbox.
-ResultCode BrokerServicesBase::SpawnTarget(const wchar_t* exe_path,
- const wchar_t* command_line,
- TargetPolicy* policy,
- PROCESS_INFORMATION* target_info) {
- if (!exe_path)
- return SBOX_ERROR_BAD_PARAMS;
-
- if (!policy)
- return SBOX_ERROR_BAD_PARAMS;
-
- // Even though the resources touched by SpawnTarget can be accessed in
- // multiple threads, the method itself cannot be called from more than
- // 1 thread. This is to protect the global variables used while setting up
- // the child process.
- static DWORD thread_id = ::GetCurrentThreadId();
- DCHECK(thread_id == ::GetCurrentThreadId());
-
- AutoLock lock(&lock_);
-
- // This downcast is safe as long as we control CreatePolicy()
- PolicyBase* policy_base = static_cast<PolicyBase*>(policy);
-
- // Construct the tokens and the job object that we are going to associate
- // with the soon to be created target process.
- HANDLE initial_token_temp;
- HANDLE lockdown_token_temp;
- DWORD win_result = policy_base->MakeTokens(&initial_token_temp,
- &lockdown_token_temp);
- base::win::ScopedHandle initial_token(initial_token_temp);
- base::win::ScopedHandle lockdown_token(lockdown_token_temp);
-
- if (ERROR_SUCCESS != win_result)
- return SBOX_ERROR_GENERIC;
-
- HANDLE job_temp;
- win_result = policy_base->MakeJobObject(&job_temp);
- base::win::ScopedHandle job(job_temp);
- if (ERROR_SUCCESS != win_result)
- return SBOX_ERROR_GENERIC;
-
- if (ERROR_ALREADY_EXISTS == ::GetLastError())
- return SBOX_ERROR_GENERIC;
-
- // Construct the thread pool here in case it is expensive.
- // The thread pool is shared by all the targets
- if (NULL == thread_pool_)
- thread_pool_ = new Win2kThreadPool();
-
- // Create the TargetProces object and spawn the target suspended. Note that
- // Brokerservices does not own the target object. It is owned by the Policy.
- base::win::ScopedProcessInformation process_info;
- TargetProcess* target = new TargetProcess(initial_token.Take(),
- lockdown_token.Take(),
- job,
- thread_pool_);
-
- std::wstring desktop = policy_base->GetAlternateDesktop();
-
- win_result = target->Create(exe_path, command_line,
- desktop.empty() ? NULL : desktop.c_str(),
- &process_info);
- if (ERROR_SUCCESS != win_result)
- return SpawnCleanup(target, win_result);
-
- // Now the policy is the owner of the target.
- if (!policy_base->AddTarget(target)) {
- return SpawnCleanup(target, 0);
- }
-
- // We are going to keep a pointer to the policy because we'll call it when
- // the job object generates notifications using the completion port.
- policy_base->AddRef();
- scoped_ptr<JobTracker> tracker(new JobTracker(job.Take(), policy_base));
- if (!AssociateCompletionPort(tracker->job, job_port_, tracker.get()))
- return SpawnCleanup(target, 0);
- // Save the tracker because in cleanup we might need to force closing
- // the Jobs.
- tracker_list_.push_back(tracker.release());
- child_process_ids_.insert(process_info.process_id());
-
- *target_info = process_info.Take();
- return SBOX_ALL_OK;
-}
-
-
-ResultCode BrokerServicesBase::WaitForAllTargets() {
- ::WaitForSingleObject(no_targets_, INFINITE);
- return SBOX_ALL_OK;
-}
-
-bool BrokerServicesBase::IsActiveTarget(DWORD process_id) {
- AutoLock lock(&lock_);
- 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 timeout) {
- 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;
-
- HANDLE process_handle;
- if (!::DuplicateHandle(::GetCurrentProcess(), peer_process,
- ::GetCurrentProcess(), &process_handle,
- SYNCHRONIZE, FALSE, 0)) {
- return SBOX_ERROR_GENERIC;
- }
- peer->process.Set(process_handle);
-
- 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;
- }
-
- // Release the pointer since it will be cleaned up by the callback.
- peer.release();
- return SBOX_ALL_OK;
-}
-
-} // namespace sandbox
« no previous file with comments | « sandbox/src/broker_services.h ('k') | sandbox/src/crosscall_client.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698