forked from google/capsicum-test
-
Notifications
You must be signed in to change notification settings - Fork 0
/
capsicum-test-main.cc
160 lines (145 loc) · 4.36 KB
/
capsicum-test-main.cc
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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
#include <sys/types.h>
#ifdef __linux__
#include <sys/vfs.h>
#include <linux/magic.h>
#elif defined(__FreeBSD__)
#include <sys/sysctl.h>
#endif
#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"
// For versions of googletest that lack GTEST_SKIP.
#ifndef GTEST_SKIP
#define GTEST_SKIP GTEST_FAIL
#endif
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() {
#ifdef __FreeBSD__
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.";
}
#endif /* FreeBSD */
}
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;
}
}
#ifdef __linux__
// Check whether our temporary directory is on a tmpfs volume.
struct statfs fsinfo;
statfs(tmpdir.c_str(), &fsinfo);
tmpdir_on_tmpfs = (fsinfo.f_type == TMPFS_MAGIC);
#endif
testing::AddGlobalTestEnvironment(new SetupEnvironment());
return RUN_ALL_TESTS();
}