// Copyright 2015 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include #include #include "base/process/kill.h" #include "base/strings/string_number_conversions.h" #include "base/test/multiprocess_test.h" #include "base/test/test_timeouts.h" #include "sandbox/mac/sandbox_compiler.h" #include "sandbox/mac/sandbox_test.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/multiprocess_func_list.h" namespace sandbox { namespace { constexpr char kTestParamSwitch[] = "sandbox-compiler-target"; SandboxCompiler::Target GetParamInChild() { std::string target_str = base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( kTestParamSwitch); CHECK(!target_str.empty()); int target_int; CHECK(base::StringToInt(target_str, &target_int)); return static_cast(target_int); } } // namespace class SandboxCompilerTest : public SandboxTest, public testing::WithParamInterface { protected: base::CommandLine MakeCmdLine(const std::string& procname) override { base::CommandLine command_line = base::MultiProcessTest::MakeCmdLine(procname); command_line.AppendSwitchASCII( kTestParamSwitch, base::NumberToString(static_cast(GetParam()))); return command_line; } }; MULTIPROCESS_TEST_MAIN(BasicProfileProcess) { SandboxCompiler compiler(GetParamInChild()); compiler.SetProfile(R"( (version 1) (deny default (with no-log)) (allow file-read* file-write* (literal "/")) )"); std::string error; CHECK(compiler.CompileAndApplyProfile(error)); return 0; } TEST_P(SandboxCompilerTest, BasicProfileTest) { base::Process process = SpawnChild("BasicProfileProcess"); ASSERT_TRUE(process.IsValid()); int exit_code = 42; EXPECT_TRUE(process.WaitForExitWithTimeout(TestTimeouts::action_max_timeout(), &exit_code)); EXPECT_EQ(exit_code, 0); } MULTIPROCESS_TEST_MAIN(BasicProfileWithParamProcess) { SandboxCompiler compiler(GetParamInChild()); compiler.SetProfile(R"( (version 1) (deny default (with no-log)) (allow file-read* file-write* (literal (param "DIR"))) )"); CHECK(compiler.SetParameter("DIR", "/")); std::string error; CHECK(compiler.CompileAndApplyProfile(error)) << error; return 0; } TEST_P(SandboxCompilerTest, BasicProfileTestWithParam) { base::Process process = SpawnChild("BasicProfileWithParamProcess"); ASSERT_TRUE(process.IsValid()); int exit_code = 42; EXPECT_TRUE(process.WaitForExitWithTimeout(TestTimeouts::action_max_timeout(), &exit_code)); EXPECT_EQ(exit_code, 0); } MULTIPROCESS_TEST_MAIN(ProfileFunctionalProcess) { SandboxCompiler compiler(GetParamInChild()); compiler.SetProfile(R"( (version 1) (deny default (with no-log)) (allow file-read-data file-read-metadata (literal "/dev/urandom")) )"); std::string error; CHECK(compiler.CompileAndApplyProfile(error)) << error; // The profile compiled and applied successfully, now try and read 1 byte from // /dev/urandom. uint8_t byte; int fd = open("/dev/urandom", O_RDONLY); CHECK_NE(fd, -1); EXPECT_TRUE(read(fd, &byte, sizeof(byte)) == sizeof(byte)); return 0; } TEST_P(SandboxCompilerTest, ProfileFunctionalityTest) { base::Process process = SpawnChild("ProfileFunctionalProcess"); ASSERT_TRUE(process.IsValid()); int exit_code = 42; EXPECT_TRUE(process.WaitForExitWithTimeout(TestTimeouts::action_max_timeout(), &exit_code)); EXPECT_EQ(exit_code, 0); } MULTIPROCESS_TEST_MAIN(ProfileFunctionalTestWithParamsProcess) { SandboxCompiler compiler(GetParamInChild()); compiler.SetProfile(R"( (version 1) (deny default (with no-log)) (if (string=? (param "ALLOW_FILE") "TRUE") (allow file-read-data file-read-metadata (literal (param "URANDOM"))) ) )"); CHECK(compiler.SetBooleanParameter("ALLOW_FILE", true)); CHECK(!compiler.SetParameter("ALLOW_FILE", "duplicate key is not allowed")); CHECK(compiler.SetParameter("URANDOM", "/dev/urandom")); std::string error; CHECK(compiler.CompileAndApplyProfile(error)) << error; // The profile compiled and applied successfully, now try and read 1 byte from // /dev/urandom. uint8_t byte; int fd = open("/dev/urandom", O_RDONLY); CHECK_NE(fd, -1); EXPECT_TRUE(read(fd, &byte, sizeof(byte)) == sizeof(byte)); // Make sure the sandbox isn't overly permissive. struct stat st; EXPECT_EQ(stat("/", &st), -1); return 0; } TEST_P(SandboxCompilerTest, ProfileFunctionalityTestWithParams) { base::Process process = SpawnChild("ProfileFunctionalTestWithParamsProcess"); ASSERT_TRUE(process.IsValid()); int exit_code = 42; EXPECT_TRUE(process.WaitForExitWithTimeout(TestTimeouts::action_max_timeout(), &exit_code)); EXPECT_EQ(exit_code, 0); } MULTIPROCESS_TEST_MAIN(ProfileFunctionalityTestErrorProcess) { SandboxCompiler compiler(GetParamInChild()); compiler.SetProfile("(+ 5 a)"); // Make sure that this invalid profile results in an error returned. std::string error; CHECK_EQ(error, ""); CHECK(!compiler.CompileAndApplyProfile(error)) << error; CHECK_NE(error, ""); return 0; } TEST_P(SandboxCompilerTest, ProfileFunctionalityTestError) { base::Process process = SpawnChild("ProfileFunctionalityTestErrorProcess"); ASSERT_TRUE(process.IsValid()); int exit_code = 42; EXPECT_TRUE(process.WaitForExitWithTimeout(TestTimeouts::action_max_timeout(), &exit_code)); EXPECT_EQ(exit_code, 0); } TEST_P(SandboxCompilerTest, DuplicateKeys) { SandboxCompiler compiler(GetParam()); compiler.SetProfile("(version 1)(deny default)"); EXPECT_TRUE(compiler.SetBooleanParameter("key1", true)); EXPECT_FALSE(compiler.SetBooleanParameter("key1", false)); EXPECT_TRUE(compiler.SetBooleanParameter("key2", false)); EXPECT_TRUE(compiler.SetParameter("key3", "value")); EXPECT_FALSE(compiler.SetParameter("key3", "value")); mac::SandboxPolicy policy; std::string error; ASSERT_TRUE(compiler.CompilePolicyToProto(policy, error)) << error; if (GetParam() == SandboxCompiler::Target::kSource) { EXPECT_EQ(3, policy.source().params_size()); EXPECT_FALSE(policy.source().profile().empty()); EXPECT_TRUE(policy.compiled().data().empty()); } else { EXPECT_EQ(0, policy.source().params_size()); EXPECT_TRUE(policy.source().profile().empty()); EXPECT_FALSE(policy.compiled().data().empty()); } } INSTANTIATE_TEST_SUITE_P(Target, SandboxCompilerTest, testing::Values(SandboxCompiler::Target::kSource, SandboxCompiler::Target::kCompiled)); } // namespace sandbox