1 #include <sys/types.h> 2 #ifdef __linux__ 3 #include <sys/vfs.h> 4 #include <linux/magic.h> 5 #elif defined(__FreeBSD__) 6 #include <sys/sysctl.h> 7 #endif 8 #include <ctype.h> 9 #include <errno.h> 10 #include <libgen.h> 11 #include <pwd.h> 12 #include <stdio.h> 13 #include <stdlib.h> 14 #include <unistd.h> 15 #include <iostream> 16 #include "gtest/gtest.h" 17 #include "capsicum-test.h" 18 19 // For versions of googletest that lack GTEST_SKIP. 20 #ifndef GTEST_SKIP 21 #define GTEST_SKIP GTEST_FAIL 22 #endif 23 24 std::string tmpdir; 25 26 class SetupEnvironment : public ::testing::Environment 27 { 28 public: 29 SetupEnvironment() : teardown_tmpdir_(false) {} 30 void SetUp() override { 31 CheckCapsicumSupport(); 32 if (tmpdir.empty()) { 33 std::cerr << "Generating temporary directory root: "; 34 CreateTemporaryRoot(); 35 } else { 36 std::cerr << "User provided temporary directory root: "; 37 } 38 std::cerr << tmpdir << std::endl; 39 } 40 void CheckCapsicumSupport() { 41 #ifdef __FreeBSD__ 42 int rc; 43 bool trap_enotcap_enabled; 44 size_t trap_enotcap_enabled_len = sizeof(trap_enotcap_enabled); 45 46 if (feature_present("security_capabilities") == 0) { 47 GTEST_SKIP() << "Skipping tests because capsicum support is not " 48 << "enabled in the kernel."; 49 } 50 // If this OID is enabled, it will send SIGTRAP to the process when 51 // `ENOTCAPABLE` is returned. 52 const char *oid = "kern.trap_enotcap"; 53 rc = sysctlbyname(oid, &trap_enotcap_enabled, &trap_enotcap_enabled_len, 54 nullptr, 0); 55 if (rc != 0) { 56 GTEST_FAIL() << "sysctlbyname failed: " << strerror(errno); 57 } 58 if (trap_enotcap_enabled) { 59 GTEST_SKIP() << "Debug sysctl, " << oid << ", enabled. " 60 << "Skipping tests because its enablement invalidates the " 61 << "test results."; 62 } 63 #endif /* FreeBSD */ 64 } 65 void CreateTemporaryRoot() { 66 char *tmpdir_name = tempnam(nullptr, "cptst"); 67 68 ASSERT_NE(tmpdir_name, nullptr); 69 ASSERT_EQ(mkdir(tmpdir_name, 0700), 0) << 70 "Could not create temp directory, " << tmpdir_name << ": " << 71 strerror(errno); 72 tmpdir = std::string(tmpdir_name); 73 free(tmpdir_name); 74 teardown_tmpdir_ = true; 75 } 76 void TearDown() override { 77 if (teardown_tmpdir_) { 78 rmdir(tmpdir.c_str()); 79 } 80 } 81 private: 82 bool teardown_tmpdir_; 83 }; 84 85 std::string capsicum_test_bindir; 86 87 int main(int argc, char* argv[]) { 88 // Set up the test program path, so capsicum-test can find programs, like 89 // mini-me* when executed from an absolute path. 90 { 91 char *new_path, *old_path, *program_name; 92 93 program_name = strdup(argv[0]); 94 assert(program_name); 95 capsicum_test_bindir = std::string(dirname(program_name)); 96 free(program_name); 97 98 old_path = getenv("PATH"); 99 assert(old_path); 100 101 assert(asprintf(&new_path, "%s:%s", capsicum_test_bindir.c_str(), 102 old_path) > 0); 103 assert(setenv("PATH", new_path, 1) == 0); 104 } 105 106 ::testing::InitGoogleTest(&argc, argv); 107 for (int ii = 1; ii < argc; ii++) { 108 if (strcmp(argv[ii], "-v") == 0) { 109 verbose = true; 110 } else if (strcmp(argv[ii], "-T") == 0) { 111 ii++; 112 assert(ii < argc); 113 tmpdir = argv[ii]; 114 struct stat info; 115 stat(tmpdir.c_str(), &info); 116 assert(S_ISDIR(info.st_mode)); 117 } else if (strcmp(argv[ii], "-t") == 0) { 118 force_mt = true; 119 } else if (strcmp(argv[ii], "-F") == 0) { 120 force_nofork = true; 121 } else if (strcmp(argv[ii], "-u") == 0) { 122 if (++ii >= argc) { 123 std::cerr << "-u needs argument" << std::endl; 124 exit(1); 125 } 126 if (isdigit(argv[ii][0])) { 127 other_uid = atoi(argv[ii]); 128 } else { 129 struct passwd *p = getpwnam(argv[ii]); 130 if (!p) { 131 std::cerr << "Failed to get entry for " << argv[ii] << ", errno=" << errno << std::endl; 132 exit(1); 133 } 134 other_uid = p->pw_uid; 135 } 136 } 137 } 138 if (other_uid == 0) { 139 struct stat info; 140 if (stat(argv[0], &info) == 0) { 141 other_uid = info.st_uid; 142 } 143 } 144 145 #ifdef __linux__ 146 // Check whether our temporary directory is on a tmpfs volume. 147 struct statfs fsinfo; 148 statfs(tmpdir.c_str(), &fsinfo); 149 tmpdir_on_tmpfs = (fsinfo.f_type == TMPFS_MAGIC); 150 #endif 151 152 testing::AddGlobalTestEnvironment(new SetupEnvironment()); 153 int rc = RUN_ALL_TESTS(); 154 ShowSkippedTests(std::cerr); 155 return rc; 156 } 157