1 /* -*- C++ -*- */ 2 #ifndef CAPSICUM_TEST_H 3 #define CAPSICUM_TEST_H 4 5 #include <errno.h> 6 #include <sys/types.h> 7 #include <sys/wait.h> 8 #include <sys/resource.h> 9 #include <signal.h> 10 11 #include <ios> 12 #include <ostream> 13 #include <string> 14 15 #include "gtest/gtest.h" 16 17 extern bool verbose; 18 extern std::string tmpdir; 19 extern bool tmpdir_on_tmpfs; 20 extern bool force_mt; 21 extern bool force_nofork; 22 extern uid_t other_uid; 23 24 static inline void *WaitingThreadFn(void *) { 25 // Loop until cancelled 26 while (true) { 27 usleep(10000); 28 pthread_testcancel(); 29 } 30 return NULL; 31 } 32 33 // If force_mt is set, run another thread in parallel with the test. This forces 34 // the kernel into multi-threaded mode. 35 template <typename T, typename Function> 36 void MaybeRunWithThread(T *self, Function fn) { 37 pthread_t subthread; 38 if (force_mt) { 39 pthread_create(&subthread, NULL, WaitingThreadFn, NULL); 40 } 41 (self->*fn)(); 42 if (force_mt) { 43 pthread_cancel(subthread); 44 pthread_join(subthread, NULL); 45 } 46 } 47 template <typename Function> 48 void MaybeRunWithThread(Function fn) { 49 pthread_t subthread; 50 if (force_mt) { 51 pthread_create(&subthread, NULL, WaitingThreadFn, NULL); 52 } 53 (fn)(); 54 if (force_mt) { 55 pthread_cancel(subthread); 56 pthread_join(subthread, NULL); 57 } 58 } 59 60 // Return the absolute path of a filename in the temp directory, `tmpdir`, 61 // with the given pathname, e.g., "/tmp/<pathname>", if `tmpdir` was set to 62 // "/tmp". 63 const char *TmpFile(const char *pathname); 64 65 // Run the given test function in a forked process, so that trapdoor 66 // entry doesn't affect other tests, and watch out for hung processes. 67 // Implemented as a macro to allow access to the test case instance's 68 // HasFailure() method, which is reported as the forked process's 69 // exit status. 70 #define _RUN_FORKED(INNERCODE, TESTCASENAME, TESTNAME) \ 71 pid_t pid = force_nofork ? 0 : fork(); \ 72 if (pid == 0) { \ 73 INNERCODE; \ 74 if (!force_nofork) { \ 75 exit(HasFailure()); \ 76 } \ 77 } else if (pid > 0) { \ 78 int rc, status; \ 79 int remaining_us = 30000000; \ 80 while (remaining_us > 0) { \ 81 status = 0; \ 82 rc = waitpid(pid, &status, WNOHANG); \ 83 if (rc != 0) break; \ 84 remaining_us -= 10000; \ 85 usleep(10000); \ 86 } \ 87 if (remaining_us <= 0) { \ 88 fprintf(stderr, "Warning: killing unresponsive test " \ 89 "%s.%s (pid %d)\n", \ 90 TESTCASENAME, TESTNAME, pid); \ 91 kill(pid, SIGKILL); \ 92 ADD_FAILURE() << "Test hung"; \ 93 } else if (rc < 0) { \ 94 fprintf(stderr, "Warning: waitpid error %s (%d)\n", \ 95 strerror(errno), errno); \ 96 ADD_FAILURE() << "Failed to wait for child"; \ 97 } else { \ 98 int rc = WIFEXITED(status) ? WEXITSTATUS(status) : -1; \ 99 EXPECT_EQ(0, rc); \ 100 } \ 101 } 102 #define _RUN_FORKED_MEM(THIS, TESTFN, TESTCASENAME, TESTNAME) \ 103 _RUN_FORKED(MaybeRunWithThread(THIS, &TESTFN), TESTCASENAME, TESTNAME); 104 #define _RUN_FORKED_FN(TESTFN, TESTCASENAME, TESTNAME) \ 105 _RUN_FORKED(MaybeRunWithThread(&TESTFN), TESTCASENAME, TESTNAME); 106 107 // Run a test case in a forked process, possibly cleaning up a 108 // test file after completion 109 #define FORK_TEST_ON(test_case_name, test_name, test_file) \ 110 static void test_case_name##_##test_name##_ForkTest(); \ 111 TEST(test_case_name, test_name ## Forked) { \ 112 _RUN_FORKED_FN(test_case_name##_##test_name##_ForkTest, \ 113 #test_case_name, #test_name); \ 114 const char *filename = test_file; \ 115 if (filename) unlink(filename); \ 116 } \ 117 static void test_case_name##_##test_name##_ForkTest() 118 119 #define FORK_TEST(test_case_name, test_name) FORK_TEST_ON(test_case_name, test_name, NULL) 120 121 // Run a test case fixture in a forked process, so that trapdoors don't 122 // affect other tests. 123 #define ICLASS_NAME(test_case_name, test_name) Forked##test_case_name##_##test_name 124 #define FORK_TEST_F(test_case_name, test_name) \ 125 class ICLASS_NAME(test_case_name, test_name) : public test_case_name { \ 126 public: \ 127 ICLASS_NAME(test_case_name, test_name)() {} \ 128 void InnerTestBody(); \ 129 }; \ 130 TEST_F(ICLASS_NAME(test_case_name, test_name), _) { \ 131 _RUN_FORKED_MEM(this, \ 132 ICLASS_NAME(test_case_name, test_name)::InnerTestBody, \ 133 #test_case_name, #test_name); \ 134 } \ 135 void ICLASS_NAME(test_case_name, test_name)::InnerTestBody() 136 137 // Emit errno information on failure 138 #define EXPECT_OK(v) EXPECT_LE(0, v) << " errno " << errno << " " << strerror(errno) 139 140 // Expect a syscall to fail with the given error. 141 #define EXPECT_SYSCALL_FAIL(E, C) \ 142 do { \ 143 SCOPED_TRACE(#C); \ 144 EXPECT_GT(0, C); \ 145 EXPECT_EQ(E, errno) << "expected '" << strerror(E) \ 146 << "' but got '" << strerror(errno) << "'"; \ 147 } while (0) 148 149 // Expect a syscall to fail with anything other than the given error. 150 #define EXPECT_SYSCALL_FAIL_NOT(E, C) \ 151 do { \ 152 EXPECT_GT(0, C); \ 153 EXPECT_NE(E, errno) << strerror(E); \ 154 } while (0) 155 156 // Expect a void syscall to fail with anything other than the given error. 157 #define EXPECT_VOID_SYSCALL_FAIL_NOT(E, C) \ 158 do { \ 159 errno = 0; \ 160 C; \ 161 EXPECT_NE(E, errno) << #C << " failed with ECAPMODE"; \ 162 } while (0) 163 164 // Expect a system call to fail due to path traversal; exact error 165 // code is OS-specific. 166 #ifdef O_BENEATH 167 #define EXPECT_OPENAT_FAIL_TRAVERSAL(fd, path, flags) \ 168 do { \ 169 SCOPED_TRACE(GTEST_STRINGIFY_(openat((fd), (path), (flags)))); \ 170 const int result = openat((fd), (path), (flags)); \ 171 if (((flags) & O_BENEATH) == O_BENEATH) { \ 172 EXPECT_SYSCALL_FAIL(E_NO_TRAVERSE_O_BENEATH, result); \ 173 } else { \ 174 EXPECT_SYSCALL_FAIL(E_NO_TRAVERSE_CAPABILITY, result); \ 175 } \ 176 if (result >= 0) { close(result); } \ 177 } while (0) 178 #else 179 #define EXPECT_OPENAT_FAIL_TRAVERSAL(fd, path, flags) \ 180 do { \ 181 SCOPED_TRACE(GTEST_STRINGIFY_(openat((fd), (path), (flags)))); \ 182 const int result = openat((fd), (path), (flags)); \ 183 EXPECT_SYSCALL_FAIL(E_NO_TRAVERSE_CAPABILITY, result); \ 184 if (result >= 0) { close(result); } \ 185 } while (0) 186 #endif 187 188 // Expect a system call to fail with ECAPMODE. 189 #define EXPECT_CAPMODE(C) EXPECT_SYSCALL_FAIL(ECAPMODE, C) 190 191 // Expect a system call to fail, but not with ECAPMODE. 192 #define EXPECT_FAIL_NOT_CAPMODE(C) EXPECT_SYSCALL_FAIL_NOT(ECAPMODE, C) 193 #define EXPECT_FAIL_VOID_NOT_CAPMODE(C) EXPECT_VOID_SYSCALL_FAIL_NOT(ECAPMODE, C) 194 195 // Expect a system call to fail with ENOTCAPABLE. 196 #define EXPECT_NOTCAPABLE(C) EXPECT_SYSCALL_FAIL(ENOTCAPABLE, C) 197 198 // Expect a system call to fail, but not with ENOTCAPABLE. 199 #define EXPECT_FAIL_NOT_NOTCAPABLE(C) EXPECT_SYSCALL_FAIL_NOT(ENOTCAPABLE, C) 200 201 // Expect a system call to fail with either ENOTCAPABLE or ECAPMODE. 202 #define EXPECT_CAPFAIL(C) \ 203 do { \ 204 int rc = C; \ 205 EXPECT_GT(0, rc); \ 206 EXPECT_TRUE(errno == ECAPMODE || errno == ENOTCAPABLE) \ 207 << #C << " did not fail with ECAPMODE/ENOTCAPABLE but " << errno \ 208 << "(" << strerror(errno) << ")"; \ 209 } while (0) 210 211 // Ensure that 'rights' are a subset of 'max'. 212 #define EXPECT_RIGHTS_IN(rights, max) \ 213 EXPECT_TRUE(cap_rights_contains((max), (rights))) \ 214 << "rights " << std::hex << *(rights) \ 215 << " not a subset of " << std::hex << *(max) 216 217 // Ensure rights are identical 218 #define EXPECT_RIGHTS_EQ(a, b) \ 219 do { \ 220 EXPECT_RIGHTS_IN((a), (b)); \ 221 EXPECT_RIGHTS_IN((b), (a)); \ 222 } while (0) 223 224 // Get the state of a process as a single character. 225 // - 'D': disk wait 226 // - 'R': runnable 227 // - 'S': sleeping/idle 228 // - 'T': stopped 229 // - 'Z': zombie 230 // On error, return either '?' or '\0'. 231 char ProcessState(int pid); 232 233 // Check process state reaches a particular expected state (or two). 234 // Retries a few times to allow for timing issues. 235 #define EXPECT_PID_REACHES_STATES(pid, expected1, expected2) { \ 236 int counter = 5; \ 237 char state; \ 238 do { \ 239 state = ProcessState(pid); \ 240 if (state == expected1 || state == expected2) break; \ 241 usleep(100000); \ 242 } while (--counter > 0); \ 243 EXPECT_TRUE(state == expected1 || state == expected2) \ 244 << " pid " << pid << " in state " << state; \ 245 } 246 247 #define EXPECT_PID_ALIVE(pid) EXPECT_PID_REACHES_STATES(pid, 'R', 'S') 248 #define EXPECT_PID_DEAD(pid) EXPECT_PID_REACHES_STATES(pid, 'Z', '\0') 249 #define EXPECT_PID_ZOMBIE(pid) EXPECT_PID_REACHES_STATES(pid, 'Z', 'Z'); 250 #define EXPECT_PID_GONE(pid) EXPECT_PID_REACHES_STATES(pid, '\0', '\0'); 251 252 enum { 253 // Magic numbers for messages sent by child processes. 254 MSG_CHILD_STARTED = 1234, 255 MSG_CHILD_FD_RECEIVED = 4321, 256 // Magic numbers for messages sent by parent processes. 257 MSG_PARENT_REQUEST_CHILD_EXIT = 9999, 258 MSG_PARENT_CLOSED_FD = 10000, 259 MSG_PARENT_CHILD_SHOULD_RUN = 10001, 260 }; 261 262 #define SEND_INT_MESSAGE(fd, message) \ 263 do { \ 264 int _msg = message; \ 265 EXPECT_EQ(sizeof(_msg), (size_t)write(fd, &_msg, sizeof(_msg))); \ 266 } while (0) 267 268 #define AWAIT_INT_MESSAGE(fd, expected) \ 269 do { \ 270 int _msg = 0; \ 271 EXPECT_EQ(sizeof(_msg), (size_t)read(fd, &_msg, sizeof(_msg))); \ 272 EXPECT_EQ(expected, _msg); \ 273 } while (0) 274 275 // Mark a test that can only be run as root. 276 #define GTEST_SKIP_IF_NOT_ROOT() \ 277 if (getuid() != 0) { GTEST_SKIP() << "requires root"; } 278 279 extern std::string capsicum_test_bindir; 280 281 #endif // CAPSICUM_TEST_H 282