Changeset View
Changeset View
Standalone View
Standalone View
contrib/capsicum-test/capsicum-test-main.cc
#include <sys/types.h> | #include <sys/types.h> | ||||
#ifdef __linux__ | #if defined(__FreeBSD__) | ||||
#include <sys/sysctl.h> | |||||
#elif defined(__linux__) | |||||
#include <sys/vfs.h> | #include <sys/vfs.h> | ||||
#include <linux/magic.h> | #include <linux/magic.h> | ||||
#endif | #endif | ||||
#include <ctype.h> | #include <ctype.h> | ||||
#include <errno.h> | #include <errno.h> | ||||
#include <libgen.h> | |||||
#include <pwd.h> | #include <pwd.h> | ||||
#include <stdio.h> | #include <stdio.h> | ||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include <unistd.h> | |||||
#include <iostream> | #include <iostream> | ||||
#include "gtest/gtest.h" | #include "gtest/gtest.h" | ||||
#include "capsicum-test.h" | #include "capsicum-test.h" | ||||
std::string tmpdir; | std::string tmpdir; | ||||
class SetupEnvironment : public ::testing::Environment | class SetupEnvironment : public ::testing::Environment | ||||
{ | { | ||||
public: | public: | ||||
SetupEnvironment() : teardown_tmpdir_(false) {} | SetupEnvironment() : teardown_tmpdir_(false) {} | ||||
void SetUp() override { | void SetUp() override { | ||||
CheckCapsicumSupport(); | |||||
if (tmpdir.empty()) { | if (tmpdir.empty()) { | ||||
std::cerr << "Generating temporary directory root: "; | std::cerr << "Generating temporary directory root: "; | ||||
CreateTemporaryRoot(); | CreateTemporaryRoot(); | ||||
} else { | } else { | ||||
std::cerr << "User provided temporary directory root: "; | std::cerr << "User provided temporary directory root: "; | ||||
} | } | ||||
std::cerr << tmpdir << std::endl; | std::cerr << tmpdir << std::endl; | ||||
} | } | ||||
void CheckCapsicumSupport() { | |||||
// For versions of googletest that lack GTEST_SKIP. | |||||
#ifndef GTEST_SKIP | |||||
#define GTEST_SKIP GTEST_FAIL | |||||
#define GTEST_SKIP_defined | |||||
#endif | |||||
#ifdef __FreeBSD__ | |||||
size_t trap_enotcap_enabled_len; | |||||
int rc; | |||||
bool trap_enotcap_enabled; | |||||
trap_enotcap_enabled_len = sizeof(trap_enotcap_enabled); | |||||
if (feature_present("security_capabilities") == 0) { | |||||
GTEST_SKIP() << "Skipping tests because capsicum support is not " | |||||
<< "enabled in the kernel."; | |||||
} | |||||
const char *oid = "kern.trap_enotcap"; | |||||
markj: The problem isn't non-determinism, it's just that trap_enotcap causes the process to receive… | |||||
Done Inline ActionsMost correct to state that the tests are skipped due to non-default setting of debugging sysctl, I suspect. emaste: Most correct to state that the tests are skipped due to non-default setting of debugging sysctl… | |||||
Done Inline ActionsYou're both right; the message was misleading. Updated! ngie: You're both right; the message was misleading.
Updated! | |||||
rc = sysctlbyname(oid, &trap_enotcap_enabled, &trap_enotcap_enabled_len, | |||||
nullptr, 0); | |||||
Done Inline Actionss/it's/its/ markj: s/it's/its/ | |||||
if (rc != 0) { | |||||
GTEST_FAIL() << "sysctlbyname failed: " << strerror(errno); | |||||
} | |||||
if (trap_enotcap_enabled) { | |||||
GTEST_SKIP() << "Sysctl " << oid << " enabled. " | |||||
<< "Skipping tests to avoid non-determinism with results"; | |||||
} | |||||
#endif /* FreeBSD */ | |||||
#ifdef GTEST_SKIP_defined | |||||
#undef GTEST_SKIP | |||||
#endif | |||||
} | |||||
void CreateTemporaryRoot() { | void CreateTemporaryRoot() { | ||||
char *tmpdir_name = tempnam(nullptr, "cptst"); | char *tmpdir_name = tempnam(nullptr, "cptst"); | ||||
ASSERT_NE(tmpdir_name, nullptr); | ASSERT_NE(tmpdir_name, nullptr); | ||||
ASSERT_EQ(mkdir(tmpdir_name, 0700), 0) << | ASSERT_EQ(mkdir(tmpdir_name, 0700), 0) << | ||||
"Could not create temp directory, " << tmpdir_name << ": " << | "Could not create temp directory, " << tmpdir_name << ": " << | ||||
strerror(errno); | strerror(errno); | ||||
tmpdir = std::string(tmpdir_name); | tmpdir = std::string(tmpdir_name); | ||||
free(tmpdir_name); | free(tmpdir_name); | ||||
teardown_tmpdir_ = true; | teardown_tmpdir_ = true; | ||||
} | } | ||||
void TearDown() override { | void TearDown() override { | ||||
if (teardown_tmpdir_) { | if (teardown_tmpdir_) { | ||||
rmdir(tmpdir.c_str()); | rmdir(tmpdir.c_str()); | ||||
} | } | ||||
} | } | ||||
private: | private: | ||||
bool teardown_tmpdir_; | bool teardown_tmpdir_; | ||||
}; | }; | ||||
std::string capsicum_test_bindir; | |||||
int main(int argc, char* argv[]) { | int main(int argc, char* argv[]) { | ||||
// Set up the test program path, so capsicum-test can find programs, like | |||||
// mini-me* when executed from an absolute path. | |||||
{ | |||||
char *new_path, *old_path, *program_name; | |||||
program_name = strdup(argv[0]); | |||||
assert(program_name); | |||||
capsicum_test_bindir = std::string(dirname(program_name)); | |||||
free(program_name); | |||||
old_path = getenv("PATH"); | |||||
assert(old_path); | |||||
assert(asprintf(&new_path, "%s:%s", capsicum_test_bindir.c_str(), | |||||
old_path) > 0); | |||||
assert(setenv("PATH", new_path, 1) == 0); | |||||
} | |||||
::testing::InitGoogleTest(&argc, argv); | ::testing::InitGoogleTest(&argc, argv); | ||||
for (int ii = 1; ii < argc; ii++) { | for (int ii = 1; ii < argc; ii++) { | ||||
if (strcmp(argv[ii], "-v") == 0) { | if (strcmp(argv[ii], "-v") == 0) { | ||||
verbose = true; | verbose = true; | ||||
} else if (strcmp(argv[ii], "-T") == 0) { | } else if (strcmp(argv[ii], "-T") == 0) { | ||||
ii++; | ii++; | ||||
assert(ii < argc); | assert(ii < argc); | ||||
tmpdir = argv[ii]; | tmpdir = argv[ii]; | ||||
▲ Show 20 Lines • Show All 43 Lines • Show Last 20 Lines |
The problem isn't non-determinism, it's just that trap_enotcap causes the process to receive SIGTRAP when a syscall would otherwise return ENOTCAPABLE. There are lots of tests here that explicitly try to trigger that error.