summaryrefslogtreecommitdiffstats
path: root/security/sandbox/chromium/sandbox/win/src/sandbox_policy_base.cc
diff options
context:
space:
mode:
Diffstat (limited to 'security/sandbox/chromium/sandbox/win/src/sandbox_policy_base.cc')
-rw-r--r--security/sandbox/chromium/sandbox/win/src/sandbox_policy_base.cc832
1 files changed, 832 insertions, 0 deletions
diff --git a/security/sandbox/chromium/sandbox/win/src/sandbox_policy_base.cc b/security/sandbox/chromium/sandbox/win/src/sandbox_policy_base.cc
new file mode 100644
index 0000000000..f228dbbc31
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/sandbox_policy_base.cc
@@ -0,0 +1,832 @@
+// 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/sandbox_policy_base.h"
+
+#include <sddl.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include "base/callback.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/stl_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/win/win_util.h"
+#include "base/win/windows_version.h"
+#include "sandbox/win/src/acl.h"
+#include "sandbox/win/src/filesystem_policy.h"
+#include "sandbox/win/src/handle_policy.h"
+#include "sandbox/win/src/interception.h"
+#include "sandbox/win/src/job.h"
+#include "sandbox/win/src/line_break_policy.h"
+#include "sandbox/win/src/named_pipe_policy.h"
+#include "sandbox/win/src/policy_broker.h"
+#include "sandbox/win/src/policy_engine_processor.h"
+#include "sandbox/win/src/policy_low_level.h"
+#include "sandbox/win/src/process_mitigations.h"
+#include "sandbox/win/src/process_mitigations_win32k_policy.h"
+#include "sandbox/win/src/process_thread_policy.h"
+#include "sandbox/win/src/registry_policy.h"
+#include "sandbox/win/src/restricted_token_utils.h"
+#include "sandbox/win/src/sandbox_policy.h"
+#include "sandbox/win/src/sandbox_utils.h"
+#include "sandbox/win/src/security_capabilities.h"
+#include "sandbox/win/src/signed_policy.h"
+#include "sandbox/win/src/sync_policy.h"
+#include "sandbox/win/src/target_process.h"
+#include "sandbox/win/src/top_level_dispatcher.h"
+#include "sandbox/win/src/window.h"
+
+namespace {
+
+// The standard windows size for one memory page.
+constexpr size_t kOneMemPage = 4096;
+// The IPC and Policy shared memory sizes.
+constexpr size_t kIPCMemSize = kOneMemPage * 2;
+constexpr size_t kPolMemSize = kOneMemPage * 14;
+
+// Helper function to allocate space (on the heap) for policy.
+sandbox::PolicyGlobal* MakeBrokerPolicyMemory() {
+ const size_t kTotalPolicySz = kPolMemSize;
+ sandbox::PolicyGlobal* policy =
+ static_cast<sandbox::PolicyGlobal*>(::operator new(kTotalPolicySz));
+ DCHECK(policy);
+ memset(policy, 0, kTotalPolicySz);
+ policy->data_size = kTotalPolicySz - sizeof(sandbox::PolicyGlobal);
+ return policy;
+}
+
+bool IsInheritableHandle(HANDLE handle) {
+ if (!handle)
+ return false;
+ if (handle == INVALID_HANDLE_VALUE)
+ return false;
+ // File handles (FILE_TYPE_DISK) and pipe handles are known to be
+ // inheritable. Console handles (FILE_TYPE_CHAR) are not
+ // inheritable via PROC_THREAD_ATTRIBUTE_HANDLE_LIST.
+ DWORD handle_type = GetFileType(handle);
+ return handle_type == FILE_TYPE_DISK || handle_type == FILE_TYPE_PIPE;
+}
+
+} // namespace
+
+namespace sandbox {
+
+SANDBOX_INTERCEPT IntegrityLevel g_shared_delayed_integrity_level;
+SANDBOX_INTERCEPT MitigationFlags g_shared_delayed_mitigations;
+
+// Initializes static members. alternate_desktop_handle_ is a desktop on
+// alternate_winstation_handle_, alternate_desktop_local_winstation_handle_ is a
+// desktop on the same winstation as the parent process.
+HWINSTA PolicyBase::alternate_winstation_handle_ = nullptr;
+HDESK PolicyBase::alternate_desktop_handle_ = nullptr;
+HDESK PolicyBase::alternate_desktop_local_winstation_handle_ = nullptr;
+IntegrityLevel PolicyBase::alternate_desktop_integrity_level_label_ =
+ INTEGRITY_LEVEL_SYSTEM;
+IntegrityLevel
+ PolicyBase::alternate_desktop_local_winstation_integrity_level_label_ =
+ INTEGRITY_LEVEL_SYSTEM;
+
+PolicyBase::PolicyBase()
+ : ref_count(1),
+ lockdown_level_(USER_LOCKDOWN),
+ initial_level_(USER_LOCKDOWN),
+ job_level_(JOB_LOCKDOWN),
+ ui_exceptions_(0),
+ memory_limit_(0),
+ use_alternate_desktop_(false),
+ use_alternate_winstation_(false),
+ file_system_init_(false),
+ relaxed_interceptions_(true),
+ stdout_handle_(INVALID_HANDLE_VALUE),
+ stderr_handle_(INVALID_HANDLE_VALUE),
+ integrity_level_(INTEGRITY_LEVEL_LAST),
+ delayed_integrity_level_(INTEGRITY_LEVEL_LAST),
+ mitigations_(0),
+ delayed_mitigations_(0),
+ is_csrss_connected_(true),
+ policy_maker_(nullptr),
+ policy_(nullptr),
+ lowbox_sid_(nullptr),
+ lockdown_default_dacl_(false),
+ add_restricting_random_sid_(false),
+ enable_opm_redirection_(false),
+ effective_token_(nullptr) {
+ ::InitializeCriticalSection(&lock_);
+ dispatcher_.reset(new TopLevelDispatcher(this));
+}
+
+PolicyBase::~PolicyBase() {
+ TargetSet::iterator it;
+ for (it = targets_.begin(); it != targets_.end(); ++it) {
+ TargetProcess* target = (*it);
+ delete target;
+ }
+ delete policy_maker_;
+ delete policy_;
+
+ if (lowbox_sid_)
+ ::LocalFree(lowbox_sid_);
+
+ ::DeleteCriticalSection(&lock_);
+}
+
+void PolicyBase::AddRef() {
+ ::InterlockedIncrement(&ref_count);
+}
+
+void PolicyBase::Release() {
+ if (0 == ::InterlockedDecrement(&ref_count))
+ delete this;
+}
+
+ResultCode PolicyBase::SetTokenLevel(TokenLevel initial, TokenLevel lockdown) {
+ if (initial < lockdown) {
+ return SBOX_ERROR_BAD_PARAMS;
+ }
+ initial_level_ = initial;
+ lockdown_level_ = lockdown;
+ return SBOX_ALL_OK;
+}
+
+TokenLevel PolicyBase::GetInitialTokenLevel() const {
+ return initial_level_;
+}
+
+TokenLevel PolicyBase::GetLockdownTokenLevel() const {
+ return lockdown_level_;
+}
+
+void PolicyBase::SetDoNotUseRestrictingSIDs() {
+ use_restricting_sids_ = false;
+}
+
+ResultCode PolicyBase::SetJobLevel(JobLevel job_level, uint32_t ui_exceptions) {
+ if (memory_limit_ && job_level == JOB_NONE) {
+ return SBOX_ERROR_BAD_PARAMS;
+ }
+ job_level_ = job_level;
+ ui_exceptions_ = ui_exceptions;
+ return SBOX_ALL_OK;
+}
+
+JobLevel PolicyBase::GetJobLevel() const {
+ return job_level_;
+}
+
+ResultCode PolicyBase::SetJobMemoryLimit(size_t memory_limit) {
+ memory_limit_ = memory_limit;
+ return SBOX_ALL_OK;
+}
+
+ResultCode PolicyBase::SetAlternateDesktop(bool alternate_winstation) {
+ use_alternate_desktop_ = true;
+ use_alternate_winstation_ = alternate_winstation;
+ return CreateAlternateDesktop(alternate_winstation);
+}
+
+std::wstring PolicyBase::GetAlternateDesktop() const {
+ // No alternate desktop or winstation. Return an empty string.
+ if (!use_alternate_desktop_ && !use_alternate_winstation_) {
+ return std::wstring();
+ }
+
+ if (use_alternate_winstation_) {
+ // The desktop and winstation should have been created by now.
+ // If we hit this scenario, it means that the user ignored the failure
+ // during SetAlternateDesktop, so we ignore it here too.
+ if (!alternate_desktop_handle_ || !alternate_winstation_handle_)
+ return std::wstring();
+
+ return GetFullDesktopName(alternate_winstation_handle_,
+ alternate_desktop_handle_);
+ }
+
+ if (!alternate_desktop_local_winstation_handle_)
+ return std::wstring();
+
+ return GetFullDesktopName(nullptr,
+ alternate_desktop_local_winstation_handle_);
+}
+
+ResultCode PolicyBase::CreateAlternateDesktop(bool alternate_winstation) {
+ if (alternate_winstation) {
+ // Check if it's already created.
+ if (alternate_winstation_handle_ && alternate_desktop_handle_)
+ return SBOX_ALL_OK;
+
+ DCHECK(!alternate_winstation_handle_);
+ // Create the window station.
+ ResultCode result = CreateAltWindowStation(&alternate_winstation_handle_);
+ if (SBOX_ALL_OK != result)
+ return result;
+
+ // Verify that everything is fine.
+ if (!alternate_winstation_handle_ ||
+ base::win::GetWindowObjectName(alternate_winstation_handle_).empty())
+ return SBOX_ERROR_CANNOT_CREATE_DESKTOP;
+
+ // Create the destkop.
+ result = CreateAltDesktop(alternate_winstation_handle_,
+ &alternate_desktop_handle_);
+ if (SBOX_ALL_OK != result)
+ return result;
+
+ // Verify that everything is fine.
+ if (!alternate_desktop_handle_ ||
+ base::win::GetWindowObjectName(alternate_desktop_handle_).empty()) {
+ return SBOX_ERROR_CANNOT_CREATE_DESKTOP;
+ }
+ } else {
+ // Check if it already exists.
+ if (alternate_desktop_local_winstation_handle_)
+ return SBOX_ALL_OK;
+
+ // Create the destkop.
+ ResultCode result =
+ CreateAltDesktop(nullptr, &alternate_desktop_local_winstation_handle_);
+ if (SBOX_ALL_OK != result)
+ return result;
+
+ // Verify that everything is fine.
+ if (!alternate_desktop_local_winstation_handle_ ||
+ base::win::GetWindowObjectName(
+ alternate_desktop_local_winstation_handle_)
+ .empty()) {
+ return SBOX_ERROR_CANNOT_CREATE_DESKTOP;
+ }
+ }
+
+ return SBOX_ALL_OK;
+}
+
+void PolicyBase::DestroyAlternateDesktop() {
+ if (use_alternate_winstation_) {
+ if (alternate_desktop_handle_) {
+ ::CloseDesktop(alternate_desktop_handle_);
+ alternate_desktop_handle_ = nullptr;
+ }
+
+ if (alternate_winstation_handle_) {
+ ::CloseWindowStation(alternate_winstation_handle_);
+ alternate_winstation_handle_ = nullptr;
+ }
+ } else {
+ if (alternate_desktop_local_winstation_handle_) {
+ ::CloseDesktop(alternate_desktop_local_winstation_handle_);
+ alternate_desktop_local_winstation_handle_ = nullptr;
+ }
+ }
+}
+
+ResultCode PolicyBase::SetIntegrityLevel(IntegrityLevel integrity_level) {
+ if (app_container_profile_)
+ return SBOX_ERROR_BAD_PARAMS;
+ integrity_level_ = integrity_level;
+ return SBOX_ALL_OK;
+}
+
+IntegrityLevel PolicyBase::GetIntegrityLevel() const {
+ return integrity_level_;
+}
+
+ResultCode PolicyBase::SetDelayedIntegrityLevel(
+ IntegrityLevel integrity_level) {
+ delayed_integrity_level_ = integrity_level;
+ return SBOX_ALL_OK;
+}
+
+ResultCode PolicyBase::SetLowBox(const wchar_t* sid) {
+ if (base::win::GetVersion() < base::win::Version::WIN8)
+ return SBOX_ERROR_UNSUPPORTED;
+
+ DCHECK(sid);
+ if (lowbox_sid_ || app_container_profile_)
+ return SBOX_ERROR_BAD_PARAMS;
+
+ if (!ConvertStringSidToSid(sid, &lowbox_sid_))
+ return SBOX_ERROR_INVALID_LOWBOX_SID;
+
+ return SBOX_ALL_OK;
+}
+
+ResultCode PolicyBase::SetProcessMitigations(MitigationFlags flags) {
+ // Prior to Win10 RS5 CreateProcess fails when AppContainer and mitigation
+ // flags are enabled. Return an error on downlevel platforms if trying to
+ // set new mitigations.
+ if (app_container_profile_ &&
+ base::win::GetVersion() < base::win::Version::WIN10_RS5) {
+ return SBOX_ERROR_BAD_PARAMS;
+ }
+ if (!CanSetProcessMitigationsPreStartup(flags))
+ return SBOX_ERROR_BAD_PARAMS;
+ mitigations_ = flags;
+ return SBOX_ALL_OK;
+}
+
+MitigationFlags PolicyBase::GetProcessMitigations() {
+ return mitigations_;
+}
+
+ResultCode PolicyBase::SetDelayedProcessMitigations(MitigationFlags flags) {
+ if (!CanSetProcessMitigationsPostStartup(flags))
+ return SBOX_ERROR_BAD_PARAMS;
+ delayed_mitigations_ = flags;
+ return SBOX_ALL_OK;
+}
+
+MitigationFlags PolicyBase::GetDelayedProcessMitigations() const {
+ return delayed_mitigations_;
+}
+
+void PolicyBase::SetStrictInterceptions() {
+ relaxed_interceptions_ = false;
+}
+
+ResultCode PolicyBase::SetStdoutHandle(HANDLE handle) {
+ if (!IsInheritableHandle(handle))
+ return SBOX_ERROR_BAD_PARAMS;
+ stdout_handle_ = handle;
+ return SBOX_ALL_OK;
+}
+
+ResultCode PolicyBase::SetStderrHandle(HANDLE handle) {
+ if (!IsInheritableHandle(handle))
+ return SBOX_ERROR_BAD_PARAMS;
+ stderr_handle_ = handle;
+ return SBOX_ALL_OK;
+}
+
+ResultCode PolicyBase::AddRule(SubSystem subsystem,
+ Semantics semantics,
+ const wchar_t* pattern) {
+ ResultCode result = AddRuleInternal(subsystem, semantics, pattern);
+ LOG_IF(ERROR, result != SBOX_ALL_OK)
+ << "Failed to add sandbox rule."
+ << " error = " << result << ", subsystem = " << subsystem
+ << ", semantics = " << semantics << ", pattern = '" << pattern << "'";
+ return result;
+}
+
+ResultCode PolicyBase::AddDllToUnload(const wchar_t* dll_name) {
+ blocklisted_dlls_.push_back(dll_name);
+ return SBOX_ALL_OK;
+}
+
+ResultCode PolicyBase::AddKernelObjectToClose(const wchar_t* handle_type,
+ const wchar_t* handle_name) {
+ return handle_closer_.AddHandle(handle_type, handle_name);
+}
+
+void PolicyBase::AddHandleToShare(HANDLE handle) {
+ CHECK(handle);
+ CHECK_NE(handle, INVALID_HANDLE_VALUE);
+
+ // Ensure the handle can be inherited.
+ bool result =
+ SetHandleInformation(handle, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
+ PCHECK(result);
+
+ handles_to_share_.push_back(handle);
+}
+
+void PolicyBase::SetLockdownDefaultDacl() {
+ lockdown_default_dacl_ = true;
+}
+
+void PolicyBase::AddRestrictingRandomSid() {
+ add_restricting_random_sid_ = true;
+}
+
+const base::HandlesToInheritVector& PolicyBase::GetHandlesBeingShared() {
+ return handles_to_share_;
+}
+
+ResultCode PolicyBase::MakeJobObject(base::win::ScopedHandle* job) {
+ if (job_level_ == JOB_NONE) {
+ job->Close();
+ return SBOX_ALL_OK;
+ }
+
+ // Create the windows job object.
+ Job job_obj;
+ DWORD result =
+ job_obj.Init(job_level_, nullptr, ui_exceptions_, memory_limit_);
+ if (ERROR_SUCCESS != result)
+ return SBOX_ERROR_CANNOT_INIT_JOB;
+
+ *job = job_obj.Take();
+ return SBOX_ALL_OK;
+}
+
+ResultCode PolicyBase::MakeTokens(base::win::ScopedHandle* initial,
+ base::win::ScopedHandle* lockdown,
+ base::win::ScopedHandle* lowbox) {
+ Sid random_sid = Sid::GenerateRandomSid();
+ PSID random_sid_ptr = nullptr;
+ if (add_restricting_random_sid_)
+ random_sid_ptr = random_sid.GetPSID();
+
+ // Create the 'naked' token. This will be the permanent token associated
+ // with the process and therefore with any thread that is not impersonating.
+ DWORD result = CreateRestrictedToken(
+ effective_token_, lockdown_level_, integrity_level_, PRIMARY,
+ lockdown_default_dacl_, random_sid_ptr, use_restricting_sids_, lockdown);
+ if (ERROR_SUCCESS != result)
+ return SBOX_ERROR_CANNOT_CREATE_RESTRICTED_TOKEN;
+
+ // If we're launching on the alternate desktop we need to make sure the
+ // integrity label on the object is no higher than the sandboxed process's
+ // integrity level. So, we lower the label on the desktop process if it's
+ // not already low enough for our process.
+ if (use_alternate_desktop_ && integrity_level_ != INTEGRITY_LEVEL_LAST) {
+ // Integrity label enum is reversed (higher level is a lower value).
+ static_assert(INTEGRITY_LEVEL_SYSTEM < INTEGRITY_LEVEL_UNTRUSTED,
+ "Integrity level ordering reversed.");
+ HDESK desktop_handle = nullptr;
+ IntegrityLevel desktop_integrity_level_label;
+ if (use_alternate_winstation_) {
+ desktop_handle = alternate_desktop_handle_;
+ desktop_integrity_level_label = alternate_desktop_integrity_level_label_;
+ } else {
+ desktop_handle = alternate_desktop_local_winstation_handle_;
+ desktop_integrity_level_label =
+ alternate_desktop_local_winstation_integrity_level_label_;
+ }
+ // If the desktop_handle hasn't been created for any reason, skip this.
+ if (desktop_handle && desktop_integrity_level_label < integrity_level_) {
+ result =
+ SetObjectIntegrityLabel(desktop_handle, SE_WINDOW_OBJECT, L"",
+ GetIntegrityLevelString(integrity_level_));
+ if (ERROR_SUCCESS != result)
+ return SBOX_ERROR_CANNOT_SET_DESKTOP_INTEGRITY;
+
+ if (use_alternate_winstation_) {
+ alternate_desktop_integrity_level_label_ = integrity_level_;
+ } else {
+ alternate_desktop_local_winstation_integrity_level_label_ =
+ integrity_level_;
+ }
+ }
+ }
+
+ if (lowbox_sid_) {
+ if (!lowbox_directory_.IsValid()) {
+ result =
+ CreateLowBoxObjectDirectory(lowbox_sid_, true, &lowbox_directory_);
+ DCHECK(result == ERROR_SUCCESS);
+ }
+
+ // The order of handles isn't important in the CreateLowBoxToken call.
+ // The kernel will maintain a reference to the object directory handle.
+ HANDLE saved_handles[1] = {lowbox_directory_.Get()};
+ DWORD saved_handles_count = lowbox_directory_.IsValid() ? 1 : 0;
+
+ Sid package_sid(lowbox_sid_);
+ SecurityCapabilities caps(package_sid);
+ if (CreateLowBoxToken(lockdown->Get(), PRIMARY, &caps, saved_handles,
+ saved_handles_count, lowbox) != ERROR_SUCCESS) {
+ return SBOX_ERROR_CANNOT_CREATE_LOWBOX_TOKEN;
+ }
+
+ if (!ReplacePackageSidInDacl(lowbox->Get(), SE_KERNEL_OBJECT, package_sid,
+ TOKEN_ALL_ACCESS)) {
+ return SBOX_ERROR_CANNOT_MODIFY_LOWBOX_TOKEN_DACL;
+ }
+ }
+
+ // Create the 'better' token. We use this token as the one that the main
+ // thread uses when booting up the process. It should contain most of
+ // what we need (before reaching main( ))
+ result = CreateRestrictedToken(
+ effective_token_, initial_level_, integrity_level_, IMPERSONATION,
+ lockdown_default_dacl_, random_sid_ptr, use_restricting_sids_, initial);
+ if (ERROR_SUCCESS != result)
+ return SBOX_ERROR_CANNOT_CREATE_RESTRICTED_IMP_TOKEN;
+
+ return SBOX_ALL_OK;
+}
+
+PSID PolicyBase::GetLowBoxSid() const {
+ return lowbox_sid_;
+}
+
+ResultCode PolicyBase::AddTarget(TargetProcess* target) {
+ if (policy_)
+ policy_maker_->Done();
+
+ if (!ApplyProcessMitigationsToSuspendedProcess(target->Process(),
+ mitigations_)) {
+ return SBOX_ERROR_APPLY_ASLR_MITIGATIONS;
+ }
+
+ ResultCode ret = SetupAllInterceptions(target);
+
+ if (ret != SBOX_ALL_OK)
+ return ret;
+
+ if (!SetupHandleCloser(target))
+ return SBOX_ERROR_SETUP_HANDLE_CLOSER;
+
+ DWORD win_error = ERROR_SUCCESS;
+ // Initialize the sandbox infrastructure for the target.
+ // TODO(wfh) do something with win_error code here.
+ ret = target->Init(dispatcher_.get(), policy_, kIPCMemSize, kPolMemSize,
+ &win_error);
+
+ if (ret != SBOX_ALL_OK)
+ return ret;
+
+ g_shared_delayed_integrity_level = delayed_integrity_level_;
+ ret = target->TransferVariable("g_shared_delayed_integrity_level",
+ &g_shared_delayed_integrity_level,
+ sizeof(g_shared_delayed_integrity_level));
+ g_shared_delayed_integrity_level = INTEGRITY_LEVEL_LAST;
+ if (SBOX_ALL_OK != ret)
+ return ret;
+
+ // Add in delayed mitigations and pseudo-mitigations enforced at startup.
+ g_shared_delayed_mitigations =
+ delayed_mitigations_ | FilterPostStartupProcessMitigations(mitigations_);
+ if (!CanSetProcessMitigationsPostStartup(g_shared_delayed_mitigations))
+ return SBOX_ERROR_BAD_PARAMS;
+
+ ret = target->TransferVariable("g_shared_delayed_mitigations",
+ &g_shared_delayed_mitigations,
+ sizeof(g_shared_delayed_mitigations));
+ g_shared_delayed_mitigations = 0;
+ if (SBOX_ALL_OK != ret)
+ return ret;
+
+ AutoLock lock(&lock_);
+ targets_.push_back(target);
+ return SBOX_ALL_OK;
+}
+
+bool PolicyBase::OnJobEmpty(HANDLE job) {
+ AutoLock lock(&lock_);
+ TargetSet::iterator it;
+ for (it = targets_.begin(); it != targets_.end(); ++it) {
+ if ((*it)->Job() == job)
+ break;
+ }
+ if (it == targets_.end()) {
+ return false;
+ }
+ TargetProcess* target = *it;
+ targets_.erase(it);
+ delete target;
+ return true;
+}
+
+ResultCode PolicyBase::SetDisconnectCsrss() {
+// Does not work on 32-bit, and the ASAN runtime falls over with the
+// CreateThread EAT patch used when this is enabled.
+// See https://crbug.com/783296#c27.
+#if defined(_WIN64) && !defined(ADDRESS_SANITIZER)
+ if (base::win::GetVersion() >= base::win::Version::WIN10) {
+ is_csrss_connected_ = false;
+ return AddKernelObjectToClose(L"ALPC Port", nullptr);
+ }
+#endif // !defined(_WIN64)
+ return SBOX_ALL_OK;
+}
+
+EvalResult PolicyBase::EvalPolicy(IpcTag service,
+ CountedParameterSetBase* params) {
+ if (policy_) {
+ if (!policy_->entry[static_cast<size_t>(service)]) {
+ // There is no policy for this particular service. This is not a big
+ // deal.
+ return DENY_ACCESS;
+ }
+ for (size_t i = 0; i < params->count; i++) {
+ if (!params->parameters[i].IsValid()) {
+ NOTREACHED();
+ return SIGNAL_ALARM;
+ }
+ }
+ PolicyProcessor pol_evaluator(policy_->entry[static_cast<size_t>(service)]);
+ PolicyResult result =
+ pol_evaluator.Evaluate(kShortEval, params->parameters, params->count);
+ if (POLICY_MATCH == result)
+ return pol_evaluator.GetAction();
+
+ DCHECK(POLICY_ERROR != result);
+ }
+
+ return DENY_ACCESS;
+}
+
+HANDLE PolicyBase::GetStdoutHandle() {
+ return stdout_handle_;
+}
+
+HANDLE PolicyBase::GetStderrHandle() {
+ return stderr_handle_;
+}
+
+void PolicyBase::SetEnableOPMRedirection() {
+ enable_opm_redirection_ = true;
+}
+
+bool PolicyBase::GetEnableOPMRedirection() {
+ return enable_opm_redirection_;
+}
+
+ResultCode PolicyBase::AddAppContainerProfile(const wchar_t* package_name,
+ bool create_profile) {
+ if (base::win::GetVersion() < base::win::Version::WIN8)
+ return SBOX_ERROR_UNSUPPORTED;
+
+ DCHECK(package_name);
+ if (lowbox_sid_ || app_container_profile_ ||
+ integrity_level_ != INTEGRITY_LEVEL_LAST) {
+ return SBOX_ERROR_BAD_PARAMS;
+ }
+
+ if (create_profile) {
+ app_container_profile_ = AppContainerProfileBase::Create(
+ package_name, L"Chrome Sandbox", L"Profile for Chrome Sandbox");
+ } else {
+ app_container_profile_ = AppContainerProfileBase::Open(package_name);
+ }
+ if (!app_container_profile_)
+ return SBOX_ERROR_CREATE_APPCONTAINER_PROFILE;
+
+ // A bug exists in CreateProcess where enabling an AppContainer profile and
+ // passing a set of mitigation flags will generate ERROR_INVALID_PARAMETER.
+ // Apply best efforts here and convert set mitigations to delayed mitigations.
+ // This bug looks to have been fixed in Win10 RS5, so exit early if possible.
+ if (base::win::GetVersion() >= base::win::Version::WIN10_RS5)
+ return SBOX_ALL_OK;
+
+ delayed_mitigations_ =
+ mitigations_ & GetAllowedPostStartupProcessMitigations();
+ DCHECK(delayed_mitigations_ ==
+ (mitigations_ & ~(MITIGATION_SEHOP |
+ MITIGATION_RESTRICT_INDIRECT_BRANCH_PREDICTION)));
+ mitigations_ = 0;
+ return SBOX_ALL_OK;
+}
+
+scoped_refptr<AppContainerProfile> PolicyBase::GetAppContainerProfile() {
+ return GetAppContainerProfileBase();
+}
+
+void PolicyBase::SetEffectiveToken(HANDLE token) {
+ CHECK(token);
+ effective_token_ = token;
+}
+
+scoped_refptr<AppContainerProfileBase>
+PolicyBase::GetAppContainerProfileBase() {
+ return app_container_profile_;
+}
+
+ResultCode PolicyBase::SetupAllInterceptions(TargetProcess* target) {
+ InterceptionManager manager(target, relaxed_interceptions_);
+
+ if (policy_) {
+ for (size_t i = 0; i < kMaxIpcTag; i++) {
+ if (policy_->entry[i] &&
+ !dispatcher_->SetupService(&manager, static_cast<IpcTag>(i)))
+ return SBOX_ERROR_SETUP_INTERCEPTION_SERVICE;
+ }
+ }
+
+ for (const std::wstring& dll : blocklisted_dlls_)
+ manager.AddToUnloadModules(dll.c_str());
+
+ if (!SetupBasicInterceptions(&manager, is_csrss_connected_))
+ return SBOX_ERROR_SETUP_BASIC_INTERCEPTIONS;
+
+ ResultCode rc = manager.InitializeInterceptions();
+ if (rc != SBOX_ALL_OK)
+ return rc;
+
+ // Finally, setup imports on the target so the interceptions can work.
+ if (!SetupNtdllImports(target))
+ return SBOX_ERROR_SETUP_NTDLL_IMPORTS;
+
+ return SBOX_ALL_OK;
+}
+
+bool PolicyBase::SetupHandleCloser(TargetProcess* target) {
+ return handle_closer_.InitializeTargetHandles(target);
+}
+
+ResultCode PolicyBase::AddRuleInternal(SubSystem subsystem,
+ Semantics semantics,
+ const wchar_t* pattern) {
+ if (!policy_) {
+ policy_ = MakeBrokerPolicyMemory();
+ DCHECK(policy_);
+ policy_maker_ = new LowLevelPolicy(policy_);
+ DCHECK(policy_maker_);
+ }
+
+ switch (subsystem) {
+ case SUBSYS_FILES: {
+ if (!file_system_init_) {
+ if (!FileSystemPolicy::SetInitialRules(policy_maker_))
+ return SBOX_ERROR_BAD_PARAMS;
+ file_system_init_ = true;
+ }
+ if (!FileSystemPolicy::GenerateRules(pattern, semantics, policy_maker_)) {
+ NOTREACHED();
+ return SBOX_ERROR_BAD_PARAMS;
+ }
+ break;
+ }
+ case SUBSYS_SYNC: {
+ if (!SyncPolicy::GenerateRules(pattern, semantics, policy_maker_)) {
+ NOTREACHED();
+ return SBOX_ERROR_BAD_PARAMS;
+ }
+ break;
+ }
+ case SUBSYS_PROCESS: {
+ if (lockdown_level_ < USER_INTERACTIVE &&
+ TargetPolicy::PROCESS_ALL_EXEC == semantics) {
+ // This is unsupported. This is a huge security risk to give full access
+ // to a process handle.
+ return SBOX_ERROR_UNSUPPORTED;
+ }
+ if (!ProcessPolicy::GenerateRules(pattern, semantics, policy_maker_)) {
+ NOTREACHED();
+ return SBOX_ERROR_BAD_PARAMS;
+ }
+ break;
+ }
+ case SUBSYS_NAMED_PIPES: {
+ if (!NamedPipePolicy::GenerateRules(pattern, semantics, policy_maker_)) {
+ NOTREACHED();
+ return SBOX_ERROR_BAD_PARAMS;
+ }
+ break;
+ }
+ case SUBSYS_REGISTRY: {
+ if (!RegistryPolicy::GenerateRules(pattern, semantics, policy_maker_)) {
+ NOTREACHED();
+ return SBOX_ERROR_BAD_PARAMS;
+ }
+ break;
+ }
+ case SUBSYS_HANDLES: {
+ if (!HandlePolicy::GenerateRules(pattern, semantics, policy_maker_)) {
+ NOTREACHED();
+ return SBOX_ERROR_BAD_PARAMS;
+ }
+ break;
+ }
+
+ case SUBSYS_WIN32K_LOCKDOWN: {
+ // Win32k intercept rules only supported on Windows 8 and above. This must
+ // match the version checks in process_mitigations.cc for consistency.
+ if (base::win::GetVersion() >= base::win::Version::WIN8) {
+ DCHECK_EQ(MITIGATION_WIN32K_DISABLE,
+ mitigations_ & MITIGATION_WIN32K_DISABLE)
+ << "Enable MITIGATION_WIN32K_DISABLE before adding win32k policy "
+ "rules.";
+ if (!ProcessMitigationsWin32KLockdownPolicy::GenerateRules(
+ pattern, semantics, policy_maker_)) {
+ NOTREACHED();
+ return SBOX_ERROR_BAD_PARAMS;
+ }
+ }
+ break;
+ }
+ case SUBSYS_SIGNED_BINARY: {
+ // Signed intercept rules only supported on Windows 10 TH2 and above. This
+ // must match the version checks in process_mitigations.cc for
+ // consistency.
+ if (base::win::GetVersion() >= base::win::Version::WIN10_TH2) {
+ DCHECK_EQ(MITIGATION_FORCE_MS_SIGNED_BINS,
+ (mitigations_ & MITIGATION_FORCE_MS_SIGNED_BINS) | (delayed_mitigations_ & MITIGATION_FORCE_MS_SIGNED_BINS))
+ << "Enable MITIGATION_FORCE_MS_SIGNED_BINS before adding signed "
+ "policy rules.";
+ if (!SignedPolicy::GenerateRules(pattern, semantics, policy_maker_)) {
+ NOTREACHED();
+ return SBOX_ERROR_BAD_PARAMS;
+ }
+ }
+ break;
+ }
+ case SUBSYS_LINE_BREAK: {
+ if (!LineBreakPolicy::GenerateRules(pattern, semantics, policy_maker_)) {
+ NOTREACHED();
+ return SBOX_ERROR_BAD_PARAMS;
+ }
+ break;
+ }
+
+ default: { return SBOX_ERROR_UNSUPPORTED; }
+ }
+
+ return SBOX_ALL_OK;
+}
+
+} // namespace sandbox