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