18ac5aef8SEnji Cooper /* -*- C++ -*- */ 28ac5aef8SEnji Cooper #ifndef CAPSICUM_TEST_H 38ac5aef8SEnji Cooper #define CAPSICUM_TEST_H 48ac5aef8SEnji Cooper 58ac5aef8SEnji Cooper #include <errno.h> 68ac5aef8SEnji Cooper #include <sys/types.h> 78ac5aef8SEnji Cooper #include <sys/wait.h> 88ac5aef8SEnji Cooper #include <sys/resource.h> 98ac5aef8SEnji Cooper #include <signal.h> 108ac5aef8SEnji Cooper 118ac5aef8SEnji Cooper #include <ios> 128ac5aef8SEnji Cooper #include <ostream> 13*2d936e6cSAlex Richardson #include <string> 148ac5aef8SEnji Cooper 158ac5aef8SEnji Cooper #include "gtest/gtest.h" 168ac5aef8SEnji Cooper 178ac5aef8SEnji Cooper extern bool verbose; 188ac5aef8SEnji Cooper extern std::string tmpdir; 198ac5aef8SEnji Cooper extern bool tmpdir_on_tmpfs; 208ac5aef8SEnji Cooper extern bool force_mt; 218ac5aef8SEnji Cooper extern bool force_nofork; 228ac5aef8SEnji Cooper extern uid_t other_uid; 238ac5aef8SEnji Cooper 248ac5aef8SEnji Cooper static inline void *WaitingThreadFn(void *) { 258ac5aef8SEnji Cooper // Loop until cancelled 268ac5aef8SEnji Cooper while (true) { 278ac5aef8SEnji Cooper usleep(10000); 288ac5aef8SEnji Cooper pthread_testcancel(); 298ac5aef8SEnji Cooper } 308ac5aef8SEnji Cooper return NULL; 318ac5aef8SEnji Cooper } 328ac5aef8SEnji Cooper 338ac5aef8SEnji Cooper // If force_mt is set, run another thread in parallel with the test. This forces 348ac5aef8SEnji Cooper // the kernel into multi-threaded mode. 358ac5aef8SEnji Cooper template <typename T, typename Function> 368ac5aef8SEnji Cooper void MaybeRunWithThread(T *self, Function fn) { 378ac5aef8SEnji Cooper pthread_t subthread; 388ac5aef8SEnji Cooper if (force_mt) { 398ac5aef8SEnji Cooper pthread_create(&subthread, NULL, WaitingThreadFn, NULL); 408ac5aef8SEnji Cooper } 418ac5aef8SEnji Cooper (self->*fn)(); 428ac5aef8SEnji Cooper if (force_mt) { 438ac5aef8SEnji Cooper pthread_cancel(subthread); 448ac5aef8SEnji Cooper pthread_join(subthread, NULL); 458ac5aef8SEnji Cooper } 468ac5aef8SEnji Cooper } 478ac5aef8SEnji Cooper template <typename Function> 488ac5aef8SEnji Cooper void MaybeRunWithThread(Function fn) { 498ac5aef8SEnji Cooper pthread_t subthread; 508ac5aef8SEnji Cooper if (force_mt) { 518ac5aef8SEnji Cooper pthread_create(&subthread, NULL, WaitingThreadFn, NULL); 528ac5aef8SEnji Cooper } 538ac5aef8SEnji Cooper (fn)(); 548ac5aef8SEnji Cooper if (force_mt) { 558ac5aef8SEnji Cooper pthread_cancel(subthread); 568ac5aef8SEnji Cooper pthread_join(subthread, NULL); 578ac5aef8SEnji Cooper } 588ac5aef8SEnji Cooper } 598ac5aef8SEnji Cooper 608ac5aef8SEnji Cooper // Return the absolute path of a filename in the temp directory, `tmpdir`, 618ac5aef8SEnji Cooper // with the given pathname, e.g., "/tmp/<pathname>", if `tmpdir` was set to 628ac5aef8SEnji Cooper // "/tmp". 638ac5aef8SEnji Cooper const char *TmpFile(const char *pathname); 648ac5aef8SEnji Cooper 658ac5aef8SEnji Cooper // Run the given test function in a forked process, so that trapdoor 668ac5aef8SEnji Cooper // entry doesn't affect other tests, and watch out for hung processes. 678ac5aef8SEnji Cooper // Implemented as a macro to allow access to the test case instance's 688ac5aef8SEnji Cooper // HasFailure() method, which is reported as the forked process's 698ac5aef8SEnji Cooper // exit status. 708ac5aef8SEnji Cooper #define _RUN_FORKED(INNERCODE, TESTCASENAME, TESTNAME) \ 718ac5aef8SEnji Cooper pid_t pid = force_nofork ? 0 : fork(); \ 728ac5aef8SEnji Cooper if (pid == 0) { \ 738ac5aef8SEnji Cooper INNERCODE; \ 748ac5aef8SEnji Cooper if (!force_nofork) { \ 758ac5aef8SEnji Cooper exit(HasFailure()); \ 768ac5aef8SEnji Cooper } \ 778ac5aef8SEnji Cooper } else if (pid > 0) { \ 788ac5aef8SEnji Cooper int rc, status; \ 79*2d936e6cSAlex Richardson int remaining_us = 30000000; \ 808ac5aef8SEnji Cooper while (remaining_us > 0) { \ 818ac5aef8SEnji Cooper status = 0; \ 828ac5aef8SEnji Cooper rc = waitpid(pid, &status, WNOHANG); \ 838ac5aef8SEnji Cooper if (rc != 0) break; \ 848ac5aef8SEnji Cooper remaining_us -= 10000; \ 858ac5aef8SEnji Cooper usleep(10000); \ 868ac5aef8SEnji Cooper } \ 878ac5aef8SEnji Cooper if (remaining_us <= 0) { \ 888ac5aef8SEnji Cooper fprintf(stderr, "Warning: killing unresponsive test " \ 898ac5aef8SEnji Cooper "%s.%s (pid %d)\n", \ 908ac5aef8SEnji Cooper TESTCASENAME, TESTNAME, pid); \ 918ac5aef8SEnji Cooper kill(pid, SIGKILL); \ 928ac5aef8SEnji Cooper ADD_FAILURE() << "Test hung"; \ 938ac5aef8SEnji Cooper } else if (rc < 0) { \ 948ac5aef8SEnji Cooper fprintf(stderr, "Warning: waitpid error %s (%d)\n", \ 958ac5aef8SEnji Cooper strerror(errno), errno); \ 968ac5aef8SEnji Cooper ADD_FAILURE() << "Failed to wait for child"; \ 978ac5aef8SEnji Cooper } else { \ 988ac5aef8SEnji Cooper int rc = WIFEXITED(status) ? WEXITSTATUS(status) : -1; \ 998ac5aef8SEnji Cooper EXPECT_EQ(0, rc); \ 1008ac5aef8SEnji Cooper } \ 1018ac5aef8SEnji Cooper } 1028ac5aef8SEnji Cooper #define _RUN_FORKED_MEM(THIS, TESTFN, TESTCASENAME, TESTNAME) \ 1038ac5aef8SEnji Cooper _RUN_FORKED(MaybeRunWithThread(THIS, &TESTFN), TESTCASENAME, TESTNAME); 1048ac5aef8SEnji Cooper #define _RUN_FORKED_FN(TESTFN, TESTCASENAME, TESTNAME) \ 1058ac5aef8SEnji Cooper _RUN_FORKED(MaybeRunWithThread(&TESTFN), TESTCASENAME, TESTNAME); 1068ac5aef8SEnji Cooper 1078ac5aef8SEnji Cooper // Run a test case in a forked process, possibly cleaning up a 1088ac5aef8SEnji Cooper // test file after completion 1098ac5aef8SEnji Cooper #define FORK_TEST_ON(test_case_name, test_name, test_file) \ 1108ac5aef8SEnji Cooper static void test_case_name##_##test_name##_ForkTest(); \ 1118ac5aef8SEnji Cooper TEST(test_case_name, test_name ## Forked) { \ 1128ac5aef8SEnji Cooper _RUN_FORKED_FN(test_case_name##_##test_name##_ForkTest, \ 1138ac5aef8SEnji Cooper #test_case_name, #test_name); \ 1148ac5aef8SEnji Cooper const char *filename = test_file; \ 1158ac5aef8SEnji Cooper if (filename) unlink(filename); \ 1168ac5aef8SEnji Cooper } \ 1178ac5aef8SEnji Cooper static void test_case_name##_##test_name##_ForkTest() 1188ac5aef8SEnji Cooper 1198ac5aef8SEnji Cooper #define FORK_TEST(test_case_name, test_name) FORK_TEST_ON(test_case_name, test_name, NULL) 1208ac5aef8SEnji Cooper 1218ac5aef8SEnji Cooper // Run a test case fixture in a forked process, so that trapdoors don't 1228ac5aef8SEnji Cooper // affect other tests. 1238ac5aef8SEnji Cooper #define ICLASS_NAME(test_case_name, test_name) Forked##test_case_name##_##test_name 1248ac5aef8SEnji Cooper #define FORK_TEST_F(test_case_name, test_name) \ 1258ac5aef8SEnji Cooper class ICLASS_NAME(test_case_name, test_name) : public test_case_name { \ 1268ac5aef8SEnji Cooper public: \ 1278ac5aef8SEnji Cooper ICLASS_NAME(test_case_name, test_name)() {} \ 1288ac5aef8SEnji Cooper void InnerTestBody(); \ 1298ac5aef8SEnji Cooper }; \ 1308ac5aef8SEnji Cooper TEST_F(ICLASS_NAME(test_case_name, test_name), _) { \ 1318ac5aef8SEnji Cooper _RUN_FORKED_MEM(this, \ 1328ac5aef8SEnji Cooper ICLASS_NAME(test_case_name, test_name)::InnerTestBody, \ 1338ac5aef8SEnji Cooper #test_case_name, #test_name); \ 1348ac5aef8SEnji Cooper } \ 1358ac5aef8SEnji Cooper void ICLASS_NAME(test_case_name, test_name)::InnerTestBody() 1368ac5aef8SEnji Cooper 1378ac5aef8SEnji Cooper // Emit errno information on failure 1388ac5aef8SEnji Cooper #define EXPECT_OK(v) EXPECT_LE(0, v) << " errno " << errno << " " << strerror(errno) 1398ac5aef8SEnji Cooper 1408ac5aef8SEnji Cooper // Expect a syscall to fail with the given error. 1418ac5aef8SEnji Cooper #define EXPECT_SYSCALL_FAIL(E, C) \ 1428ac5aef8SEnji Cooper do { \ 1438ac5aef8SEnji Cooper EXPECT_GT(0, C); \ 1448ac5aef8SEnji Cooper EXPECT_EQ(E, errno); \ 1458ac5aef8SEnji Cooper } while (0) 1468ac5aef8SEnji Cooper 1478ac5aef8SEnji Cooper // Expect a syscall to fail with anything other than the given error. 1488ac5aef8SEnji Cooper #define EXPECT_SYSCALL_FAIL_NOT(E, C) \ 1498ac5aef8SEnji Cooper do { \ 1508ac5aef8SEnji Cooper EXPECT_GT(0, C); \ 1518ac5aef8SEnji Cooper EXPECT_NE(E, errno); \ 1528ac5aef8SEnji Cooper } while (0) 1538ac5aef8SEnji Cooper 1548ac5aef8SEnji Cooper // Expect a void syscall to fail with anything other than the given error. 1558ac5aef8SEnji Cooper #define EXPECT_VOID_SYSCALL_FAIL_NOT(E, C) \ 1568ac5aef8SEnji Cooper do { \ 1578ac5aef8SEnji Cooper errno = 0; \ 1588ac5aef8SEnji Cooper C; \ 1598ac5aef8SEnji Cooper EXPECT_NE(E, errno) << #C << " failed with ECAPMODE"; \ 1608ac5aef8SEnji Cooper } while (0) 1618ac5aef8SEnji Cooper 1628ac5aef8SEnji Cooper // Expect a system call to fail due to path traversal; exact error 1638ac5aef8SEnji Cooper // code is OS-specific. 1648ac5aef8SEnji Cooper #ifdef O_BENEATH 1658ac5aef8SEnji Cooper #define EXPECT_OPENAT_FAIL_TRAVERSAL(fd, path, flags) \ 1668ac5aef8SEnji Cooper do { \ 1678ac5aef8SEnji Cooper const int result = openat((fd), (path), (flags)); \ 1688ac5aef8SEnji Cooper if (((flags) & O_BENEATH) == O_BENEATH) { \ 1698ac5aef8SEnji Cooper EXPECT_SYSCALL_FAIL(E_NO_TRAVERSE_O_BENEATH, result); \ 1708ac5aef8SEnji Cooper } else { \ 1718ac5aef8SEnji Cooper EXPECT_SYSCALL_FAIL(E_NO_TRAVERSE_CAPABILITY, result); \ 1728ac5aef8SEnji Cooper } \ 173*2d936e6cSAlex Richardson if (result >= 0) { close(result); } \ 1748ac5aef8SEnji Cooper } while (0) 1758ac5aef8SEnji Cooper #else 1768ac5aef8SEnji Cooper #define EXPECT_OPENAT_FAIL_TRAVERSAL(fd, path, flags) \ 1778ac5aef8SEnji Cooper do { \ 1788ac5aef8SEnji Cooper const int result = openat((fd), (path), (flags)); \ 1798ac5aef8SEnji Cooper EXPECT_SYSCALL_FAIL(E_NO_TRAVERSE_CAPABILITY, result); \ 180*2d936e6cSAlex Richardson if (result >= 0) { close(result); } \ 1818ac5aef8SEnji Cooper } while (0) 1828ac5aef8SEnji Cooper #endif 1838ac5aef8SEnji Cooper 1848ac5aef8SEnji Cooper // Expect a system call to fail with ECAPMODE. 1858ac5aef8SEnji Cooper #define EXPECT_CAPMODE(C) EXPECT_SYSCALL_FAIL(ECAPMODE, C) 1868ac5aef8SEnji Cooper 1878ac5aef8SEnji Cooper // Expect a system call to fail, but not with ECAPMODE. 1888ac5aef8SEnji Cooper #define EXPECT_FAIL_NOT_CAPMODE(C) EXPECT_SYSCALL_FAIL_NOT(ECAPMODE, C) 1898ac5aef8SEnji Cooper #define EXPECT_FAIL_VOID_NOT_CAPMODE(C) EXPECT_VOID_SYSCALL_FAIL_NOT(ECAPMODE, C) 1908ac5aef8SEnji Cooper 1918ac5aef8SEnji Cooper // Expect a system call to fail with ENOTCAPABLE. 1928ac5aef8SEnji Cooper #define EXPECT_NOTCAPABLE(C) EXPECT_SYSCALL_FAIL(ENOTCAPABLE, C) 1938ac5aef8SEnji Cooper 1948ac5aef8SEnji Cooper // Expect a system call to fail, but not with ENOTCAPABLE. 1958ac5aef8SEnji Cooper #define EXPECT_FAIL_NOT_NOTCAPABLE(C) EXPECT_SYSCALL_FAIL_NOT(ENOTCAPABLE, C) 1968ac5aef8SEnji Cooper 1978ac5aef8SEnji Cooper // Expect a system call to fail with either ENOTCAPABLE or ECAPMODE. 1988ac5aef8SEnji Cooper #define EXPECT_CAPFAIL(C) \ 1998ac5aef8SEnji Cooper do { \ 2008ac5aef8SEnji Cooper int rc = C; \ 2018ac5aef8SEnji Cooper EXPECT_GT(0, rc); \ 2028ac5aef8SEnji Cooper EXPECT_TRUE(errno == ECAPMODE || errno == ENOTCAPABLE) \ 2038ac5aef8SEnji Cooper << #C << " did not fail with ECAPMODE/ENOTCAPABLE but " << errno; \ 2048ac5aef8SEnji Cooper } while (0) 2058ac5aef8SEnji Cooper 2068ac5aef8SEnji Cooper // Ensure that 'rights' are a subset of 'max'. 2078ac5aef8SEnji Cooper #define EXPECT_RIGHTS_IN(rights, max) \ 2088ac5aef8SEnji Cooper EXPECT_TRUE(cap_rights_contains((max), (rights))) \ 2098ac5aef8SEnji Cooper << "rights " << std::hex << *(rights) \ 2108ac5aef8SEnji Cooper << " not a subset of " << std::hex << *(max) 2118ac5aef8SEnji Cooper 2128ac5aef8SEnji Cooper // Ensure rights are identical 2138ac5aef8SEnji Cooper #define EXPECT_RIGHTS_EQ(a, b) \ 2148ac5aef8SEnji Cooper do { \ 2158ac5aef8SEnji Cooper EXPECT_RIGHTS_IN((a), (b)); \ 2168ac5aef8SEnji Cooper EXPECT_RIGHTS_IN((b), (a)); \ 2178ac5aef8SEnji Cooper } while (0) 2188ac5aef8SEnji Cooper 2198ac5aef8SEnji Cooper // Get the state of a process as a single character. 2208ac5aef8SEnji Cooper // - 'D': disk wait 2218ac5aef8SEnji Cooper // - 'R': runnable 2228ac5aef8SEnji Cooper // - 'S': sleeping/idle 2238ac5aef8SEnji Cooper // - 'T': stopped 2248ac5aef8SEnji Cooper // - 'Z': zombie 2258ac5aef8SEnji Cooper // On error, return either '?' or '\0'. 2268ac5aef8SEnji Cooper char ProcessState(int pid); 2278ac5aef8SEnji Cooper 2288ac5aef8SEnji Cooper // Check process state reaches a particular expected state (or two). 2298ac5aef8SEnji Cooper // Retries a few times to allow for timing issues. 2308ac5aef8SEnji Cooper #define EXPECT_PID_REACHES_STATES(pid, expected1, expected2) { \ 2318ac5aef8SEnji Cooper int counter = 5; \ 2328ac5aef8SEnji Cooper char state; \ 2338ac5aef8SEnji Cooper do { \ 2348ac5aef8SEnji Cooper state = ProcessState(pid); \ 2358ac5aef8SEnji Cooper if (state == expected1 || state == expected2) break; \ 2368ac5aef8SEnji Cooper usleep(100000); \ 2378ac5aef8SEnji Cooper } while (--counter > 0); \ 2388ac5aef8SEnji Cooper EXPECT_TRUE(state == expected1 || state == expected2) \ 2398ac5aef8SEnji Cooper << " pid " << pid << " in state " << state; \ 2408ac5aef8SEnji Cooper } 2418ac5aef8SEnji Cooper 2428ac5aef8SEnji Cooper #define EXPECT_PID_ALIVE(pid) EXPECT_PID_REACHES_STATES(pid, 'R', 'S') 2438ac5aef8SEnji Cooper #define EXPECT_PID_DEAD(pid) EXPECT_PID_REACHES_STATES(pid, 'Z', '\0') 2448ac5aef8SEnji Cooper #define EXPECT_PID_ZOMBIE(pid) EXPECT_PID_REACHES_STATES(pid, 'Z', 'Z'); 2458ac5aef8SEnji Cooper #define EXPECT_PID_GONE(pid) EXPECT_PID_REACHES_STATES(pid, '\0', '\0'); 2468ac5aef8SEnji Cooper 2478ac5aef8SEnji Cooper // Mark a test that can only be run as root. 248*2d936e6cSAlex Richardson #define GTEST_SKIP_IF_NOT_ROOT() \ 249*2d936e6cSAlex Richardson if (getuid() != 0) { GTEST_SKIP() << "requires root"; } 250*2d936e6cSAlex Richardson 251*2d936e6cSAlex Richardson extern std::string capsicum_test_bindir; 2528ac5aef8SEnji Cooper 2538ac5aef8SEnji Cooper #endif // CAPSICUM_TEST_H 254