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