blob: 7a145bcddaf3988830bdb4f0f654cd74028a2a76 [file] [log] [blame] [edit]
// Copyright 2019 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef PATCHPANEL_MINIJAILED_PROCESS_RUNNER_H_
#define PATCHPANEL_MINIJAILED_PROCESS_RUNNER_H_
#include <linux/filter.h>
#include <sys/types.h>
#include <map>
#include <memory>
#include <string>
#include <string_view>
#include <vector>
#include <base/containers/span.h>
#include <base/time/time.h>
#include <brillo/minijail/minijail.h>
#include "patchpanel/iptables.h"
#include "patchpanel/system.h"
namespace patchpanel {
// Runs the current process with minimal privileges. This function is expected
// to be used by child processes that need only CAP_NET_RAW and to run as the
// patchpaneld user.
void EnterChildProcessJail();
// Runs the current process with minimal privileges. This function is expected
// to be used by child processes that need only CAP_NET_ADMIN and to run as the
// patchpaneld user.
void EnterChildProcessJailWithNetAdmin();
// Enforces the expected processes are run with the correct privileges.
class MinijailedProcessRunner {
public:
// Run iptables in batch with iptables-restore. See the comments for
// AcquireIptablesBatchMode() below.
class ScopedIptablesBatchMode {
public:
~ScopedIptablesBatchMode();
private:
friend class MinijailedProcessRunner; // to access ctor
explicit ScopedIptablesBatchMode(MinijailedProcessRunner* runner);
MinijailedProcessRunner* runner_;
};
static MinijailedProcessRunner* GetInstance();
MinijailedProcessRunner(const MinijailedProcessRunner&) = delete;
MinijailedProcessRunner& operator=(const MinijailedProcessRunner&) = delete;
virtual ~MinijailedProcessRunner() = default;
// Runs ip. If |as_patchpanel_user|, runs as user 'patchpaneld' and under the
// group 'patchpaneld', as well as inherits supplemntary groups (i.e. group
// 'tun') of user 'patchpaneld'. If not, runs as 'nobody'.
virtual int ip(std::string_view obj,
std::string_view cmd,
base::span<const std::string> argv,
bool as_patchpanel_user = false,
bool log_failures = true);
virtual int ip(std::string_view obj,
std::string_view cmd,
base::span<std::string_view> argv,
bool as_patchpanel_user = false,
bool log_failures = true);
virtual int ip(std::string_view obj,
std::string_view cmd,
std::initializer_list<std::string_view> argv,
bool as_patchpanel_user = false,
bool log_failures = true);
virtual int ip6(std::string_view obj,
std::string_view cmd,
base::span<const std::string> argv,
bool as_patchpanel_user = false,
bool log_failures = true);
virtual int ip6(std::string_view obj,
std::string_view cmd,
base::span<std::string_view> argv,
bool as_patchpanel_user = false,
bool log_failures = true);
virtual int ip6(std::string_view obj,
std::string_view cmd,
std::initializer_list<std::string_view> argv,
bool as_patchpanel_user = false,
bool log_failures = true);
// Acquires a "lock" to instruct this class to execute the following
// iptables() and ip6tables() calls in batch. In detail:
// - After this function is called, the semantics of the iptables() and
// ip6tables() call will be changed: the iptables (or ip6tables) won't be
// issued immediately after called, and the rule will be cached instead.
// |log_failures| in the function param won't have effect in this mode, and
// the returning success only indicates that the input argument passes the
// basic check instead of the rule is executed successfully (return 0 on
// success or -1 otherwise).
// - When either 1) the returned object of this function is destructed or 2)
// CommitIptablesRules() is called, all the cached iptables commands will be
// executed using iptables-restore. Their difference is that the caller can
// get the execution result with CommitIptablesRules().
// - Due to the nature of iptables-restore, the cached rules can be partially
// submitted on failure (if the cached rules are for multiple tables). Thus
// all the rules in batch must be expected to succeed.
virtual std::unique_ptr<ScopedIptablesBatchMode> AcquireIptablesBatchMode();
// Executes the pending rules started from |batch_mode| is acquired. This
// function has same effect with dropping |batch_mode| directly, except that
// this function will return whether the execution succeeded or not.
bool CommitIptablesRules(std::unique_ptr<ScopedIptablesBatchMode> batch_mode);
// Runs iptables. If |output| is not nullptr, it will be filled with the
// result from stdout of iptables command.
virtual int iptables(Iptables::Table table,
Iptables::Command command,
std::string_view chain,
base::span<const std::string> argv,
bool log_failures = true,
std::string* output = nullptr);
virtual int iptables(Iptables::Table table,
Iptables::Command command,
std::string_view chain,
base::span<std::string_view> argv,
bool log_failures = true,
std::string* output = nullptr);
virtual int iptables(Iptables::Table table,
Iptables::Command command,
std::string_view chain,
std::initializer_list<std::string_view> argv,
bool log_failures = true,
std::string* output = nullptr);
virtual int ip6tables(Iptables::Table table,
Iptables::Command command,
std::string_view chain,
base::span<const std::string> argv,
bool log_failures = true,
std::string* output = nullptr);
virtual int ip6tables(Iptables::Table table,
Iptables::Command command,
std::string_view chain,
base::span<std::string_view> argv,
bool log_failures = true,
std::string* output = nullptr);
virtual int ip6tables(Iptables::Table table,
Iptables::Command command,
std::string_view chain,
std::initializer_list<std::string_view> argv,
bool log_failures = true,
std::string* output = nullptr);
// Installs all |modules| via modprobe.
virtual int modprobe_all(base::span<const std::string> modules,
bool log_failures = true);
// Creates a new named network namespace with name |netns_name|.
virtual int ip_netns_add(std::string_view netns_name,
bool log_failures = true);
// Attaches a name to the network namespace of the given pid
// TODO(hugobenichi) How can patchpanel create a |netns_name| file in
// /run/netns without running ip as root ?
virtual int ip_netns_attach(std::string_view netns_name,
pid_t netns_pid,
bool log_failures = true);
virtual int ip_netns_delete(std::string_view netns_name,
bool log_failures = true);
// Run conntrack command with given command option and |argv|.
virtual int conntrack(std::string_view command,
base::span<const std::string> argv,
bool log_failures = true);
virtual int iptables_restore(std::string_view script_file,
bool log_failures = true);
virtual int ip6tables_restore(std::string_view script_file,
bool log_failures = true);
protected:
// Constructor for the singleton.
MinijailedProcessRunner();
// Constructor used in the unit tests.
MinijailedProcessRunner(brillo::Minijail* mj, std::unique_ptr<System> system);
// Used by ip() and ip6().
// Runs a process (argv[0]) with optional arguments (argv[1]...)
// in a minijail as user |patchpaneld| and user the group |patchpaneld| with
// CAP_NET_ADMIN and CAP_NET_RAW capabilities. Inherits supplementary groups
// of |patchpaneld|.
virtual int RunIp(base::span<std::string_view> argv,
bool as_patchpanel_user,
bool log_failures = true);
virtual int RunIptables(std::string_view iptables_path,
Iptables::Table table,
Iptables::Command command,
std::string_view chain,
base::span<std::string_view> argv,
bool log_failures,
std::string* output);
virtual int RunIptablesRestore(std::string_view iptables_restore_path,
std::string_view script_file,
bool log_failures);
virtual int RunIpNetns(base::span<std::string_view> argv, bool log_failures);
virtual bool RunPendingIptablesInBatch();
// Converts string_view elements in |argv| to cstrings and returns a vector
// of these cstrings. |buffer| is a view for underneath buffer used for
// storing data of string_view. User is responsible to allocate and manage
// the life cycle of underlying buffer.
static std::vector<char*> StringViewToCstrings(
base::span<std::string_view> argv, base::span<char> buffer);
private:
friend base::LazyInstanceTraitsBase<MinijailedProcessRunner>;
int RunSyncDestroy(base::span<std::string_view> argv,
brillo::Minijail* mj,
minijail* jail,
bool log_failures,
std::string* output);
using TableToRules = std::map<Iptables::Table, std::vector<std::string>>;
bool AppendPendingIptablesRule(Iptables::Table table,
Iptables::Command command,
std::string_view chain,
base::span<std::string_view> argv,
TableToRules* cached_rules);
bool RunPendingIptablesInBatchImpl(std::string_view iptables_restore_path,
const TableToRules& table_to_rules);
// Configures |jail| to apply the seccomp filter on iptables.
virtual void UseIptablesSeccompFilter(minijail* jail);
brillo::Minijail* mj_;
std::unique_ptr<System> system_;
bool iptables_batch_mode_ = false;
TableToRules pending_iptables_rules_;
TableToRules pending_ip6tables_rules_;
// Only set and used in UseIptablesSeccompFilter(). See the implementation
// there for details.
std::vector<struct sock_filter> iptables_seccomp_filter_data_;
struct sock_fprog iptables_seccomp_filter_;
};
} // namespace patchpanel
#endif // PATCHPANEL_MINIJAILED_PROCESS_RUNNER_H_