Modernize namespace_test a little

PiperOrigin-RevId: 402795383
Change-Id: Ia576259078f40a3ca6b96094bd15c3ea7b0b79d9
This commit is contained in:
Christian Blichmann 2021-10-13 04:17:18 -07:00 committed by Copybara-Service
parent 1260b5f38b
commit d85f40b8b0

View File

@ -19,6 +19,8 @@
#include <syscall.h> #include <syscall.h>
#include <unistd.h> #include <unistd.h>
#include <initializer_list>
#include <memory>
#include <utility> #include <utility>
#include <glog/logging.h> #include <glog/logging.h>
@ -46,25 +48,36 @@ namespace file_util = ::sapi::file_util;
using ::sapi::CreateNamedTempFile; using ::sapi::CreateNamedTempFile;
using ::sapi::GetTestSourcePath; using ::sapi::GetTestSourcePath;
using ::sapi::GetTestTempPath; using ::sapi::GetTestTempPath;
using ::testing::Eq;
using ::testing::Ne;
int RunSandboxeeWithArgsAndPolicy(const std::string& sandboxee,
std::initializer_list<std::string> args,
std::unique_ptr<Policy> policy) {
Sandbox2 sandbox(absl::make_unique<Executor>(sandboxee, args),
std::move(policy));
Result result = sandbox.Run();
EXPECT_THAT(result.final_status(), Eq(Result::OK));
return result.reason_code();
}
constexpr absl::string_view kNamespaceTestBinary =
"sandbox2/testcases/namespace";
constexpr absl::string_view kHostnameTestBinary = "sandbox2/testcases/hostname";
TEST(NamespaceTest, FileNamespaceWorks) { TEST(NamespaceTest, FileNamespaceWorks) {
// Mount /binary_path RO and check that it exists and is readable. // Mount /binary_path RO and check that it exists and is readable.
// /etc/passwd should not exist. // /etc/passwd should not exist.
const std::string path = GetTestSourcePath("sandbox2/testcases/namespace");
std::vector<std::string> args = {path, "0", "/binary_path", "/etc/passwd"};
auto executor = absl::make_unique<Executor>(path, args);
SAPI_ASSERT_OK_AND_ASSIGN(auto policy,
PolicyBuilder()
// Don't restrict the syscalls at all
.DangerDefaultAllowAll()
.AddFileAt(path, "/binary_path")
.TryBuild());
Sandbox2 sandbox(std::move(executor), std::move(policy)); const std::string path = GetTestSourcePath(kNamespaceTestBinary);
auto result = sandbox.Run(); int reason_code = RunSandboxeeWithArgsAndPolicy(
path, {path, "0", "/binary_path", "/etc/passwd"},
ASSERT_EQ(result.final_status(), Result::OK); PolicyBuilder()
EXPECT_EQ(result.reason_code(), 2); .DangerDefaultAllowAll() // Do not restrict syscalls
.AddFileAt(path, "/binary_path")
.BuildOrDie());
EXPECT_THAT(reason_code, Eq(2));
} }
TEST(NamespaceTest, ReadOnlyIsRespected) { TEST(NamespaceTest, ReadOnlyIsRespected) {
@ -72,205 +85,134 @@ TEST(NamespaceTest, ReadOnlyIsRespected) {
auto [name, fd] = CreateNamedTempFile(GetTestTempPath("temp_file")).value(); auto [name, fd] = CreateNamedTempFile(GetTestTempPath("temp_file")).value();
file_util::fileops::FDCloser temp_closer(fd); file_util::fileops::FDCloser temp_closer(fd);
const std::string path = GetTestSourcePath("sandbox2/testcases/namespace"); const std::string path = GetTestSourcePath(kNamespaceTestBinary);
{ {
// First check that it is readable // Check that it is readable
std::vector<std::string> args = {path, "0", "/temp_file"}; int reason_code = RunSandboxeeWithArgsAndPolicy(
auto executor = absl::make_unique<Executor>(path, args); path, {path, "0", "/temp_file"},
SAPI_ASSERT_OK_AND_ASSIGN(auto policy, PolicyBuilder()
PolicyBuilder() .DangerDefaultAllowAll() // Do not restrict syscalls
// Don't restrict the syscalls at all .AddFileAt(name, "/temp_file")
.DangerDefaultAllowAll() .BuildOrDie());
.AddFileAt(name, "/temp_file") EXPECT_THAT(reason_code, Eq(0));
.TryBuild());
Sandbox2 sandbox(std::move(executor), std::move(policy));
auto result = sandbox.Run();
ASSERT_EQ(result.final_status(), Result::OK);
EXPECT_EQ(result.reason_code(), 0);
} }
{ {
// Then check that it is not writeable // Now check that it is not writeable
std::vector<std::string> args = {path, "1", "/temp_file"}; int reason_code = RunSandboxeeWithArgsAndPolicy(
auto executor = absl::make_unique<Executor>(path, args); path, {path, "1", "/temp_file"},
SAPI_ASSERT_OK_AND_ASSIGN(auto policy, PolicyBuilder()
PolicyBuilder() .DangerDefaultAllowAll() // Do not restrict syscalls
// Don't restrict the syscalls at all .AddFileAt(name, "/temp_file")
.DangerDefaultAllowAll() .BuildOrDie());
.AddFileAt(name, "/temp_file") EXPECT_THAT(reason_code, Eq(1));
.TryBuild());
Sandbox2 sandbox(std::move(executor), std::move(policy));
auto result = sandbox.Run();
ASSERT_EQ(result.final_status(), Result::OK);
EXPECT_EQ(result.reason_code(), 1);
} }
} }
TEST(NamespaceTest, UserNamespaceWorks) { TEST(NamespaceTest, UserNamespaceWorks) {
const std::string path = GetTestSourcePath(kNamespaceTestBinary);
// Check that getpid() returns 2 (which is the case inside pid NS). // Check that getpid() returns 2 (which is the case inside pid NS).
const std::string path = GetTestSourcePath("sandbox2/testcases/namespace");
std::vector<std::string> args = {path, "2"};
{ {
auto executor = absl::make_unique<Executor>(path, args); int reason_code = RunSandboxeeWithArgsAndPolicy(
SAPI_ASSERT_OK_AND_ASSIGN(auto policy, path, {path, "2"},
PolicyBuilder() PolicyBuilder()
// Don't restrict the syscalls at all .DangerDefaultAllowAll() // Do not restrict syscalls
.DangerDefaultAllowAll() .BuildOrDie());
.TryBuild()); EXPECT_THAT(reason_code, Eq(0));
Sandbox2 sandbox(std::move(executor), std::move(policy));
auto result = sandbox.Run();
ASSERT_EQ(result.final_status(), Result::OK);
EXPECT_EQ(result.reason_code(), 0);
} }
// Validate that getpid() does not return 2 when outside of an pid NS. // Validate that getpid() does not return 2 when outside of a pid NS.
{ {
auto executor = absl::make_unique<Executor>(path, args); int reason_code = RunSandboxeeWithArgsAndPolicy(
SAPI_ASSERT_OK_AND_ASSIGN(auto policy, path, {path, "2"},
PolicyBuilder() PolicyBuilder()
.DisableNamespaces() .DisableNamespaces()
// Don't restrict the syscalls at all .DangerDefaultAllowAll() // Do not restrict syscalls
.DangerDefaultAllowAll() .BuildOrDie());
.TryBuild()); EXPECT_THAT(reason_code, Ne(0));
Sandbox2 sandbox(std::move(executor), std::move(policy));
auto result = sandbox.Run();
ASSERT_EQ(result.final_status(), Result::OK);
EXPECT_NE(result.reason_code(), 0);
} }
} }
TEST(NamespaceTest, UserNamespaceIDMapWritten) { TEST(NamespaceTest, UserNamespaceIDMapWritten) {
// Check that the idmap is initialized before the sandbox application is // Check that the idmap is initialized before the sandbox application is
// started. // started.
const std::string path = GetTestSourcePath("sandbox2/testcases/namespace"); const std::string path = GetTestSourcePath(kNamespaceTestBinary);
{ {
std::vector<std::string> args = {path, "3", "1000", "1000"}; int reason_code = RunSandboxeeWithArgsAndPolicy(
auto executor = absl::make_unique<Executor>(path, args); path, {path, "3", "1000", "1000"},
SAPI_ASSERT_OK_AND_ASSIGN(auto policy, PolicyBuilder()
PolicyBuilder() .DangerDefaultAllowAll() // Do not restrict syscalls
// Don't restrict the syscalls at all .BuildOrDie());
.DangerDefaultAllowAll() EXPECT_THAT(reason_code, Eq(0));
.TryBuild());
Sandbox2 sandbox(std::move(executor), std::move(policy));
auto result = sandbox.Run();
ASSERT_EQ(result.final_status(), Result::OK);
EXPECT_EQ(result.reason_code(), 0);
} }
// Check that the uid/gid is the same when not using namespaces. // Check that the uid/gid is the same when not using namespaces.
{ {
const std::string uid = absl::StrCat(getuid()); int reason_code = RunSandboxeeWithArgsAndPolicy(
const std::string gid = absl::StrCat(getgid()); path, {path, "3", absl::StrCat(getuid()), absl::StrCat(getgid())},
std::vector<std::string> args = {path, "3", uid, gid}; PolicyBuilder()
auto executor = absl::make_unique<Executor>(path, args); .DisableNamespaces()
SAPI_ASSERT_OK_AND_ASSIGN(auto policy, .DangerDefaultAllowAll() // Do not restrict syscalls
PolicyBuilder() .BuildOrDie());
.DisableNamespaces() EXPECT_THAT(reason_code, Eq(0));
// Don't restrict the syscalls at all
.DangerDefaultAllowAll()
.TryBuild());
Sandbox2 sandbox(std::move(executor), std::move(policy));
auto result = sandbox.Run();
ASSERT_EQ(result.final_status(), Result::OK);
EXPECT_EQ(result.reason_code(), 0);
} }
} }
TEST(NamespaceTest, RootReadOnly) { TEST(NamespaceTest, RootReadOnly) {
// Mount rw tmpfs at /tmp and check it is rw. // Mount rw tmpfs at /tmp and check it is RW.
// Check also that / is ro. // Check also that / is RO.
const std::string path = GetTestSourcePath("sandbox2/testcases/namespace"); const std::string path = GetTestSourcePath(kNamespaceTestBinary);
std::vector<std::string> args = {path, "4", "/tmp/testfile", "/testfile"}; int reason_code = RunSandboxeeWithArgsAndPolicy(
auto executor = absl::make_unique<Executor>(path, args); path, {path, "4", "/tmp/testfile", "/testfile"},
SAPI_ASSERT_OK_AND_ASSIGN(auto policy, PolicyBuilder()
PolicyBuilder() .DangerDefaultAllowAll() // Do not restrict syscalls
// Don't restrict the syscalls at all .AddTmpfs("/tmp", /*size=*/4ULL << 20 /* 4 MiB */)
.DangerDefaultAllowAll() .BuildOrDie());
.AddTmpfs("/tmp") EXPECT_THAT(reason_code, Eq(2));
.TryBuild());
Sandbox2 sandbox(std::move(executor), std::move(policy));
auto result = sandbox.Run();
ASSERT_EQ(result.final_status(), Result::OK);
EXPECT_EQ(result.reason_code(), 2);
} }
TEST(NamespaceTest, RootWritable) { TEST(NamespaceTest, RootWritable) {
// Mount root rw and check it // Mount root rw and check it
const std::string path = GetTestSourcePath("sandbox2/testcases/namespace"); const std::string path = GetTestSourcePath(kNamespaceTestBinary);
std::vector<std::string> args = {path, "4", "/testfile"}; int reason_code = RunSandboxeeWithArgsAndPolicy(
auto executor = absl::make_unique<Executor>(path, args); path, {path, "4", "/testfile"},
SAPI_ASSERT_OK_AND_ASSIGN(auto policy, PolicyBuilder()
PolicyBuilder() .DangerDefaultAllowAll() // Do not restrict syscalls
// Don't restrict the syscalls at all .SetRootWritable()
.DangerDefaultAllowAll() .BuildOrDie());
.SetRootWritable() EXPECT_THAT(reason_code, Eq(0));
.TryBuild());
Sandbox2 sandbox(std::move(executor), std::move(policy));
auto result = sandbox.Run();
ASSERT_EQ(result.final_status(), Result::OK);
EXPECT_EQ(result.reason_code(), 0);
} }
class HostnameTest : public testing::Test { TEST(HostnameTest, None) {
protected: const std::string path = GetTestSourcePath(kHostnameTestBinary);
void Try(std::string arg, std::unique_ptr<Policy> policy) { int reason_code = RunSandboxeeWithArgsAndPolicy(
const std::string path = GetTestSourcePath("sandbox2/testcases/hostname"); path, {path, "sandbox2"},
std::vector<std::string> args = {path, std::move(arg)}; PolicyBuilder()
auto executor = absl::make_unique<Executor>(path, args); .DisableNamespaces()
Sandbox2 sandbox(std::move(executor), std::move(policy)); .DangerDefaultAllowAll() // Do not restrict syscalls
auto result = sandbox.Run(); .BuildOrDie());
ASSERT_EQ(result.final_status(), Result::OK); EXPECT_THAT(reason_code, Eq(1));
code_ = result.reason_code();
}
int code_;
};
TEST_F(HostnameTest, None) {
SAPI_ASSERT_OK_AND_ASSIGN(auto policy,
PolicyBuilder()
.DisableNamespaces()
// Don't restrict the syscalls at all
.DangerDefaultAllowAll()
.TryBuild());
Try("sandbox2", std::move(policy));
EXPECT_EQ(code_, 1);
} }
TEST_F(HostnameTest, Default) { TEST(HostnameTest, Default) {
SAPI_ASSERT_OK_AND_ASSIGN(auto policy, const std::string path = GetTestSourcePath(kHostnameTestBinary);
PolicyBuilder() int reason_code = RunSandboxeeWithArgsAndPolicy(
// Don't restrict the syscalls at all path, {path, "sandbox2"},
.DangerDefaultAllowAll() PolicyBuilder()
.TryBuild()); .DangerDefaultAllowAll() // Do not restrict syscalls
Try("sandbox2", std::move(policy)); .BuildOrDie());
EXPECT_EQ(code_, 0); EXPECT_THAT(reason_code, Eq(0));
} }
TEST_F(HostnameTest, Configured) { TEST(HostnameTest, Configured) {
SAPI_ASSERT_OK_AND_ASSIGN(auto policy, const std::string path = GetTestSourcePath(kHostnameTestBinary);
PolicyBuilder() int reason_code = RunSandboxeeWithArgsAndPolicy(
// Don't restrict the syscalls at all path, {path, "configured"},
.DangerDefaultAllowAll() PolicyBuilder()
.SetHostname("configured") .DangerDefaultAllowAll() // Do not restrict syscalls
.TryBuild()); .SetHostname("configured")
Try("configured", std::move(policy)); .BuildOrDie());
EXPECT_EQ(code_, 0); EXPECT_THAT(reason_code, Eq(0));
} }
} // namespace } // namespace