diff options
author | mdempsky@chromium.org <mdempsky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-04-11 00:44:13 +0000 |
---|---|---|
committer | mdempsky@chromium.org <mdempsky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-04-11 00:44:13 +0000 |
commit | 3cb62e837a26f09a64732105171ccbc7a7ca9f50 (patch) | |
tree | 70447b5876a2312eb5424c90c30b2332d0b428bf | |
parent | 07283f73e209e11aacdc2c0c6a6ffe80eb5e0e3a (diff) | |
download | chromium_src-3cb62e837a26f09a64732105171ccbc7a7ca9f50.zip chromium_src-3cb62e837a26f09a64732105171ccbc7a7ca9f50.tar.gz chromium_src-3cb62e837a26f09a64732105171ccbc7a7ca9f50.tar.bz2 |
Add unit test to check for broker FD leak
BUG=360274
Review URL: https://codereview.chromium.org/229893002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@263147 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | sandbox/linux/services/broker_process.h | 2 | ||||
-rw-r--r-- | sandbox/linux/services/broker_process_unittest.cc | 59 | ||||
-rw-r--r-- | sandbox/linux/tests/unit_tests.cc | 11 | ||||
-rw-r--r-- | sandbox/linux/tests/unit_tests.h | 13 | ||||
-rw-r--r-- | sandbox/linux/tests/unit_tests_unittest.cc | 5 |
5 files changed, 90 insertions, 0 deletions
diff --git a/sandbox/linux/services/broker_process.h b/sandbox/linux/services/broker_process.h index b312b8f6..6645deb 100644 --- a/sandbox/linux/services/broker_process.h +++ b/sandbox/linux/services/broker_process.h @@ -97,6 +97,8 @@ class SANDBOX_EXPORT BrokerProcess { const std::vector<std::string> allowed_w_files_; // Files allowed for write. int ipc_socketpair_; // Our communication channel to parent or child. DISALLOW_IMPLICIT_CONSTRUCTORS(BrokerProcess); + + friend class BrokerProcessTestHelper; }; } // namespace sandbox diff --git a/sandbox/linux/services/broker_process_unittest.cc b/sandbox/linux/services/broker_process_unittest.cc index 7f1a685..dfc149e 100644 --- a/sandbox/linux/services/broker_process_unittest.cc +++ b/sandbox/linux/services/broker_process_unittest.cc @@ -11,6 +11,7 @@ #include <sys/wait.h> #include <unistd.h> +#include <algorithm> #include <string> #include <vector> @@ -21,12 +22,20 @@ #include "base/logging.h" #include "base/memory/scoped_ptr.h" #include "base/posix/eintr_wrapper.h" +#include "base/posix/unix_domain_socket_linux.h" #include "sandbox/linux/tests/test_utils.h" #include "sandbox/linux/tests/unit_tests.h" #include "testing/gtest/include/gtest/gtest.h" namespace sandbox { +class BrokerProcessTestHelper { + public: + static int get_ipc_socketpair(const BrokerProcess* broker) { + return broker->ipc_socketpair_; + } +}; + namespace { // Creates and open a temporary file on creation and closes @@ -434,4 +443,54 @@ TEST(BrokerProcess, OpenComplexFlagsNoClientCheck) { // expected. } +// We need to allow noise because the broker will log when it receives our +// bogus IPCs. +SANDBOX_TEST_ALLOW_NOISE(BrokerProcess, RecvMsgDescriptorLeak) { + // Find the four lowest available file descriptors. + int available_fds[4]; + SANDBOX_ASSERT(0 == pipe(available_fds)); + SANDBOX_ASSERT(0 == pipe(available_fds + 2)); + + // Save one FD to send to the broker later, and close the others. + base::ScopedFD message_fd(available_fds[0]); + for (size_t i = 1; i < arraysize(available_fds); i++) { + SANDBOX_ASSERT(0 == IGNORE_EINTR(close(available_fds[i]))); + } + + // Lower our file descriptor limit to just allow three more file descriptors + // to be allocated. (N.B., RLIMIT_NOFILE doesn't limit the number of file + // descriptors a process can have: it only limits the highest value that can + // be assigned to newly-created descriptors allocated by the process.) + const rlim_t fd_limit = + 1 + *std::max_element(available_fds, + available_fds + arraysize(available_fds)); + const struct rlimit new_rlim = {fd_limit, fd_limit}; + SANDBOX_ASSERT(0 == setrlimit(RLIMIT_NOFILE, &new_rlim)); + + static const char kCpuInfo[] = "/proc/cpuinfo"; + std::vector<std::string> read_whitelist; + read_whitelist.push_back(kCpuInfo); + + BrokerProcess open_broker(EPERM, read_whitelist, std::vector<std::string>()); + SANDBOX_ASSERT(open_broker.Init(base::Bind(&NoOpCallback))); + + const int ipc_fd = BrokerProcessTestHelper::get_ipc_socketpair(&open_broker); + SANDBOX_ASSERT(ipc_fd >= 0); + + static const char kBogus[] = "not a pickle"; + std::vector<int> fds; + fds.push_back(message_fd.get()); + + // The broker process should only have a couple spare file descriptors + // available, but for good measure we send it fd_limit bogus IPCs anyway. + for (rlim_t i = 0; i < fd_limit; ++i) { + SANDBOX_ASSERT( + UnixDomainSocket::SendMsg(ipc_fd, kBogus, sizeof(kBogus), fds)); + } + + const int fd = open_broker.Open(kCpuInfo, O_RDONLY); + SANDBOX_ASSERT(fd >= 0); + SANDBOX_ASSERT(0 == IGNORE_EINTR(close(fd))); +} + } // namespace sandbox diff --git a/sandbox/linux/tests/unit_tests.cc b/sandbox/linux/tests/unit_tests.cc index 2e714aa..eeb5616 100644 --- a/sandbox/linux/tests/unit_tests.cc +++ b/sandbox/linux/tests/unit_tests.cc @@ -208,6 +208,17 @@ void UnitTests::DeathSuccess(int status, const std::string& msg, const void*) { EXPECT_FALSE(subprocess_exited_but_printed_messages) << details; } +void UnitTests::DeathSuccessAllowNoise(int status, + const std::string& msg, + const void*) { + std::string details(TestFailedMessage(msg)); + + bool subprocess_terminated_normally = WIFEXITED(status); + ASSERT_TRUE(subprocess_terminated_normally) << details; + int subprocess_exit_status = WEXITSTATUS(status); + ASSERT_EQ(kExpectedValue, subprocess_exit_status) << details; +} + void UnitTests::DeathMessage(int status, const std::string& msg, const void* aux) { diff --git a/sandbox/linux/tests/unit_tests.h b/sandbox/linux/tests/unit_tests.h index 3f6092e..0cb682b 100644 --- a/sandbox/linux/tests/unit_tests.h +++ b/sandbox/linux/tests/unit_tests.h @@ -40,6 +40,8 @@ bool IsRunningOnValgrind(); // gtests's ASSERT_XXX() macros instead of SANDBOX_ASSERT(). See // unit_tests.cc for examples. #define DEATH_SUCCESS() sandbox::UnitTests::DeathSuccess, NULL +#define DEATH_SUCCESS_ALLOW_NOISE() \ + sandbox::UnitTests::DeathSuccessAllowNoise, NULL #define DEATH_MESSAGE(msg) \ sandbox::UnitTests::DeathMessage, \ static_cast<const void*>(static_cast<const char*>(msg)) @@ -68,6 +70,11 @@ bool IsRunningOnValgrind(); #define SANDBOX_TEST(test_case_name, test_name) \ SANDBOX_DEATH_TEST(test_case_name, test_name, DEATH_SUCCESS()) +// SANDBOX_TEST_ALLOW_NOISE is just like SANDBOX_TEST, except it does not +// consider log error messages printed by the test to be test failures. +#define SANDBOX_TEST_ALLOW_NOISE(test_case_name, test_name) \ + SANDBOX_DEATH_TEST(test_case_name, test_name, DEATH_SUCCESS_ALLOW_NOISE()) + // Simple assertion macro that is compatible with running inside of a death // test. We unfortunately cannot use any of the GTest macros. #define SANDBOX_STR(x) #x @@ -109,6 +116,12 @@ class UnitTests { // of this DeathCheck is unused (and thus unnamed) static void DeathSuccess(int status, const std::string& msg, const void*); + // A DeathCheck method that verifies that the test completed succcessfully + // allowing for log error messages. + static void DeathSuccessAllowNoise(int status, + const std::string& msg, + const void*); + // A DeathCheck method that verifies that the test completed with error // code "1" and printed a message containing a particular substring. The // "aux" pointer should point to a C-string containing the expected error diff --git a/sandbox/linux/tests/unit_tests_unittest.cc b/sandbox/linux/tests/unit_tests_unittest.cc index 5ec5648..78a3645 100644 --- a/sandbox/linux/tests/unit_tests_unittest.cc +++ b/sandbox/linux/tests/unit_tests_unittest.cc @@ -8,6 +8,7 @@ #include <sys/wait.h> #include <unistd.h> +#include "base/logging.h" #include "base/posix/eintr_wrapper.h" #include "sandbox/linux/tests/unit_tests.h" @@ -33,6 +34,10 @@ SANDBOX_DEATH_TEST(UnitTests, raise(kExpectedSignalNumber); } +SANDBOX_TEST_ALLOW_NOISE(UnitTests, NoisyTest) { + LOG(ERROR) << "The cow says moo!"; +} + // Test that a subprocess can be forked() and can use exit(3) instead of // _exit(2). TEST(UnitTests, SubProcessCanExit) { |