Skip to content

Commit

Permalink
Shift to use GoogleTest's skipped test tracking
Browse files Browse the repository at this point in the history
Drop local hand-rolled mechanism for skipping tests, and instead
use GTEST_SKIP().

Rename test cases that have a condition to include "..If<Condition>"
in their names, so it's clear from the final output why a test might
be skipped.

Split the Capability.SyscallAt test into the parts that need root
and the parts that don't.
  • Loading branch information
daviddrysdale committed Feb 18, 2020
1 parent 95d053d commit 50a6d30
Show file tree
Hide file tree
Showing 8 changed files with 80 additions and 101 deletions.
77 changes: 50 additions & 27 deletions 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 Down
4 changes: 1 addition & 3 deletions capsicum-test-main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -156,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 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;
}
}
}
16 changes: 2 additions & 14 deletions capsicum-test.h
Original file line number Diff line number Diff line change
Expand Up @@ -242,21 +242,9 @@ 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); \
} 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;

Expand Down
5 changes: 2 additions & 3 deletions fexecve.cc
Original file line number Diff line number Diff line change
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
46 changes: 21 additions & 25 deletions linux.cc
Original file line number Diff line number Diff line change
Expand Up @@ -104,10 +104,9 @@ TEST(Linux, TimerFD) {
close(fd);
}

FORK_TEST(Linux, SignalFD) {
FORK_TEST(Linux, SignalFDIfSingleThreaded) {
if (force_mt) {
TEST_SKIPPED("multi-threaded run clashes with signals");
return;
GTEST_SKIP() << "multi-threaded run clashes with signals";
}
pid_t me = getpid();
sigset_t mask;
Expand Down Expand Up @@ -372,8 +371,8 @@ TEST(Linux, fstatat) {

// fanotify support may not be available at compile-time
#ifdef __NR_fanotify_init
TEST(Linux, fanotify) {
REQUIRE_ROOT();
TEST(Linux, FanotifyIfRoot) {
GTEST_SKIP_IF_NOT_ROOT();
int fa_fd = fanotify_init(FAN_CLASS_NOTIF, O_RDWR);
EXPECT_OK(fa_fd);
if (fa_fd < 0) return; // May not be enabled
Expand Down Expand Up @@ -577,7 +576,7 @@ TEST(Linux, inotify) {
unlink(TmpFile("cap_inotify"));
}

TEST(Linux, ArchChange) {
TEST(Linux, ArchChangeIfAvailable) {
const char* prog_candidates[] = {"./mini-me.32", "./mini-me.x32", "./mini-me.64"};
const char* progs[] = {NULL, NULL, NULL};
char* argv_pass[] = {(char*)"to-come", (char*)"--capmode", NULL};
Expand All @@ -593,8 +592,7 @@ TEST(Linux, ArchChange) {
}
}
if (count == 0) {
TEST_SKIPPED("no different-architecture programs available");
return;
GTEST_SKIP() << "no different-architecture programs available";
}

for (int ii = 0; ii < count; ii++) {
Expand All @@ -617,8 +615,8 @@ TEST(Linux, ArchChange) {
}
}

FORK_TEST(Linux, Namespace) {
REQUIRE_ROOT();
FORK_TEST(Linux, NamespaceIfRoot) {
GTEST_SKIP_IF_NOT_ROOT();
pid_t me = getpid_();

// Create a new UTS namespace.
Expand Down Expand Up @@ -758,9 +756,9 @@ static int ChildFunc(void *arg) {
#define STACK_SIZE (1024 * 1024)
static char child_stack[STACK_SIZE];

// TODO(drysdale): fork into a user namespace first so REQUIRE_ROOT can be removed.
TEST(Linux, PidNamespacePdFork) {
REQUIRE_ROOT();
// TODO(drysdale): fork into a user namespace first so GTEST_SKIP_IF_NOT_ROOT can be removed.
TEST(Linux, PidNamespacePdForkIfRoot) {
GTEST_SKIP_IF_NOT_ROOT();
// Pass process descriptors in both directions across a PID namespace boundary.
// pdfork() off a child before we start, holding its process descriptor in a global
// variable that's accessible to children.
Expand Down Expand Up @@ -871,8 +869,8 @@ int NSInit(void *data) {
return 0;
}

TEST(Linux, DeadNSInit) {
REQUIRE_ROOT();
TEST(Linux, DeadNSInitIfRoot) {
GTEST_SKIP_IF_NOT_ROOT();

// Prepare sockets to communicate with child process.
EXPECT_OK(socketpair(AF_UNIX, SOCK_STREAM, 0, shared_sock_fds));
Expand Down Expand Up @@ -916,8 +914,8 @@ TEST(Linux, DeadNSInit) {
}
}

TEST(Linux, DeadNSInit2) {
REQUIRE_ROOT();
TEST(Linux, DeadNSInit2IfRoot) {
GTEST_SKIP_IF_NOT_ROOT();

// Prepare sockets to communicate with child process.
EXPECT_OK(socketpair(AF_UNIX, SOCK_STREAM, 0, shared_sock_fds));
Expand Down Expand Up @@ -1188,7 +1186,7 @@ TEST(Linux, AIO) {
#ifndef KCMP_FILE
#define KCMP_FILE 0
#endif
TEST(Linux, Kcmp) {
TEST(Linux, KcmpIfAvailable) {
// This requires CONFIG_CHECKPOINT_RESTORE in kernel config.
int fd = open("/etc/passwd", O_RDONLY);
EXPECT_OK(fd);
Expand All @@ -1197,8 +1195,7 @@ TEST(Linux, Kcmp) {
errno = 0;
int rc = syscall(__NR_kcmp, parent, parent, KCMP_FILE, fd, fd);
if (rc == -1 && errno == ENOSYS) {
TEST_SKIPPED("kcmp(2) gives -ENOSYS");
return;
GTEST_SKIP() << "kcmp(2) gives -ENOSYS";
}

pid_t child = fork();
Expand Down Expand Up @@ -1362,8 +1359,8 @@ TEST(Linux, InvalidRightsSyscall) {
unlink(TmpFile("cap_invalid_rights"));
}

FORK_TEST_ON(Linux, OpenByHandleAt, TmpFile("cap_openbyhandle_testfile")) {
REQUIRE_ROOT();
FORK_TEST_ON(Linux, OpenByHandleAtIfRoot, TmpFile("cap_openbyhandle_testfile")) {
GTEST_SKIP_IF_NOT_ROOT();
int dir = open(tmpdir.c_str(), O_RDONLY);
EXPECT_OK(dir);
int fd = openat(dir, "cap_openbyhandle_testfile", O_RDWR|O_CREAT, 0644);
Expand Down Expand Up @@ -1424,11 +1421,10 @@ int memfd_create_(const char *name, unsigned int flags) {

#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)
#include <linux/memfd.h> // Requires 3.17 kernel
TEST(Linux, MemFDDeathTest) {
TEST(Linux, MemFDDeathTestIfAvailable) {
int memfd = memfd_create_("capsicum-test", MFD_ALLOW_SEALING);
if (memfd == -1 && errno == ENOSYS) {
TEST_SKIPPED("memfd_create(2) gives -ENOSYS");
return;
GTEST_SKIP() << "memfd_create(2) gives -ENOSYS";
}
const int LEN = 16;
EXPECT_OK(ftruncate(memfd, LEN));
Expand Down
5 changes: 2 additions & 3 deletions mqueue.cc
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,13 @@ void seen_it_done_it(int) {
invoked = true;
}

FORK_TEST_ON_MQ(PosixMqueue, CapMode, "/cap_mq") {
FORK_TEST_ON_MQ(PosixMqueue, CapModeIfMqOpenAvailable, "/cap_mq") {
int mq = mq_open_("/cap_mq", O_RDWR|O_CREAT, 0644, NULL);
// On FreeBSD, turn on message queue support with:
// - 'kldload mqueuefs'
// - 'options P1003_1B_MQUEUE' in kernel build config.
if (mq < 0 && errno == ENOSYS) {
TEST_SKIPPED("mq_open -> -ENOSYS");
return;
GTEST_SKIP() << "mq_open -> -ENOSYS";
}
EXPECT_OK(mq);
cap_rights_t r_read;
Expand Down
4 changes: 2 additions & 2 deletions procdesc.cc
Original file line number Diff line number Diff line change
Expand Up @@ -519,8 +519,8 @@ TEST_F(PipePdfork, CloseLast) {
signal(SIGCHLD, original);
}

FORK_TEST(Pdfork, OtherUser) {
REQUIRE_ROOT();
FORK_TEST(Pdfork, OtherUserIfRoot) {
GTEST_SKIP_IF_NOT_ROOT();
int pd;
pid_t pid = pdfork(&pd, 0);
EXPECT_OK(pid);
Expand Down

0 comments on commit 50a6d30

Please sign in to comment.