Update capsicum-test to git commit 7707222b46abe52d18fd4fbb76115ffdb3e6f74b

This includes changes to use GTEST_SKIP() instead of the local hand-rolled
mechanism as well as a few minor cleanups.
This commit is contained in:
Alex Richardson 2021-02-16 14:35:12 +00:00
commit 2d936e6c99
9 changed files with 121 additions and 125 deletions

View File

@ -1085,8 +1085,6 @@ TEST(Capability, SyscallAt) {
cap_rights_init(&r_no_mkdir, CAP_READ, CAP_LOOKUP, CAP_UNLINKAT, CAP_MKFIFOAT); cap_rights_init(&r_no_mkdir, CAP_READ, CAP_LOOKUP, CAP_UNLINKAT, CAP_MKFIFOAT);
cap_rights_t r_no_mkfifo; cap_rights_t r_no_mkfifo;
cap_rights_init(&r_no_mkfifo, CAP_READ, CAP_LOOKUP, CAP_UNLINKAT, CAP_MKDIRAT); 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_t r_create;
cap_rights_init(&r_create, CAP_READ, CAP_LOOKUP, CAP_CREATE); cap_rights_init(&r_create, CAP_READ, CAP_LOOKUP, CAP_CREATE);
cap_rights_t r_bind; cap_rights_t r_bind;
@ -1106,9 +1104,6 @@ TEST(Capability, SyscallAt) {
int cap_dfd_no_mkfifo = dup(dfd); int cap_dfd_no_mkfifo = dup(dfd);
EXPECT_OK(cap_dfd_no_mkfifo); EXPECT_OK(cap_dfd_no_mkfifo);
EXPECT_OK(cap_rights_limit(cap_dfd_no_mkfifo, &r_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); int cap_dfd_create = dup(dfd);
EXPECT_OK(cap_dfd_create); EXPECT_OK(cap_dfd_create);
EXPECT_OK(cap_rights_limit(cap_dfd_create, &r_create)); EXPECT_OK(cap_rights_limit(cap_dfd_create, &r_create));
@ -1148,24 +1143,7 @@ TEST(Capability, SyscallAt) {
unlink(TmpFile("cap_at_topdir/cap_socket")); unlink(TmpFile("cap_at_topdir/cap_socket"));
#endif #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_all);
close(cap_dfd_no_mknod);
close(cap_dfd_no_mkfifo); close(cap_dfd_no_mkfifo);
close(cap_dfd_no_mkdir); close(cap_dfd_no_mkdir);
close(cap_dfd_no_unlink); close(cap_dfd_no_unlink);
@ -1177,7 +1155,53 @@ TEST(Capability, SyscallAt) {
rmdir(TmpFile("cap_at_topdir")); 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); int fd = open(TmpFile("cap_extattr"), O_RDONLY|O_CREAT, 0644);
EXPECT_OK(fd); EXPECT_OK(fd);
@ -1185,9 +1209,8 @@ FORK_TEST_ON(Capability, ExtendedAttributes, TmpFile("cap_extattr")) {
int rc = fgetxattr_(fd, "user.capsicumtest", buffer, sizeof(buffer)); int rc = fgetxattr_(fd, "user.capsicumtest", buffer, sizeof(buffer));
if (rc < 0 && errno == ENOTSUP) { if (rc < 0 && errno == ENOTSUP) {
// Need user_xattr mount option for non-root users on Linux // Need user_xattr mount option for non-root users on Linux
TEST_SKIPPED("/tmp doesn't support extended attributes");
close(fd); close(fd);
return; GTEST_SKIP() << "/tmp doesn't support extended attributes";
} }
cap_rights_t r_rws; cap_rights_t r_rws;
@ -1278,8 +1301,8 @@ TEST(Capability, PipeUnseekable) {
close(fds[1]); close(fds[1]);
} }
TEST(Capability, NoBypassDAC) { TEST(Capability, NoBypassDACIfRoot) {
REQUIRE_ROOT(); GTEST_SKIP_IF_NOT_ROOT();
int fd = open(TmpFile("cap_root_owned"), O_RDONLY|O_CREAT, 0644); int fd = open(TmpFile("cap_root_owned"), O_RDONLY|O_CREAT, 0644);
EXPECT_OK(fd); EXPECT_OK(fd);
cap_rights_t rights; cap_rights_t rights;
@ -1289,7 +1312,10 @@ TEST(Capability, NoBypassDAC) {
pid_t child = fork(); pid_t child = fork();
if (child == 0) { if (child == 0) {
// Child: change uid to a lesser being // 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. // Attempt to fchmod the file, and fail.
// Having CAP_FCHMOD doesn't bypass the need to comply with DAC policy. // Having CAP_FCHMOD doesn't bypass the need to comply with DAC policy.
int rc = fchmod(fd, 0666); int rc = fchmod(fd, 0666);

View File

@ -84,24 +84,30 @@ private:
std::string capsicum_test_bindir; 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[]) { int main(int argc, char* argv[]) {
// Set up the test program path, so capsicum-test can find programs, like // Set up the test program path, so capsicum-test can find programs, like
// mini-me* when executed from an absolute path. // mini-me* when executed from an absolute path.
{ char *program_name;
char *new_path, *old_path, *program_name;
program_name = strdup(argv[0]); // Copy argv[0], so dirname can do an in-place manipulation of the buffer's
assert(program_name); // contents.
capsicum_test_bindir = std::string(dirname(program_name)); program_name = strdup(argv[0]);
free(program_name); assert(program_name);
capsicum_test_bindir = std::string(dirname(program_name));
free(program_name);
old_path = getenv("PATH"); AddDirectoryToPath(capsicum_test_bindir.c_str());
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++) {
@ -150,7 +156,5 @@ int main(int argc, char* argv[]) {
#endif #endif
testing::AddGlobalTestEnvironment(new SetupEnvironment()); testing::AddGlobalTestEnvironment(new SetupEnvironment());
int rc = RUN_ALL_TESTS(); return RUN_ALL_TESTS();
ShowSkippedTests(std::cerr);
return rc;
} }

View File

@ -76,27 +76,3 @@ char ProcessState(int pid) {
} }
#endif #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;
}
}
}

View File

@ -10,6 +10,7 @@
#include <ios> #include <ios>
#include <ostream> #include <ostream>
#include <string>
#include "gtest/gtest.h" #include "gtest/gtest.h"
@ -75,7 +76,7 @@ const char *TmpFile(const char *pathname);
} \ } \
} else if (pid > 0) { \ } else if (pid > 0) { \
int rc, status; \ int rc, status; \
int remaining_us = 10000000; \ int remaining_us = 30000000; \
while (remaining_us > 0) { \ while (remaining_us > 0) { \
status = 0; \ status = 0; \
rc = waitpid(pid, &status, WNOHANG); \ rc = waitpid(pid, &status, WNOHANG); \
@ -169,12 +170,14 @@ const char *TmpFile(const char *pathname);
} else { \ } else { \
EXPECT_SYSCALL_FAIL(E_NO_TRAVERSE_CAPABILITY, result); \ EXPECT_SYSCALL_FAIL(E_NO_TRAVERSE_CAPABILITY, result); \
} \ } \
if (result >= 0) { close(result); } \
} while (0) } while (0)
#else #else
#define EXPECT_OPENAT_FAIL_TRAVERSAL(fd, path, flags) \ #define EXPECT_OPENAT_FAIL_TRAVERSAL(fd, path, flags) \
do { \ do { \
const int result = openat((fd), (path), (flags)); \ const int result = openat((fd), (path), (flags)); \
EXPECT_SYSCALL_FAIL(E_NO_TRAVERSE_CAPABILITY, result); \ EXPECT_SYSCALL_FAIL(E_NO_TRAVERSE_CAPABILITY, result); \
if (result >= 0) { close(result); } \
} while (0) } while (0)
#endif #endif
@ -241,21 +244,10 @@ char ProcessState(int pid);
#define EXPECT_PID_ZOMBIE(pid) EXPECT_PID_REACHES_STATES(pid, 'Z', 'Z'); #define EXPECT_PID_ZOMBIE(pid) EXPECT_PID_REACHES_STATES(pid, 'Z', 'Z');
#define EXPECT_PID_GONE(pid) EXPECT_PID_REACHES_STATES(pid, '\0', '\0'); #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. // Mark a test that can only be run as root.
#define REQUIRE_ROOT() \ #define GTEST_SKIP_IF_NOT_ROOT() \
if (getuid() != 0) { \ if (getuid() != 0) { GTEST_SKIP() << "requires root"; }
TEST_SKIPPED("requires root"); \
return; \ extern std::string capsicum_test_bindir;
}
#endif // CAPSICUM_TEST_H #endif // CAPSICUM_TEST_H

View File

@ -1,6 +1,6 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/wait.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <limits.h> #include <limits.h>
@ -126,10 +126,9 @@ FORK_TEST_F(Fexecve, ExecutePermissionCheck) {
} }
} }
FORK_TEST_F(Fexecve, SetuidIgnored) { FORK_TEST_F(Fexecve, SetuidIgnoredIfNonRoot) {
if (geteuid() == 0) { if (geteuid() == 0) {
TEST_SKIPPED("requires non-root"); GTEST_SKIP() << "requires non-root";
return;
} }
int fd = open(exec_prog_setuid_.c_str(), O_RDONLY); int fd = open(exec_prog_setuid_.c_str(), O_RDONLY);
EXPECT_OK(fd); EXPECT_OK(fd);
@ -173,7 +172,7 @@ class Execveat : public Execve {
}; };
TEST_F(Execveat, NoUpwardTraversal) { TEST_F(Execveat, NoUpwardTraversal) {
char *abspath = realpath(exec_prog_, NULL); char *abspath = realpath(exec_prog_.c_str(), NULL);
char cwd[1024]; char cwd[1024];
getcwd(cwd, sizeof(cwd)); getcwd(cwd, sizeof(cwd));
@ -193,7 +192,7 @@ TEST_F(Execveat, NoUpwardTraversal) {
char buffer[1024] = "../"; char buffer[1024] = "../";
strcat(buffer, ++p); strcat(buffer, ++p);
strcat(buffer, "/"); strcat(buffer, "/");
strcat(buffer, exec_prog_); strcat(buffer, exec_prog_.c_str());
EXPECT_SYSCALL_FAIL(E_NO_TRAVERSE_CAPABILITY, EXPECT_SYSCALL_FAIL(E_NO_TRAVERSE_CAPABILITY,
execveat(dfd, buffer, argv_pass_, null_envp, 0)); execveat(dfd, buffer, argv_pass_, null_envp, 0));
exit(HasFailure() ? 99 : 123); exit(HasFailure() ? 99 : 123);

View File

@ -104,10 +104,9 @@ TEST(Linux, TimerFD) {
close(fd); close(fd);
} }
FORK_TEST(Linux, SignalFD) { FORK_TEST(Linux, SignalFDIfSingleThreaded) {
if (force_mt) { if (force_mt) {
TEST_SKIPPED("multi-threaded run clashes with signals"); GTEST_SKIP() << "multi-threaded run clashes with signals";
return;
} }
pid_t me = getpid(); pid_t me = getpid();
sigset_t mask; sigset_t mask;
@ -372,8 +371,8 @@ TEST(Linux, fstatat) {
// fanotify support may not be available at compile-time // fanotify support may not be available at compile-time
#ifdef __NR_fanotify_init #ifdef __NR_fanotify_init
TEST(Linux, fanotify) { TEST(Linux, FanotifyIfRoot) {
REQUIRE_ROOT(); GTEST_SKIP_IF_NOT_ROOT();
int fa_fd = fanotify_init(FAN_CLASS_NOTIF, O_RDWR); int fa_fd = fanotify_init(FAN_CLASS_NOTIF, O_RDWR);
EXPECT_OK(fa_fd); EXPECT_OK(fa_fd);
if (fa_fd < 0) return; // May not be enabled if (fa_fd < 0) return; // May not be enabled
@ -577,7 +576,7 @@ TEST(Linux, inotify) {
unlink(TmpFile("cap_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* prog_candidates[] = {"./mini-me.32", "./mini-me.x32", "./mini-me.64"};
const char* progs[] = {NULL, NULL, NULL}; const char* progs[] = {NULL, NULL, NULL};
char* argv_pass[] = {(char*)"to-come", (char*)"--capmode", NULL}; char* argv_pass[] = {(char*)"to-come", (char*)"--capmode", NULL};
@ -593,8 +592,7 @@ TEST(Linux, ArchChange) {
} }
} }
if (count == 0) { if (count == 0) {
TEST_SKIPPED("no different-architecture programs available"); GTEST_SKIP() << "no different-architecture programs available";
return;
} }
for (int ii = 0; ii < count; ii++) { for (int ii = 0; ii < count; ii++) {
@ -617,8 +615,8 @@ TEST(Linux, ArchChange) {
} }
} }
FORK_TEST(Linux, Namespace) { FORK_TEST(Linux, NamespaceIfRoot) {
REQUIRE_ROOT(); GTEST_SKIP_IF_NOT_ROOT();
pid_t me = getpid_(); pid_t me = getpid_();
// Create a new UTS namespace. // Create a new UTS namespace.
@ -758,9 +756,9 @@ static int ChildFunc(void *arg) {
#define STACK_SIZE (1024 * 1024) #define STACK_SIZE (1024 * 1024)
static char child_stack[STACK_SIZE]; static char child_stack[STACK_SIZE];
// TODO(drysdale): fork into a user namespace first so REQUIRE_ROOT can be removed. // TODO(drysdale): fork into a user namespace first so GTEST_SKIP_IF_NOT_ROOT can be removed.
TEST(Linux, PidNamespacePdFork) { TEST(Linux, PidNamespacePdForkIfRoot) {
REQUIRE_ROOT(); GTEST_SKIP_IF_NOT_ROOT();
// Pass process descriptors in both directions across a PID namespace boundary. // 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 // pdfork() off a child before we start, holding its process descriptor in a global
// variable that's accessible to children. // variable that's accessible to children.
@ -871,8 +869,8 @@ int NSInit(void *data) {
return 0; return 0;
} }
TEST(Linux, DeadNSInit) { TEST(Linux, DeadNSInitIfRoot) {
REQUIRE_ROOT(); GTEST_SKIP_IF_NOT_ROOT();
// Prepare sockets to communicate with child process. // Prepare sockets to communicate with child process.
EXPECT_OK(socketpair(AF_UNIX, SOCK_STREAM, 0, shared_sock_fds)); EXPECT_OK(socketpair(AF_UNIX, SOCK_STREAM, 0, shared_sock_fds));
@ -916,8 +914,8 @@ TEST(Linux, DeadNSInit) {
} }
} }
TEST(Linux, DeadNSInit2) { TEST(Linux, DeadNSInit2IfRoot) {
REQUIRE_ROOT(); GTEST_SKIP_IF_NOT_ROOT();
// Prepare sockets to communicate with child process. // Prepare sockets to communicate with child process.
EXPECT_OK(socketpair(AF_UNIX, SOCK_STREAM, 0, shared_sock_fds)); EXPECT_OK(socketpair(AF_UNIX, SOCK_STREAM, 0, shared_sock_fds));
@ -1188,7 +1186,7 @@ TEST(Linux, AIO) {
#ifndef KCMP_FILE #ifndef KCMP_FILE
#define KCMP_FILE 0 #define KCMP_FILE 0
#endif #endif
TEST(Linux, Kcmp) { TEST(Linux, KcmpIfAvailable) {
// This requires CONFIG_CHECKPOINT_RESTORE in kernel config. // This requires CONFIG_CHECKPOINT_RESTORE in kernel config.
int fd = open("/etc/passwd", O_RDONLY); int fd = open("/etc/passwd", O_RDONLY);
EXPECT_OK(fd); EXPECT_OK(fd);
@ -1197,8 +1195,7 @@ TEST(Linux, Kcmp) {
errno = 0; errno = 0;
int rc = syscall(__NR_kcmp, parent, parent, KCMP_FILE, fd, fd); int rc = syscall(__NR_kcmp, parent, parent, KCMP_FILE, fd, fd);
if (rc == -1 && errno == ENOSYS) { if (rc == -1 && errno == ENOSYS) {
TEST_SKIPPED("kcmp(2) gives -ENOSYS"); GTEST_SKIP() << "kcmp(2) gives -ENOSYS";
return;
} }
pid_t child = fork(); pid_t child = fork();
@ -1362,8 +1359,8 @@ TEST(Linux, InvalidRightsSyscall) {
unlink(TmpFile("cap_invalid_rights")); unlink(TmpFile("cap_invalid_rights"));
} }
FORK_TEST_ON(Linux, OpenByHandleAt, TmpFile("cap_openbyhandle_testfile")) { FORK_TEST_ON(Linux, OpenByHandleAtIfRoot, TmpFile("cap_openbyhandle_testfile")) {
REQUIRE_ROOT(); GTEST_SKIP_IF_NOT_ROOT();
int dir = open(tmpdir.c_str(), O_RDONLY); int dir = open(tmpdir.c_str(), O_RDONLY);
EXPECT_OK(dir); EXPECT_OK(dir);
int fd = openat(dir, "cap_openbyhandle_testfile", O_RDWR|O_CREAT, 0644); int fd = openat(dir, "cap_openbyhandle_testfile", O_RDWR|O_CREAT, 0644);
@ -1380,8 +1377,9 @@ FORK_TEST_ON(Linux, OpenByHandleAt, TmpFile("cap_openbyhandle_testfile")) {
fd = open_by_handle_at(dir, fhandle, O_RDONLY); fd = open_by_handle_at(dir, fhandle, O_RDONLY);
EXPECT_OK(fd); EXPECT_OK(fd);
char buffer[200]; char buffer[200];
EXPECT_OK(read(fd, buffer, 199)); ssize_t len = read(fd, buffer, 199);
EXPECT_EQ(std::string(message), std::string(buffer)); EXPECT_OK(len);
EXPECT_EQ(std::string(message), std::string(buffer, len));
close(fd); close(fd);
// Cannot issue open_by_handle_at after entering capability mode. // Cannot issue open_by_handle_at after entering capability mode.
@ -1423,11 +1421,10 @@ int memfd_create_(const char *name, unsigned int flags) {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)
#include <linux/memfd.h> // Requires 3.17 kernel #include <linux/memfd.h> // Requires 3.17 kernel
TEST(Linux, MemFDDeathTest) { TEST(Linux, MemFDDeathTestIfAvailable) {
int memfd = memfd_create_("capsicum-test", MFD_ALLOW_SEALING); int memfd = memfd_create_("capsicum-test", MFD_ALLOW_SEALING);
if (memfd == -1 && errno == ENOSYS) { if (memfd == -1 && errno == ENOSYS) {
TEST_SKIPPED("memfd_create(2) gives -ENOSYS"); GTEST_SKIP() << "memfd_create(2) gives -ENOSYS";
return;
} }
const int LEN = 16; const int LEN = 16;
EXPECT_OK(ftruncate(memfd, LEN)); EXPECT_OK(ftruncate(memfd, LEN));

View File

@ -1,7 +1,7 @@
all: capsicum-test smoketest mini-me mini-me.noexec mini-me.setuid $(EXTRA_PROGS) all: capsicum-test smoketest mini-me mini-me.noexec mini-me.setuid $(EXTRA_PROGS)
OBJECTS=capsicum-test-main.o capsicum-test.o capability-fd.o fexecve.o procdesc.o capmode.o fcntl.o ioctl.o openat.o sysctl.o select.o mqueue.o socket.o sctp.o capability-fd-pair.o linux.o overhead.o rename.o OBJECTS=capsicum-test-main.o capsicum-test.o capability-fd.o fexecve.o procdesc.o capmode.o fcntl.o ioctl.o openat.o sysctl.o select.o mqueue.o socket.o sctp.o capability-fd-pair.o linux.o overhead.o rename.o
GTEST_DIR=gtest-1.8.1 GTEST_DIR=gtest-1.10.0
GTEST_INCS=-I$(GTEST_DIR)/include -I$(GTEST_DIR) GTEST_INCS=-I$(GTEST_DIR)/include -I$(GTEST_DIR)
GTEST_FLAGS=-DGTEST_USE_OWN_TR1_TUPLE=1 -DGTEST_HAS_TR1_TUPLE=1 GTEST_FLAGS=-DGTEST_USE_OWN_TR1_TUPLE=1 -DGTEST_HAS_TR1_TUPLE=1
CXXFLAGS+=$(ARCHFLAG) -Wall -g $(GTEST_INCS) $(GTEST_FLAGS) --std=c++11 CXXFLAGS+=$(ARCHFLAG) -Wall -g $(GTEST_INCS) $(GTEST_FLAGS) --std=c++11
@ -28,7 +28,7 @@ smoketest: $(SMOKETEST_OBJECTS) $(LOCAL_LIBS)
test: capsicum-test mini-me mini-me.noexec mini-me.setuid $(EXTRA_PROGS) test: capsicum-test mini-me mini-me.noexec mini-me.setuid $(EXTRA_PROGS)
./capsicum-test ./capsicum-test
gtest-all.o: gtest-all.o:
$(CXX) $(ARCHFLAG) -I$(GTEST_DIR)/include -I$(GTEST_DIR) $(GTEST_FLAGS) -c ${GTEST_DIR}/src/gtest-all.cc $(CXX) $(CXXFLAGS) $(ARCHFLAG) -I$(GTEST_DIR)/include -I$(GTEST_DIR) $(GTEST_FLAGS) -c ${GTEST_DIR}/src/gtest-all.cc
libgtest.a: gtest-all.o libgtest.a: gtest-all.o
$(AR) -rv libgtest.a gtest-all.o $(AR) -rv libgtest.a gtest-all.o

View File

@ -28,14 +28,13 @@ void seen_it_done_it(int) {
invoked = true; 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); int mq = mq_open_("/cap_mq", O_RDWR|O_CREAT, 0644, NULL);
// On FreeBSD, turn on message queue support with: // On FreeBSD, turn on message queue support with:
// - 'kldload mqueuefs' // - 'kldload mqueuefs'
// - 'options P1003_1B_MQUEUE' in kernel build config. // - 'options P1003_1B_MQUEUE' in kernel build config.
if (mq < 0 && errno == ENOSYS) { if (mq < 0 && errno == ENOSYS) {
TEST_SKIPPED("mq_open -> -ENOSYS"); GTEST_SKIP() << "mq_open -> -ENOSYS";
return;
} }
EXPECT_OK(mq); EXPECT_OK(mq);
cap_rights_t r_read; cap_rights_t r_read;

View File

@ -519,8 +519,8 @@ TEST_F(PipePdfork, CloseLast) {
signal(SIGCHLD, original); signal(SIGCHLD, original);
} }
FORK_TEST(Pdfork, OtherUser) { FORK_TEST(Pdfork, OtherUserIfRoot) {
REQUIRE_ROOT(); GTEST_SKIP_IF_NOT_ROOT();
int pd; int pd;
pid_t pid = pdfork(&pd, 0); pid_t pid = pdfork(&pd, 0);
EXPECT_OK(pid); EXPECT_OK(pid);
@ -531,7 +531,10 @@ FORK_TEST(Pdfork, OtherUser) {
usleep(100); usleep(100);
// Now that the second process has been pdfork()ed, change euid. // Now that the second process has been pdfork()ed, change euid.
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());
if (verbose) fprintf(stderr, "uid=%d euid=%d\n", getuid(), geteuid()); if (verbose) fprintf(stderr, "uid=%d euid=%d\n", getuid(), geteuid());
// Fail to kill child with normal PID operation. // Fail to kill child with normal PID operation.