chromium/sandbox/policy/win/sandbox_win.h

// Copyright 2012 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_POLICY_WIN_SANDBOX_WIN_H_
#define SANDBOX_POLICY_WIN_SANDBOX_WIN_H_

#include <stdint.h>

#include <optional>
#include <string>
#include <string_view>

#include "base/functional/bind.h"
#include "base/functional/callback_forward.h"
#include "base/process/launch.h"
#include "base/process/process_handle.h"
#include "base/timer/elapsed_timer.h"
#include "base/win/scoped_process_information.h"
#include "build/build_config.h"
#include "sandbox/policy/export.h"
#include "sandbox/policy/sandbox_delegate.h"
#include "sandbox/policy/sandbox_type.h"
#include "sandbox/win/src/sandbox_types.h"
#include "sandbox/win/src/security_level.h"

namespace base {
class CommandLine;
class Value;
}  // namespace base

namespace sandbox {
class BrokerServices;
class TargetConfig;
class TargetPolicy;
class TargetServices;

namespace mojom {
enum class Sandbox;
}  // namespace mojom
}  // namespace sandbox

namespace sandbox {
namespace policy {

// Helper to recording timing information during process creation.
class SANDBOX_POLICY_EXPORT SandboxLaunchTimer final {
 public:
  SandboxLaunchTimer() = default;
  SandboxLaunchTimer(const SandboxLaunchTimer&) = delete;
  SandboxLaunchTimer(SandboxLaunchTimer&& other) = default;
  SandboxLaunchTimer& operator=(const SandboxLaunchTimer&) = delete;

  // Call after the policy base object is created.
  void OnPolicyCreated() { policy_created_ = timer_.Elapsed(); }

  // Call after the delegate has generated policy settings.
  void OnPolicyGenerated() { policy_generated_ = timer_.Elapsed(); }

  // Call after CreateProcess() has returned a suspended process.
  void OnProcessSpawned() { process_spawned_ = timer_.Elapsed(); }

  // Call after unsuspending the process.
  void OnProcessResumed() { process_resumed_ = timer_.Elapsed(); }

  // Returns when this timer was created.
  int64_t GetStartTimeInMicroseconds() const {
    return timer_.start_time().since_origin().InMicroseconds();
  }

  // Call once to record histograms for a successful process launch.
  void RecordHistograms();

 private:
  // `timer_` starts when this object is created.
  base::ElapsedTimer timer_;
  base::TimeDelta policy_created_;
  base::TimeDelta policy_generated_;
  base::TimeDelta process_spawned_;
  base::TimeDelta process_resumed_;
};

class SANDBOX_POLICY_EXPORT SandboxWin {
 public:
  // Create a sandboxed process `process` with the specified `cmd_line`.
  // `handles_to_inherit` specifies a set of handles to inherit.
  // `delegate` specifies the sandbox delegate to use when resolving specific
  // sandbox policy.
  //
  // If SBOX_ALL_OK is returned, then `result_callback` will be called with the
  // process creation result. Otherwise, returns one of sandbox::ResultCode for
  // any other error.
  static ResultCode StartSandboxedProcess(
      const base::CommandLine& cmd_line,
      const base::HandlesToInheritVector& handles_to_inherit,
      SandboxDelegate* delegate,
      StartSandboxedProcessCallback result_callback);

  // Generates a sandbox policy into `policy` to match the one that would be
  // applied during `StartSandboxedProcess` for the identical set of arguments.
  //
  // Returns SBOX_ALL_OK if the policy was successfully generated.
  // Returns SBOX_ERROR_UNSANDBOXED_PROCESS if the process has no valid
  // sandbox policy because it should be run unsandboxed, otherwise returns one
  // of sandbox::ResultCode for any other error while constructing the policy.
  static ResultCode GeneratePolicyForSandboxedProcess(
      const base::CommandLine& cmd_line,
      const base::HandlesToInheritVector& handles_to_inherit,
      SandboxDelegate* delegate,
      TargetPolicy* policy);

  // Wrapper around TargetPolicy::SetJobLevel that checks if the
  // sandbox should be let to run without a job object assigned.
  static ResultCode SetJobLevel(sandbox::mojom::Sandbox sandbox_type,
                                JobLevel job_level,
                                uint32_t ui_exceptions,
                                TargetConfig* config);

  // Closes handles that are opened at process creation and initialization.
  static void AddBaseHandleClosePolicy(TargetConfig* config);

  // Add AppContainer policy for |sid| on supported OS.
  static ResultCode AddAppContainerPolicy(TargetConfig* config,
                                          const wchar_t* sid);

  // Add the win32k lockdown policy on supported OS.
  static ResultCode AddWin32kLockdownPolicy(TargetConfig* config);

  // Add the AppContainer sandbox profile to the config. `sandbox_type`
  // determines what policy is enabled. `appcontainer_id` is used to create
  // a unique package SID, it can be anything the caller wants.
  static ResultCode AddAppContainerProfileToConfig(
      const base::CommandLine& command_line,
      sandbox::mojom::Sandbox sandbox_type,
      const std::string& appcontainer_id,
      TargetConfig* config);

  // Returns whether the AppContainer sandbox is enabled or not for a specific
  // sandbox type from |command_line| and |sandbox_type|.
  static bool IsAppContainerEnabledForSandbox(
      const base::CommandLine& command_line,
      sandbox::mojom::Sandbox sandbox_type);

  static bool InitBrokerServices(BrokerServices* broker_services);
  static bool InitTargetServices(TargetServices* target_services);

  // Report diagnostic information about policies applied to sandboxed
  // processes. This is a snapshot and may describe processes which
  // have subsequently finished. This can be invoked on any sequence and posts
  // to |response| to the origin sequence on completion. |response|
  // will be an empty value if an error is encountered.
  static ResultCode GetPolicyDiagnostics(
      base::OnceCallback<void(base::Value)> response);

  // Provides a friendly name for the sandbox for chrome://sandbox and tracing.
  static std::string GetSandboxTypeInEnglish(
      sandbox::mojom::Sandbox sandbox_type);

  // Helper for sandbox delegates to generate a SandboxTag
  static std::string GetSandboxTagForDelegate(
      std::string_view prefix,
      sandbox::mojom::Sandbox sandbox_type);

 private:
  FRIEND_TEST_ALL_PREFIXES(SandboxWinTest, GetJobMemoryLimit);

  static void FinishStartSandboxedProcess(
      SandboxDelegate* delegate,
      SandboxLaunchTimer timer,
      StartSandboxedProcessCallback result_callback,
      base::win::ScopedProcessInformation target,
      DWORD last_error,
      ResultCode result);

  static std::optional<size_t> GetJobMemoryLimit(
      sandbox::mojom::Sandbox sandbox_type);
};

// Add a block list DLL to a configuration |config| based on the name of the DLL
// passed as |module_name|. The DLL must be loaded in the current process.
SANDBOX_POLICY_EXPORT
void BlocklistAddOneDllForTesting(const wchar_t* module_name,
                                  TargetConfig* config);

}  // namespace policy
}  // namespace sandbox

#endif  // SANDBOX_POLICY_WIN_SANDBOX_WIN_H_