michael@0: // Copyright (c) 2012 The Chromium Authors. All rights reserved. michael@0: // Use of this source code is governed by a BSD-style license that can be michael@0: // found in the LICENSE file. michael@0: michael@0: #include "sandbox/win/src/sandbox_policy_base.h" michael@0: michael@0: #include "base/basictypes.h" michael@0: #include "base/callback.h" michael@0: #include "base/logging.h" michael@0: #include "base/win/windows_version.h" michael@0: #include "sandbox/win/src/app_container.h" michael@0: #include "sandbox/win/src/filesystem_dispatcher.h" michael@0: #include "sandbox/win/src/filesystem_policy.h" michael@0: #include "sandbox/win/src/handle_dispatcher.h" michael@0: #include "sandbox/win/src/handle_policy.h" michael@0: #include "sandbox/win/src/job.h" michael@0: #include "sandbox/win/src/interception.h" michael@0: #include "sandbox/win/src/process_mitigations.h" michael@0: #include "sandbox/win/src/named_pipe_dispatcher.h" michael@0: #include "sandbox/win/src/named_pipe_policy.h" michael@0: #include "sandbox/win/src/policy_broker.h" michael@0: #include "sandbox/win/src/policy_engine_processor.h" michael@0: #include "sandbox/win/src/policy_low_level.h" michael@0: #include "sandbox/win/src/process_thread_dispatcher.h" michael@0: #include "sandbox/win/src/process_thread_policy.h" michael@0: #include "sandbox/win/src/registry_dispatcher.h" michael@0: #include "sandbox/win/src/registry_policy.h" michael@0: #include "sandbox/win/src/restricted_token_utils.h" michael@0: #include "sandbox/win/src/sandbox_policy.h" michael@0: #include "sandbox/win/src/sync_dispatcher.h" michael@0: #include "sandbox/win/src/sync_policy.h" michael@0: #include "sandbox/win/src/target_process.h" michael@0: #include "sandbox/win/src/window.h" michael@0: michael@0: namespace { michael@0: michael@0: // The standard windows size for one memory page. michael@0: const size_t kOneMemPage = 4096; michael@0: // The IPC and Policy shared memory sizes. michael@0: const size_t kIPCMemSize = kOneMemPage * 2; michael@0: const size_t kPolMemSize = kOneMemPage * 14; michael@0: michael@0: // Helper function to allocate space (on the heap) for policy. michael@0: sandbox::PolicyGlobal* MakeBrokerPolicyMemory() { michael@0: const size_t kTotalPolicySz = kPolMemSize; michael@0: sandbox::PolicyGlobal* policy = static_cast michael@0: (::operator new(kTotalPolicySz)); michael@0: DCHECK(policy); michael@0: memset(policy, 0, kTotalPolicySz); michael@0: policy->data_size = kTotalPolicySz - sizeof(sandbox::PolicyGlobal); michael@0: return policy; michael@0: } michael@0: michael@0: bool IsInheritableHandle(HANDLE handle) { michael@0: if (!handle) michael@0: return false; michael@0: if (handle == INVALID_HANDLE_VALUE) michael@0: return false; michael@0: // File handles (FILE_TYPE_DISK) and pipe handles are known to be michael@0: // inheritable. Console handles (FILE_TYPE_CHAR) are not michael@0: // inheritable via PROC_THREAD_ATTRIBUTE_HANDLE_LIST. michael@0: DWORD handle_type = GetFileType(handle); michael@0: return handle_type == FILE_TYPE_DISK || handle_type == FILE_TYPE_PIPE; michael@0: } michael@0: michael@0: } michael@0: michael@0: namespace sandbox { michael@0: michael@0: SANDBOX_INTERCEPT IntegrityLevel g_shared_delayed_integrity_level; michael@0: SANDBOX_INTERCEPT MitigationFlags g_shared_delayed_mitigations; michael@0: michael@0: // Initializes static members. michael@0: HWINSTA PolicyBase::alternate_winstation_handle_ = NULL; michael@0: HDESK PolicyBase::alternate_desktop_handle_ = NULL; michael@0: michael@0: PolicyBase::PolicyBase() michael@0: : ref_count(1), michael@0: lockdown_level_(USER_LOCKDOWN), michael@0: initial_level_(USER_LOCKDOWN), michael@0: job_level_(JOB_LOCKDOWN), michael@0: ui_exceptions_(0), michael@0: use_alternate_desktop_(false), michael@0: use_alternate_winstation_(false), michael@0: file_system_init_(false), michael@0: relaxed_interceptions_(true), michael@0: stdout_handle_(INVALID_HANDLE_VALUE), michael@0: stderr_handle_(INVALID_HANDLE_VALUE), michael@0: integrity_level_(INTEGRITY_LEVEL_LAST), michael@0: delayed_integrity_level_(INTEGRITY_LEVEL_LAST), michael@0: mitigations_(0), michael@0: delayed_mitigations_(0), michael@0: policy_maker_(NULL), michael@0: policy_(NULL) { michael@0: ::InitializeCriticalSection(&lock_); michael@0: // Initialize the IPC dispatcher array. michael@0: memset(&ipc_targets_, NULL, sizeof(ipc_targets_)); michael@0: Dispatcher* dispatcher = NULL; michael@0: michael@0: dispatcher = new FilesystemDispatcher(this); michael@0: ipc_targets_[IPC_NTCREATEFILE_TAG] = dispatcher; michael@0: ipc_targets_[IPC_NTOPENFILE_TAG] = dispatcher; michael@0: ipc_targets_[IPC_NTSETINFO_RENAME_TAG] = dispatcher; michael@0: ipc_targets_[IPC_NTQUERYATTRIBUTESFILE_TAG] = dispatcher; michael@0: ipc_targets_[IPC_NTQUERYFULLATTRIBUTESFILE_TAG] = dispatcher; michael@0: michael@0: dispatcher = new NamedPipeDispatcher(this); michael@0: ipc_targets_[IPC_CREATENAMEDPIPEW_TAG] = dispatcher; michael@0: michael@0: dispatcher = new ThreadProcessDispatcher(this); michael@0: ipc_targets_[IPC_NTOPENTHREAD_TAG] = dispatcher; michael@0: ipc_targets_[IPC_NTOPENPROCESS_TAG] = dispatcher; michael@0: ipc_targets_[IPC_CREATEPROCESSW_TAG] = dispatcher; michael@0: ipc_targets_[IPC_NTOPENPROCESSTOKEN_TAG] = dispatcher; michael@0: ipc_targets_[IPC_NTOPENPROCESSTOKENEX_TAG] = dispatcher; michael@0: michael@0: dispatcher = new SyncDispatcher(this); michael@0: ipc_targets_[IPC_CREATEEVENT_TAG] = dispatcher; michael@0: ipc_targets_[IPC_OPENEVENT_TAG] = dispatcher; michael@0: michael@0: dispatcher = new RegistryDispatcher(this); michael@0: ipc_targets_[IPC_NTCREATEKEY_TAG] = dispatcher; michael@0: ipc_targets_[IPC_NTOPENKEY_TAG] = dispatcher; michael@0: michael@0: dispatcher = new HandleDispatcher(this); michael@0: ipc_targets_[IPC_DUPLICATEHANDLEPROXY_TAG] = dispatcher; michael@0: } michael@0: michael@0: PolicyBase::~PolicyBase() { michael@0: TargetSet::iterator it; michael@0: for (it = targets_.begin(); it != targets_.end(); ++it) { michael@0: TargetProcess* target = (*it); michael@0: delete target; michael@0: } michael@0: delete ipc_targets_[IPC_NTCREATEFILE_TAG]; michael@0: delete ipc_targets_[IPC_CREATENAMEDPIPEW_TAG]; michael@0: delete ipc_targets_[IPC_NTOPENTHREAD_TAG]; michael@0: delete ipc_targets_[IPC_CREATEEVENT_TAG]; michael@0: delete ipc_targets_[IPC_NTCREATEKEY_TAG]; michael@0: delete ipc_targets_[IPC_DUPLICATEHANDLEPROXY_TAG]; michael@0: delete policy_maker_; michael@0: delete policy_; michael@0: ::DeleteCriticalSection(&lock_); michael@0: } michael@0: michael@0: void PolicyBase::AddRef() { michael@0: ::InterlockedIncrement(&ref_count); michael@0: } michael@0: michael@0: void PolicyBase::Release() { michael@0: if (0 == ::InterlockedDecrement(&ref_count)) michael@0: delete this; michael@0: } michael@0: michael@0: ResultCode PolicyBase::SetTokenLevel(TokenLevel initial, TokenLevel lockdown) { michael@0: if (initial < lockdown) { michael@0: return SBOX_ERROR_BAD_PARAMS; michael@0: } michael@0: initial_level_ = initial; michael@0: lockdown_level_ = lockdown; michael@0: return SBOX_ALL_OK; michael@0: } michael@0: michael@0: ResultCode PolicyBase::SetJobLevel(JobLevel job_level, uint32 ui_exceptions) { michael@0: job_level_ = job_level; michael@0: ui_exceptions_ = ui_exceptions; michael@0: return SBOX_ALL_OK; michael@0: } michael@0: michael@0: ResultCode PolicyBase::SetAlternateDesktop(bool alternate_winstation) { michael@0: use_alternate_desktop_ = true; michael@0: use_alternate_winstation_ = alternate_winstation; michael@0: return CreateAlternateDesktop(alternate_winstation); michael@0: } michael@0: michael@0: string16 PolicyBase::GetAlternateDesktop() const { michael@0: // No alternate desktop or winstation. Return an empty string. michael@0: if (!use_alternate_desktop_ && !use_alternate_winstation_) { michael@0: return string16(); michael@0: } michael@0: michael@0: // The desktop and winstation should have been created by now. michael@0: // If we hit this scenario, it means that the user ignored the failure michael@0: // during SetAlternateDesktop, so we ignore it here too. michael@0: if (use_alternate_desktop_ && !alternate_desktop_handle_) { michael@0: return string16(); michael@0: } michael@0: if (use_alternate_winstation_ && (!alternate_desktop_handle_ || michael@0: !alternate_winstation_handle_)) { michael@0: return string16(); michael@0: } michael@0: michael@0: return GetFullDesktopName(alternate_winstation_handle_, michael@0: alternate_desktop_handle_); michael@0: } michael@0: michael@0: ResultCode PolicyBase::CreateAlternateDesktop(bool alternate_winstation) { michael@0: if (alternate_winstation) { michael@0: // Previously called with alternate_winstation = false? michael@0: if (!alternate_winstation_handle_ && alternate_desktop_handle_) michael@0: return SBOX_ERROR_UNSUPPORTED; michael@0: michael@0: // Check if it's already created. michael@0: if (alternate_winstation_handle_ && alternate_desktop_handle_) michael@0: return SBOX_ALL_OK; michael@0: michael@0: DCHECK(!alternate_winstation_handle_); michael@0: // Create the window station. michael@0: ResultCode result = CreateAltWindowStation(&alternate_winstation_handle_); michael@0: if (SBOX_ALL_OK != result) michael@0: return result; michael@0: michael@0: // Verify that everything is fine. michael@0: if (!alternate_winstation_handle_ || michael@0: GetWindowObjectName(alternate_winstation_handle_).empty()) michael@0: return SBOX_ERROR_CANNOT_CREATE_DESKTOP; michael@0: michael@0: // Create the destkop. michael@0: result = CreateAltDesktop(alternate_winstation_handle_, michael@0: &alternate_desktop_handle_); michael@0: if (SBOX_ALL_OK != result) michael@0: return result; michael@0: michael@0: // Verify that everything is fine. michael@0: if (!alternate_desktop_handle_ || michael@0: GetWindowObjectName(alternate_desktop_handle_).empty()) michael@0: return SBOX_ERROR_CANNOT_CREATE_DESKTOP; michael@0: } else { michael@0: // Previously called with alternate_winstation = true? michael@0: if (alternate_winstation_handle_) michael@0: return SBOX_ERROR_UNSUPPORTED; michael@0: michael@0: // Check if it already exists. michael@0: if (alternate_desktop_handle_) michael@0: return SBOX_ALL_OK; michael@0: michael@0: // Create the destkop. michael@0: ResultCode result = CreateAltDesktop(NULL, &alternate_desktop_handle_); michael@0: if (SBOX_ALL_OK != result) michael@0: return result; michael@0: michael@0: // Verify that everything is fine. michael@0: if (!alternate_desktop_handle_ || michael@0: GetWindowObjectName(alternate_desktop_handle_).empty()) michael@0: return SBOX_ERROR_CANNOT_CREATE_DESKTOP; michael@0: } michael@0: michael@0: return SBOX_ALL_OK; michael@0: } michael@0: michael@0: void PolicyBase::DestroyAlternateDesktop() { michael@0: if (alternate_desktop_handle_) { michael@0: ::CloseDesktop(alternate_desktop_handle_); michael@0: alternate_desktop_handle_ = NULL; michael@0: } michael@0: michael@0: if (alternate_winstation_handle_) { michael@0: ::CloseWindowStation(alternate_winstation_handle_); michael@0: alternate_winstation_handle_ = NULL; michael@0: } michael@0: } michael@0: michael@0: ResultCode PolicyBase::SetIntegrityLevel(IntegrityLevel integrity_level) { michael@0: integrity_level_ = integrity_level; michael@0: return SBOX_ALL_OK; michael@0: } michael@0: michael@0: ResultCode PolicyBase::SetDelayedIntegrityLevel( michael@0: IntegrityLevel integrity_level) { michael@0: delayed_integrity_level_ = integrity_level; michael@0: return SBOX_ALL_OK; michael@0: } michael@0: michael@0: ResultCode PolicyBase::SetAppContainer(const wchar_t* sid) { michael@0: if (base::win::OSInfo::GetInstance()->version() < base::win::VERSION_WIN8) michael@0: return SBOX_ALL_OK; michael@0: michael@0: // Windows refuses to work with an impersonation token for a process inside michael@0: // an AppContainer. If the caller wants to use a more privileged initial michael@0: // token, or if the lockdown level will prevent the process from starting, michael@0: // we have to fail the operation. michael@0: if (lockdown_level_ < USER_LIMITED || lockdown_level_ != initial_level_) michael@0: return SBOX_ERROR_CANNOT_INIT_APPCONTAINER; michael@0: michael@0: DCHECK(!appcontainer_list_.get()); michael@0: appcontainer_list_.reset(new AppContainerAttributes); michael@0: ResultCode rv = appcontainer_list_->SetAppContainer(sid, capabilities_); michael@0: if (rv != SBOX_ALL_OK) michael@0: return rv; michael@0: michael@0: return SBOX_ALL_OK; michael@0: } michael@0: michael@0: ResultCode PolicyBase::SetCapability(const wchar_t* sid) { michael@0: capabilities_.push_back(sid); michael@0: return SBOX_ALL_OK; michael@0: } michael@0: michael@0: ResultCode PolicyBase::SetProcessMitigations( michael@0: MitigationFlags flags) { michael@0: if (!CanSetProcessMitigationsPreStartup(flags)) michael@0: return SBOX_ERROR_BAD_PARAMS; michael@0: mitigations_ = flags; michael@0: return SBOX_ALL_OK; michael@0: } michael@0: michael@0: MitigationFlags PolicyBase::GetProcessMitigations() { michael@0: return mitigations_; michael@0: } michael@0: michael@0: ResultCode PolicyBase::SetDelayedProcessMitigations( michael@0: MitigationFlags flags) { michael@0: if (!CanSetProcessMitigationsPostStartup(flags)) michael@0: return SBOX_ERROR_BAD_PARAMS; michael@0: delayed_mitigations_ = flags; michael@0: return SBOX_ALL_OK; michael@0: } michael@0: michael@0: MitigationFlags PolicyBase::GetDelayedProcessMitigations() { michael@0: return delayed_mitigations_; michael@0: } michael@0: michael@0: void PolicyBase::SetStrictInterceptions() { michael@0: relaxed_interceptions_ = false; michael@0: } michael@0: michael@0: ResultCode PolicyBase::SetStdoutHandle(HANDLE handle) { michael@0: if (!IsInheritableHandle(handle)) michael@0: return SBOX_ERROR_BAD_PARAMS; michael@0: stdout_handle_ = handle; michael@0: return SBOX_ALL_OK; michael@0: } michael@0: michael@0: ResultCode PolicyBase::SetStderrHandle(HANDLE handle) { michael@0: if (!IsInheritableHandle(handle)) michael@0: return SBOX_ERROR_BAD_PARAMS; michael@0: stderr_handle_ = handle; michael@0: return SBOX_ALL_OK; michael@0: } michael@0: michael@0: ResultCode PolicyBase::AddRule(SubSystem subsystem, Semantics semantics, michael@0: const wchar_t* pattern) { michael@0: if (NULL == policy_) { michael@0: policy_ = MakeBrokerPolicyMemory(); michael@0: DCHECK(policy_); michael@0: policy_maker_ = new LowLevelPolicy(policy_); michael@0: DCHECK(policy_maker_); michael@0: } michael@0: michael@0: switch (subsystem) { michael@0: case SUBSYS_FILES: { michael@0: if (!file_system_init_) { michael@0: if (!FileSystemPolicy::SetInitialRules(policy_maker_)) michael@0: return SBOX_ERROR_BAD_PARAMS; michael@0: file_system_init_ = true; michael@0: } michael@0: if (!FileSystemPolicy::GenerateRules(pattern, semantics, policy_maker_)) { michael@0: NOTREACHED(); michael@0: return SBOX_ERROR_BAD_PARAMS; michael@0: } michael@0: break; michael@0: } michael@0: case SUBSYS_SYNC: { michael@0: if (!SyncPolicy::GenerateRules(pattern, semantics, policy_maker_)) { michael@0: NOTREACHED(); michael@0: return SBOX_ERROR_BAD_PARAMS; michael@0: } michael@0: break; michael@0: } michael@0: case SUBSYS_PROCESS: { michael@0: if (lockdown_level_ < USER_INTERACTIVE && michael@0: TargetPolicy::PROCESS_ALL_EXEC == semantics) { michael@0: // This is unsupported. This is a huge security risk to give full access michael@0: // to a process handle. michael@0: return SBOX_ERROR_UNSUPPORTED; michael@0: } michael@0: if (!ProcessPolicy::GenerateRules(pattern, semantics, policy_maker_)) { michael@0: NOTREACHED(); michael@0: return SBOX_ERROR_BAD_PARAMS; michael@0: } michael@0: break; michael@0: } michael@0: case SUBSYS_NAMED_PIPES: { michael@0: if (!NamedPipePolicy::GenerateRules(pattern, semantics, policy_maker_)) { michael@0: NOTREACHED(); michael@0: return SBOX_ERROR_BAD_PARAMS; michael@0: } michael@0: break; michael@0: } michael@0: case SUBSYS_REGISTRY: { michael@0: if (!RegistryPolicy::GenerateRules(pattern, semantics, policy_maker_)) { michael@0: NOTREACHED(); michael@0: return SBOX_ERROR_BAD_PARAMS; michael@0: } michael@0: break; michael@0: } michael@0: case SUBSYS_HANDLES: { michael@0: if (!HandlePolicy::GenerateRules(pattern, semantics, policy_maker_)) { michael@0: NOTREACHED(); michael@0: return SBOX_ERROR_BAD_PARAMS; michael@0: } michael@0: break; michael@0: } michael@0: default: { michael@0: return SBOX_ERROR_UNSUPPORTED; michael@0: } michael@0: } michael@0: michael@0: return SBOX_ALL_OK; michael@0: } michael@0: michael@0: ResultCode PolicyBase::AddDllToUnload(const wchar_t* dll_name) { michael@0: blacklisted_dlls_.push_back(dll_name); michael@0: return SBOX_ALL_OK; michael@0: } michael@0: michael@0: ResultCode PolicyBase::AddKernelObjectToClose(const char16* handle_type, michael@0: const char16* handle_name) { michael@0: return handle_closer_.AddHandle(handle_type, handle_name); michael@0: } michael@0: michael@0: // When an IPC is ready in any of the targets we get called. We manage an array michael@0: // of IPC dispatchers which are keyed on the IPC tag so we normally delegate michael@0: // to the appropriate dispatcher unless we can handle the IPC call ourselves. michael@0: Dispatcher* PolicyBase::OnMessageReady(IPCParams* ipc, michael@0: CallbackGeneric* callback) { michael@0: DCHECK(callback); michael@0: static const IPCParams ping1 = {IPC_PING1_TAG, ULONG_TYPE}; michael@0: static const IPCParams ping2 = {IPC_PING2_TAG, INOUTPTR_TYPE}; michael@0: michael@0: if (ping1.Matches(ipc) || ping2.Matches(ipc)) { michael@0: *callback = reinterpret_cast( michael@0: static_cast(&PolicyBase::Ping)); michael@0: return this; michael@0: } michael@0: michael@0: Dispatcher* dispatch = GetDispatcher(ipc->ipc_tag); michael@0: if (!dispatch) { michael@0: NOTREACHED(); michael@0: return NULL; michael@0: } michael@0: return dispatch->OnMessageReady(ipc, callback); michael@0: } michael@0: michael@0: // Delegate to the appropriate dispatcher. michael@0: bool PolicyBase::SetupService(InterceptionManager* manager, int service) { michael@0: if (IPC_PING1_TAG == service || IPC_PING2_TAG == service) michael@0: return true; michael@0: michael@0: Dispatcher* dispatch = GetDispatcher(service); michael@0: if (!dispatch) { michael@0: NOTREACHED(); michael@0: return false; michael@0: } michael@0: return dispatch->SetupService(manager, service); michael@0: } michael@0: michael@0: ResultCode PolicyBase::MakeJobObject(HANDLE* job) { michael@0: if (job_level_ != JOB_NONE) { michael@0: // Create the windows job object. michael@0: Job job_obj; michael@0: DWORD result = job_obj.Init(job_level_, NULL, ui_exceptions_); michael@0: if (ERROR_SUCCESS != result) { michael@0: return SBOX_ERROR_GENERIC; michael@0: } michael@0: *job = job_obj.Detach(); michael@0: } else { michael@0: *job = NULL; michael@0: } michael@0: return SBOX_ALL_OK; michael@0: } michael@0: michael@0: ResultCode PolicyBase::MakeTokens(HANDLE* initial, HANDLE* lockdown) { michael@0: // Create the 'naked' token. This will be the permanent token associated michael@0: // with the process and therefore with any thread that is not impersonating. michael@0: DWORD result = CreateRestrictedToken(lockdown, lockdown_level_, michael@0: integrity_level_, PRIMARY); michael@0: if (ERROR_SUCCESS != result) { michael@0: return SBOX_ERROR_GENERIC; michael@0: } michael@0: michael@0: if (appcontainer_list_.get() && appcontainer_list_->HasAppContainer()) { michael@0: // Windows refuses to work with an impersonation token. See SetAppContainer michael@0: // implementation for more details. michael@0: if (lockdown_level_ < USER_LIMITED || lockdown_level_ != initial_level_) michael@0: return SBOX_ERROR_CANNOT_INIT_APPCONTAINER; michael@0: michael@0: *initial = INVALID_HANDLE_VALUE; michael@0: return SBOX_ALL_OK; michael@0: } michael@0: michael@0: // Create the 'better' token. We use this token as the one that the main michael@0: // thread uses when booting up the process. It should contain most of michael@0: // what we need (before reaching main( )) michael@0: result = CreateRestrictedToken(initial, initial_level_, michael@0: integrity_level_, IMPERSONATION); michael@0: if (ERROR_SUCCESS != result) { michael@0: ::CloseHandle(*lockdown); michael@0: return SBOX_ERROR_GENERIC; michael@0: } michael@0: return SBOX_ALL_OK; michael@0: } michael@0: michael@0: const AppContainerAttributes* PolicyBase::GetAppContainer() { michael@0: if (!appcontainer_list_.get() || !appcontainer_list_->HasAppContainer()) michael@0: return NULL; michael@0: michael@0: return appcontainer_list_.get(); michael@0: } michael@0: michael@0: bool PolicyBase::AddTarget(TargetProcess* target) { michael@0: if (NULL != policy_) michael@0: policy_maker_->Done(); michael@0: michael@0: if (!ApplyProcessMitigationsToSuspendedProcess(target->Process(), michael@0: mitigations_)) { michael@0: return false; michael@0: } michael@0: michael@0: if (!SetupAllInterceptions(target)) michael@0: return false; michael@0: michael@0: if (!SetupHandleCloser(target)) michael@0: return false; michael@0: michael@0: // Initialize the sandbox infrastructure for the target. michael@0: if (ERROR_SUCCESS != target->Init(this, policy_, kIPCMemSize, kPolMemSize)) michael@0: return false; michael@0: michael@0: g_shared_delayed_integrity_level = delayed_integrity_level_; michael@0: ResultCode ret = target->TransferVariable( michael@0: "g_shared_delayed_integrity_level", michael@0: &g_shared_delayed_integrity_level, michael@0: sizeof(g_shared_delayed_integrity_level)); michael@0: g_shared_delayed_integrity_level = INTEGRITY_LEVEL_LAST; michael@0: if (SBOX_ALL_OK != ret) michael@0: return false; michael@0: michael@0: // Add in delayed mitigations and pseudo-mitigations enforced at startup. michael@0: g_shared_delayed_mitigations = delayed_mitigations_ | michael@0: FilterPostStartupProcessMitigations(mitigations_); michael@0: if (!CanSetProcessMitigationsPostStartup(g_shared_delayed_mitigations)) michael@0: return false; michael@0: michael@0: ret = target->TransferVariable("g_shared_delayed_mitigations", michael@0: &g_shared_delayed_mitigations, michael@0: sizeof(g_shared_delayed_mitigations)); michael@0: g_shared_delayed_mitigations = 0; michael@0: if (SBOX_ALL_OK != ret) michael@0: return false; michael@0: michael@0: AutoLock lock(&lock_); michael@0: targets_.push_back(target); michael@0: return true; michael@0: } michael@0: michael@0: bool PolicyBase::OnJobEmpty(HANDLE job) { michael@0: AutoLock lock(&lock_); michael@0: TargetSet::iterator it; michael@0: for (it = targets_.begin(); it != targets_.end(); ++it) { michael@0: if ((*it)->Job() == job) michael@0: break; michael@0: } michael@0: if (it == targets_.end()) { michael@0: return false; michael@0: } michael@0: TargetProcess* target = *it; michael@0: targets_.erase(it); michael@0: delete target; michael@0: return true; michael@0: } michael@0: michael@0: EvalResult PolicyBase::EvalPolicy(int service, michael@0: CountedParameterSetBase* params) { michael@0: if (NULL != policy_) { michael@0: if (NULL == policy_->entry[service]) { michael@0: // There is no policy for this particular service. This is not a big michael@0: // deal. michael@0: return DENY_ACCESS; michael@0: } michael@0: for (int i = 0; i < params->count; i++) { michael@0: if (!params->parameters[i].IsValid()) { michael@0: NOTREACHED(); michael@0: return SIGNAL_ALARM; michael@0: } michael@0: } michael@0: PolicyProcessor pol_evaluator(policy_->entry[service]); michael@0: PolicyResult result = pol_evaluator.Evaluate(kShortEval, michael@0: params->parameters, michael@0: params->count); michael@0: if (POLICY_MATCH == result) { michael@0: return pol_evaluator.GetAction(); michael@0: } michael@0: DCHECK(POLICY_ERROR != result); michael@0: } michael@0: michael@0: return DENY_ACCESS; michael@0: } michael@0: michael@0: HANDLE PolicyBase::GetStdoutHandle() { michael@0: return stdout_handle_; michael@0: } michael@0: michael@0: HANDLE PolicyBase::GetStderrHandle() { michael@0: return stderr_handle_; michael@0: } michael@0: michael@0: // We service IPC_PING_TAG message which is a way to test a round trip of the michael@0: // IPC subsystem. We receive a integer cookie and we are expected to return the michael@0: // cookie times two (or three) and the current tick count. michael@0: bool PolicyBase::Ping(IPCInfo* ipc, void* arg1) { michael@0: switch (ipc->ipc_tag) { michael@0: case IPC_PING1_TAG: { michael@0: IPCInt ipc_int(arg1); michael@0: uint32 cookie = ipc_int.As32Bit(); michael@0: ipc->return_info.extended_count = 2; michael@0: ipc->return_info.extended[0].unsigned_int = ::GetTickCount(); michael@0: ipc->return_info.extended[1].unsigned_int = 2 * cookie; michael@0: return true; michael@0: } michael@0: case IPC_PING2_TAG: { michael@0: CountedBuffer* io_buffer = reinterpret_cast(arg1); michael@0: if (sizeof(uint32) != io_buffer->Size()) michael@0: return false; michael@0: michael@0: uint32* cookie = reinterpret_cast(io_buffer->Buffer()); michael@0: *cookie = (*cookie) * 3; michael@0: return true; michael@0: } michael@0: default: return false; michael@0: } michael@0: } michael@0: michael@0: Dispatcher* PolicyBase::GetDispatcher(int ipc_tag) { michael@0: if (ipc_tag >= IPC_LAST_TAG || ipc_tag <= IPC_UNUSED_TAG) michael@0: return NULL; michael@0: michael@0: return ipc_targets_[ipc_tag]; michael@0: } michael@0: michael@0: bool PolicyBase::SetupAllInterceptions(TargetProcess* target) { michael@0: InterceptionManager manager(target, relaxed_interceptions_); michael@0: michael@0: if (policy_) { michael@0: for (int i = 0; i < IPC_LAST_TAG; i++) { michael@0: if (policy_->entry[i] && !ipc_targets_[i]->SetupService(&manager, i)) michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: if (!blacklisted_dlls_.empty()) { michael@0: std::vector::iterator it = blacklisted_dlls_.begin(); michael@0: for (; it != blacklisted_dlls_.end(); ++it) { michael@0: manager.AddToUnloadModules(it->c_str()); michael@0: } michael@0: } michael@0: michael@0: if (!handle_closer_.SetupHandleInterceptions(&manager)) michael@0: return false; michael@0: michael@0: if (!SetupBasicInterceptions(&manager)) michael@0: return false; michael@0: michael@0: if (!manager.InitializeInterceptions()) michael@0: return false; michael@0: michael@0: // Finally, setup imports on the target so the interceptions can work. michael@0: return SetupNtdllImports(target); michael@0: } michael@0: michael@0: bool PolicyBase::SetupHandleCloser(TargetProcess* target) { michael@0: return handle_closer_.InitializeTargetHandles(target); michael@0: } michael@0: michael@0: } // namespace sandbox