// Copyright 2011 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SANDBOX_WIN_SRC_SANDBOX_POLICY_BASE_H_
#define SANDBOX_WIN_SRC_SANDBOX_POLICY_BASE_H_
#include <stddef.h>
#include <stdint.h>
#include <list>
#include <memory>
#include <string>
#include <string_view>
#include <vector>
#include <optional>
#include "base/compiler_specific.h"
#include "base/containers/span.h"
#include "base/dcheck_is_on.h"
#include "base/memory/raw_ptr.h"
#include "base/process/launch.h"
#include "base/synchronization/lock.h"
#include "base/win/access_token.h"
#include "base/win/windows_types.h"
#include "sandbox/win/src/app_container_base.h"
#include "sandbox/win/src/handle_closer.h"
#include "sandbox/win/src/ipc_tags.h"
#include "sandbox/win/src/job.h"
#include "sandbox/win/src/policy_engine_opcodes.h"
#include "sandbox/win/src/policy_engine_params.h"
#include "sandbox/win/src/sandbox_policy.h"
namespace sandbox {
class BrokerServicesBase;
class Dispatcher;
class LowLevelPolicy;
class PolicyDiagnostic;
class TargetProcess;
struct PolicyGlobal;
// The members of this class are shared between multiple sandbox::PolicyBase
// objects and must be safe for access from multiple threads once created.
// When shared members will not be destroyed until BrokerServicesBase is
// destroyed at process shutdown.
class ConfigBase final : public TargetConfig {
public:
ConfigBase() noexcept;
~ConfigBase() override;
ConfigBase(const ConfigBase&) = delete;
ConfigBase& operator=(const ConfigBase&) = delete;
bool IsConfigured() const override;
ResultCode SetTokenLevel(TokenLevel initial, TokenLevel lockdown) override;
TokenLevel GetInitialTokenLevel() const override;
TokenLevel GetLockdownTokenLevel() const override;
ResultCode SetJobLevel(JobLevel job_level, uint32_t ui_exceptions) override;
JobLevel GetJobLevel() const override;
void SetJobMemoryLimit(size_t memory_limit) override;
ResultCode AllowFileAccess(FileSemantics semantics,
const wchar_t* pattern) override;
ResultCode AllowExtraDlls(const wchar_t* pattern) override;
ResultCode SetFakeGdiInit() override;
void AddDllToUnload(const wchar_t* dll_name) override;
ResultCode SetIntegrityLevel(IntegrityLevel integrity_level) override;
IntegrityLevel GetIntegrityLevel() const override;
void SetDelayedIntegrityLevel(IntegrityLevel integrity_level) override;
ResultCode SetLowBox(const wchar_t* sid) override;
ResultCode SetProcessMitigations(MitigationFlags flags) override;
MitigationFlags GetProcessMitigations() override;
ResultCode SetDelayedProcessMitigations(MitigationFlags flags) override;
MitigationFlags GetDelayedProcessMitigations() const override;
void AddRestrictingRandomSid() override;
void SetLockdownDefaultDacl() override;
ResultCode AddAppContainerProfile(
const wchar_t* package_name,
ACProfileRegistration registration) override;
AppContainer* GetAppContainer() override;
void AddKernelObjectToClose(HandleToClose handle_info) override;
void SetDisconnectCsrss() override;
void SetDesktop(Desktop desktop) override;
void SetFilterEnvironment(bool filter) override;
bool GetEnvironmentFiltered() override;
void SetZeroAppShim() override;
private:
// Can call Freeze()
friend class BrokerServicesBase;
// Can examine private fields.
friend class PolicyDiagnostic;
// Can call private accessors.
friend class PolicyBase;
// Can ask for the low-level policy.
friend class TopLevelDispatcher;
// Promise that no further changes will be made to the configuration, and
// this object can be reused by multiple policies.
bool Freeze();
// Use in DCHECK only - returns `true` in non-DCHECK builds.
bool IsOnCreatingThread() const;
// Lazily populates the policy_ and policy_maker_ members for internal rules.
// Can only be called before the object is fully configured.
LowLevelPolicy* PolicyMaker();
// Some IPCs are only configured if a matching policy has been set, this
// method allows TopLevelDispatcher to determine if a policy exists for a
// given service. Only call after calling Freeze().
bool NeedsIpc(IpcTag service) const;
#if DCHECK_IS_ON()
// Used to sequence-check in DCHECK builds.
uint32_t creating_thread_id_;
#endif // DCHECK_IS_ON()
// Once true the configuration is frozen and can be applied to later policies.
bool configured_ = false;
// Should only be called once the object is configured.
PolicyGlobal* policy();
std::optional<base::span<const uint8_t>> policy_span();
std::vector<std::wstring>& blocklisted_dlls();
AppContainerBase* app_container();
IntegrityLevel integrity_level() { return integrity_level_; }
IntegrityLevel delayed_integrity_level() { return delayed_integrity_level_; }
bool add_restricting_random_sid() { return add_restricting_random_sid_; }
bool lockdown_default_dacl() { return lockdown_default_dacl_; }
bool is_csrss_connected() { return is_csrss_connected_; }
size_t memory_limit() { return memory_limit_; }
uint32_t ui_exceptions() { return ui_exceptions_; }
Desktop desktop() { return desktop_; }
const HandleCloserConfig& handle_closer() { return handle_closer_; }
bool zero_appshim() { return zero_appshim_; }
TokenLevel lockdown_level_;
TokenLevel initial_level_;
JobLevel job_level_;
IntegrityLevel integrity_level_;
IntegrityLevel delayed_integrity_level_;
MitigationFlags mitigations_;
MitigationFlags delayed_mitigations_;
bool add_restricting_random_sid_;
bool lockdown_default_dacl_;
bool is_csrss_connected_;
size_t memory_limit_;
uint32_t ui_exceptions_;
Desktop desktop_;
bool filter_environment_;
bool zero_appshim_;
HandleCloserConfig handle_closer_;
// Object in charge of generating the low level policy. Will be reset() when
// Freeze() is called.
std::unique_ptr<LowLevelPolicy> policy_maker_;
// Memory structure that stores the low level policy rules for proxied calls.
raw_ptr<PolicyGlobal> policy_;
// The list of dlls to unload in the target process.
std::vector<std::wstring> blocklisted_dlls_;
// AppContainer to be applied to the target process.
std::unique_ptr<AppContainerBase> app_container_;
};
class PolicyBase final : public TargetPolicy {
public:
PolicyBase(std::string_view key);
~PolicyBase() override;
PolicyBase(const PolicyBase&) = delete;
PolicyBase& operator=(const PolicyBase&) = delete;
// TargetPolicy:
TargetConfig* GetConfig() override;
ResultCode SetStdoutHandle(HANDLE handle) override;
ResultCode SetStderrHandle(HANDLE handle) override;
void AddHandleToShare(HANDLE handle) override;
void AddDelegateData(base::span<const uint8_t> data) override;
// Creates a Job object with the level specified in a previous call to
// SetJobLevel().
ResultCode InitJob();
// Returns the handle for this policy's job, or nullptr if the job is
// not initialized.
HANDLE GetJobHandle();
// Returns true if a job is associated with this policy.
bool HasJob();
// Updates the active process limit on the policy's job to zero.
// Has no effect if the job is allowed to spawn processes.
ResultCode DropActiveProcessLimit();
// Creates the two tokens with the levels specified in a previous call to
// SetTokenLevel().
ResultCode MakeTokens(std::optional<base::win::AccessToken>& initial,
std::optional<base::win::AccessToken>& lockdown);
// Applies the sandbox to |target| and takes ownership. Internally a
// call to TargetProcess::Init() is issued.
ResultCode ApplyToTarget(std::unique_ptr<TargetProcess> target);
EvalResult EvalPolicy(IpcTag service, CountedParameterSetBase* params);
HANDLE GetStdoutHandle();
HANDLE GetStderrHandle();
// Returns the list of handles being shared with the target process.
const base::HandlesToInheritVector& GetHandlesBeingShared();
private:
// BrokerServicesBase is allowed to set shared backing fields for TargetConfig.
friend class sandbox::BrokerServicesBase;
// Allow PolicyDiagnostic to snapshot PolicyBase for diagnostics.
friend class PolicyDiagnostic;
// Allow TopLevelDispatcher to know which IPC policy rules are necessary.
friend class TopLevelDispatcher;
// Sets up interceptions for a new target. This policy must own |target|.
ResultCode SetupAllInterceptions(TargetProcess& target);
// Sets up the handle closer for a new target. This policy must own |target|.
bool SetupHandleCloser(TargetProcess& target);
// TargetConfig will really be a ConfigBase.
bool SetConfig(TargetConfig* config);
// Gets possibly shared data or allocates if it did not already exist.
ConfigBase* config();
// Tag provided when this policy was created - mainly for debugging.
std::string tag_;
// Backing data if this object was created with an empty tag_.
std::unique_ptr<ConfigBase> config_;
// Shared backing data if this object will share fields with other policies.
raw_ptr<ConfigBase> config_ptr_;
// Remaining members are unique to this instance and will be configured every
// time.
// Returns nullopt if no data has been set, or a view into the data.
std::optional<base::span<const uint8_t>> delegate_data_span();
// The user-defined global policy settings.
HANDLE stdout_handle_;
HANDLE stderr_handle_;
// An opaque blob of data the delegate uses to prime any pre-sandbox hooks.
std::unique_ptr<const std::vector<uint8_t>> delegate_data_;
std::unique_ptr<Dispatcher> dispatcher_;
// Contains the list of handles being shared with the target process.
// This list contains handles other than the stderr/stdout handles which are
// shared with the target at times.
base::HandlesToInheritVector handles_to_share_;
Job job_;
// The policy takes ownership of a target as it is applied to it.
std::unique_ptr<TargetProcess> target_;
};
} // namespace sandbox
#endif // SANDBOX_WIN_SRC_SANDBOX_POLICY_BASE_H_