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>
138ac5aef8SEnji Cooper #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 
WaitingThreadFn(void *)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>
MaybeRunWithThread(T * self,Function fn)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>
MaybeRunWithThread(Function fn)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;                                          \
798ac5aef8SEnji Cooper       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       SCOPED_TRACE(#C); \
1448ac5aef8SEnji Cooper       EXPECT_GT(0, C); \
1458ac5aef8SEnji Cooper       EXPECT_EQ(E, errno) << "expected '" << strerror(E) \
1468ac5aef8SEnji Cooper                           << "' but got '" << strerror(errno) << "'"; \
1478ac5aef8SEnji Cooper     } while (0)
1488ac5aef8SEnji Cooper 
1498ac5aef8SEnji Cooper // Expect a syscall to fail with anything other than the given error.
1508ac5aef8SEnji Cooper #define EXPECT_SYSCALL_FAIL_NOT(E, C) \
1518ac5aef8SEnji Cooper     do { \
1528ac5aef8SEnji Cooper       EXPECT_GT(0, C); \
1538ac5aef8SEnji Cooper       EXPECT_NE(E, errno) << strerror(E); \
1548ac5aef8SEnji Cooper     } while (0)
1558ac5aef8SEnji Cooper 
1568ac5aef8SEnji Cooper // Expect a void syscall to fail with anything other than the given error.
1578ac5aef8SEnji Cooper #define EXPECT_VOID_SYSCALL_FAIL_NOT(E, C)   \
1588ac5aef8SEnji Cooper     do { \
1598ac5aef8SEnji Cooper       errno = 0; \
1608ac5aef8SEnji Cooper       C; \
1618ac5aef8SEnji Cooper       EXPECT_NE(E, errno) << #C << " failed with ECAPMODE"; \
1628ac5aef8SEnji Cooper     } while (0)
1638ac5aef8SEnji Cooper 
1648ac5aef8SEnji Cooper // Expect a system call to fail due to path traversal; exact error
1658ac5aef8SEnji Cooper // code is OS-specific.
1668ac5aef8SEnji Cooper #ifdef O_BENEATH
1678ac5aef8SEnji Cooper #define EXPECT_OPENAT_FAIL_TRAVERSAL(fd, path, flags) \
1688ac5aef8SEnji Cooper     do {                                              \
1698ac5aef8SEnji Cooper       SCOPED_TRACE(GTEST_STRINGIFY_(openat((fd), (path), (flags)))); \
1708ac5aef8SEnji Cooper       const int result = openat((fd), (path), (flags)); \
1718ac5aef8SEnji Cooper       if (((flags) & O_BENEATH) == O_BENEATH) { \
1728ac5aef8SEnji Cooper         EXPECT_SYSCALL_FAIL(E_NO_TRAVERSE_O_BENEATH, result); \
1738ac5aef8SEnji Cooper       } else { \
1748ac5aef8SEnji Cooper         EXPECT_SYSCALL_FAIL(E_NO_TRAVERSE_CAPABILITY, result); \
1758ac5aef8SEnji Cooper       } \
1768ac5aef8SEnji Cooper       if (result >= 0) { close(result); } \
1778ac5aef8SEnji Cooper     } while (0)
1788ac5aef8SEnji Cooper #else
1798ac5aef8SEnji Cooper #define EXPECT_OPENAT_FAIL_TRAVERSAL(fd, path, flags) \
1808ac5aef8SEnji Cooper     do { \
1818ac5aef8SEnji Cooper       SCOPED_TRACE(GTEST_STRINGIFY_(openat((fd), (path), (flags)))); \
1828ac5aef8SEnji Cooper       const int result = openat((fd), (path), (flags)); \
1838ac5aef8SEnji Cooper       EXPECT_SYSCALL_FAIL(E_NO_TRAVERSE_CAPABILITY, result); \
1848ac5aef8SEnji Cooper       if (result >= 0) { close(result); } \
1858ac5aef8SEnji Cooper     } while (0)
1868ac5aef8SEnji Cooper #endif
1878ac5aef8SEnji Cooper 
1888ac5aef8SEnji Cooper // Expect a system call to fail with ECAPMODE.
1898ac5aef8SEnji Cooper #define EXPECT_CAPMODE(C) EXPECT_SYSCALL_FAIL(ECAPMODE, C)
1908ac5aef8SEnji Cooper 
1918ac5aef8SEnji Cooper // Expect a system call to fail, but not with ECAPMODE.
1928ac5aef8SEnji Cooper #define EXPECT_FAIL_NOT_CAPMODE(C) EXPECT_SYSCALL_FAIL_NOT(ECAPMODE, C)
1938ac5aef8SEnji Cooper #define EXPECT_FAIL_VOID_NOT_CAPMODE(C) EXPECT_VOID_SYSCALL_FAIL_NOT(ECAPMODE, C)
1948ac5aef8SEnji Cooper 
1958ac5aef8SEnji Cooper // Expect a system call to fail with ENOTCAPABLE.
1968ac5aef8SEnji Cooper #define EXPECT_NOTCAPABLE(C) EXPECT_SYSCALL_FAIL(ENOTCAPABLE, C)
1978ac5aef8SEnji Cooper 
1988ac5aef8SEnji Cooper // Expect a system call to fail, but not with ENOTCAPABLE.
1998ac5aef8SEnji Cooper #define EXPECT_FAIL_NOT_NOTCAPABLE(C) EXPECT_SYSCALL_FAIL_NOT(ENOTCAPABLE, C)
2008ac5aef8SEnji Cooper 
2018ac5aef8SEnji Cooper // Expect a system call to fail with either ENOTCAPABLE or ECAPMODE.
2028ac5aef8SEnji Cooper #define EXPECT_CAPFAIL(C) \
2038ac5aef8SEnji Cooper     do { \
2048ac5aef8SEnji Cooper       int rc = C; \
2058ac5aef8SEnji Cooper       EXPECT_GT(0, rc); \
2068ac5aef8SEnji Cooper       EXPECT_TRUE(errno == ECAPMODE || errno == ENOTCAPABLE) \
2078ac5aef8SEnji Cooper         << #C << " did not fail with ECAPMODE/ENOTCAPABLE but " << errno \
2088ac5aef8SEnji Cooper         << "(" << strerror(errno) << ")"; \
2098ac5aef8SEnji Cooper     } while (0)
2108ac5aef8SEnji Cooper 
2118ac5aef8SEnji Cooper // Ensure that 'rights' are a subset of 'max'.
2128ac5aef8SEnji Cooper #define EXPECT_RIGHTS_IN(rights, max) \
2138ac5aef8SEnji Cooper     EXPECT_TRUE(cap_rights_contains((max), (rights)))  \
2148ac5aef8SEnji Cooper     << "rights " << std::hex << *(rights) \
2158ac5aef8SEnji Cooper     << " not a subset of " << std::hex << *(max)
2168ac5aef8SEnji Cooper 
2178ac5aef8SEnji Cooper // Ensure rights are identical
2188ac5aef8SEnji Cooper #define EXPECT_RIGHTS_EQ(a, b) \
2198ac5aef8SEnji Cooper   do { \
2208ac5aef8SEnji Cooper     EXPECT_RIGHTS_IN((a), (b)); \
2218ac5aef8SEnji Cooper     EXPECT_RIGHTS_IN((b), (a)); \
2228ac5aef8SEnji Cooper   } while (0)
2238ac5aef8SEnji Cooper 
2248ac5aef8SEnji Cooper // Get the state of a process as a single character.
2258ac5aef8SEnji Cooper //  - 'D': disk wait
2268ac5aef8SEnji Cooper //  - 'R': runnable
2278ac5aef8SEnji Cooper //  - 'S': sleeping/idle
2288ac5aef8SEnji Cooper //  - 'T': stopped
2298ac5aef8SEnji Cooper //  - 'Z': zombie
2308ac5aef8SEnji Cooper // On error, return either '?' or '\0'.
2318ac5aef8SEnji Cooper char ProcessState(int pid);
2328ac5aef8SEnji Cooper 
2338ac5aef8SEnji Cooper // Check process state reaches a particular expected state (or two).
2348ac5aef8SEnji Cooper // Retries a few times to allow for timing issues.
2358ac5aef8SEnji Cooper #define EXPECT_PID_REACHES_STATES(pid, expected1, expected2) { \
2368ac5aef8SEnji Cooper   int counter = 5; \
2378ac5aef8SEnji Cooper   char state; \
2388ac5aef8SEnji Cooper   do { \
2398ac5aef8SEnji Cooper     state = ProcessState(pid); \
2408ac5aef8SEnji Cooper     if (state == expected1 || state == expected2) break; \
2418ac5aef8SEnji Cooper     usleep(100000); \
2428ac5aef8SEnji Cooper   } while (--counter > 0); \
2438ac5aef8SEnji Cooper   EXPECT_TRUE(state == expected1 || state == expected2) \
2448ac5aef8SEnji Cooper       << " pid " << pid << " in state " << state; \
2458ac5aef8SEnji Cooper }
2468ac5aef8SEnji Cooper 
2478ac5aef8SEnji Cooper #define EXPECT_PID_ALIVE(pid)   EXPECT_PID_REACHES_STATES(pid, 'R', 'S')
2488ac5aef8SEnji Cooper #define EXPECT_PID_DEAD(pid)    EXPECT_PID_REACHES_STATES(pid, 'Z', '\0')
2498ac5aef8SEnji Cooper #define EXPECT_PID_ZOMBIE(pid)  EXPECT_PID_REACHES_STATES(pid, 'Z', 'Z');
2508ac5aef8SEnji Cooper #define EXPECT_PID_GONE(pid)    EXPECT_PID_REACHES_STATES(pid, '\0', '\0');
25180986ae0SLi-Wen Hsu 
2528ac5aef8SEnji Cooper enum {
2538ac5aef8SEnji Cooper   // Magic numbers for messages sent by child processes.
2548ac5aef8SEnji Cooper   MSG_CHILD_STARTED = 1234,
2558ac5aef8SEnji Cooper   MSG_CHILD_FD_RECEIVED = 4321,
2568ac5aef8SEnji Cooper   // Magic numbers for messages sent by parent processes.
2578ac5aef8SEnji Cooper   MSG_PARENT_REQUEST_CHILD_EXIT = 9999,
2588ac5aef8SEnji Cooper   MSG_PARENT_CLOSED_FD = 10000,
2598ac5aef8SEnji Cooper   MSG_PARENT_CHILD_SHOULD_RUN = 10001,
2608ac5aef8SEnji Cooper };
2618ac5aef8SEnji Cooper 
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