Index: sandbox/linux/syscall_broker/broker_process_unittest.cc |
diff --git a/sandbox/linux/syscall_broker/broker_process_unittest.cc b/sandbox/linux/syscall_broker/broker_process_unittest.cc |
index 997667c36ad8a6b1b0dd78be1086054feb711e4c..ee284f210ab3f316c53459e3aa18699d3e2d8da5 100644 |
--- a/sandbox/linux/syscall_broker/broker_process_unittest.cc |
+++ b/sandbox/linux/syscall_broker/broker_process_unittest.cc |
@@ -54,11 +54,10 @@ bool NoOpCallback() { |
} // namespace |
TEST(BrokerProcess, CreateAndDestroy) { |
- std::vector<std::string> read_whitelist; |
- read_whitelist.push_back("/proc/cpuinfo"); |
+ std::vector<BrokerFilePermission> permissions; |
+ permissions.push_back(BrokerFilePermission::ReadOnly("/proc/cpuinfo")); |
- scoped_ptr<BrokerProcess> open_broker( |
- new BrokerProcess(EPERM, read_whitelist, std::vector<std::string>())); |
+ scoped_ptr<BrokerProcess> open_broker(new BrokerProcess(EPERM, permissions)); |
ASSERT_TRUE(open_broker->Init(base::Bind(&NoOpCallback))); |
ASSERT_TRUE(TestUtils::CurrentProcessHasChildren()); |
@@ -68,8 +67,8 @@ TEST(BrokerProcess, CreateAndDestroy) { |
} |
TEST(BrokerProcess, TestOpenAccessNull) { |
- const std::vector<std::string> empty; |
- BrokerProcess open_broker(EPERM, empty, empty); |
+ std::vector<BrokerFilePermission> empty; |
+ BrokerProcess open_broker(EPERM, empty); |
ASSERT_TRUE(open_broker.Init(base::Bind(&NoOpCallback))); |
int fd = open_broker.Open(NULL, O_RDONLY); |
@@ -88,17 +87,14 @@ void TestOpenFilePerms(bool fast_check_in_client, int denied_errno) { |
const char kRW_WhiteListed[] = "/proc/DOESNOTEXIST3"; |
const char k_NotWhitelisted[] = "/proc/DOESNOTEXIST4"; |
- std::vector<std::string> read_whitelist; |
- read_whitelist.push_back(kR_WhiteListed); |
- read_whitelist.push_back(kR_WhiteListedButDenied); |
- read_whitelist.push_back(kRW_WhiteListed); |
- |
- std::vector<std::string> write_whitelist; |
- write_whitelist.push_back(kW_WhiteListed); |
- write_whitelist.push_back(kRW_WhiteListed); |
+ std::vector<BrokerFilePermission> permissions; |
+ permissions.push_back(BrokerFilePermission::ReadOnly(kR_WhiteListed)); |
+ permissions.push_back( |
+ BrokerFilePermission::ReadOnly(kR_WhiteListedButDenied)); |
+ permissions.push_back(BrokerFilePermission::WriteOnly(kW_WhiteListed)); |
+ permissions.push_back(BrokerFilePermission::ReadWrite(kRW_WhiteListed)); |
- BrokerProcess open_broker( |
- denied_errno, read_whitelist, write_whitelist, fast_check_in_client); |
+ BrokerProcess open_broker(denied_errno, permissions, fast_check_in_client); |
ASSERT_TRUE(open_broker.Init(base::Bind(&NoOpCallback))); |
int fd = -1; |
@@ -243,13 +239,78 @@ TEST(BrokerProcess, OpenOpenFilePermsNoClientCheckNoEnt) { |
// expected. |
} |
-void TestOpenCpuinfo(bool fast_check_in_client) { |
+void TestBadPaths(bool fast_check_in_client) { |
+ const char kFileCpuInfo[] = "/proc/cpuinfo"; |
+ const char kNotAbsPath[] = "proc/cpuinfo"; |
+ const char kDotDotStart[] = "/../proc/cpuinfo"; |
+ const char kDotDotMiddle[] = "/proc/self/../cpuinfo"; |
+ const char kDotDotEnd[] = "/proc/.."; |
+ const char kTrailingSlash[] = "/proc/"; |
+ |
+ std::vector<BrokerFilePermission> permissions; |
+ |
+ permissions.push_back(BrokerFilePermission::ReadOnlyRecursive("/proc/")); |
+ scoped_ptr<BrokerProcess> open_broker( |
+ new BrokerProcess(EPERM, permissions, fast_check_in_client)); |
+ ASSERT_TRUE(open_broker->Init(base::Bind(&NoOpCallback))); |
+ // Open cpuinfo via the broker. |
+ int cpuinfo_fd = open_broker->Open(kFileCpuInfo, O_RDONLY); |
+ base::ScopedFD cpuinfo_fd_closer(cpuinfo_fd); |
+ ASSERT_GE(cpuinfo_fd, 0); |
+ |
+ int fd = -1; |
+ int can_access; |
+ |
+ can_access = open_broker->Access(kNotAbsPath, R_OK); |
+ ASSERT_EQ(can_access, -EPERM); |
+ fd = open_broker->Open(kNotAbsPath, O_RDONLY); |
+ ASSERT_EQ(fd, -EPERM); |
+ |
+ can_access = open_broker->Access(kDotDotStart, R_OK); |
+ ASSERT_EQ(can_access, -EPERM); |
+ fd = open_broker->Open(kDotDotStart, O_RDONLY); |
+ ASSERT_EQ(fd, -EPERM); |
+ |
+ can_access = open_broker->Access(kDotDotMiddle, R_OK); |
+ ASSERT_EQ(can_access, -EPERM); |
+ fd = open_broker->Open(kDotDotMiddle, O_RDONLY); |
+ ASSERT_EQ(fd, -EPERM); |
+ |
+ can_access = open_broker->Access(kDotDotEnd, R_OK); |
+ ASSERT_EQ(can_access, -EPERM); |
+ fd = open_broker->Open(kDotDotEnd, O_RDONLY); |
+ ASSERT_EQ(fd, -EPERM); |
+ |
+ can_access = open_broker->Access(kTrailingSlash, R_OK); |
+ ASSERT_EQ(can_access, -EPERM); |
+ fd = open_broker->Open(kTrailingSlash, O_RDONLY); |
+ ASSERT_EQ(fd, -EPERM); |
+} |
+ |
+TEST(BrokerProcess, BadPathsClientCheck) { |
+ TestBadPaths(true /* fast_check_in_client */); |
+ // Don't do anything here, so that ASSERT works in the subfunction as |
+ // expected. |
+} |
+ |
+TEST(BrokerProcess, BadPathsNoClientCheck) { |
+ TestBadPaths(false /* fast_check_in_client */); |
+ // Don't do anything here, so that ASSERT works in the subfunction as |
+ // expected. |
+} |
+ |
+void TestOpenCpuinfo(bool fast_check_in_client, bool recursive) { |
const char kFileCpuInfo[] = "/proc/cpuinfo"; |
- std::vector<std::string> read_whitelist; |
- read_whitelist.push_back(kFileCpuInfo); |
+ const char kDirProc[] = "/proc/"; |
- scoped_ptr<BrokerProcess> open_broker(new BrokerProcess( |
- EPERM, read_whitelist, std::vector<std::string>(), fast_check_in_client)); |
+ std::vector<BrokerFilePermission> permissions; |
+ if (recursive) |
+ permissions.push_back(BrokerFilePermission::ReadOnlyRecursive(kDirProc)); |
+ else |
+ permissions.push_back(BrokerFilePermission::ReadOnly(kFileCpuInfo)); |
+ |
+ scoped_ptr<BrokerProcess> open_broker( |
+ new BrokerProcess(EPERM, permissions, fast_check_in_client)); |
ASSERT_TRUE(open_broker->Init(base::Bind(&NoOpCallback))); |
int fd = -1; |
@@ -293,16 +354,28 @@ void TestOpenCpuinfo(bool fast_check_in_client) { |
ASSERT_FALSE(TestUtils::CurrentProcessHasChildren()); |
} |
-// Run the same thing twice. The second time, we make sure that no security |
-// check is performed on the client. |
+// Run this test 4 times. With and without the check in client |
+// and using a recursive path. |
TEST(BrokerProcess, OpenCpuinfoWithClientCheck) { |
- TestOpenCpuinfo(true /* fast_check_in_client */); |
+ TestOpenCpuinfo(true /* fast_check_in_client */, false /* not recursive */); |
// Don't do anything here, so that ASSERT works in the subfunction as |
// expected. |
} |
TEST(BrokerProcess, OpenCpuinfoNoClientCheck) { |
- TestOpenCpuinfo(false /* fast_check_in_client */); |
+ TestOpenCpuinfo(false /* fast_check_in_client */, false /* not recursive */); |
+ // Don't do anything here, so that ASSERT works in the subfunction as |
+ // expected. |
+} |
+ |
+TEST(BrokerProcess, OpenCpuinfoWithClientCheckRecursive) { |
+ TestOpenCpuinfo(true /* fast_check_in_client */, true /* recursive */); |
+ // Don't do anything here, so that ASSERT works in the subfunction as |
+ // expected. |
+} |
+ |
+TEST(BrokerProcess, OpenCpuinfoNoClientCheckRecursive) { |
+ TestOpenCpuinfo(false /* fast_check_in_client */, true /* recursive */); |
// Don't do anything here, so that ASSERT works in the subfunction as |
// expected. |
} |
@@ -311,10 +384,10 @@ TEST(BrokerProcess, OpenFileRW) { |
ScopedTemporaryFile tempfile; |
const char* tempfile_name = tempfile.full_file_name(); |
- std::vector<std::string> whitelist; |
- whitelist.push_back(tempfile_name); |
+ std::vector<BrokerFilePermission> permissions; |
+ permissions.push_back(BrokerFilePermission::ReadWrite(tempfile_name)); |
- BrokerProcess open_broker(EPERM, whitelist, whitelist); |
+ BrokerProcess open_broker(EPERM, permissions); |
ASSERT_TRUE(open_broker.Init(base::Bind(&NoOpCallback))); |
// Check we can access that file with read or write. |
@@ -344,13 +417,11 @@ TEST(BrokerProcess, OpenFileRW) { |
// SANDBOX_TEST because the process could die with a SIGPIPE |
// and we want this to happen in a subprocess. |
SANDBOX_TEST(BrokerProcess, BrokerDied) { |
- std::vector<std::string> read_whitelist; |
- read_whitelist.push_back("/proc/cpuinfo"); |
+ const char kCpuInfo[] = "/proc/cpuinfo"; |
+ std::vector<BrokerFilePermission> permissions; |
+ permissions.push_back(BrokerFilePermission::ReadOnly(kCpuInfo)); |
- BrokerProcess open_broker(EPERM, |
- read_whitelist, |
- std::vector<std::string>(), |
- true /* fast_check_in_client */, |
+ BrokerProcess open_broker(EPERM, permissions, true /* fast_check_in_client */, |
true /* quiet_failures_for_tests */); |
SANDBOX_ASSERT(open_broker.Init(base::Bind(&NoOpCallback))); |
const pid_t broker_pid = open_broker.broker_pid(); |
@@ -366,16 +437,16 @@ SANDBOX_TEST(BrokerProcess, BrokerDied) { |
SANDBOX_ASSERT(SIGKILL == process_info.si_status); |
// Check that doing Open with a dead broker won't SIGPIPE us. |
- SANDBOX_ASSERT(open_broker.Open("/proc/cpuinfo", O_RDONLY) == -ENOMEM); |
- SANDBOX_ASSERT(open_broker.Access("/proc/cpuinfo", O_RDONLY) == -ENOMEM); |
+ SANDBOX_ASSERT(open_broker.Open(kCpuInfo, O_RDONLY) == -ENOMEM); |
+ SANDBOX_ASSERT(open_broker.Access(kCpuInfo, O_RDONLY) == -ENOMEM); |
} |
void TestOpenComplexFlags(bool fast_check_in_client) { |
const char kCpuInfo[] = "/proc/cpuinfo"; |
- std::vector<std::string> whitelist; |
- whitelist.push_back(kCpuInfo); |
+ std::vector<BrokerFilePermission> permissions; |
+ permissions.push_back(BrokerFilePermission::ReadOnly(kCpuInfo)); |
- BrokerProcess open_broker(EPERM, whitelist, whitelist, fast_check_in_client); |
+ BrokerProcess open_broker(EPERM, permissions, fast_check_in_client); |
ASSERT_TRUE(open_broker.Init(base::Bind(&NoOpCallback))); |
// Test that we do the right thing for O_CLOEXEC and O_NONBLOCK. |
int fd = -1; |
@@ -454,10 +525,10 @@ SANDBOX_TEST_ALLOW_NOISE(BrokerProcess, RecvMsgDescriptorLeak) { |
SANDBOX_ASSERT(0 == setrlimit(RLIMIT_NOFILE, &rlim)); |
static const char kCpuInfo[] = "/proc/cpuinfo"; |
- std::vector<std::string> read_whitelist; |
- read_whitelist.push_back(kCpuInfo); |
+ std::vector<BrokerFilePermission> permissions; |
+ permissions.push_back(BrokerFilePermission::ReadOnly(kCpuInfo)); |
- BrokerProcess open_broker(EPERM, read_whitelist, std::vector<std::string>()); |
+ BrokerProcess open_broker(EPERM, permissions); |
SANDBOX_ASSERT(open_broker.Init(base::Bind(&NoOpCallback))); |
const int ipc_fd = BrokerProcessTestHelper::GetIPCDescriptor(&open_broker); |
@@ -498,16 +569,15 @@ bool WaitForClosedPipeWriter(int reader, int timeout_in_ms) { |
// Closing the broker client's IPC channel should terminate the broker |
// process. |
TEST(BrokerProcess, BrokerDiesOnClosedChannel) { |
- std::vector<std::string> read_whitelist; |
- read_whitelist.push_back("/proc/cpuinfo"); |
+ std::vector<BrokerFilePermission> permissions; |
+ permissions.push_back(BrokerFilePermission::ReadOnly("/proc/cpuinfo")); |
// Get the writing end of a pipe into the broker (child) process so |
// that we can reliably detect when it dies. |
int lifeline_fds[2]; |
PCHECK(0 == pipe(lifeline_fds)); |
- BrokerProcess open_broker(EPERM, read_whitelist, std::vector<std::string>(), |
- true /* fast_check_in_client */, |
+ BrokerProcess open_broker(EPERM, permissions, true /* fast_check_in_client */, |
false /* quiet_failures_for_tests */); |
ASSERT_TRUE(open_broker.Init(base::Bind(&CloseFD, lifeline_fds[0]))); |
// Make sure the writing end only exists in the broker process. |
@@ -533,6 +603,55 @@ TEST(BrokerProcess, BrokerDiesOnClosedChannel) { |
EXPECT_EQ(1, process_info.si_status); |
} |
+TEST(BrokerProcess, CreateFile) { |
+ std::string temp_str; |
+ { |
+ ScopedTemporaryFile tmp_file; |
+ temp_str = tmp_file.full_file_name(); |
+ } |
+ const char* tempfile_name = temp_str.c_str(); |
+ |
+ std::vector<BrokerFilePermission> permissions; |
+ permissions.push_back(BrokerFilePermission::ReadWriteCreate(tempfile_name)); |
+ |
+ BrokerProcess open_broker(EPERM, permissions); |
+ ASSERT_TRUE(open_broker.Init(base::Bind(&NoOpCallback))); |
+ |
+ int fd = -1; |
+ |
+ // Try without O_EXCL |
+ fd = open_broker.Open(tempfile_name, O_RDWR | O_CREAT); |
+ ASSERT_EQ(fd, -EPERM); |
+ |
+ const char kTestText[] = "TESTTESTTEST"; |
+ // Create a file |
+ fd = open_broker.Open(tempfile_name, O_RDWR | O_CREAT | O_EXCL); |
+ ASSERT_GE(fd, 0); |
+ { |
+ base::ScopedFD scoped_fd(fd); |
+ |
+ // Confirm fail if file exists |
+ int bad_fd = open_broker.Open(tempfile_name, O_RDWR | O_CREAT | O_EXCL); |
+ ASSERT_EQ(bad_fd, -EEXIST); |
+ |
+ // Write to the descriptor opened by the broker. |
+ |
+ ssize_t len = HANDLE_EINTR(write(fd, kTestText, sizeof(kTestText))); |
+ ASSERT_EQ(len, static_cast<ssize_t>(sizeof(kTestText))); |
+ } |
+ |
+ int fd_check = open(tempfile_name, O_RDONLY); |
+ ASSERT_GE(fd_check, 0); |
+ { |
+ base::ScopedFD scoped_fd(fd_check); |
+ char buf[1024]; |
+ ssize_t len = HANDLE_EINTR(read(fd_check, buf, sizeof(buf))); |
+ |
+ ASSERT_EQ(len, static_cast<ssize_t>(sizeof(kTestText))); |
+ ASSERT_EQ(memcmp(kTestText, buf, sizeof(kTestText)), 0); |
+ } |
+} |
+ |
} // namespace syscall_broker |
} // namespace sandbox |