blob: 112d54baed6ea07a8ad1848340767d4c2838ddd8 [file] [log] [blame]
// Copyright 2019 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "patchpanel/minijailed_process_runner.h"
#include <linux/capability.h>
#include <memory>
#include <brillo/minijail/mock_minijail.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "patchpanel/net_util.h"
using testing::_;
using testing::DoAll;
using testing::Eq;
using testing::Return;
using testing::SetArgPointee;
using testing::StrEq;
namespace patchpanel {
namespace {
constexpr pid_t kFakePid = 123;
class FakeSyscallImpl : public MinijailedProcessRunner::SyscallImpl {
public:
pid_t WaitPID(pid_t pid, int* wstatus, int options) override { return pid; }
};
class MinijailProcessRunnerTest : public testing::Test {
protected:
MinijailProcessRunnerTest()
: runner_(&mj_, std::make_unique<FakeSyscallImpl>()) {}
void SetUp() override {
ON_CALL(mj_, DropRoot(_, _, _)).WillByDefault(Return(true));
ON_CALL(mj_, RunPipesAndDestroy(_, _, _, _, _, _))
.WillByDefault(DoAll(SetArgPointee<2>(kFakePid), Return(true)));
}
brillo::MockMinijail mj_;
MinijailedProcessRunner runner_;
};
// Special matcher needed for vector<char*> type.
// Lifted from shill/process_manager_test.cc
MATCHER_P2(IsProcessArgs, program, args, "") {
if (std::string(arg[0]) != program) {
return false;
}
int index = 1;
for (const auto& option : args) {
if (std::string(arg[index++]) != option) {
return false;
}
}
return arg[index] == nullptr;
}
TEST_F(MinijailProcessRunnerTest, modprobe_all) {
uint64_t caps = CAP_TO_MASK(CAP_SYS_MODULE);
const std::vector<std::string> args = {"-a", "module1", "module2"};
EXPECT_CALL(mj_, New());
EXPECT_CALL(mj_, DropRoot(_, StrEq("nobody"), StrEq("nobody")));
EXPECT_CALL(mj_, UseCapabilities(_, Eq(caps)));
EXPECT_CALL(mj_, RunPipesAndDestroy(_, IsProcessArgs("/sbin/modprobe", args),
_, _, _, _));
runner_.modprobe_all({"module1", "module2"});
}
TEST_F(MinijailProcessRunnerTest, sysctl_w) {
const std::vector<std::string> args = {"-w", "a.b.c=1"};
EXPECT_CALL(mj_, New());
EXPECT_CALL(mj_, RunPipesAndDestroy(
_, IsProcessArgs("/usr/sbin/sysctl", args), _, _, _, _));
runner_.sysctl_w("a.b.c", "1");
}
TEST_F(MinijailProcessRunnerTest, chown) {
uint64_t caps = CAP_TO_MASK(CAP_CHOWN);
const std::vector<std::string> args = {"12345:23456", "foo"};
EXPECT_CALL(mj_, New());
EXPECT_CALL(mj_, DropRoot(_, StrEq("nobody"), StrEq("nobody")));
EXPECT_CALL(mj_, UseCapabilities(_, Eq(caps)));
EXPECT_CALL(mj_, RunPipesAndDestroy(_, IsProcessArgs("/bin/chown", args), _,
_, _, _));
runner_.chown("12345", "23456", "foo");
}
TEST_F(MinijailProcessRunnerTest, brctl) {
uint64_t caps = CAP_TO_MASK(CAP_NET_ADMIN) | CAP_TO_MASK(CAP_NET_RAW);
const std::vector<std::string> args = {"cmd", "arg", "arg"};
EXPECT_CALL(mj_, New());
EXPECT_CALL(mj_, DropRoot(_, StrEq("nobody"), StrEq("nobody")));
EXPECT_CALL(mj_, UseCapabilities(_, Eq(caps)));
EXPECT_CALL(mj_, RunPipesAndDestroy(_, IsProcessArgs("/sbin/brctl", args), _,
_, _, _));
runner_.brctl("cmd", {"arg", "arg"});
}
TEST_F(MinijailProcessRunnerTest, ip) {
uint64_t caps = CAP_TO_MASK(CAP_NET_ADMIN) | CAP_TO_MASK(CAP_NET_RAW);
const std::vector<std::string> args = {"obj", "cmd", "arg", "arg"};
EXPECT_CALL(mj_, New());
EXPECT_CALL(mj_, DropRoot(_, StrEq("nobody"), StrEq("nobody")));
EXPECT_CALL(mj_, UseCapabilities(_, Eq(caps)));
EXPECT_CALL(
mj_, RunPipesAndDestroy(_, IsProcessArgs("/bin/ip", args), _, _, _, _));
runner_.ip("obj", "cmd", {"arg", "arg"});
}
TEST_F(MinijailProcessRunnerTest, ip6) {
uint64_t caps = CAP_TO_MASK(CAP_NET_ADMIN) | CAP_TO_MASK(CAP_NET_RAW);
const std::vector<std::string> args = {"-6", "obj", "cmd", "arg", "arg"};
EXPECT_CALL(mj_, New());
EXPECT_CALL(mj_, DropRoot(_, StrEq("nobody"), StrEq("nobody")));
EXPECT_CALL(mj_, UseCapabilities(_, Eq(caps)));
EXPECT_CALL(
mj_, RunPipesAndDestroy(_, IsProcessArgs("/bin/ip", args), _, _, _, _));
runner_.ip6("obj", "cmd", {"arg", "arg"});
}
TEST_F(MinijailProcessRunnerTest, iptables) {
const std::vector<std::string> args = {"-t", "table", "arg", "arg"};
EXPECT_CALL(mj_, New());
EXPECT_CALL(mj_, RunPipesAndDestroy(_, IsProcessArgs("/sbin/iptables", args),
_, _, _, _));
runner_.iptables("table", {"arg", "arg"});
}
TEST_F(MinijailProcessRunnerTest, ip6tables) {
const std::vector<std::string> args = {"-t", "table", "arg", "arg"};
EXPECT_CALL(mj_, New());
EXPECT_CALL(mj_, RunPipesAndDestroy(_, IsProcessArgs("/sbin/ip6tables", args),
_, _, _, _));
runner_.ip6tables("table", {"arg", "arg"});
}
} // namespace
} // namespace patchpanel