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