Skip to content

Commit

Permalink
Update capsicum-test to git commit 7707222b46abe52d18fd4fbb76115ffdb3…
Browse files Browse the repository at this point in the history
…e6f74b

This includes changes to use GTEST_SKIP() instead of the local hand-rolled
mechanism as well as a few minor cleanups.

(cherry picked from commit 2d936e6)
  • Loading branch information
arichardson committed Jul 25, 2021
1 parent fd25224 commit 53b9ebb
Show file tree
Hide file tree
Showing 9 changed files with 121 additions and 125 deletions.
82 changes: 54 additions & 28 deletions contrib/capsicum-test/capability-fd.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1085,8 +1085,6 @@ TEST(Capability, SyscallAt) {
cap_rights_init(&r_no_mkdir, CAP_READ, CAP_LOOKUP, CAP_UNLINKAT, CAP_MKFIFOAT);
cap_rights_t r_no_mkfifo;
cap_rights_init(&r_no_mkfifo, CAP_READ, CAP_LOOKUP, CAP_UNLINKAT, CAP_MKDIRAT);
cap_rights_t r_no_mknod;
cap_rights_init(&r_no_mknod, CAP_READ, CAP_LOOKUP, CAP_UNLINKAT, CAP_MKDIRAT);
cap_rights_t r_create;
cap_rights_init(&r_create, CAP_READ, CAP_LOOKUP, CAP_CREATE);
cap_rights_t r_bind;
Expand All @@ -1106,9 +1104,6 @@ TEST(Capability, SyscallAt) {
int cap_dfd_no_mkfifo = dup(dfd);
EXPECT_OK(cap_dfd_no_mkfifo);
EXPECT_OK(cap_rights_limit(cap_dfd_no_mkfifo, &r_no_mkfifo));
int cap_dfd_no_mknod = dup(dfd);
EXPECT_OK(cap_dfd_no_mknod);
EXPECT_OK(cap_rights_limit(cap_dfd_no_mknod, &r_no_mknod));
int cap_dfd_create = dup(dfd);
EXPECT_OK(cap_dfd_create);
EXPECT_OK(cap_rights_limit(cap_dfd_create, &r_create));
Expand Down Expand Up @@ -1148,24 +1143,7 @@ TEST(Capability, SyscallAt) {
unlink(TmpFile("cap_at_topdir/cap_socket"));
#endif

if (getuid() == 0) {
// Need CAP_MKNODAT to mknodat(2) a device
EXPECT_NOTCAPABLE(mknodat(cap_dfd_no_mknod, "cap_device", S_IFCHR|0755, makedev(99, 123)));
unlink(TmpFile("cap_at_topdir/cap_device"));
EXPECT_OK(mknodat(cap_dfd_all, "cap_device", S_IFCHR|0755, makedev(99, 123)));
unlink(TmpFile("cap_at_topdir/cap_device"));

// Need CAP_MKFIFOAT to mknodat(2) for a FIFO.
EXPECT_NOTCAPABLE(mknodat(cap_dfd_no_mkfifo, "cap_fifo", S_IFIFO|0755, 0));
unlink(TmpFile("cap_at_topdir/cap_fifo"));
EXPECT_OK(mknodat(cap_dfd_all, "cap_fifo", S_IFIFO|0755, 0));
unlink(TmpFile("cap_at_topdir/cap_fifo"));
} else {
TEST_SKIPPED("requires root (partial)");
}

close(cap_dfd_all);
close(cap_dfd_no_mknod);
close(cap_dfd_no_mkfifo);
close(cap_dfd_no_mkdir);
close(cap_dfd_no_unlink);
Expand All @@ -1177,17 +1155,62 @@ TEST(Capability, SyscallAt) {
rmdir(TmpFile("cap_at_topdir"));
}

FORK_TEST_ON(Capability, ExtendedAttributes, TmpFile("cap_extattr")) {
TEST(Capability, SyscallAtIfRoot) {
GTEST_SKIP_IF_NOT_ROOT();
int rc = mkdir(TmpFile("cap_at_topdir"), 0755);
EXPECT_OK(rc);
if (rc < 0 && errno != EEXIST) return;

cap_rights_t r_all;
cap_rights_init(&r_all, CAP_READ, CAP_LOOKUP, CAP_MKNODAT, CAP_UNLINKAT, CAP_MKDIRAT, CAP_MKFIFOAT);
cap_rights_t r_no_mkfifo;
cap_rights_init(&r_no_mkfifo, CAP_READ, CAP_LOOKUP, CAP_UNLINKAT, CAP_MKDIRAT);
cap_rights_t r_no_mknod;
cap_rights_init(&r_no_mknod, CAP_READ, CAP_LOOKUP, CAP_UNLINKAT, CAP_MKDIRAT);

int dfd = open(TmpFile("cap_at_topdir"), O_RDONLY);
EXPECT_OK(dfd);
int cap_dfd_all = dup(dfd);
EXPECT_OK(cap_dfd_all);
EXPECT_OK(cap_rights_limit(cap_dfd_all, &r_all));
int cap_dfd_no_mkfifo = dup(dfd);
EXPECT_OK(cap_dfd_no_mkfifo);
EXPECT_OK(cap_rights_limit(cap_dfd_no_mkfifo, &r_no_mkfifo));
int cap_dfd_no_mknod = dup(dfd);
EXPECT_OK(cap_dfd_no_mknod);
EXPECT_OK(cap_rights_limit(cap_dfd_no_mknod, &r_no_mknod));

// Need CAP_MKNODAT to mknodat(2) a device
EXPECT_NOTCAPABLE(mknodat(cap_dfd_no_mknod, "cap_device", S_IFCHR|0755, makedev(99, 123)));
unlink(TmpFile("cap_at_topdir/cap_device"));
EXPECT_OK(mknodat(cap_dfd_all, "cap_device", S_IFCHR|0755, makedev(99, 123)));
unlink(TmpFile("cap_at_topdir/cap_device"));

// Need CAP_MKFIFOAT to mknodat(2) for a FIFO.
EXPECT_NOTCAPABLE(mknodat(cap_dfd_no_mkfifo, "cap_fifo", S_IFIFO|0755, 0));
unlink(TmpFile("cap_at_topdir/cap_fifo"));
EXPECT_OK(mknodat(cap_dfd_all, "cap_fifo", S_IFIFO|0755, 0));
unlink(TmpFile("cap_at_topdir/cap_fifo"));

close(cap_dfd_all);
close(cap_dfd_no_mknod);
close(cap_dfd_no_mkfifo);
close(dfd);

// Tidy up.
rmdir(TmpFile("cap_at_topdir"));
}

FORK_TEST_ON(Capability, ExtendedAttributesIfAvailable, TmpFile("cap_extattr")) {
int fd = open(TmpFile("cap_extattr"), O_RDONLY|O_CREAT, 0644);
EXPECT_OK(fd);

char buffer[1024];
int rc = fgetxattr_(fd, "user.capsicumtest", buffer, sizeof(buffer));
if (rc < 0 && errno == ENOTSUP) {
// Need user_xattr mount option for non-root users on Linux
TEST_SKIPPED("/tmp doesn't support extended attributes");
close(fd);
return;
GTEST_SKIP() << "/tmp doesn't support extended attributes";
}

cap_rights_t r_rws;
Expand Down Expand Up @@ -1278,8 +1301,8 @@ TEST(Capability, PipeUnseekable) {
close(fds[1]);
}

TEST(Capability, NoBypassDAC) {
REQUIRE_ROOT();
TEST(Capability, NoBypassDACIfRoot) {
GTEST_SKIP_IF_NOT_ROOT();
int fd = open(TmpFile("cap_root_owned"), O_RDONLY|O_CREAT, 0644);
EXPECT_OK(fd);
cap_rights_t rights;
Expand All @@ -1289,7 +1312,10 @@ TEST(Capability, NoBypassDAC) {
pid_t child = fork();
if (child == 0) {
// Child: change uid to a lesser being
setuid(other_uid);
ASSERT_NE(0u, other_uid) << "other_uid not initialized correctly, "
"please pass the -u <uid> flag.";
EXPECT_EQ(0, setuid(other_uid));
EXPECT_EQ(other_uid, getuid());
// Attempt to fchmod the file, and fail.
// Having CAP_FCHMOD doesn't bypass the need to comply with DAC policy.
int rc = fchmod(fd, 0666);
Expand Down
36 changes: 20 additions & 16 deletions contrib/capsicum-test/capsicum-test-main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -84,24 +84,30 @@ class SetupEnvironment : public ::testing::Environment

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 *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);
char *program_name;

old_path = getenv("PATH");
assert(old_path);
// 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);

assert(asprintf(&new_path, "%s:%s", capsicum_test_bindir.c_str(),
old_path) > 0);
assert(setenv("PATH", new_path, 1) == 0);
}
AddDirectoryToPath(capsicum_test_bindir.c_str());

::testing::InitGoogleTest(&argc, argv);
for (int ii = 1; ii < argc; ii++) {
Expand Down Expand Up @@ -150,7 +156,5 @@ int main(int argc, char* argv[]) {
#endif

testing::AddGlobalTestEnvironment(new SetupEnvironment());
int rc = RUN_ALL_TESTS();
ShowSkippedTests(std::cerr);
return rc;
return RUN_ALL_TESTS();
}
24 changes: 0 additions & 24 deletions contrib/capsicum-test/capsicum-test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -76,27 +76,3 @@ char ProcessState(int pid) {
}
#endif
}

typedef std::vector<std::string> TestList;
typedef std::map<std::string, TestList*> SkippedTestMap;
static SkippedTestMap skipped_tests;
void TestSkipped(const char *testcase, const char *test, const std::string& reason) {
if (skipped_tests.find(reason) == skipped_tests.end()) {
skipped_tests[reason] = new TestList;
}
std::string testname(testcase);
testname += ".";
testname += test;
skipped_tests[reason]->push_back(testname);
}

void ShowSkippedTests(std::ostream& os) {
for (SkippedTestMap::iterator skiplist = skipped_tests.begin();
skiplist != skipped_tests.end(); ++skiplist) {
os << "Following tests were skipped because: " << skiplist->first << std::endl;
for (size_t ii = 0; ii < skiplist->second->size(); ++ii) {
const std::string& testname((*skiplist->second)[ii]);
os << " " << testname << std::endl;
}
}
}
24 changes: 8 additions & 16 deletions contrib/capsicum-test/capsicum-test.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

#include <ios>
#include <ostream>
#include <string>

#include "gtest/gtest.h"

Expand Down Expand Up @@ -75,7 +76,7 @@ const char *TmpFile(const char *pathname);
} \
} else if (pid > 0) { \
int rc, status; \
int remaining_us = 10000000; \
int remaining_us = 30000000; \
while (remaining_us > 0) { \
status = 0; \
rc = waitpid(pid, &status, WNOHANG); \
Expand Down Expand Up @@ -169,12 +170,14 @@ const char *TmpFile(const char *pathname);
} else { \
EXPECT_SYSCALL_FAIL(E_NO_TRAVERSE_CAPABILITY, result); \
} \
if (result >= 0) { close(result); } \
} while (0)
#else
#define EXPECT_OPENAT_FAIL_TRAVERSAL(fd, path, flags) \
do { \
const int result = openat((fd), (path), (flags)); \
EXPECT_SYSCALL_FAIL(E_NO_TRAVERSE_CAPABILITY, result); \
if (result >= 0) { close(result); } \
} while (0)
#endif

Expand Down Expand Up @@ -241,21 +244,10 @@ char ProcessState(int pid);
#define EXPECT_PID_ZOMBIE(pid) EXPECT_PID_REACHES_STATES(pid, 'Z', 'Z');
#define EXPECT_PID_GONE(pid) EXPECT_PID_REACHES_STATES(pid, '\0', '\0');

void ShowSkippedTests(std::ostream& os);
void TestSkipped(const char *testcase, const char *test, const std::string& reason);
#define TEST_SKIPPED(reason) \
do { \
const ::testing::TestInfo* const info = ::testing::UnitTest::GetInstance()->current_test_info(); \
std::cerr << "Skipping " << info->test_case_name() << "::" << info->name() << " because: " << reason << std::endl; \
TestSkipped(info->test_case_name(), info->name(), reason); \
GTEST_SKIP(); \
} while (0)

// Mark a test that can only be run as root.
#define REQUIRE_ROOT() \
if (getuid() != 0) { \
TEST_SKIPPED("requires root"); \
return; \
}
#define GTEST_SKIP_IF_NOT_ROOT() \
if (getuid() != 0) { GTEST_SKIP() << "requires root"; }

extern std::string capsicum_test_bindir;

#endif // CAPSICUM_TEST_H
11 changes: 5 additions & 6 deletions contrib/capsicum-test/fexecve.cc
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
Expand Down Expand Up @@ -126,10 +126,9 @@ FORK_TEST_F(Fexecve, ExecutePermissionCheck) {
}
}

FORK_TEST_F(Fexecve, SetuidIgnored) {
FORK_TEST_F(Fexecve, SetuidIgnoredIfNonRoot) {
if (geteuid() == 0) {
TEST_SKIPPED("requires non-root");
return;
GTEST_SKIP() << "requires non-root";
}
int fd = open(exec_prog_setuid_.c_str(), O_RDONLY);
EXPECT_OK(fd);
Expand Down Expand Up @@ -173,7 +172,7 @@ class Execveat : public Execve {
};

TEST_F(Execveat, NoUpwardTraversal) {
char *abspath = realpath(exec_prog_, NULL);
char *abspath = realpath(exec_prog_.c_str(), NULL);
char cwd[1024];
getcwd(cwd, sizeof(cwd));

Expand All @@ -193,7 +192,7 @@ TEST_F(Execveat, NoUpwardTraversal) {
char buffer[1024] = "../";
strcat(buffer, ++p);
strcat(buffer, "/");
strcat(buffer, exec_prog_);
strcat(buffer, exec_prog_.c_str());
EXPECT_SYSCALL_FAIL(E_NO_TRAVERSE_CAPABILITY,
execveat(dfd, buffer, argv_pass_, null_envp, 0));
exit(HasFailure() ? 99 : 123);
Expand Down
Loading

0 comments on commit 53b9ebb

Please sign in to comment.