blob: 6dbac6fd960199a6c6f73d021167dca9c5034d87 [file] [log] [blame]
// Copyright 2012 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CROS_DISKS_SANDBOXED_PROCESS_H_
#define CROS_DISKS_SANDBOXED_PROCESS_H_
#include <sys/types.h>
#include <memory>
#include <optional>
#include <string>
#include <vector>
#include <base/containers/span.h>
#include <base/files/file.h>
#include <base/files/file_path.h>
#include <base/functional/callback.h>
#include "cros-disks/process.h"
#include "cros-disks/sandboxed_init.h"
struct minijail;
namespace cros_disks {
class SandboxedProcess : public Process {
public:
SandboxedProcess();
SandboxedProcess(const SandboxedProcess&) = delete;
SandboxedProcess& operator=(const SandboxedProcess&) = delete;
~SandboxedProcess() override;
bool KillPidNamespace() override;
// Loads the seccomp filters from the given |file|. The calling process will
// be aborted if |file| does not exist, cannot be read or is malformed.
void SetSeccompPolicy(const base::FilePath& file);
// Puts the process to be sandboxed in a new cgroup namespace.
void NewCgroupNamespace();
// Puts the process to be sandboxed in a new IPC namespace.
void NewIpcNamespace();
// Puts the process to be sandboxed in a new mount namespace.
void NewMountNamespace();
// Puts the process to be sandboxed in an existing mount namespace.
// Can be combined with NewMountNamespace() above: the process will first
// enter the existing namespace and then unshare a new child namespace.
void EnterExistingMountNamespace(const std::string& ns_path);
// Puts the process to be sandboxed in a new network namespace.
void NewNetworkNamespace();
// Puts the process to be sandboxed in a new PID namespace.
void NewPidNamespace();
// Assuming the process is sandboxed in a new mount namespace, some essential
// mountpoints like / and /proc are being set up.
bool SetUpMinimalMounts();
// Maps a file or a folder into process' mount namespace.
bool BindMount(const std::string& from,
const std::string& to,
bool writeable,
bool recursive);
// Mounts source to the specified folder in the new mount namespace.
bool Mount(const std::string& src,
const std::string& to,
const std::string& type,
const char* data);
// Makes the process to call pivot_root for an empty /.
bool EnterPivotRoot();
// Sets the no_new_privs bit.
void SetNoNewPrivileges();
// Sets the process capabilities of the process to be sandboxed.
void SetCapabilities(uint64_t capabilities);
// Sets the primary group ID of the process to be sandboxed.
void SetGroupId(gid_t group_id);
// Sets the user ID of the process to be sandboxed.
void SetUserId(uid_t user_id);
// Sets supplementary group IDs of the process to be sandboxed.
void SetSupplementaryGroupIds(base::span<const gid_t> gids);
// Adds the minijail to |cgroup|.
bool AddToCgroup(const std::string& cgroup);
// Preserves the given file descriptor to still be available in the sandboxed
// process.
void PreserveFile(int fd);
// Sets the flag that will simulate progress by delaying the execution of the
// sandboxed program by 10 seconds.
//
// Precondition: NewPidNamespace() was called.
void SimulateProgressForTesting() {
DCHECK(use_pid_namespace_);
simulate_progress_for_testing_ = true;
}
// Should the destruction of this SandboxedProcess trigger the destruction of
// the PID namespace it manages and all the process that are still running in
// it?
void SetKillPidNamespace(const bool kill) { kill_pid_namespace_ = kill; }
protected:
// Process overrides:
pid_t StartImpl(base::ScopedFD in_fd, base::ScopedFD out_fd) override;
int WaitImpl() override;
int WaitNonBlockingImpl() override;
// Minijail object.
minijail* jail_;
// Does this SandboxedProcess use a PID namespace?
bool use_pid_namespace_ = false;
// Whether the destruction of this SandboxedProcess triggers the destruction
// of the PID namespace and all the process that are still running in it.
bool kill_pid_namespace_ = false;
// Should simulate progress and delay the start of the process for testing?
bool simulate_progress_for_testing_ = false;
// Write end of the pipe used to terminate the init process inside the PID
// namespace. This end of the pipe is closed when the SandboxedProcess
// instance is destroyed, generating a SIGIO in the child init process, which
// triggers termination of init and all its nested children. Only used when
// |use_pid_namespace_| is true.
base::ScopedFD termination_fd_;
};
// Interface for creating preconfigured instances of |SandboxedProcess|.
class SandboxedProcessFactory {
public:
SandboxedProcessFactory() = default;
virtual ~SandboxedProcessFactory() = default;
virtual std::unique_ptr<SandboxedProcess> CreateSandboxedProcess() const = 0;
};
// Ties executable with the corresponding seccomp policy configuration.
struct SandboxedExecutable {
base::FilePath executable;
base::FilePath seccomp_policy;
};
// Fake SandboxedProcess for testing. Doesn't launch any actual process.
class FakeSandboxedProcess : public SandboxedProcess {
public:
virtual int OnProcessLaunch(const std::vector<std::string>& argv);
bool GetSimulateProgressForTesting() const {
return simulate_progress_for_testing_;
}
private:
pid_t StartImpl(base::ScopedFD, base::ScopedFD) final;
int WaitImpl() final;
int WaitNonBlockingImpl() final;
std::optional<int> ret_code_;
};
} // namespace cros_disks
#endif // CROS_DISKS_SANDBOXED_PROCESS_H_