unit_tests.cc revision eb525c5499e34cc9c4b825d6d9e75bb07cc06ace
1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include <fcntl.h> 6#include <poll.h> 7#include <signal.h> 8#include <stdio.h> 9#include <sys/resource.h> 10#include <sys/time.h> 11#include <unistd.h> 12 13#include "base/file_util.h" 14#include "base/third_party/valgrind/valgrind.h" 15#include "build/build_config.h" 16#include "sandbox/linux/tests/unit_tests.h" 17 18namespace { 19std::string TestFailedMessage(const std::string& msg) { 20 return msg.empty() ? std::string() : "Actual test failure: " + msg; 21} 22 23int GetSubProcessTimeoutTimeInSeconds() { 24 // 10s ought to be enough for anybody. 25 return 10; 26} 27 28// Returns the number of threads of the current process or -1. 29int CountThreads() { 30 struct stat task_stat; 31 int task_d = stat("/proc/self/task", &task_stat); 32 // task_stat.st_nlink should be the number of tasks + 2 (accounting for 33 // "." and "..". 34 if (task_d != 0 || task_stat.st_nlink < 3) 35 return -1; 36 const int num_threads = task_stat.st_nlink - 2; 37 return num_threads; 38} 39 40} // namespace 41 42namespace sandbox { 43 44static const int kExpectedValue = 42; 45static const int kIgnoreThisTest = 43; 46static const int kExitWithAssertionFailure = 1; 47static const int kExitForTimeout = 2; 48 49static void SigAlrmHandler(int) { 50 const char failure_message[] = "Timeout reached!\n"; 51 // Make sure that we never block here. 52 if (!fcntl(2, F_SETFL, O_NONBLOCK)) { 53 if (write(2, failure_message, sizeof(failure_message) - 1) < 0) { 54 } 55 } 56 _exit(kExitForTimeout); 57} 58 59// Set a timeout with a handler that will automatically fail the 60// test. 61static void SetProcessTimeout(int time_in_seconds) { 62 struct sigaction act = {}; 63 act.sa_handler = SigAlrmHandler; 64 SANDBOX_ASSERT(sigemptyset(&act.sa_mask) == 0); 65 act.sa_flags = 0; 66 67 struct sigaction old_act; 68 SANDBOX_ASSERT(sigaction(SIGALRM, &act, &old_act) == 0); 69 70 // We don't implemenet signal chaining, so make sure that nothing else 71 // is expecting to handle SIGALRM. 72 SANDBOX_ASSERT((old_act.sa_flags & SA_SIGINFO) == 0); 73 SANDBOX_ASSERT(old_act.sa_handler == SIG_DFL); 74 sigset_t sigalrm_set; 75 SANDBOX_ASSERT(sigemptyset(&sigalrm_set) == 0); 76 SANDBOX_ASSERT(sigaddset(&sigalrm_set, SIGALRM) == 0); 77 SANDBOX_ASSERT(sigprocmask(SIG_UNBLOCK, &sigalrm_set, NULL) == 0); 78 SANDBOX_ASSERT(alarm(time_in_seconds) == 0); // There should be no previous 79 // alarm. 80} 81 82// Runs a test in a sub-process. This is necessary for most of the code 83// in the BPF sandbox, as it potentially makes global state changes and as 84// it also tends to raise fatal errors, if the code has been used in an 85// insecure manner. 86void UnitTests::RunTestInProcess(UnitTests::Test test, void *arg, 87 DeathCheck death, const void *death_aux) { 88 // We need to fork(), so we can't be multi-threaded, as threads could hold 89 // locks. 90 int num_threads = CountThreads(); 91#if defined(THREAD_SANITIZER) 92 // Under TSAN, there is a special helper thread. It should be completely 93 // invisible to our testing, so we ignore it. It should be ok to fork() 94 // with this thread. It's currently buggy, but it's the best we can do until 95 // there is a way to delay the start of the thread 96 // (https://code.google.com/p/thread-sanitizer/issues/detail?id=19). 97 num_threads--; 98#endif 99 ASSERT_EQ(1, num_threads) << "Running sandbox tests with multiple threads " 100 << "is not supported and will make the tests " 101 << "flaky.\n"; 102 int fds[2]; 103 ASSERT_EQ(0, pipe(fds)); 104 // Check that our pipe is not on one of the standard file descriptor. 105 SANDBOX_ASSERT(fds[0] > 2 && fds[1] > 2); 106 107 pid_t pid; 108 ASSERT_LE(0, (pid = fork())); 109 if (!pid) { 110 // In child process 111 // Redirect stderr to our pipe. This way, we can capture all error 112 // messages, if we decide we want to do so in our tests. 113 SANDBOX_ASSERT(dup2(fds[1], 2) == 2); 114 SANDBOX_ASSERT(!close(fds[0])); 115 SANDBOX_ASSERT(!close(fds[1])); 116 117 // Don't set a timeout if running on Valgrind, since it's generally much 118 // slower. 119 if (!RUNNING_ON_VALGRIND) { 120 SetProcessTimeout(GetSubProcessTimeoutTimeInSeconds()); 121 } 122 123 // Disable core files. They are not very useful for our individual test 124 // cases. 125 struct rlimit no_core = { 0 }; 126 setrlimit(RLIMIT_CORE, &no_core); 127 128 test(arg); 129 _exit(kExpectedValue); 130 } 131 132 (void)HANDLE_EINTR(close(fds[1])); 133 std::vector<char> msg_buf; 134 ssize_t rc; 135 136 // Make sure read() will never block as we'll use poll() to 137 // block with a timeout instead. 138 const int fcntl_ret = fcntl(fds[0], F_SETFL, O_NONBLOCK); 139 ASSERT_EQ(fcntl_ret, 0); 140 struct pollfd poll_fd = { fds[0], POLLIN | POLLRDHUP, 0 }; 141 142 int poll_ret; 143 // We prefer the SIGALRM timeout to trigger in the child than this timeout 144 // so we double the common value here. 145 int poll_timeout = GetSubProcessTimeoutTimeInSeconds() * 2 * 1000; 146 while ((poll_ret = poll(&poll_fd, 1, poll_timeout) > 0)) { 147 const size_t kCapacity = 256; 148 const size_t len = msg_buf.size(); 149 msg_buf.resize(len + kCapacity); 150 rc = HANDLE_EINTR(read(fds[0], &msg_buf[len], kCapacity)); 151 msg_buf.resize(len + std::max(rc, static_cast<ssize_t>(0))); 152 if (rc <= 0) 153 break; 154 } 155 ASSERT_NE(poll_ret, -1) << "poll() failed"; 156 ASSERT_NE(poll_ret, 0) << "Timeout while reading child state"; 157 (void)HANDLE_EINTR(close(fds[0])); 158 std::string msg(msg_buf.begin(), msg_buf.end()); 159 160 int status = 0; 161 int waitpid_returned = HANDLE_EINTR(waitpid(pid, &status, 0)); 162 ASSERT_EQ(pid, waitpid_returned) << TestFailedMessage(msg); 163 164 // At run-time, we sometimes decide that a test shouldn't actually 165 // run (e.g. when testing sandbox features on a kernel that doesn't 166 // have sandboxing support). When that happens, don't attempt to 167 // call the "death" function, as it might be looking for a 168 // death-test condition that would never have triggered. 169 if (!WIFEXITED(status) || WEXITSTATUS(status) != kIgnoreThisTest || 170 !msg.empty()) { 171 // We use gtest's ASSERT_XXX() macros instead of the DeathCheck 172 // functions. This means, on failure, "return" is called. This 173 // only works correctly, if the call of the "death" callback is 174 // the very last thing in our function. 175 death(status, msg, death_aux); 176 } 177} 178 179void UnitTests::DeathSuccess(int status, const std::string& msg, 180 const void *) { 181 std::string details(TestFailedMessage(msg)); 182 183 bool subprocess_terminated_normally = WIFEXITED(status); 184 ASSERT_TRUE(subprocess_terminated_normally) << details; 185 int subprocess_exit_status = WEXITSTATUS(status); 186 ASSERT_EQ(kExpectedValue, subprocess_exit_status) << details; 187 bool subprocess_exited_but_printed_messages = !msg.empty(); 188 EXPECT_FALSE(subprocess_exited_but_printed_messages) << details; 189} 190 191void UnitTests::DeathMessage(int status, const std::string& msg, 192 const void *aux) { 193 std::string details(TestFailedMessage(msg)); 194 const char *expected_msg = static_cast<const char *>(aux); 195 196 bool subprocess_terminated_normally = WIFEXITED(status); 197 ASSERT_TRUE(subprocess_terminated_normally) << details; 198 int subprocess_exit_status = WEXITSTATUS(status); 199 ASSERT_EQ(kExitWithAssertionFailure, subprocess_exit_status) << details; 200 bool subprocess_exited_without_matching_message = 201 msg.find(expected_msg) == std::string::npos; 202 EXPECT_FALSE(subprocess_exited_without_matching_message) << details; 203} 204 205void UnitTests::DeathExitCode(int status, const std::string& msg, 206 const void *aux) { 207 int expected_exit_code = static_cast<int>(reinterpret_cast<intptr_t>(aux)); 208 std::string details(TestFailedMessage(msg)); 209 210 bool subprocess_terminated_normally = WIFEXITED(status); 211 ASSERT_TRUE(subprocess_terminated_normally) << details; 212 int subprocess_exit_status = WEXITSTATUS(status); 213 ASSERT_EQ(subprocess_exit_status, expected_exit_code) << details; 214} 215 216void UnitTests::DeathBySignal(int status, const std::string& msg, 217 const void *aux) { 218 int expected_signo = static_cast<int>(reinterpret_cast<intptr_t>(aux)); 219 std::string details(TestFailedMessage(msg)); 220 221 bool subprocess_terminated_by_signal = WIFSIGNALED(status); 222 ASSERT_TRUE(subprocess_terminated_by_signal) << details; 223 int subprocess_signal_number = WTERMSIG(status); 224 ASSERT_EQ(subprocess_signal_number, expected_signo) << details; 225} 226 227void UnitTests::AssertionFailure(const char *expr, const char *file, 228 int line) { 229 fprintf(stderr, "%s:%d:%s", file, line, expr); 230 fflush(stderr); 231 _exit(kExitWithAssertionFailure); 232} 233 234void UnitTests::IgnoreThisTest() { 235 fflush(stderr); 236 _exit(kIgnoreThisTest); 237} 238 239} // namespace 240