xref: /freebsd/contrib/capsicum-test/capsicum-test-main.cc (revision 2d936e6c99ad1c4fb01f6c99a96dcc924ee44b9d)
18ac5aef8SEnji Cooper #include <sys/types.h>
28ac5aef8SEnji Cooper #ifdef __linux__
38ac5aef8SEnji Cooper #include <sys/vfs.h>
48ac5aef8SEnji Cooper #include <linux/magic.h>
58ac5aef8SEnji Cooper #elif defined(__FreeBSD__)
68ac5aef8SEnji Cooper #include <sys/sysctl.h>
78ac5aef8SEnji Cooper #endif
88ac5aef8SEnji Cooper #include <ctype.h>
98ac5aef8SEnji Cooper #include <errno.h>
108ac5aef8SEnji Cooper #include <libgen.h>
118ac5aef8SEnji Cooper #include <pwd.h>
128ac5aef8SEnji Cooper #include <stdio.h>
138ac5aef8SEnji Cooper #include <stdlib.h>
148ac5aef8SEnji Cooper #include <unistd.h>
158ac5aef8SEnji Cooper #include <iostream>
168ac5aef8SEnji Cooper #include "gtest/gtest.h"
178ac5aef8SEnji Cooper #include "capsicum-test.h"
188ac5aef8SEnji Cooper 
198ac5aef8SEnji Cooper // For versions of googletest that lack GTEST_SKIP.
208ac5aef8SEnji Cooper #ifndef GTEST_SKIP
218ac5aef8SEnji Cooper #define GTEST_SKIP GTEST_FAIL
228ac5aef8SEnji Cooper #endif
238ac5aef8SEnji Cooper 
248ac5aef8SEnji Cooper std::string tmpdir;
258ac5aef8SEnji Cooper 
268ac5aef8SEnji Cooper class SetupEnvironment : public ::testing::Environment
278ac5aef8SEnji Cooper {
288ac5aef8SEnji Cooper public:
SetupEnvironment()298ac5aef8SEnji Cooper   SetupEnvironment() : teardown_tmpdir_(false) {}
SetUp()308ac5aef8SEnji Cooper   void SetUp() override {
318ac5aef8SEnji Cooper     CheckCapsicumSupport();
328ac5aef8SEnji Cooper     if (tmpdir.empty()) {
338ac5aef8SEnji Cooper       std::cerr << "Generating temporary directory root: ";
348ac5aef8SEnji Cooper       CreateTemporaryRoot();
358ac5aef8SEnji Cooper     } else {
368ac5aef8SEnji Cooper       std::cerr << "User provided temporary directory root: ";
378ac5aef8SEnji Cooper     }
388ac5aef8SEnji Cooper     std::cerr << tmpdir << std::endl;
398ac5aef8SEnji Cooper   }
CheckCapsicumSupport()408ac5aef8SEnji Cooper   void CheckCapsicumSupport() {
418ac5aef8SEnji Cooper #ifdef __FreeBSD__
428ac5aef8SEnji Cooper     int rc;
438ac5aef8SEnji Cooper     bool trap_enotcap_enabled;
448ac5aef8SEnji Cooper     size_t trap_enotcap_enabled_len = sizeof(trap_enotcap_enabled);
458ac5aef8SEnji Cooper 
468ac5aef8SEnji Cooper     if (feature_present("security_capabilities") == 0) {
478ac5aef8SEnji Cooper       GTEST_SKIP() << "Skipping tests because capsicum support is not "
488ac5aef8SEnji Cooper                    << "enabled in the kernel.";
498ac5aef8SEnji Cooper     }
508ac5aef8SEnji Cooper     // If this OID is enabled, it will send SIGTRAP to the process when
518ac5aef8SEnji Cooper     // `ENOTCAPABLE` is returned.
528ac5aef8SEnji Cooper     const char *oid = "kern.trap_enotcap";
538ac5aef8SEnji Cooper     rc = sysctlbyname(oid, &trap_enotcap_enabled, &trap_enotcap_enabled_len,
548ac5aef8SEnji Cooper       nullptr, 0);
558ac5aef8SEnji Cooper     if (rc != 0) {
568ac5aef8SEnji Cooper       GTEST_FAIL() << "sysctlbyname failed: " << strerror(errno);
578ac5aef8SEnji Cooper     }
588ac5aef8SEnji Cooper     if (trap_enotcap_enabled) {
598ac5aef8SEnji Cooper       GTEST_SKIP() << "Debug sysctl, " << oid << ", enabled. "
608ac5aef8SEnji Cooper                    << "Skipping tests because its enablement invalidates the "
618ac5aef8SEnji Cooper                    << "test results.";
628ac5aef8SEnji Cooper     }
638ac5aef8SEnji Cooper #endif /* FreeBSD */
648ac5aef8SEnji Cooper   }
CreateTemporaryRoot()658ac5aef8SEnji Cooper   void CreateTemporaryRoot() {
668ac5aef8SEnji Cooper     char *tmpdir_name = tempnam(nullptr, "cptst");
678ac5aef8SEnji Cooper 
688ac5aef8SEnji Cooper     ASSERT_NE(tmpdir_name, nullptr);
698ac5aef8SEnji Cooper     ASSERT_EQ(mkdir(tmpdir_name, 0700), 0) <<
708ac5aef8SEnji Cooper         "Could not create temp directory, " << tmpdir_name << ": " <<
718ac5aef8SEnji Cooper         strerror(errno);
728ac5aef8SEnji Cooper     tmpdir = std::string(tmpdir_name);
738ac5aef8SEnji Cooper     free(tmpdir_name);
748ac5aef8SEnji Cooper     teardown_tmpdir_ = true;
758ac5aef8SEnji Cooper   }
TearDown()768ac5aef8SEnji Cooper   void TearDown() override {
778ac5aef8SEnji Cooper     if (teardown_tmpdir_) {
788ac5aef8SEnji Cooper       rmdir(tmpdir.c_str());
798ac5aef8SEnji Cooper     }
808ac5aef8SEnji Cooper   }
818ac5aef8SEnji Cooper private:
828ac5aef8SEnji Cooper   bool teardown_tmpdir_;
838ac5aef8SEnji Cooper };
848ac5aef8SEnji Cooper 
858ac5aef8SEnji Cooper std::string capsicum_test_bindir;
868ac5aef8SEnji Cooper 
87*2d936e6cSAlex Richardson // Adds a directory to $PATH.
AddDirectoryToPath(const char * dir)88*2d936e6cSAlex Richardson static void AddDirectoryToPath(const char *dir) {
89*2d936e6cSAlex Richardson   char *new_path, *old_path;
90*2d936e6cSAlex Richardson 
91*2d936e6cSAlex Richardson   old_path = getenv("PATH");
92*2d936e6cSAlex Richardson   assert(old_path);
93*2d936e6cSAlex Richardson 
94*2d936e6cSAlex Richardson   assert(asprintf(&new_path, "%s:%s", dir, old_path) > 0);
95*2d936e6cSAlex Richardson   assert(setenv("PATH", new_path, 1) == 0);
96*2d936e6cSAlex Richardson }
97*2d936e6cSAlex Richardson 
main(int argc,char * argv[])988ac5aef8SEnji Cooper int main(int argc, char* argv[]) {
998ac5aef8SEnji Cooper   // Set up the test program path, so capsicum-test can find programs, like
1008ac5aef8SEnji Cooper   // mini-me* when executed from an absolute path.
101*2d936e6cSAlex Richardson   char *program_name;
1028ac5aef8SEnji Cooper 
103*2d936e6cSAlex Richardson   // Copy argv[0], so dirname can do an in-place manipulation of the buffer's
104*2d936e6cSAlex Richardson   // contents.
1058ac5aef8SEnji Cooper   program_name = strdup(argv[0]);
1068ac5aef8SEnji Cooper   assert(program_name);
1078ac5aef8SEnji Cooper   capsicum_test_bindir = std::string(dirname(program_name));
1088ac5aef8SEnji Cooper   free(program_name);
1098ac5aef8SEnji Cooper 
110*2d936e6cSAlex Richardson   AddDirectoryToPath(capsicum_test_bindir.c_str());
1118ac5aef8SEnji Cooper 
1128ac5aef8SEnji Cooper   ::testing::InitGoogleTest(&argc, argv);
1138ac5aef8SEnji Cooper   for (int ii = 1; ii < argc; ii++) {
1148ac5aef8SEnji Cooper     if (strcmp(argv[ii], "-v") == 0) {
1158ac5aef8SEnji Cooper       verbose = true;
1168ac5aef8SEnji Cooper     } else if (strcmp(argv[ii], "-T") == 0) {
1178ac5aef8SEnji Cooper       ii++;
1188ac5aef8SEnji Cooper       assert(ii < argc);
1198ac5aef8SEnji Cooper       tmpdir = argv[ii];
1208ac5aef8SEnji Cooper       struct stat info;
1218ac5aef8SEnji Cooper       stat(tmpdir.c_str(), &info);
1228ac5aef8SEnji Cooper       assert(S_ISDIR(info.st_mode));
1238ac5aef8SEnji Cooper     } else if (strcmp(argv[ii], "-t") == 0) {
1248ac5aef8SEnji Cooper       force_mt = true;
1258ac5aef8SEnji Cooper     } else if (strcmp(argv[ii], "-F") == 0) {
1268ac5aef8SEnji Cooper       force_nofork = true;
1278ac5aef8SEnji Cooper     } else if (strcmp(argv[ii], "-u") == 0) {
1288ac5aef8SEnji Cooper       if (++ii >= argc) {
1298ac5aef8SEnji Cooper         std::cerr << "-u needs argument" << std::endl;
1308ac5aef8SEnji Cooper         exit(1);
1318ac5aef8SEnji Cooper       }
1328ac5aef8SEnji Cooper       if (isdigit(argv[ii][0])) {
1338ac5aef8SEnji Cooper         other_uid = atoi(argv[ii]);
1348ac5aef8SEnji Cooper       } else {
1358ac5aef8SEnji Cooper         struct passwd *p = getpwnam(argv[ii]);
1368ac5aef8SEnji Cooper         if (!p) {
1378ac5aef8SEnji Cooper           std::cerr << "Failed to get entry for " << argv[ii] << ", errno=" << errno << std::endl;
1388ac5aef8SEnji Cooper           exit(1);
1398ac5aef8SEnji Cooper         }
1408ac5aef8SEnji Cooper         other_uid = p->pw_uid;
1418ac5aef8SEnji Cooper       }
1428ac5aef8SEnji Cooper     }
1438ac5aef8SEnji Cooper   }
1448ac5aef8SEnji Cooper   if (other_uid == 0) {
1458ac5aef8SEnji Cooper     struct stat info;
1468ac5aef8SEnji Cooper     if (stat(argv[0], &info) == 0) {
1478ac5aef8SEnji Cooper       other_uid = info.st_uid;
1488ac5aef8SEnji Cooper     }
1498ac5aef8SEnji Cooper   }
1508ac5aef8SEnji Cooper 
1518ac5aef8SEnji Cooper #ifdef __linux__
1528ac5aef8SEnji Cooper   // Check whether our temporary directory is on a tmpfs volume.
1538ac5aef8SEnji Cooper   struct statfs fsinfo;
1548ac5aef8SEnji Cooper   statfs(tmpdir.c_str(), &fsinfo);
1558ac5aef8SEnji Cooper   tmpdir_on_tmpfs = (fsinfo.f_type == TMPFS_MAGIC);
1568ac5aef8SEnji Cooper #endif
1578ac5aef8SEnji Cooper 
1588ac5aef8SEnji Cooper   testing::AddGlobalTestEnvironment(new SetupEnvironment());
159*2d936e6cSAlex Richardson   return RUN_ALL_TESTS();
1608ac5aef8SEnji Cooper }
161