svn commit: r345783 - in head: contrib/capsicum-test tests/sys/capsicum
Enji Cooper
ngie at FreeBSD.org
Tue Sep 3 14:06:08 UTC 2019
Author: ngie
Date: Mon Apr 1 21:24:50 2019
New Revision: 345783
URL: https://svnweb.freebsd.org/changeset/base/345783
Log:
Integrate capsicum-test into the FreeBSD test suite
This change takes capsicum-test from upstream and applies some local changes to make the
tests work on FreeBSD when executed via Kyua.
The local modifications are as follows:
1. Make `OpenatTest.WithFlag` pass with the new dot-dot lookup behavior in FreeBSD 12.x+.
2. capsicum-test references a set of helper binaries: `mini-me`, `mini-me.noexec`, and
`mini-me.setuid`, as part of the execve/fexecve tests, via execve, fexecve, and open.
It achieves this upstream by assuming `mini-me*` is in the current directory, however,
in order for Kyua to execute `capsicum-test`, it needs to provide a full path to
`mini-me*`. In order to achieve this, I made `capsicum-test` cache the executable's
path from argv[0] in main(..) and use the cached value to compute the path to
`mini-me*` as part of the execve/fexecve testcases.
3. The capsicum-test test suite assumes that it's always being run on CAPABILITIES enabled
kernels. However, there's a chance that the test will be run on a host without a
CAPABILITIES enabled kernel, so we must check for the support before running the tests.
The way to achieve this is to add the relevant `feature_present("security_capabilities")`
check to SetupEnvironment::SetUp() and skip the tests when the support is not available.
While here, add a check for `kern.trap_enotcap` being enabled. As noted by markj@ in
https://github.com/google/capsicum-test/issues/23, this sysctl being enabled can trigger
non-deterministic failures. Therefore, the tests should be skipped if this sysctl is
enabled.
All local changes have been submitted to the capsicum-test project
(https://github.com/google/capsicum-test) and are in various stages of review.
Please see the following pull requests for more details:
1. https://github.com/google/capsicum-test/pull/35
2. https://github.com/google/capsicum-test/pull/41
3. https://github.com/google/capsicum-test/pull/42
Reviewed by: asomers
Discussed with: emaste, markj
Approved by: emaste (mentor)
MFC after: 2 months
Differential Revision: https://reviews.freebsd.org/D19758
Added:
head/contrib/capsicum-test/
- copied from r345782, vendor/google/capsicum-test/dist/
Modified:
head/contrib/capsicum-test/capsicum-test-main.cc
head/contrib/capsicum-test/capsicum.h
head/contrib/capsicum-test/fexecve.cc
head/contrib/capsicum-test/openat.cc
head/tests/sys/capsicum/Makefile
Modified: head/contrib/capsicum-test/capsicum-test-main.cc
==============================================================================
--- vendor/google/capsicum-test/dist/capsicum-test-main.cc Mon Apr 1 21:04:13 2019 (r345782)
+++ head/contrib/capsicum-test/capsicum-test-main.cc Mon Apr 1 21:24:50 2019 (r345783)
@@ -2,16 +2,25 @@
#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
@@ -19,6 +28,7 @@ class SetupEnvironment : public ::testing::Environment
public:
SetupEnvironment() : teardown_tmpdir_(false) {}
void SetUp() override {
+ CheckCapsicumSupport();
if (tmpdir.empty()) {
std::cerr << "Generating temporary directory root: ";
CreateTemporaryRoot();
@@ -27,6 +37,31 @@ class SetupEnvironment : public ::testing::Environment
}
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");
@@ -47,7 +82,27 @@ class SetupEnvironment : public ::testing::Environment
bool teardown_tmpdir_;
};
+std::string capsicum_test_bindir;
+
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);
+
+ old_path = getenv("PATH");
+ 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);
for (int ii = 1; ii < argc; ii++) {
if (strcmp(argv[ii], "-v") == 0) {
Modified: head/contrib/capsicum-test/capsicum.h
==============================================================================
--- vendor/google/capsicum-test/dist/capsicum.h Mon Apr 1 21:04:13 2019 (r345782)
+++ head/contrib/capsicum-test/capsicum.h Mon Apr 1 21:24:50 2019 (r345783)
@@ -167,4 +167,9 @@ static inline void cap_rights_describe(const cap_right
#endif /* new/old style rights manipulation */
+#ifdef __cplusplus
+#include <string>
+extern std::string capsicum_test_bindir;
+#endif
+
#endif /*__CAPSICUM_H__*/
Modified: head/contrib/capsicum-test/fexecve.cc
==============================================================================
--- vendor/google/capsicum-test/dist/fexecve.cc Mon Apr 1 21:04:13 2019 (r345782)
+++ head/contrib/capsicum-test/fexecve.cc Mon Apr 1 21:24:50 2019 (r345783)
@@ -1,12 +1,12 @@
-#include <errno.h>
-#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
+#include <errno.h>
#include <fcntl.h>
-#include <unistd.h>
#include <limits.h>
#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
#include <sstream>
@@ -14,41 +14,76 @@
#include "capsicum.h"
#include "capsicum-test.h"
-// We need a program to exec(), but for fexecve() to work in capability
-// mode that program needs to be statically linked (otherwise ld.so will
-// attempt to traverse the filesystem to load (e.g.) /lib/libc.so and
-// fail).
-#define EXEC_PROG "./mini-me"
-#define EXEC_PROG_NOEXEC EXEC_PROG ".noexec"
-#define EXEC_PROG_SETUID EXEC_PROG ".setuid"
-
// Arguments to use in execve() calls.
-static char* argv_pass[] = {(char*)EXEC_PROG, (char*)"--pass", NULL};
-static char* argv_fail[] = {(char*)EXEC_PROG, (char*)"--fail", NULL};
-static char* argv_checkroot[] = {(char*)EXEC_PROG, (char*)"--checkroot", NULL};
static char* null_envp[] = {NULL};
class Execve : public ::testing::Test {
public:
- Execve() : exec_fd_(open(EXEC_PROG, O_RDONLY)) {
+ Execve() : exec_fd_(-1) {
+ // We need a program to exec(), but for fexecve() to work in capability
+ // mode that program needs to be statically linked (otherwise ld.so will
+ // attempt to traverse the filesystem to load (e.g.) /lib/libc.so and
+ // fail).
+ exec_prog_ = capsicum_test_bindir + "/mini-me";
+ exec_prog_noexec_ = capsicum_test_bindir + "/mini-me.noexec";
+ exec_prog_setuid_ = capsicum_test_bindir + "/mini-me.setuid";
+
+ exec_fd_ = open(exec_prog_.c_str(), O_RDONLY);
if (exec_fd_ < 0) {
- fprintf(stderr, "Error! Failed to open %s\n", EXEC_PROG);
+ fprintf(stderr, "Error! Failed to open %s\n", exec_prog_.c_str());
}
+ argv_checkroot_[0] = (char*)exec_prog_.c_str();
+ argv_fail_[0] = (char*)exec_prog_.c_str();
+ argv_pass_[0] = (char*)exec_prog_.c_str();
}
- ~Execve() { if (exec_fd_ >= 0) close(exec_fd_); }
+ ~Execve() {
+ if (exec_fd_ >= 0) {
+ close(exec_fd_);
+ exec_fd_ = -1;
+ }
+ }
protected:
+ char* argv_checkroot_[3] = {nullptr, (char*)"--checkroot", nullptr};
+ char* argv_fail_[3] = {nullptr, (char*)"--fail", nullptr};
+ char* argv_pass_[3] = {nullptr, (char*)"--pass", nullptr};
+ std::string exec_prog_, exec_prog_noexec_, exec_prog_setuid_;
int exec_fd_;
};
+class Fexecve : public Execve {
+ public:
+ Fexecve() : Execve() {}
+};
+
+class FexecveWithScript : public Fexecve {
+ public:
+ FexecveWithScript() :
+ Fexecve(), temp_script_filename_(TmpFile("cap_sh_script")) {}
+
+ void SetUp() override {
+ // First, build an executable shell script
+ int fd = open(temp_script_filename_, O_RDWR|O_CREAT, 0755);
+ EXPECT_OK(fd);
+ const char* contents = "#!/bin/sh\nexit 99\n";
+ EXPECT_OK(write(fd, contents, strlen(contents)));
+ close(fd);
+ }
+ void TearDown() override {
+ (void)::unlink(temp_script_filename_);
+ }
+
+ const char *temp_script_filename_;
+};
+
FORK_TEST_F(Execve, BasicFexecve) {
- EXPECT_OK(fexecve_(exec_fd_, argv_pass, null_envp));
+ EXPECT_OK(fexecve_(exec_fd_, argv_pass_, null_envp));
// Should not reach here, exec() takes over.
EXPECT_TRUE(!"fexecve() should never return");
}
FORK_TEST_F(Execve, InCapMode) {
EXPECT_OK(cap_enter());
- EXPECT_OK(fexecve_(exec_fd_, argv_pass, null_envp));
+ EXPECT_OK(fexecve_(exec_fd_, argv_pass_, null_envp));
// Should not reach here, exec() takes over.
EXPECT_TRUE(!"fexecve() should never return");
}
@@ -60,7 +95,7 @@ FORK_TEST_F(Execve, FailWithoutCap) {
cap_rights_t rights;
cap_rights_init(&rights, 0);
EXPECT_OK(cap_rights_limit(cap_fd, &rights));
- EXPECT_EQ(-1, fexecve_(cap_fd, argv_fail, null_envp));
+ EXPECT_EQ(-1, fexecve_(cap_fd, argv_fail_, null_envp));
EXPECT_EQ(ENOTCAPABLE, errno);
}
@@ -73,59 +108,54 @@ FORK_TEST_F(Execve, SucceedWithCap) {
// rights -- just CAP_FEXECVE|CAP_READ or CAP_FEXECVE would be preferable.
cap_rights_init(&rights, CAP_FEXECVE, CAP_LOOKUP, CAP_READ);
EXPECT_OK(cap_rights_limit(cap_fd, &rights));
- EXPECT_OK(fexecve_(cap_fd, argv_pass, null_envp));
+ EXPECT_OK(fexecve_(cap_fd, argv_pass_, null_envp));
// Should not reach here, exec() takes over.
EXPECT_TRUE(!"fexecve() should have succeeded");
}
-FORK_TEST(Fexecve, ExecutePermissionCheck) {
- int fd = open(EXEC_PROG_NOEXEC, O_RDONLY);
+FORK_TEST_F(Fexecve, ExecutePermissionCheck) {
+ int fd = open(exec_prog_noexec_.c_str(), O_RDONLY);
EXPECT_OK(fd);
if (fd >= 0) {
struct stat data;
EXPECT_OK(fstat(fd, &data));
EXPECT_EQ((mode_t)0, data.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH));
- EXPECT_EQ(-1, fexecve_(fd, argv_fail, null_envp));
+ EXPECT_EQ(-1, fexecve_(fd, argv_fail_, null_envp));
EXPECT_EQ(EACCES, errno);
close(fd);
}
}
-FORK_TEST(Fexecve, SetuidIgnored) {
+FORK_TEST_F(Fexecve, SetuidIgnored) {
if (geteuid() == 0) {
TEST_SKIPPED("requires non-root");
return;
}
- int fd = open(EXEC_PROG_SETUID, O_RDONLY);
+ int fd = open(exec_prog_setuid_.c_str(), O_RDONLY);
EXPECT_OK(fd);
EXPECT_OK(cap_enter());
if (fd >= 0) {
struct stat data;
EXPECT_OK(fstat(fd, &data));
EXPECT_EQ((mode_t)S_ISUID, data.st_mode & S_ISUID);
- EXPECT_OK(fexecve_(fd, argv_checkroot, null_envp));
+ EXPECT_OK(fexecve_(fd, argv_checkroot_, null_envp));
// Should not reach here, exec() takes over.
EXPECT_TRUE(!"fexecve() should have succeeded");
close(fd);
}
}
-FORK_TEST(Fexecve, ExecveFailure) {
+FORK_TEST_F(Fexecve, ExecveFailure) {
EXPECT_OK(cap_enter());
- EXPECT_EQ(-1, execve(argv_fail[0], argv_fail, null_envp));
+ EXPECT_EQ(-1, execve(argv_fail_[0], argv_fail_, null_envp));
EXPECT_EQ(ECAPMODE, errno);
}
-FORK_TEST_ON(Fexecve, CapModeScriptFail, TmpFile("cap_sh_script")) {
- // First, build an executable shell script
- int fd = open(TmpFile("cap_sh_script"), O_RDWR|O_CREAT, 0755);
- EXPECT_OK(fd);
- const char* contents = "#!/bin/sh\nexit 99\n";
- EXPECT_OK(write(fd, contents, strlen(contents)));
- close(fd);
+FORK_TEST_F(FexecveWithScript, CapModeScriptFail) {
+ int fd;
// Open the script file, with CAP_FEXECVE rights.
- fd = open(TmpFile("cap_sh_script"), O_RDONLY);
+ fd = open(temp_script_filename_, O_RDONLY);
cap_rights_t rights;
cap_rights_init(&rights, CAP_FEXECVE, CAP_READ, CAP_SEEK);
EXPECT_OK(cap_rights_limit(fd, &rights));
@@ -133,12 +163,17 @@ FORK_TEST_ON(Fexecve, CapModeScriptFail, TmpFile("cap_
EXPECT_OK(cap_enter()); // Enter capability mode
// Attempt fexecve; should fail, because "/bin/sh" is inaccessible.
- EXPECT_EQ(-1, fexecve_(fd, argv_pass, null_envp));
+ EXPECT_EQ(-1, fexecve_(fd, argv_pass_, null_envp));
}
#ifdef HAVE_EXECVEAT
-TEST(Execveat, NoUpwardTraversal) {
- char *abspath = realpath(EXEC_PROG, NULL);
+class Execveat : public Execve {
+ public:
+ Execveat() : Execve() {}
+};
+
+TEST_F(Execveat, NoUpwardTraversal) {
+ char *abspath = realpath(exec_prog_, NULL);
char cwd[1024];
getcwd(cwd, sizeof(cwd));
@@ -148,9 +183,9 @@ TEST(Execveat, NoUpwardTraversal) {
EXPECT_OK(cap_enter()); // Enter capability mode.
// Can't execveat() an absolute path, even relative to a dfd.
EXPECT_SYSCALL_FAIL(ECAPMODE,
- execveat(AT_FDCWD, abspath, argv_pass, null_envp, 0));
+ execveat(AT_FDCWD, abspath, argv_pass_, null_envp, 0));
EXPECT_SYSCALL_FAIL(E_NO_TRAVERSE_CAPABILITY,
- execveat(dfd, abspath, argv_pass, null_envp, 0));
+ execveat(dfd, abspath, argv_pass_, null_envp, 0));
// Can't execveat() a relative path ("../<dir>/./<exe>").
char *p = cwd + strlen(cwd);
@@ -158,9 +193,9 @@ TEST(Execveat, NoUpwardTraversal) {
char buffer[1024] = "../";
strcat(buffer, ++p);
strcat(buffer, "/");
- strcat(buffer, EXEC_PROG);
+ strcat(buffer, exec_prog_);
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);
}
int status;
Modified: head/contrib/capsicum-test/openat.cc
==============================================================================
--- vendor/google/capsicum-test/dist/openat.cc Mon Apr 1 21:04:13 2019 (r345782)
+++ head/contrib/capsicum-test/openat.cc Mon Apr 1 21:24:50 2019 (r345783)
@@ -148,7 +148,7 @@ FORK_TEST(Openat, Relative) {
}
#define TOPDIR "cap_topdir"
-#define SUBDIR_ABS TOPDIR "/subdir"
+#define SUBDIR TOPDIR "/subdir"
class OpenatTest : public ::testing::Test {
public:
// Build a collection of files, subdirs and symlinks:
@@ -156,20 +156,20 @@ class OpenatTest : public ::testing::Test {
// /topfile
// /subdir/
// /subdir/bottomfile
- // /symlink.samedir -> topfile
- // /dsymlink.samedir -> ./
- // /symlink.down -> subdir/bottomfile
- // /dsymlink.down -> subdir/
- // /symlink.absolute_in -> /tmp/cap_topdir/topfile
- // /dsymlink.absolute_in -> /tmp/cap_topdir/
- // /symlink.absolute_out -> /etc/passwd
- // /dsymlink.absolute_out -> /etc/
- // /symlink.relative_in -> ../../tmp/cap_topdir/topfile
- // /dsymlink.relative_in -> ../../tmp/cap_topdir/
- // /symlink.relative_out -> ../../etc/passwd
- // /dsymlink.relative_out -> ../../etc/
- // /subdir/symlink.up -> ../topfile
- // /subdir/dsymlink.up -> ../
+ // /symlink.samedir -> topfile
+ // /dsymlink.samedir -> ./
+ // /symlink.down -> subdir/bottomfile
+ // /dsymlink.down -> subdir/
+ // /symlink.absolute_out -> /etc/passwd
+ // /dsymlink.absolute_out -> /etc/
+ // /symlink.relative_in -> ../../tmp/cap_topdir/topfile
+ // /dsymlink.relative_in -> ../../tmp/cap_topdir/
+ // /symlink.relative_out -> ../../etc/passwd
+ // /dsymlink.relative_out -> ../../etc/
+ // /subdir/dsymlink.absolute_in -> /tmp/cap_topdir/
+ // /subdir/dsymlink.up -> ../
+ // /subdir/symlink.absolute_in -> /tmp/cap_topdir/topfile
+ // /subdir/symlink.up -> ../topfile
// (In practice, this is a little more complicated because tmpdir might
// not be "/tmp".)
OpenatTest() {
@@ -179,7 +179,7 @@ class OpenatTest : public ::testing::Test {
if (rc < 0) {
EXPECT_EQ(EEXIST, errno);
}
- rc = mkdir(TmpFile(SUBDIR_ABS), 0755);
+ rc = mkdir(TmpFile(SUBDIR), 0755);
EXPECT_OK(rc);
if (rc < 0) {
EXPECT_EQ(EEXIST, errno);
@@ -197,34 +197,34 @@ class OpenatTest : public ::testing::Test {
// Create normal files in each.
CreateFile(TmpFile(TOPDIR "/topfile"), "Top-level file");
- CreateFile(TmpFile(SUBDIR_ABS "/bottomfile"), "File in subdirectory");
+ CreateFile(TmpFile(SUBDIR "/bottomfile"), "File in subdirectory");
// Create various symlinks to files.
EXPECT_OK(symlink("topfile", TmpFile(TOPDIR "/symlink.samedir")));
EXPECT_OK(symlink("subdir/bottomfile", TmpFile(TOPDIR "/symlink.down")));
- EXPECT_OK(symlink(TmpFile(TOPDIR "/topfile"), TmpFile(TOPDIR "/symlink.absolute_in")));
+ EXPECT_OK(symlink(TmpFile(TOPDIR "/topfile"), TmpFile(SUBDIR "/symlink.absolute_in")));
EXPECT_OK(symlink("/etc/passwd", TmpFile(TOPDIR "/symlink.absolute_out")));
std::string dots2top = dots2root + TmpFile(TOPDIR "/topfile");
EXPECT_OK(symlink(dots2top.c_str(), TmpFile(TOPDIR "/symlink.relative_in")));
std::string dots2passwd = dots2root + "/etc/passwd";
EXPECT_OK(symlink(dots2passwd.c_str(), TmpFile(TOPDIR "/symlink.relative_out")));
- EXPECT_OK(symlink("../topfile", TmpFile(SUBDIR_ABS "/symlink.up")));
+ EXPECT_OK(symlink("../topfile", TmpFile(SUBDIR "/symlink.up")));
// Create various symlinks to directories.
EXPECT_OK(symlink("./", TmpFile(TOPDIR "/dsymlink.samedir")));
EXPECT_OK(symlink("subdir/", TmpFile(TOPDIR "/dsymlink.down")));
- EXPECT_OK(symlink(TmpFile(TOPDIR "/"), TmpFile(TOPDIR "/dsymlink.absolute_in")));
+ EXPECT_OK(symlink(TmpFile(TOPDIR "/"), TmpFile(SUBDIR "/dsymlink.absolute_in")));
EXPECT_OK(symlink("/etc/", TmpFile(TOPDIR "/dsymlink.absolute_out")));
std::string dots2cwd = dots2root + tmpdir + "/";
EXPECT_OK(symlink(dots2cwd.c_str(), TmpFile(TOPDIR "/dsymlink.relative_in")));
std::string dots2etc = dots2root + "/etc/";
EXPECT_OK(symlink(dots2etc.c_str(), TmpFile(TOPDIR "/dsymlink.relative_out")));
- EXPECT_OK(symlink("../", TmpFile(SUBDIR_ABS "/dsymlink.up")));
+ EXPECT_OK(symlink("../", TmpFile(SUBDIR "/dsymlink.up")));
// Open directory FDs for those directories and for cwd.
dir_fd_ = open(TmpFile(TOPDIR), O_RDONLY);
EXPECT_OK(dir_fd_);
- sub_fd_ = open(TmpFile(SUBDIR_ABS), O_RDONLY);
+ sub_fd_ = open(TmpFile(SUBDIR), O_RDONLY);
EXPECT_OK(sub_fd_);
cwd_ = openat(AT_FDCWD, ".", O_RDONLY);
EXPECT_OK(cwd_);
@@ -236,23 +236,23 @@ class OpenatTest : public ::testing::Test {
close(cwd_);
close(sub_fd_);
close(dir_fd_);
- unlink(TmpFile(SUBDIR_ABS "/symlink.up"));
- unlink(TmpFile(TOPDIR "/symlink.absolute_in"));
+ unlink(TmpFile(SUBDIR "/symlink.up"));
+ unlink(TmpFile(SUBDIR "/symlink.absolute_in"));
unlink(TmpFile(TOPDIR "/symlink.absolute_out"));
unlink(TmpFile(TOPDIR "/symlink.relative_in"));
unlink(TmpFile(TOPDIR "/symlink.relative_out"));
unlink(TmpFile(TOPDIR "/symlink.down"));
unlink(TmpFile(TOPDIR "/symlink.samedir"));
- unlink(TmpFile(SUBDIR_ABS "/dsymlink.up"));
- unlink(TmpFile(TOPDIR "/dsymlink.absolute_in"));
+ unlink(TmpFile(SUBDIR "/dsymlink.up"));
+ unlink(TmpFile(SUBDIR "/dsymlink.absolute_in"));
unlink(TmpFile(TOPDIR "/dsymlink.absolute_out"));
unlink(TmpFile(TOPDIR "/dsymlink.relative_in"));
unlink(TmpFile(TOPDIR "/dsymlink.relative_out"));
unlink(TmpFile(TOPDIR "/dsymlink.down"));
unlink(TmpFile(TOPDIR "/dsymlink.samedir"));
- unlink(TmpFile(SUBDIR_ABS "/bottomfile"));
+ unlink(TmpFile(SUBDIR "/bottomfile"));
unlink(TmpFile(TOPDIR "/topfile"));
- rmdir(TmpFile(SUBDIR_ABS));
+ rmdir(TmpFile(SUBDIR));
rmdir(TmpFile(TOPDIR));
}
@@ -281,18 +281,18 @@ class OpenatTest : public ::testing::Test {
// Should only be able to open symlinks that stay within the directory.
EXPECT_OPEN_OK(openat(dir_fd_, "symlink.samedir", O_RDONLY|oflag));
EXPECT_OPEN_OK(openat(dir_fd_, "symlink.down", O_RDONLY|oflag));
- EXPECT_OPENAT_FAIL_TRAVERSAL(dir_fd_, "symlink.absolute_in", O_RDONLY|oflag);
EXPECT_OPENAT_FAIL_TRAVERSAL(dir_fd_, "symlink.absolute_out", O_RDONLY|oflag);
EXPECT_OPENAT_FAIL_TRAVERSAL(dir_fd_, "symlink.relative_in", O_RDONLY|oflag);
EXPECT_OPENAT_FAIL_TRAVERSAL(dir_fd_, "symlink.relative_out", O_RDONLY|oflag);
+ EXPECT_OPENAT_FAIL_TRAVERSAL(sub_fd_, "symlink.absolute_in", O_RDONLY|oflag);
EXPECT_OPENAT_FAIL_TRAVERSAL(sub_fd_, "symlink.up", O_RDONLY|oflag);
EXPECT_OPEN_OK(openat(dir_fd_, "dsymlink.samedir/topfile", O_RDONLY|oflag));
EXPECT_OPEN_OK(openat(dir_fd_, "dsymlink.down/bottomfile", O_RDONLY|oflag));
- EXPECT_OPENAT_FAIL_TRAVERSAL(dir_fd_, "dsymlink.absolute_in/topfile", O_RDONLY|oflag);
EXPECT_OPENAT_FAIL_TRAVERSAL(dir_fd_, "dsymlink.absolute_out/passwd", O_RDONLY|oflag);
EXPECT_OPENAT_FAIL_TRAVERSAL(dir_fd_, "dsymlink.relative_in/topfile", O_RDONLY|oflag);
EXPECT_OPENAT_FAIL_TRAVERSAL(dir_fd_, "dsymlink.relative_out/passwd", O_RDONLY|oflag);
+ EXPECT_OPENAT_FAIL_TRAVERSAL(sub_fd_, "dsymlink.absolute_in/topfile", O_RDONLY|oflag);
EXPECT_OPENAT_FAIL_TRAVERSAL(sub_fd_, "dsymlink.up/topfile", O_RDONLY|oflag);
// Although recall that O_NOFOLLOW prevents symlink following in final component.
@@ -310,10 +310,10 @@ TEST_F(OpenatTest, WithCapability) {
// Any kind of symlink can be opened relative to an ordinary directory FD.
EXPECT_OPEN_OK(openat(dir_fd_, "symlink.samedir", O_RDONLY));
EXPECT_OPEN_OK(openat(dir_fd_, "symlink.down", O_RDONLY));
- EXPECT_OPEN_OK(openat(dir_fd_, "symlink.absolute_in", O_RDONLY));
EXPECT_OPEN_OK(openat(dir_fd_, "symlink.absolute_out", O_RDONLY));
EXPECT_OPEN_OK(openat(dir_fd_, "symlink.relative_in", O_RDONLY));
EXPECT_OPEN_OK(openat(dir_fd_, "symlink.relative_out", O_RDONLY));
+ EXPECT_OPEN_OK(openat(sub_fd_, "symlink.absolute_in", O_RDONLY));
EXPECT_OPEN_OK(openat(sub_fd_, "symlink.up", O_RDONLY));
// Now make both DFDs into Capsicum capabilities.
Modified: head/tests/sys/capsicum/Makefile
==============================================================================
--- head/tests/sys/capsicum/Makefile Mon Apr 1 21:04:13 2019 (r345782)
+++ head/tests/sys/capsicum/Makefile Mon Apr 1 21:24:50 2019 (r345783)
@@ -1,11 +1,56 @@
# $FreeBSD$
+.include <src.opts.mk>
+
TESTSDIR= ${TESTSBASE}/sys/capsicum
ATF_TESTS_C+= bindat_connectat
ATF_TESTS_C+= ioctls_test
CFLAGS+= -I${SRCTOP}/tests
+
+.if ${MK_GOOGLETEST} != no
+
+.PATH: ${SRCTOP}/contrib/capsicum-test
+
+GTESTS+= capsicum-test
+
+SRCS.capsicum-test+= \
+ capsicum-test-main.cc \
+ capsicum-test.cc \
+ capability-fd.cc \
+ fexecve.cc \
+ procdesc.cc \
+ capmode.cc \
+ fcntl.cc \
+ ioctl.cc \
+ openat.cc \
+ sysctl.cc \
+ select.cc \
+ mqueue.cc \
+ socket.cc \
+ sctp.cc \
+ capability-fd-pair.cc \
+ overhead.cc \
+ rename.cc
+
+LIBADD.capsicum-test+= gtest pthread
+TEST_METADATA.capsicum-test= required_user="unprivileged"
+
+.for p in mini-me mini-me.noexec mini-me.setuid
+PROGS+= $p
+NO_SHARED.$p=
+SRCS.$p= mini-me.c
+.endfor
+
+BINDIR= ${TESTSDIR}
+
+BINMODE.mini-me.noexec= ${NOBINMODE}
+BINMODE.mini-me.setuid= 4555
+
+WARNS.capsicum-test= 3
+
+.endif
WARNS?= 6
More information about the svn-src-head
mailing list