diff options
Diffstat (limited to 'sandbox/linux/tests/unit_tests.cc')
-rw-r--r-- | sandbox/linux/tests/unit_tests.cc | 353 |
1 files changed, 0 insertions, 353 deletions
diff --git a/sandbox/linux/tests/unit_tests.cc b/sandbox/linux/tests/unit_tests.cc deleted file mode 100644 index b78b5f8da4..0000000000 --- a/sandbox/linux/tests/unit_tests.cc +++ /dev/null @@ -1,353 +0,0 @@ -// Copyright (c) 2012 The Chromium 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 <fcntl.h> -#include <poll.h> -#include <signal.h> -#include <stdio.h> -#include <sys/resource.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <sys/time.h> -#include <time.h> -#include <unistd.h> - -#include "base/files/file_util.h" -#include "base/posix/eintr_wrapper.h" -#include "build/build_config.h" -#include "sandbox/linux/tests/unit_tests.h" -#include "third_party/valgrind/valgrind.h" - -// Specifically, PNaCl toolchain does not have this flag. -#if !defined(POLLRDHUP) -#define POLLRDHUP 0x2000 -#endif - -namespace { -std::string TestFailedMessage(const std::string& msg) { - return msg.empty() ? std::string() : "Actual test failure: " + msg; -} - -int GetSubProcessTimeoutTimeInSeconds() { - // Previously 10s, but that timed out (just) on Chromecast. - return 12; -} - -// Returns the number of threads of the current process or -1. -int CountThreads() { - struct stat task_stat; - int task_d = stat("/proc/self/task", &task_stat); - // task_stat.st_nlink should be the number of tasks + 2 (accounting for - // "." and "..". - if (task_d != 0 || task_stat.st_nlink < 3) - return -1; - const int num_threads = task_stat.st_nlink - 2; - return num_threads; -} - -} // namespace - -namespace sandbox { - -bool IsAndroid() { -#if defined(OS_ANDROID) - return true; -#else - return false; -#endif -} - -bool IsArchitectureArm() { -#if defined(ARCH_CPU_ARM_FAMILY) - return true; -#else - return false; -#endif -} - -// TODO(jln): figure out why base/.../dynamic_annotations.h's -// RunningOnValgrind() cannot link. -bool IsRunningOnValgrind() { return RUNNING_ON_VALGRIND; } - -static const int kExpectedValue = 42; -static const int kIgnoreThisTest = 43; -static const int kExitWithAssertionFailure = 1; -#if !defined(OS_NACL_NONSFI) -static const int kExitForTimeout = 2; -#endif - -#if defined(SANDBOX_USES_BASE_TEST_SUITE) -// This is due to StackDumpSignalHandler() performing _exit(1). -// TODO(jln): get rid of the collision with kExitWithAssertionFailure. -const int kExitAfterSIGSEGV = 1; -#endif - -// PNaCl toolchain's signal ABIs are incompatible with Linux's. -// So, for simplicity, just drop the "timeout" feature from unittest framework -// with relying on the buildbot's timeout feature. -#if !defined(OS_NACL_NONSFI) -static void SigAlrmHandler(int) { - const char failure_message[] = "Timeout reached!\n"; - // Make sure that we never block here. - if (!fcntl(2, F_SETFL, O_NONBLOCK)) { - ignore_result(write(2, failure_message, sizeof(failure_message) - 1)); - } - _exit(kExitForTimeout); -} - -// Set a timeout with a handler that will automatically fail the -// test. -static void SetProcessTimeout(int time_in_seconds) { - struct sigaction act = {}; - act.sa_handler = SigAlrmHandler; - SANDBOX_ASSERT(sigemptyset(&act.sa_mask) == 0); - act.sa_flags = 0; - - struct sigaction old_act; - SANDBOX_ASSERT(sigaction(SIGALRM, &act, &old_act) == 0); - - // We don't implemenet signal chaining, so make sure that nothing else - // is expecting to handle SIGALRM. - SANDBOX_ASSERT((old_act.sa_flags & SA_SIGINFO) == 0); - SANDBOX_ASSERT(old_act.sa_handler == SIG_DFL); - sigset_t sigalrm_set; - SANDBOX_ASSERT(sigemptyset(&sigalrm_set) == 0); - SANDBOX_ASSERT(sigaddset(&sigalrm_set, SIGALRM) == 0); - SANDBOX_ASSERT(sigprocmask(SIG_UNBLOCK, &sigalrm_set, NULL) == 0); - SANDBOX_ASSERT(alarm(time_in_seconds) == 0); // There should be no previous - // alarm. -} -#endif // !defined(OS_NACL_NONSFI) - -// Runs a test in a sub-process. This is necessary for most of the code -// in the BPF sandbox, as it potentially makes global state changes and as -// it also tends to raise fatal errors, if the code has been used in an -// insecure manner. -void UnitTests::RunTestInProcess(SandboxTestRunner* test_runner, - DeathCheck death, - const void* death_aux) { - CHECK(test_runner); - // We need to fork(), so we can't be multi-threaded, as threads could hold - // locks. - int num_threads = CountThreads(); -#if !defined(THREAD_SANITIZER) - const int kNumExpectedThreads = 1; -#else - // Under TSAN, there is a special helper thread. It should be completely - // invisible to our testing, so we ignore it. It should be ok to fork() - // with this thread. It's currently buggy, but it's the best we can do until - // there is a way to delay the start of the thread - // (https://code.google.com/p/thread-sanitizer/issues/detail?id=19). - const int kNumExpectedThreads = 2; -#endif - - // The kernel is at liberty to wake a thread id futex before updating /proc. - // If another test running in the same process has stopped a thread, it may - // appear as still running in /proc. - // We poll /proc, with an exponential back-off. At most, we'll sleep around - // 2^iterations nanoseconds in nanosleep(). - for (unsigned int iteration = 0; iteration < 30; iteration++) { - struct timespec ts = {0, 1L << iteration /* nanoseconds */}; - PCHECK(0 == HANDLE_EINTR(nanosleep(&ts, &ts))); - num_threads = CountThreads(); - if (kNumExpectedThreads == num_threads) - break; - } - - ASSERT_EQ(kNumExpectedThreads, num_threads) - << "Running sandbox tests with multiple threads " - << "is not supported and will make the tests flaky."; - int fds[2]; - ASSERT_EQ(0, pipe(fds)); - // Check that our pipe is not on one of the standard file descriptor. - SANDBOX_ASSERT(fds[0] > 2 && fds[1] > 2); - - pid_t pid; - ASSERT_LE(0, (pid = fork())); - if (!pid) { - // In child process - // Redirect stderr to our pipe. This way, we can capture all error - // messages, if we decide we want to do so in our tests. - SANDBOX_ASSERT(dup2(fds[1], 2) == 2); - SANDBOX_ASSERT(!close(fds[0])); - SANDBOX_ASSERT(!close(fds[1])); - - // Don't set a timeout if running on Valgrind, since it's generally much - // slower. - if (!IsRunningOnValgrind()) { -#if !defined(OS_NACL_NONSFI) - SetProcessTimeout(GetSubProcessTimeoutTimeInSeconds()); -#endif - } - - // Disable core files. They are not very useful for our individual test - // cases. - struct rlimit no_core = {0}; - setrlimit(RLIMIT_CORE, &no_core); - - test_runner->Run(); - if (test_runner->ShouldCheckForLeaks()) { -#if defined(LEAK_SANITIZER) - __lsan_do_leak_check(); -#endif - } - _exit(kExpectedValue); - } - - close(fds[1]); - std::vector<char> msg_buf; - ssize_t rc; - - // Make sure read() will never block as we'll use poll() to - // block with a timeout instead. - const int fcntl_ret = fcntl(fds[0], F_SETFL, O_NONBLOCK); - ASSERT_EQ(0, fcntl_ret); - struct pollfd poll_fd = {fds[0], POLLIN | POLLRDHUP, 0}; - - int poll_ret; - // We prefer the SIGALRM timeout to trigger in the child than this timeout - // so we double the common value here. - int poll_timeout = GetSubProcessTimeoutTimeInSeconds() * 2 * 1000; - while ((poll_ret = poll(&poll_fd, 1, poll_timeout) > 0)) { - const size_t kCapacity = 256; - const size_t len = msg_buf.size(); - msg_buf.resize(len + kCapacity); - rc = HANDLE_EINTR(read(fds[0], &msg_buf[len], kCapacity)); - msg_buf.resize(len + std::max(rc, static_cast<ssize_t>(0))); - if (rc <= 0) - break; - } - ASSERT_NE(poll_ret, -1) << "poll() failed"; - ASSERT_NE(poll_ret, 0) << "Timeout while reading child state"; - close(fds[0]); - std::string msg(msg_buf.begin(), msg_buf.end()); - - int status = 0; - int waitpid_returned = HANDLE_EINTR(waitpid(pid, &status, 0)); - ASSERT_EQ(pid, waitpid_returned) << TestFailedMessage(msg); - - // At run-time, we sometimes decide that a test shouldn't actually - // run (e.g. when testing sandbox features on a kernel that doesn't - // have sandboxing support). When that happens, don't attempt to - // call the "death" function, as it might be looking for a - // death-test condition that would never have triggered. - if (!WIFEXITED(status) || WEXITSTATUS(status) != kIgnoreThisTest || - !msg.empty()) { - // We use gtest's ASSERT_XXX() macros instead of the DeathCheck - // functions. This means, on failure, "return" is called. This - // only works correctly, if the call of the "death" callback is - // the very last thing in our function. - death(status, msg, death_aux); - } -} - -void UnitTests::DeathSuccess(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; - bool subprocess_exited_but_printed_messages = !msg.empty(); - 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) { - std::string details(TestFailedMessage(msg)); - const char* expected_msg = static_cast<const char*>(aux); - - bool subprocess_terminated_normally = WIFEXITED(status); - ASSERT_TRUE(subprocess_terminated_normally) << "Exit status: " << status - << " " << details; - int subprocess_exit_status = WEXITSTATUS(status); - ASSERT_EQ(1, subprocess_exit_status) << details; - - bool subprocess_exited_without_matching_message = - msg.find(expected_msg) == std::string::npos; - -// In official builds CHECK messages are dropped, so look for SIGABRT. -// See https://code.google.com/p/chromium/issues/detail?id=437312 -#if defined(OFFICIAL_BUILD) && defined(NDEBUG) && !defined(OS_ANDROID) - if (subprocess_exited_without_matching_message) { - static const char kSigAbortMessage[] = "Received signal 6"; - subprocess_exited_without_matching_message = - msg.find(kSigAbortMessage) == std::string::npos; - } -#endif - EXPECT_FALSE(subprocess_exited_without_matching_message) << details; -} - -void UnitTests::DeathSEGVMessage(int status, - const std::string& msg, - const void* aux) { - std::string details(TestFailedMessage(msg)); - const char* expected_msg = static_cast<const char*>(aux); - -#if !defined(SANDBOX_USES_BASE_TEST_SUITE) - const bool subprocess_got_sigsegv = - WIFSIGNALED(status) && (SIGSEGV == WTERMSIG(status)); -#else - // This hack is required when a signal handler is installed - // for SEGV that will _exit(1). - const bool subprocess_got_sigsegv = - WIFEXITED(status) && (kExitAfterSIGSEGV == WEXITSTATUS(status)); -#endif - - ASSERT_TRUE(subprocess_got_sigsegv) << "Exit status: " << status - << " " << details; - - bool subprocess_exited_without_matching_message = - msg.find(expected_msg) == std::string::npos; - EXPECT_FALSE(subprocess_exited_without_matching_message) << details; -} - -void UnitTests::DeathExitCode(int status, - const std::string& msg, - const void* aux) { - int expected_exit_code = static_cast<int>(reinterpret_cast<intptr_t>(aux)); - 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(expected_exit_code, subprocess_exit_status) << details; -} - -void UnitTests::DeathBySignal(int status, - const std::string& msg, - const void* aux) { - int expected_signo = static_cast<int>(reinterpret_cast<intptr_t>(aux)); - std::string details(TestFailedMessage(msg)); - - bool subprocess_terminated_by_signal = WIFSIGNALED(status); - ASSERT_TRUE(subprocess_terminated_by_signal) << details; - int subprocess_signal_number = WTERMSIG(status); - ASSERT_EQ(expected_signo, subprocess_signal_number) << details; -} - -void UnitTests::AssertionFailure(const char* expr, const char* file, int line) { - fprintf(stderr, "%s:%d:%s", file, line, expr); - fflush(stderr); - _exit(kExitWithAssertionFailure); -} - -void UnitTests::IgnoreThisTest() { - fflush(stderr); - _exit(kIgnoreThisTest); -} - -} // namespace |