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

Unified Diff: sandbox/win/src/broker_services.cc

Issue 1851213002: Remove sandbox on Windows. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fix nacl compile issues Created 4 years, 9 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/win/src/broker_services.h ('k') | sandbox/win/src/crosscall_client.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: sandbox/win/src/broker_services.cc
diff --git a/sandbox/win/src/broker_services.cc b/sandbox/win/src/broker_services.cc
deleted file mode 100644
index 26b2561021dc2f32d9395aac7244990f56c84b22..0000000000000000000000000000000000000000
--- a/sandbox/win/src/broker_services.cc
+++ /dev/null
@@ -1,582 +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/win/src/broker_services.h"
-
-#include <AclAPI.h>
-#include <stddef.h>
-#include <utility>
-
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/stl_util.h"
-#include "base/threading/platform_thread.h"
-#include "base/win/scoped_handle.h"
-#include "base/win/scoped_process_information.h"
-#include "base/win/startup_information.h"
-#include "base/win/windows_version.h"
-#include "sandbox/win/src/app_container.h"
-#include "sandbox/win/src/process_mitigations.h"
-#include "sandbox/win/src/sandbox.h"
-#include "sandbox/win/src/sandbox_policy_base.h"
-#include "sandbox/win/src/target_process.h"
-#include "sandbox/win/src/win2k_threadpool.h"
-#include "sandbox/win/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 {
- JobTracker(base::win::ScopedHandle job, sandbox::PolicyBase* policy)
- : job(std::move(job)), policy(policy) {}
- ~JobTracker() {
- FreeResources();
- }
-
- // Releases the Job and notifies the associated Policy object to release its
- // resources as well.
- void FreeResources();
-
- base::win::ScopedHandle job;
- sandbox::PolicyBase* policy;
-};
-
-void JobTracker::FreeResources() {
- if (policy) {
- BOOL res = ::TerminateJobObject(job.Get(), sandbox::SBOX_ALL_OK);
- DCHECK(res);
- // Closing the job causes the target process to be destroyed so this needs
- // to happen before calling OnJobEmpty().
- HANDLE stale_job_handle = job.Get();
- job.Close();
-
- // In OnJobEmpty() we don't actually use the job handle directly.
- policy->OnJobEmpty(stale_job_handle);
- policy->Release();
- policy = NULL;
- }
-}
-
-// Helper structure that allows the broker to track peer processes
-struct PeerTracker {
- PeerTracker(DWORD process_id, HANDLE broker_job_port)
- : wait_object(NULL), id(process_id), job_port(broker_job_port) {
- }
-
- HANDLE wait_object;
- base::win::ScopedHandle process;
- DWORD id;
- HANDLE 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) {
-}
-
-// 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 (job_port_.IsValid() || (NULL != thread_pool_))
- return SBOX_ERROR_UNEXPECTED_CALL;
-
- ::InitializeCriticalSection(&lock_);
-
- job_port_.Set(::CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0));
- if (!job_port_.IsValid())
- return SBOX_ERROR_GENERIC;
-
- no_targets_.Set(::CreateEventW(NULL, TRUE, FALSE, NULL));
-
- job_thread_.Set(::CreateThread(NULL, 0, // Default security and stack.
- TargetEventsThread, this, NULL, NULL));
- if (!job_thread_.IsValid())
- 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_.IsValid())
- 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_.Get(), 0, THREAD_CTRL_QUIT, FALSE);
-
- if (job_thread_.IsValid() &&
- WAIT_TIMEOUT == ::WaitForSingleObject(job_thread_.Get(), 1000)) {
- // Cannot clean broker services.
- NOTREACHED();
- return;
- }
-
- STLDeleteElements(&tracker_list_);
- delete thread_pool_;
-
- // Cancel the wait events and delete remaining peer trackers.
- for (PeerTrackerMap::iterator it = peer_map_.begin();
- it != peer_map_.end(); ++it) {
- DeregisterPeerTracker(it->second);
- }
-
- ::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;
-}
-
-// 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_.Get();
- HANDLE no_targets = broker->no_targets_.Get();
-
- int target_counter = 0;
- int untracked_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.
- tracker->FreeResources();
- break;
- }
-
- case JOB_OBJECT_MSG_NEW_PROCESS: {
- DWORD handle = static_cast<DWORD>(reinterpret_cast<uintptr_t>(ovl));
- {
- AutoLock lock(&broker->lock_);
- size_t count = broker->child_process_ids_.count(handle);
- // Child process created from sandboxed process.
- if (count == 0)
- untracked_target_counter++;
- }
- ++target_counter;
- if (1 == target_counter) {
- ::ResetEvent(no_targets);
- }
- break;
- }
-
- case JOB_OBJECT_MSG_EXIT_PROCESS:
- case JOB_OBJECT_MSG_ABNORMAL_EXIT_PROCESS: {
- size_t erase_result = 0;
- {
- AutoLock lock(&broker->lock_);
- erase_result = broker->child_process_ids_.erase(
- static_cast<DWORD>(reinterpret_cast<uintptr_t>(ovl)));
- }
- if (erase_result != 1U) {
- // The process was untracked e.g. a child process of the target.
- --untracked_target_counter;
- DCHECK(untracked_target_counter >= 0);
- }
- --target_counter;
- if (0 == target_counter)
- ::SetEvent(no_targets);
-
- DCHECK(target_counter >= 0);
- break;
- }
-
- case JOB_OBJECT_MSG_ACTIVE_PROCESS_LIMIT: {
- // A child process attempted and failed to create a child process.
- // Windows does not reveal the process id.
- untracked_target_counter++;
- target_counter++;
- break;
- }
-
- case JOB_OBJECT_MSG_PROCESS_MEMORY_LIMIT: {
- BOOL res = ::TerminateJobObject(tracker->job.Get(),
- SBOX_FATAL_MEMORY_EXCEEDED);
- DCHECK(res);
- 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(
- static_cast<DWORD>(reinterpret_cast<uintptr_t>(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);
-
- if (policy_base->GetAppContainer() && policy_base->GetLowBoxSid())
- return SBOX_ERROR_BAD_PARAMS;
-
- // Construct the tokens and the job object that we are going to associate
- // with the soon to be created target process.
- base::win::ScopedHandle initial_token;
- base::win::ScopedHandle lockdown_token;
- base::win::ScopedHandle lowbox_token;
- ResultCode result = SBOX_ALL_OK;
-
- result =
- policy_base->MakeTokens(&initial_token, &lockdown_token, &lowbox_token);
- if (SBOX_ALL_OK != result)
- return result;
-
- base::win::ScopedHandle job;
- result = policy_base->MakeJobObject(&job);
- if (SBOX_ALL_OK != result)
- return result;
-
- // Initialize the startup information from the policy.
- base::win::StartupInformation startup_info;
- // The liftime of |mitigations|, |inherit_handle_list| and
- // |child_process_creation| have to be at least as long as
- // |startup_info| because |UpdateProcThreadAttribute| requires that
- // its |lpValue| parameter persist until |DeleteProcThreadAttributeList| is
- // called; StartupInformation's destructor makes such a call.
- DWORD64 mitigations;
- std::vector<HANDLE> inherited_handle_list;
- DWORD child_process_creation = PROCESS_CREATION_CHILD_PROCESS_RESTRICTED;
-
- base::string16 desktop = policy_base->GetAlternateDesktop();
- if (!desktop.empty()) {
- startup_info.startup_info()->lpDesktop =
- const_cast<wchar_t*>(desktop.c_str());
- }
-
- bool inherit_handles = false;
-
- int attribute_count = 0;
- const AppContainerAttributes* app_container =
- policy_base->GetAppContainer();
- if (app_container)
- ++attribute_count;
-
- size_t mitigations_size;
- ConvertProcessMitigationsToPolicy(policy_base->GetProcessMitigations(),
- &mitigations, &mitigations_size);
- if (mitigations)
- ++attribute_count;
-
- bool restrict_child_process_creation = false;
- if (base::win::GetVersion() >= base::win::VERSION_WIN10_TH2 &&
- policy_base->GetJobLevel() <= JOB_LIMITED_USER) {
- restrict_child_process_creation = true;
- ++attribute_count;
- }
-
- HANDLE stdout_handle = policy_base->GetStdoutHandle();
- HANDLE stderr_handle = policy_base->GetStderrHandle();
-
- if (stdout_handle != INVALID_HANDLE_VALUE)
- inherited_handle_list.push_back(stdout_handle);
-
- // Handles in the list must be unique.
- if (stderr_handle != stdout_handle && stderr_handle != INVALID_HANDLE_VALUE)
- inherited_handle_list.push_back(stderr_handle);
-
- const base::HandlesToInheritVector& policy_handle_list =
- policy_base->GetHandlesBeingShared();
-
- for (HANDLE handle : policy_handle_list)
- inherited_handle_list.push_back(handle);
-
- if (inherited_handle_list.size())
- ++attribute_count;
-
- if (!startup_info.InitializeProcThreadAttributeList(attribute_count))
- return SBOX_ERROR_PROC_THREAD_ATTRIBUTES;
-
- if (app_container) {
- result = app_container->ShareForStartup(&startup_info);
- if (SBOX_ALL_OK != result)
- return result;
- }
-
- if (mitigations) {
- if (!startup_info.UpdateProcThreadAttribute(
- PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY, &mitigations,
- mitigations_size)) {
- return SBOX_ERROR_PROC_THREAD_ATTRIBUTES;
- }
- }
-
- if (restrict_child_process_creation) {
- if (!startup_info.UpdateProcThreadAttribute(
- PROC_THREAD_ATTRIBUTE_CHILD_PROCESS_POLICY,
- &child_process_creation, sizeof(child_process_creation))) {
- return SBOX_ERROR_PROC_THREAD_ATTRIBUTES;
- }
- }
-
- if (inherited_handle_list.size()) {
- if (!startup_info.UpdateProcThreadAttribute(
- PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
- &inherited_handle_list[0],
- sizeof(HANDLE) * inherited_handle_list.size())) {
- return SBOX_ERROR_PROC_THREAD_ATTRIBUTES;
- }
- startup_info.startup_info()->dwFlags |= STARTF_USESTDHANDLES;
- startup_info.startup_info()->hStdInput = INVALID_HANDLE_VALUE;
- startup_info.startup_info()->hStdOutput = stdout_handle;
- startup_info.startup_info()->hStdError = stderr_handle;
- // Allowing inheritance of handles is only secure now that we
- // have limited which handles will be inherited.
- inherit_handles = true;
- }
-
- // 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 TargetProcess 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(std::move(initial_token), std::move(lockdown_token),
- std::move(lowbox_token), job.Get(), thread_pool_);
-
- DWORD win_result = target->Create(exe_path, command_line, inherit_handles,
- startup_info, &process_info);
-
- if (ERROR_SUCCESS != win_result) {
- SpawnCleanup(target, win_result);
- return SBOX_ERROR_CREATE_PROCESS;
- }
-
- // 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();
- if (job.IsValid()) {
- scoped_ptr<JobTracker> tracker(new JobTracker(std::move(job), policy_base));
-
- // There is no obvious recovery after failure here. Previous version with
- // SpawnCleanup() caused deletion of TargetProcess twice. crbug.com/480639
- CHECK(AssociateCompletionPort(tracker->job.Get(), job_port_.Get(),
- tracker.get()));
-
- // 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());
- } else {
- // We have to signal the event once here because the completion port will
- // never get a message that this target is being terminated thus we should
- // not block WaitForAllTargets until we have at least one target with job.
- if (child_process_ids_.empty())
- ::SetEvent(no_targets_.Get());
- // We can not track the life time of such processes and it is responsibility
- // of the host application to make sure that spawned targets without jobs
- // are terminated when the main application don't need them anymore.
- // Sandbox policy engine needs to know that these processes are valid
- // targets for e.g. BrokerDuplicateHandle so track them as peer processes.
- AddTargetPeer(process_info.process_handle());
- }
-
- *target_info = process_info.Take();
- return SBOX_ALL_OK;
-}
-
-
-ResultCode BrokerServicesBase::WaitForAllTargets() {
- ::WaitForSingleObject(no_targets_.Get(), 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>(static_cast<uintptr_t>(peer->id)));
-}
-
-ResultCode BrokerServicesBase::AddTargetPeer(HANDLE peer_process) {
- scoped_ptr<PeerTracker> peer(new PeerTracker(::GetProcessId(peer_process),
- job_port_.Get()));
- 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.Get(), 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.
- ignore_result(peer.release());
- return SBOX_ALL_OK;
-}
-
-ResultCode BrokerServicesBase::InstallAppContainer(const wchar_t* sid,
- const wchar_t* name) {
- if (base::win::OSInfo::GetInstance()->version() < base::win::VERSION_WIN8)
- return SBOX_ERROR_UNSUPPORTED;
-
- base::string16 old_name = LookupAppContainer(sid);
- if (old_name.empty())
- return CreateAppContainer(sid, name);
-
- if (old_name != name)
- return SBOX_ERROR_INVALID_APP_CONTAINER;
-
- return SBOX_ALL_OK;
-}
-
-ResultCode BrokerServicesBase::UninstallAppContainer(const wchar_t* sid) {
- if (base::win::OSInfo::GetInstance()->version() < base::win::VERSION_WIN8)
- return SBOX_ERROR_UNSUPPORTED;
-
- base::string16 name = LookupAppContainer(sid);
- if (name.empty())
- return SBOX_ERROR_INVALID_APP_CONTAINER;
-
- return DeleteAppContainer(sid);
-}
-
-} // namespace sandbox
« no previous file with comments | « sandbox/win/src/broker_services.h ('k') | sandbox/win/src/crosscall_client.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698