capsicum-tests: remove Linux support
Now that this project is part of freebsd-src, it no longer needs to be portable. Remove Linux-only tests, cross-os compatibility code, and compatibility with older FreeBSD versions. Leave in place some originally Linux-only tests that could now be ported to FreeBSD, like the pipe2 tests. Sponsored by: ConnectWise Reviewed by: oshogbo Differential Revision: https://reviews.freebsd.org/D54985
This commit is contained in:
@@ -1,9 +1,8 @@
|
||||
# Capsicum User Space Tests
|
||||
|
||||
This directory holds unit tests for [Capsicum](http://www.cl.cam.ac.uk/research/security/capsicum/)
|
||||
This directory holds unit tests for [Capsicum](https://man.freebsd.org/cgi/man.cgi?query=capsicum)
|
||||
object-capabilities. The tests exercise the syscall interface to a Capsicum-enabled operating system,
|
||||
currently either [FreeBSD >=10.x](http://www.freebsd.org) or a modified Linux kernel (the
|
||||
[capsicum-linux](http://github.com/google/capsicum-linux) project).
|
||||
Currently, [FreeBSD >=10.x](http://www.freebsd.org) is the only such operating system.
|
||||
|
||||
The tests are written in C++11 and use the [Google Test](https://code.google.com/p/googletest/)
|
||||
framework, with some additions to fork off particular tests (because a process that enters capability
|
||||
@@ -17,46 +16,15 @@ The original basis for these tests was:
|
||||
written by Robert Watson and Jonathan Anderson for the original FreeBSD 9.x Capsicum implementation
|
||||
- [unit tests](http://git.chromium.org/gitweb/?p=chromiumos/third_party/kernel-capsicum.git;a=tree;f=tools/testing/capsicum_tests;hb=refs/heads/capsicum) written by Meredydd Luff for the original Capsicum-Linux port.
|
||||
|
||||
These tests were coalesced and moved into an independent repository to enable
|
||||
comparative testing across multiple OSes, and then substantially extended.
|
||||
These tests were coalesced and moved into an [independent repository](https://github.com/google/capsicum-test)
|
||||
to enable comparative testing across multiple OSes, and then substantially extended.
|
||||
|
||||
## OS Configuration
|
||||
Subsequently, the [capsicum-linux port](https://github.com/google/capsicum-linux) was abandoned by
|
||||
its maintainers, rendering the independent repository obsolete. So the tests were copied back into
|
||||
the FreeBSD source tree in time for 16.0-RELEASE.
|
||||
|
||||
### Linux
|
||||
|
||||
The following kernel configuration options are needed to run the tests:
|
||||
|
||||
- `CONFIG_SECURITY_CAPSICUM`: enable the Capsicum framework
|
||||
- `CONFIG_PROCDESC`: enable Capsicum process-descriptor functionality
|
||||
- `CONFIG_DEBUG_FS`: enable debug filesystem
|
||||
- `CONFIG_IP_SCTP`: enable SCTP support
|
||||
|
||||
### FreeBSD (>= 10.x)
|
||||
## Configuration
|
||||
|
||||
The following kernel configuration options are needed so that all tests can run:
|
||||
|
||||
- `options P1003_1B_MQUEUE`: Enable POSIX message queues (or `kldload mqueuefs`)
|
||||
|
||||
## Other Dependencies
|
||||
|
||||
### Linux
|
||||
|
||||
The following additional development packages are needed to build the full test suite on Linux.
|
||||
|
||||
- `libcaprights`: See below
|
||||
- `libcap-dev`: Provides headers for POSIX.1e capabilities.
|
||||
- `libsctp1`: Provides SCTP library functions.
|
||||
- `libsctp-dev`: Provides headers for SCTP library functions.
|
||||
|
||||
|
||||
## Linux libcaprights
|
||||
|
||||
The Capsicum userspace library is held in the `libcaprights/` subdirectory. Ideally, this
|
||||
library should be built (with `./configure; make` or `dpkg-buildpackage -uc -us`) and
|
||||
installed (with `make install` or `dpkg -i libcaprights*.deb`) so that the tests will
|
||||
use behave like a normal Capsicum-aware application.
|
||||
|
||||
However, if no installed copy of the library is found, the `GNUmakefile` will attempt
|
||||
to use the local `libcaprights/*.c` source; this requires `./configure` to have been
|
||||
performed in the `libcaprights` subdirectory. The local code is also used for
|
||||
cross-compiled builds of the test suite (e.g. `make ARCH=32` or `make ARCH=x32`).
|
||||
|
||||
@@ -46,143 +46,3 @@ TEST(CapabilityPair, sendfile) {
|
||||
close(sock_fds[1]);
|
||||
unlink(TmpFile("cap_sendfile_in"));
|
||||
}
|
||||
|
||||
#ifdef HAVE_TEE
|
||||
TEST(CapabilityPair, tee) {
|
||||
int pipe1_fds[2];
|
||||
EXPECT_OK(pipe2(pipe1_fds, O_NONBLOCK));
|
||||
int pipe2_fds[2];
|
||||
EXPECT_OK(pipe2(pipe2_fds, O_NONBLOCK));
|
||||
|
||||
// Put some data into pipe1.
|
||||
unsigned char buffer[4] = {1, 2, 3, 4};
|
||||
EXPECT_OK(write(pipe1_fds[1], buffer, 4));
|
||||
|
||||
cap_rights_t r_ro;
|
||||
cap_rights_init(&r_ro, CAP_READ);
|
||||
cap_rights_t r_wo;
|
||||
cap_rights_init(&r_wo, CAP_WRITE);
|
||||
cap_rights_t r_rw;
|
||||
cap_rights_init(&r_rw, CAP_READ, CAP_WRITE);
|
||||
|
||||
// Various attempts to tee into pipe2.
|
||||
int cap_in_wo = dup(pipe1_fds[0]);
|
||||
EXPECT_OK(cap_in_wo);
|
||||
EXPECT_OK(cap_rights_limit(cap_in_wo, &r_wo));
|
||||
int cap_in_rw = dup(pipe1_fds[0]);
|
||||
EXPECT_OK(cap_in_rw);
|
||||
EXPECT_OK(cap_rights_limit(cap_in_rw, &r_rw));
|
||||
int cap_out_ro = dup(pipe2_fds[1]);
|
||||
EXPECT_OK(cap_out_ro);
|
||||
EXPECT_OK(cap_rights_limit(cap_out_ro, &r_ro));
|
||||
int cap_out_rw = dup(pipe2_fds[1]);
|
||||
EXPECT_OK(cap_out_rw);
|
||||
EXPECT_OK(cap_rights_limit(cap_out_rw, &r_rw));
|
||||
|
||||
EXPECT_NOTCAPABLE(tee(cap_in_wo, cap_out_rw, 4, SPLICE_F_NONBLOCK));
|
||||
EXPECT_NOTCAPABLE(tee(cap_in_rw, cap_out_ro, 4, SPLICE_F_NONBLOCK));
|
||||
EXPECT_OK(tee(cap_in_rw, cap_out_rw, 4, SPLICE_F_NONBLOCK));
|
||||
|
||||
close(cap_in_wo);
|
||||
close(cap_in_rw);
|
||||
close(cap_out_ro);
|
||||
close(cap_out_rw);
|
||||
close(pipe1_fds[0]);
|
||||
close(pipe1_fds[1]);
|
||||
close(pipe2_fds[0]);
|
||||
close(pipe2_fds[1]);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SPLICE
|
||||
TEST(CapabilityPair, splice) {
|
||||
int pipe1_fds[2];
|
||||
EXPECT_OK(pipe2(pipe1_fds, O_NONBLOCK));
|
||||
int pipe2_fds[2];
|
||||
EXPECT_OK(pipe2(pipe2_fds, O_NONBLOCK));
|
||||
|
||||
// Put some data into pipe1.
|
||||
unsigned char buffer[4] = {1, 2, 3, 4};
|
||||
EXPECT_OK(write(pipe1_fds[1], buffer, 4));
|
||||
|
||||
cap_rights_t r_ro;
|
||||
cap_rights_init(&r_ro, CAP_READ);
|
||||
cap_rights_t r_wo;
|
||||
cap_rights_init(&r_wo, CAP_WRITE);
|
||||
cap_rights_t r_rs;
|
||||
cap_rights_init(&r_rs, CAP_READ, CAP_SEEK);
|
||||
cap_rights_t r_ws;
|
||||
cap_rights_init(&r_ws, CAP_WRITE, CAP_SEEK);
|
||||
|
||||
// Various attempts to splice.
|
||||
int cap_in_wo = dup(pipe1_fds[0]);
|
||||
EXPECT_OK(cap_in_wo);
|
||||
EXPECT_OK(cap_rights_limit(cap_in_wo, &r_wo));
|
||||
int cap_in_ro = dup(pipe1_fds[0]);
|
||||
EXPECT_OK(cap_in_ro);
|
||||
EXPECT_OK(cap_rights_limit(cap_in_ro, &r_ro));
|
||||
int cap_in_ro_seek = dup(pipe1_fds[0]);
|
||||
EXPECT_OK(cap_in_ro_seek);
|
||||
EXPECT_OK(cap_rights_limit(cap_in_ro_seek, &r_rs));
|
||||
int cap_out_wo = dup(pipe2_fds[1]);
|
||||
EXPECT_OK(cap_out_wo);
|
||||
EXPECT_OK(cap_rights_limit(cap_out_wo, &r_wo));
|
||||
int cap_out_ro = dup(pipe2_fds[1]);
|
||||
EXPECT_OK(cap_out_ro);
|
||||
EXPECT_OK(cap_rights_limit(cap_out_ro, &r_ro));
|
||||
int cap_out_wo_seek = dup(pipe2_fds[1]);
|
||||
EXPECT_OK(cap_out_wo_seek);
|
||||
EXPECT_OK(cap_rights_limit(cap_out_wo_seek, &r_ws));
|
||||
|
||||
EXPECT_NOTCAPABLE(splice(cap_in_ro, NULL, cap_out_wo_seek, NULL, 4, SPLICE_F_NONBLOCK));
|
||||
EXPECT_NOTCAPABLE(splice(cap_in_wo, NULL, cap_out_wo_seek, NULL, 4, SPLICE_F_NONBLOCK));
|
||||
EXPECT_NOTCAPABLE(splice(cap_in_ro_seek, NULL, cap_out_ro, NULL, 4, SPLICE_F_NONBLOCK));
|
||||
EXPECT_NOTCAPABLE(splice(cap_in_ro_seek, NULL, cap_out_wo, NULL, 4, SPLICE_F_NONBLOCK));
|
||||
EXPECT_OK(splice(cap_in_ro_seek, NULL, cap_out_wo_seek, NULL, 4, SPLICE_F_NONBLOCK));
|
||||
|
||||
close(cap_in_wo);
|
||||
close(cap_in_ro);
|
||||
close(cap_in_ro_seek);
|
||||
close(cap_out_wo);
|
||||
close(cap_out_ro);
|
||||
close(cap_out_wo_seek);
|
||||
close(pipe1_fds[0]);
|
||||
close(pipe1_fds[1]);
|
||||
close(pipe2_fds[0]);
|
||||
close(pipe2_fds[1]);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_VMSPLICE
|
||||
// Although it only involves a single file descriptor, test vmsplice(2) here too.
|
||||
TEST(CapabilityPair, vmsplice) {
|
||||
int pipe_fds[2];
|
||||
EXPECT_OK(pipe2(pipe_fds, O_NONBLOCK));
|
||||
|
||||
cap_rights_t r_ro;
|
||||
cap_rights_init(&r_ro, CAP_READ);
|
||||
cap_rights_t r_rw;
|
||||
cap_rights_init(&r_rw, CAP_READ, CAP_WRITE);
|
||||
|
||||
int cap_ro = dup(pipe_fds[1]);
|
||||
EXPECT_OK(cap_ro);
|
||||
EXPECT_OK(cap_rights_limit(cap_ro, &r_ro));
|
||||
int cap_rw = dup(pipe_fds[1]);
|
||||
EXPECT_OK(cap_rw);
|
||||
EXPECT_OK(cap_rights_limit(cap_rw, &r_rw));
|
||||
|
||||
unsigned char buffer[4] = {1, 2, 3, 4};
|
||||
struct iovec iov;
|
||||
memset(&iov, 0, sizeof(iov));
|
||||
iov.iov_base = buffer;
|
||||
iov.iov_len = sizeof(buffer);
|
||||
|
||||
EXPECT_NOTCAPABLE(vmsplice(cap_ro, &iov, 1, SPLICE_F_NONBLOCK));
|
||||
EXPECT_OK(vmsplice(cap_rw, &iov, 1, SPLICE_F_NONBLOCK));
|
||||
|
||||
close(cap_ro);
|
||||
close(cap_rw);
|
||||
close(pipe_fds[0]);
|
||||
close(pipe_fds[1]);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -110,40 +110,11 @@ static right_info known_rights[] = {
|
||||
RIGHTS_INFO(CAP_KQUEUE),
|
||||
/* Rights that are only present in some version or some OS, and so are #ifdef'ed */
|
||||
/* LINKAT got split */
|
||||
#ifdef CAP_LINKAT
|
||||
RIGHTS_INFO(CAP_LINKAT),
|
||||
#endif
|
||||
#ifdef CAP_LINKAT_SOURCE
|
||||
RIGHTS_INFO(CAP_LINKAT_SOURCE),
|
||||
#endif
|
||||
#ifdef CAP_LINKAT_TARGET
|
||||
RIGHTS_INFO(CAP_LINKAT_TARGET),
|
||||
#endif
|
||||
/* Linux aliased some FD operations for pdgetpid/pdkill */
|
||||
#ifdef CAP_PDGETPID_FREEBSD
|
||||
RIGHTS_INFO(CAP_PDGETPID_FREEBSD),
|
||||
#endif
|
||||
#ifdef CAP_PDKILL_FREEBSD
|
||||
RIGHTS_INFO(CAP_PDKILL_FREEBSD),
|
||||
#endif
|
||||
/* Linux-specific rights */
|
||||
#ifdef CAP_FSIGNAL
|
||||
RIGHTS_INFO(CAP_FSIGNAL),
|
||||
#endif
|
||||
#ifdef CAP_EPOLL_CTL
|
||||
RIGHTS_INFO(CAP_EPOLL_CTL),
|
||||
#endif
|
||||
#ifdef CAP_NOTIFY
|
||||
RIGHTS_INFO(CAP_NOTIFY),
|
||||
#endif
|
||||
#ifdef CAP_SETNS
|
||||
RIGHTS_INFO(CAP_SETNS),
|
||||
#endif
|
||||
#ifdef CAP_PERFMON
|
||||
RIGHTS_INFO(CAP_PERFMON),
|
||||
#endif
|
||||
#ifdef CAP_BPF
|
||||
RIGHTS_INFO(CAP_BPF),
|
||||
#endif
|
||||
/* Rights in later versions of FreeBSD (>10.0) */
|
||||
};
|
||||
@@ -152,7 +123,7 @@ void ShowCapRights(FILE *out, int fd) {
|
||||
size_t ii;
|
||||
bool first = true;
|
||||
cap_rights_t rights;
|
||||
CAP_SET_NONE(&rights);
|
||||
CAP_NONE(&rights);
|
||||
if (cap_rights_get(fd, &rights) < 0) {
|
||||
fprintf(out, "Failed to get rights for fd %d: errno %d\n", fd, errno);
|
||||
return;
|
||||
@@ -210,11 +181,11 @@ FORK_TEST(Capability, CapNew) {
|
||||
cap_rights_t r_rws;
|
||||
cap_rights_init(&r_rws, CAP_READ, CAP_WRITE, CAP_SEEK);
|
||||
cap_rights_t r_all;
|
||||
CAP_SET_ALL(&r_all);
|
||||
CAP_ALL(&r_all);
|
||||
|
||||
int cap_fd = dup(STDOUT_FILENO);
|
||||
cap_rights_t rights;
|
||||
CAP_SET_NONE(&rights);
|
||||
CAP_NONE(&rights);
|
||||
EXPECT_OK(cap_rights_get(cap_fd, &rights));
|
||||
EXPECT_RIGHTS_EQ(&r_all, &rights);
|
||||
|
||||
@@ -511,7 +482,7 @@ static void TryFileOps(int fd, cap_rights_t rights) {
|
||||
close(cap_cap_fd);
|
||||
|
||||
char ch;
|
||||
CHECK_RIGHT_RESULT(read(cap_fd, &ch, sizeof(ch)), rights, CAP_READ, CAP_SEEK_ASWAS);
|
||||
CHECK_RIGHT_RESULT(read(cap_fd, &ch, sizeof(ch)), rights, CAP_READ, 0);
|
||||
|
||||
ssize_t len1 = pread(cap_fd, &ch, sizeof(ch), 0);
|
||||
CHECK_RIGHT_RESULT(len1, rights, CAP_PREAD);
|
||||
@@ -519,11 +490,10 @@ static void TryFileOps(int fd, cap_rights_t rights) {
|
||||
CHECK_RIGHT_RESULT(len2, rights, CAP_PREAD);
|
||||
EXPECT_EQ(len1, len2);
|
||||
|
||||
CHECK_RIGHT_RESULT(write(cap_fd, &ch, sizeof(ch)), rights, CAP_WRITE, CAP_SEEK_ASWAS);
|
||||
CHECK_RIGHT_RESULT(write(cap_fd, &ch, sizeof(ch)), rights, CAP_WRITE, 0);
|
||||
CHECK_RIGHT_RESULT(pwrite(cap_fd, &ch, sizeof(ch), 0), rights, CAP_PWRITE);
|
||||
CHECK_RIGHT_RESULT(lseek(cap_fd, 0, SEEK_SET), rights, CAP_SEEK);
|
||||
|
||||
#ifdef HAVE_CHFLAGS
|
||||
// Note: this is not expected to work over NFS.
|
||||
struct statfs sf;
|
||||
EXPECT_OK(fstatfs(fd, &sf));
|
||||
@@ -531,7 +501,6 @@ static void TryFileOps(int fd, cap_rights_t rights) {
|
||||
if (!is_nfs) {
|
||||
CHECK_RIGHT_RESULT(fchflags(cap_fd, UF_NODUMP), rights, CAP_FCHFLAGS);
|
||||
}
|
||||
#endif
|
||||
|
||||
CHECK_RIGHT_MMAP_RESULT(mmap(NULL, getpagesize(), PROT_NONE, MAP_SHARED, cap_fd, 0),
|
||||
rights, CAP_MMAP);
|
||||
@@ -551,9 +520,6 @@ static void TryFileOps(int fd, cap_rights_t rights) {
|
||||
rights, CAP_MMAP_RWX);
|
||||
|
||||
CHECK_RIGHT_RESULT(fsync(cap_fd), rights, CAP_FSYNC);
|
||||
#ifdef HAVE_SYNC_FILE_RANGE
|
||||
CHECK_RIGHT_RESULT(sync_file_range(cap_fd, 0, 1, 0), rights, CAP_FSYNC, CAP_SEEK);
|
||||
#endif
|
||||
|
||||
int rc = fcntl(cap_fd, F_GETFL);
|
||||
CHECK_RIGHT_RESULT(rc, rights, CAP_FCNTL);
|
||||
@@ -575,10 +541,6 @@ static void TryFileOps(int fd, cap_rights_t rights) {
|
||||
struct statfs cap_sf;
|
||||
CHECK_RIGHT_RESULT(fstatfs(cap_fd, &cap_sf), rights, CAP_FSTATFS);
|
||||
|
||||
#ifdef HAVE_FPATHCONF
|
||||
CHECK_RIGHT_RESULT(fpathconf(cap_fd, _PC_NAME_MAX), rights, CAP_FPATHCONF);
|
||||
#endif
|
||||
|
||||
CHECK_RIGHT_RESULT(futimes(cap_fd, NULL), rights, CAP_FUTIMES);
|
||||
|
||||
struct pollfd pollfd;
|
||||
@@ -806,14 +768,12 @@ static void TryDirOps(int dirfd, cap_rights_t rights) {
|
||||
}
|
||||
EXPECT_OK(unlinkat(dirfd, "cap_fsync", 0));
|
||||
|
||||
#ifdef HAVE_CHFLAGSAT
|
||||
rc = openat(dirfd, "cap_chflagsat", O_CREAT, 0600);
|
||||
EXPECT_OK(rc);
|
||||
EXPECT_OK(close(rc));
|
||||
rc = chflagsat(dfd_cap, "cap_chflagsat", UF_NODUMP, 0);
|
||||
CHECK_RIGHT_RESULT(rc, rights, CAP_CHFLAGSAT, CAP_LOOKUP);
|
||||
EXPECT_OK(unlinkat(dirfd, "cap_chflagsat", 0));
|
||||
#endif
|
||||
|
||||
rc = openat(dirfd, "cap_fchownat", O_CREAT, 0600);
|
||||
EXPECT_OK(rc);
|
||||
@@ -871,13 +831,11 @@ static void TryDirOps(int dirfd, cap_rights_t rights) {
|
||||
EXPECT_OK(unlinkat(dirfd, "cap_mkdirat", AT_REMOVEDIR));
|
||||
}
|
||||
|
||||
#ifdef HAVE_MKFIFOAT
|
||||
rc = mkfifoat(dfd_cap, "cap_mkfifoat", 0600);
|
||||
CHECK_RIGHT_RESULT(rc, rights, CAP_MKFIFOAT, CAP_LOOKUP);
|
||||
if (rc >= 0) {
|
||||
EXPECT_OK(unlinkat(dirfd, "cap_mkfifoat", 0));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (getuid() == 0) {
|
||||
rc = mknodat(dfd_cap, "cap_mknodat", S_IFCHR | 0600, 0);
|
||||
@@ -980,12 +938,10 @@ FORK_TEST(Capability, DirOperations) {
|
||||
DirOperationsTest(0);
|
||||
}
|
||||
|
||||
#ifdef O_PATH
|
||||
FORK_TEST(Capability, PathDirOperations) {
|
||||
// Make the dfd in the test a path-only file descriptor.
|
||||
DirOperationsTest(O_PATH);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void TryReadWrite(int cap_fd) {
|
||||
char buffer[64];
|
||||
@@ -1136,22 +1092,6 @@ TEST(Capability, SyscallAt) {
|
||||
EXPECT_OK(mkfifoat(cap_dfd_all, "cap_fifo", 0755));
|
||||
unlink(TmpFile("cap_at_topdir/cap_fifo"));
|
||||
|
||||
#ifdef HAVE_MKNOD_REG
|
||||
// Need CAP_CREATE to create a regular file with mknodat(2).
|
||||
EXPECT_NOTCAPABLE(mknodat(cap_dfd_all, "cap_regular", S_IFREG|0755, 0));
|
||||
unlink(TmpFile("cap_at_topdir/cap_regular"));
|
||||
EXPECT_OK(mknodat(cap_dfd_create, "cap_regular", S_IFREG|0755, 0));
|
||||
unlink(TmpFile("cap_at_topdir/cap_regular"));
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_MKNOD_SOCKET
|
||||
// Need CAP_BIND to create a UNIX domain socket with mknodat(2).
|
||||
EXPECT_NOTCAPABLE(mknodat(cap_dfd_all, "cap_socket", S_IFSOCK|0755, 0));
|
||||
unlink(TmpFile("cap_at_topdir/cap_socket"));
|
||||
EXPECT_OK(mknodat(cap_dfd_bind, "cap_socket", S_IFSOCK|0755, 0));
|
||||
unlink(TmpFile("cap_at_topdir/cap_socket"));
|
||||
#endif
|
||||
|
||||
close(cap_dfd_all);
|
||||
close(cap_dfd_no_mkfifo);
|
||||
close(cap_dfd_no_mkdir);
|
||||
|
||||
@@ -3,9 +3,7 @@
|
||||
// whether or not they return the expected ECAPMODE.
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#ifdef __FreeBSD__
|
||||
#include <sys/sockio.h>
|
||||
#endif
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/mman.h>
|
||||
@@ -69,18 +67,14 @@ FORK_TEST_F(WithFiles, DisallowedFileSyscalls) {
|
||||
EXPECT_CAPMODE(access(TmpFile("cap_capmode_access"), F_OK));
|
||||
EXPECT_CAPMODE(acct(TmpFile("cap_capmode_acct")));
|
||||
EXPECT_CAPMODE(chdir(TmpFile("cap_capmode_chdir")));
|
||||
#ifdef HAVE_CHFLAGS
|
||||
EXPECT_CAPMODE(chflags(TmpFile("cap_capmode_chflags"), UF_NODUMP));
|
||||
#endif
|
||||
EXPECT_CAPMODE(chmod(TmpFile("cap_capmode_chmod"), 0644));
|
||||
EXPECT_CAPMODE(chown(TmpFile("cap_capmode_chown"), -1, -1));
|
||||
EXPECT_CAPMODE(chroot(TmpFile("cap_capmode_chroot")));
|
||||
EXPECT_CAPMODE(creat(TmpFile("cap_capmode_creat"), 0644));
|
||||
EXPECT_CAPMODE(fchdir(fd_dir_));
|
||||
#ifdef HAVE_GETFSSTAT
|
||||
struct statfs statfs;
|
||||
EXPECT_CAPMODE(getfsstat(&statfs, sizeof(statfs), MNT_NOWAIT));
|
||||
#endif
|
||||
EXPECT_CAPMODE(link(TmpFile("foo"), TmpFile("bar")));
|
||||
struct stat sb;
|
||||
EXPECT_CAPMODE(lstat(TmpFile("cap_capmode_lstat"), &sb));
|
||||
@@ -89,9 +83,7 @@ FORK_TEST_F(WithFiles, DisallowedFileSyscalls) {
|
||||
EXPECT_CAPMODE(open("/dev/null", O_RDWR));
|
||||
char buf[64];
|
||||
EXPECT_CAPMODE(readlink(TmpFile("cap_capmode_readlink"), buf, sizeof(buf)));
|
||||
#ifdef HAVE_REVOKE
|
||||
EXPECT_CAPMODE(revoke(TmpFile("cap_capmode_revoke")));
|
||||
#endif
|
||||
EXPECT_CAPMODE(stat(TmpFile("cap_capmode_stat"), &sb));
|
||||
EXPECT_CAPMODE(symlink(TmpFile("cap_capmode_symlink_from"), TmpFile("cap_capmode_symlink_to")));
|
||||
EXPECT_CAPMODE(unlink(TmpFile("cap_capmode_unlink")));
|
||||
@@ -122,9 +114,7 @@ FORK_TEST_F(WithFiles, AllowedFileSyscalls) {
|
||||
int fd_dup = dup(fd_file_);
|
||||
EXPECT_OK(fd_dup);
|
||||
EXPECT_OK(dup2(fd_file_, fd_dup));
|
||||
#ifdef HAVE_DUP3
|
||||
EXPECT_OK(dup3(fd_file_, fd_dup, 0));
|
||||
#endif
|
||||
if (fd_dup >= 0) close(fd_dup);
|
||||
|
||||
struct stat sb;
|
||||
@@ -134,12 +124,10 @@ FORK_TEST_F(WithFiles, AllowedFileSyscalls) {
|
||||
EXPECT_OK(read(fd_file_, &ch, sizeof(ch)));
|
||||
EXPECT_OK(write(fd_file_, &ch, sizeof(ch)));
|
||||
|
||||
#ifdef HAVE_CHFLAGS
|
||||
rc = fchflags(fd_file_, UF_NODUMP);
|
||||
if (rc < 0) {
|
||||
EXPECT_NE(ECAPMODE, errno);
|
||||
}
|
||||
#endif
|
||||
|
||||
char buf[1024];
|
||||
rc = getdents_(fd_dir_, (void*)buf, sizeof(buf));
|
||||
@@ -152,7 +140,7 @@ FORK_TEST_F(WithFiles, AllowedFileSyscalls) {
|
||||
struct iovec io;
|
||||
io.iov_base = data;
|
||||
io.iov_len = 2;
|
||||
#if !defined(__i386__) && !defined(__linux__)
|
||||
#if !defined(__i386__)
|
||||
// TODO(drysdale): reinstate these tests for 32-bit runs when possible
|
||||
// libc bug is fixed.
|
||||
EXPECT_OK(pwritev(fd_file_, &io, 1, 0));
|
||||
@@ -160,18 +148,6 @@ FORK_TEST_F(WithFiles, AllowedFileSyscalls) {
|
||||
#endif
|
||||
EXPECT_OK(writev(fd_file_, &io, 1));
|
||||
EXPECT_OK(readv(fd_file_, &io, 1));
|
||||
|
||||
#ifdef HAVE_SYNCFS
|
||||
EXPECT_OK(syncfs(fd_file_));
|
||||
#endif
|
||||
#ifdef HAVE_SYNC_FILE_RANGE
|
||||
EXPECT_OK(sync_file_range(fd_file_, 0, 1, 0));
|
||||
#endif
|
||||
#ifdef HAVE_READAHEAD
|
||||
if (!tmpdir_on_tmpfs) { // tmpfs doesn't support readahead(2)
|
||||
EXPECT_OK(readahead(fd_file_, 0, 1));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
FORK_TEST_F(WithFiles, AllowedSocketSyscalls) {
|
||||
@@ -301,19 +277,10 @@ FORK_TEST(Capmode, AllowedIdentifierSyscalls) {
|
||||
gid_t egid;
|
||||
gid_t sgid;
|
||||
EXPECT_OK(getresgid(&rgid, &egid, &sgid));
|
||||
#ifdef HAVE_GETLOGIN
|
||||
EXPECT_TRUE(getlogin() != NULL);
|
||||
#endif
|
||||
|
||||
// Set various identifiers (to their existing values).
|
||||
EXPECT_OK(setgid(my_gid));
|
||||
#ifdef HAVE_SETFSGID
|
||||
EXPECT_OK(setfsgid(my_gid));
|
||||
#endif
|
||||
EXPECT_OK(setuid(my_uid));
|
||||
#ifdef HAVE_SETFSUID
|
||||
EXPECT_OK(setfsuid(my_uid));
|
||||
#endif
|
||||
EXPECT_OK(setregid(my_gid, my_gid));
|
||||
EXPECT_OK(setresgid(my_gid, my_gid, my_gid));
|
||||
EXPECT_OK(setreuid(my_uid, my_uid));
|
||||
@@ -410,14 +377,6 @@ FORK_TEST(Capmode, AllowedPipeSyscalls) {
|
||||
int rc = pipe(fd2);
|
||||
EXPECT_EQ(0, rc);
|
||||
|
||||
#ifdef HAVE_VMSPLICE
|
||||
char buf[11] = "0123456789";
|
||||
struct iovec iov;
|
||||
iov.iov_base = buf;
|
||||
iov.iov_len = sizeof(buf);
|
||||
EXPECT_FAIL_NOT_CAPMODE(vmsplice(fd2[0], &iov, 1, SPLICE_F_NONBLOCK));
|
||||
#endif
|
||||
|
||||
if (rc == 0) {
|
||||
close(fd2[0]);
|
||||
close(fd2[1]);
|
||||
@@ -605,7 +564,6 @@ FORK_TEST_F(WithFiles, AllowedMiscSyscalls) {
|
||||
|
||||
// TODO(FreeBSD): ktrace
|
||||
|
||||
#ifdef HAVE_SYSARCH
|
||||
// sysarch() is, by definition, architecture-dependent
|
||||
#if defined (__amd64__) || defined (__i386__)
|
||||
long sysarch_arg = 0;
|
||||
@@ -613,14 +571,13 @@ FORK_TEST_F(WithFiles, AllowedMiscSyscalls) {
|
||||
#else
|
||||
// TOOD(jra): write a test for other architectures, like arm
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void *thread_fn(void *p) {
|
||||
int fd = (int)(intptr_t)p;
|
||||
if (verbose) fprintf(stderr, " thread waiting to run\n");
|
||||
AWAIT_INT_MESSAGE(fd, MSG_PARENT_CHILD_SHOULD_RUN);
|
||||
EXPECT_OK(getpid_());
|
||||
EXPECT_OK(getpid());
|
||||
EXPECT_CAPMODE(open("/dev/null", O_RDWR));
|
||||
// Return whether there have been any failures to the main thread.
|
||||
void *rval = (void *)(intptr_t)testing::Test::HasFailure();
|
||||
@@ -670,7 +627,7 @@ FORK_TEST(Capmode, NewThread) {
|
||||
SEND_INT_MESSAGE(proc_pipe[0], MSG_PARENT_CHILD_SHOULD_RUN);
|
||||
|
||||
// Do an allowed syscall.
|
||||
EXPECT_OK(getpid_());
|
||||
EXPECT_OK(getpid());
|
||||
// Wait for the first child to exit (should get a zero exit code message).
|
||||
AWAIT_INT_MESSAGE(proc_pipe[0], 0);
|
||||
|
||||
@@ -686,7 +643,7 @@ FORK_TEST(Capmode, NewThread) {
|
||||
if (verbose) fprintf(stderr, " second child started\n");
|
||||
EXPECT_OK(close(proc_pipe[0]));
|
||||
// Child: do an allowed and a disallowed syscall.
|
||||
EXPECT_OK(getpid_());
|
||||
EXPECT_OK(getpid());
|
||||
EXPECT_CAPMODE(open("/dev/null", O_RDWR));
|
||||
// Notify the parent of success/failure.
|
||||
int rval = (int)testing::Test::HasFailure();
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#ifndef __CAPSICUM_FREEBSD_H__
|
||||
#define __CAPSICUM_FREEBSD_H__
|
||||
#ifdef __FreeBSD__
|
||||
/************************************************************
|
||||
* FreeBSD Capsicum Functionality.
|
||||
************************************************************/
|
||||
@@ -12,15 +11,9 @@ extern "C" {
|
||||
/* FreeBSD definitions. */
|
||||
#include <errno.h>
|
||||
#include <sys/param.h>
|
||||
#if __FreeBSD_version >= 1100014 || \
|
||||
(__FreeBSD_version >= 1001511 && __FreeBSD_version < 1100000)
|
||||
#include <sys/capsicum.h>
|
||||
#else
|
||||
#include <sys/capability.h>
|
||||
#endif
|
||||
#include <sys/procdesc.h>
|
||||
|
||||
#if __FreeBSD_version >= 1000000
|
||||
#define AT_SYSCALLS_IN_CAPMODE
|
||||
#define HAVE_CAP_RIGHTS_GET
|
||||
#define HAVE_CAP_RIGHTS_LIMIT
|
||||
@@ -32,11 +25,7 @@ typedef uint32_t cap_fcntl_t;
|
||||
// ioctl(2) and cap_ioctls_limit(2) take unsigned long.
|
||||
typedef unsigned long cap_ioctl_t;
|
||||
|
||||
#if __FreeBSD_version >= 1101000
|
||||
#define HAVE_OPENAT_INTERMEDIATE_DOTDOT
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
@@ -45,13 +34,8 @@ typedef unsigned long cap_ioctl_t;
|
||||
// Use fexecve_() in tests to allow Linux variant to bypass glibc version.
|
||||
#define fexecve_(F, A, E) fexecve(F, A, E)
|
||||
|
||||
#ifdef ENOTBENEATH
|
||||
#define E_NO_TRAVERSE_CAPABILITY ENOTBENEATH
|
||||
#define E_NO_TRAVERSE_O_BENEATH ENOTBENEATH
|
||||
#else
|
||||
#define E_NO_TRAVERSE_CAPABILITY ENOTCAPABLE
|
||||
#define E_NO_TRAVERSE_O_BENEATH ENOTCAPABLE
|
||||
#endif
|
||||
|
||||
// FreeBSD limits the number of ioctls in cap_ioctls_limit to 256
|
||||
#define CAP_IOCTLS_LIMIT_MAX 256
|
||||
@@ -66,6 +50,4 @@ typedef unsigned long cap_ioctl_t;
|
||||
// FreeBSD generates a capability from sctp_peeloff(cap_fd,...).
|
||||
#define CAP_FROM_PEELOFF
|
||||
|
||||
#endif /* __FreeBSD__ */
|
||||
|
||||
#endif /*__CAPSICUM_FREEBSD_H__*/
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
#ifndef __CAPSICUM_LINUX_H__
|
||||
#define __CAPSICUM_LINUX_H__
|
||||
|
||||
#ifdef __linux__
|
||||
/************************************************************
|
||||
* Linux Capsicum Functionality.
|
||||
************************************************************/
|
||||
#include <errno.h>
|
||||
#include <sys/procdesc.h>
|
||||
#include <sys/capsicum.h>
|
||||
|
||||
#define HAVE_CAP_RIGHTS_LIMIT
|
||||
#define HAVE_CAP_RIGHTS_GET
|
||||
#define HAVE_CAP_FCNTLS_LIMIT
|
||||
#define HAVE_CAP_IOCTLS_LIMIT
|
||||
#define HAVE_PROC_FDINFO
|
||||
#define HAVE_PDWAIT4
|
||||
#define CAP_FROM_ACCEPT
|
||||
// TODO(drysdale): uncomment if/when Linux propagates rights on sctp_peeloff.
|
||||
// Linux does not generate a capability from sctp_peeloff(cap_fd,...).
|
||||
// #define CAP_FROM_PEELOFF
|
||||
// TODO(drysdale): uncomment if/when Linux allows intermediate .. path segments
|
||||
// for openat()-like operations.
|
||||
// #define HAVE_OPENAT_INTERMEDIATE_DOTDOT
|
||||
|
||||
// Failure to open file due to path traversal generates EPERM
|
||||
#ifdef ENOTBENEATH
|
||||
#define E_NO_TRAVERSE_CAPABILITY ENOTBENEATH
|
||||
#define E_NO_TRAVERSE_O_BENEATH ENOTBENEATH
|
||||
#else
|
||||
#define E_NO_TRAVERSE_CAPABILITY EPERM
|
||||
#define E_NO_TRAVERSE_O_BENEATH EPERM
|
||||
#endif
|
||||
|
||||
// Too many links
|
||||
#define E_TOO_MANY_LINKS ELOOP
|
||||
|
||||
#endif /* __linux__ */
|
||||
|
||||
#endif /*__CAPSICUM_LINUX_H__*/
|
||||
@@ -5,114 +5,11 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
#include <sys/param.h>
|
||||
#if __FreeBSD_version >= 1100014 || \
|
||||
(__FreeBSD_version >= 1001511 && __FreeBSD_version < 1100000)
|
||||
#include <sys/capsicum.h>
|
||||
#else
|
||||
#include <sys/capability.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
#include <linux/capsicum.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef CAP_RIGHTS_VERSION
|
||||
/************************************************************
|
||||
* Capsicum compatibility layer: implement new (FreeBSD10.x)
|
||||
* rights manipulation API in terms of original (FreeBSD9.x)
|
||||
* functionality.
|
||||
************************************************************/
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/* Rights manipulation macros/functions.
|
||||
* Note that these use variadic macros, available in C99 / C++11 (and
|
||||
* also in earlier gcc versions).
|
||||
*/
|
||||
#define cap_rights_init(rights, ...) _cap_rights_init((rights), __VA_ARGS__, 0ULL)
|
||||
#define cap_rights_set(rights, ...) _cap_rights_set((rights), __VA_ARGS__, 0ULL)
|
||||
#define cap_rights_clear(rights, ...) _cap_rights_clear((rights), __VA_ARGS__, 0ULL)
|
||||
#define cap_rights_is_set(rights, ...) _cap_rights_is_set((rights), __VA_ARGS__, 0ULL)
|
||||
|
||||
inline cap_rights_t* _cap_rights_init(cap_rights_t *rights, ...) {
|
||||
va_list ap;
|
||||
cap_rights_t right;
|
||||
*rights = 0;
|
||||
va_start(ap, rights);
|
||||
while (true) {
|
||||
right = va_arg(ap, cap_rights_t);
|
||||
*rights |= right;
|
||||
if (right == 0) break;
|
||||
}
|
||||
va_end(ap);
|
||||
return rights;
|
||||
}
|
||||
|
||||
inline cap_rights_t* _cap_rights_set(cap_rights_t *rights, ...) {
|
||||
va_list ap;
|
||||
cap_rights_t right;
|
||||
va_start(ap, rights);
|
||||
while (true) {
|
||||
right = va_arg(ap, cap_rights_t);
|
||||
*rights |= right;
|
||||
if (right == 0) break;
|
||||
}
|
||||
va_end(ap);
|
||||
return rights;
|
||||
}
|
||||
|
||||
inline cap_rights_t* _cap_rights_clear(cap_rights_t *rights, ...) {
|
||||
va_list ap;
|
||||
cap_rights_t right;
|
||||
va_start(ap, rights);
|
||||
while (true) {
|
||||
right = va_arg(ap, cap_rights_t);
|
||||
*rights &= ~right;
|
||||
if (right == 0) break;
|
||||
}
|
||||
va_end(ap);
|
||||
return rights;
|
||||
}
|
||||
|
||||
inline bool _cap_rights_is_set(const cap_rights_t *rights, ...) {
|
||||
va_list ap;
|
||||
cap_rights_t right;
|
||||
cap_rights_t accumulated = 0;
|
||||
va_start(ap, rights);
|
||||
while (true) {
|
||||
right = va_arg(ap, cap_rights_t);
|
||||
accumulated |= right;
|
||||
if (right == 0) break;
|
||||
}
|
||||
va_end(ap);
|
||||
return (accumulated & *rights) == accumulated;
|
||||
}
|
||||
|
||||
inline bool _cap_rights_is_valid(const cap_rights_t *rights) {
|
||||
return true;
|
||||
}
|
||||
|
||||
inline cap_rights_t* cap_rights_merge(cap_rights_t *dst, const cap_rights_t *src) {
|
||||
*dst |= *src;
|
||||
return dst;
|
||||
}
|
||||
|
||||
inline cap_rights_t* cap_rights_remove(cap_rights_t *dst, const cap_rights_t *src) {
|
||||
*dst &= ~(*src);
|
||||
return dst;
|
||||
}
|
||||
|
||||
inline bool cap_rights_contains(const cap_rights_t *big, const cap_rights_t *little) {
|
||||
return ((*big) & (*little)) == (*little);
|
||||
}
|
||||
|
||||
#endif /* old/new style rights manipulation */
|
||||
|
||||
#endif /*__CAPSICUM_RIGHTS_H__*/
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
#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>
|
||||
@@ -16,11 +11,6 @@
|
||||
#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
|
||||
@@ -38,7 +28,6 @@ public:
|
||||
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);
|
||||
@@ -60,7 +49,6 @@ public:
|
||||
<< "Skipping tests because its enablement invalidates the "
|
||||
<< "test results.";
|
||||
}
|
||||
#endif /* FreeBSD */
|
||||
}
|
||||
void CreateTemporaryRoot() {
|
||||
char *tmpdir_name = tempnam(nullptr, "cptst");
|
||||
@@ -148,13 +136,6 @@ int main(int argc, char* argv[]) {
|
||||
}
|
||||
}
|
||||
|
||||
#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();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "capsicum-test.h"
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
#include <sys/param.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/queue.h>
|
||||
@@ -8,7 +7,6 @@
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/user.h>
|
||||
#include <libprocstat.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@@ -38,26 +36,6 @@ const char *TmpFile(const char *p) {
|
||||
}
|
||||
|
||||
char ProcessState(int pid) {
|
||||
#ifdef __linux__
|
||||
// Open the process status file.
|
||||
char s[1024];
|
||||
snprintf(s, sizeof(s), "/proc/%d/status", pid);
|
||||
FILE *f = fopen(s, "r");
|
||||
if (f == NULL) return '\0';
|
||||
|
||||
// Read the file line by line looking for the state line.
|
||||
const char *prompt = "State:\t";
|
||||
while (!feof(f)) {
|
||||
fgets(s, sizeof(s), f);
|
||||
if (!strncmp(s, prompt, strlen(prompt))) {
|
||||
fclose(f);
|
||||
return s[strlen(prompt)];
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
return '?';
|
||||
#endif
|
||||
#ifdef __FreeBSD__
|
||||
// First check if the process exists/we have permission to see it. This
|
||||
// Avoids warning messages being printed to stderr by libprocstat.
|
||||
size_t len = 0;
|
||||
@@ -115,5 +93,4 @@ char ProcessState(int pid) {
|
||||
procstat_close(prstat);
|
||||
if (verbose) fprintf(stderr, "Process %d in state '%c'\n", pid, result);
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -4,141 +4,11 @@
|
||||
#ifndef __CAPSICUM_H__
|
||||
#define __CAPSICUM_H__
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
#include <stdio.h>
|
||||
|
||||
#include "capsicum-freebsd.h"
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
#include "capsicum-linux.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* CAP_ALL/CAP_NONE is a value in FreeBSD9.x Capsicum, but a functional macro
|
||||
* in FreeBSD10.x Capsicum. Always use CAP_SET_ALL/CAP_SET_NONE instead.
|
||||
*/
|
||||
#ifndef CAP_SET_ALL
|
||||
#ifdef CAP_RIGHTS_VERSION
|
||||
#define CAP_SET_ALL(rights) CAP_ALL(rights)
|
||||
#else
|
||||
#define CAP_SET_ALL(rights) *(rights) = CAP_MASK_VALID
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef CAP_SET_NONE
|
||||
#ifdef CAP_RIGHTS_VERSION
|
||||
#define CAP_SET_NONE(rights) CAP_NONE(rights)
|
||||
#else
|
||||
#define CAP_SET_NONE(rights) *(rights) = 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
/************************************************************
|
||||
* Define new-style rights in terms of old-style rights if
|
||||
* absent.
|
||||
************************************************************/
|
||||
#include "capsicum-rights.h"
|
||||
|
||||
/*
|
||||
* Cope with systems (e.g. FreeBSD 10.x) where CAP_RENAMEAT hasn't been split out.
|
||||
* (src, dest): RENAMEAT, LINKAT => RENAMEAT_SOURCE, RENAMEAT_TARGET
|
||||
*/
|
||||
#ifndef CAP_RENAMEAT_SOURCE
|
||||
#define CAP_RENAMEAT_SOURCE CAP_RENAMEAT
|
||||
#endif
|
||||
#ifndef CAP_RENAMEAT_TARGET
|
||||
#define CAP_RENAMEAT_TARGET CAP_LINKAT
|
||||
#endif
|
||||
/*
|
||||
* Cope with systems (e.g. FreeBSD 10.x) where CAP_RENAMEAT hasn't been split out.
|
||||
* (src, dest): 0, LINKAT => LINKAT_SOURCE, LINKAT_TARGET
|
||||
*/
|
||||
#ifndef CAP_LINKAT_SOURCE
|
||||
#define CAP_LINKAT_SOURCE CAP_LOOKUP
|
||||
#endif
|
||||
#ifndef CAP_LINKAT_TARGET
|
||||
#define CAP_LINKAT_TARGET CAP_LINKAT
|
||||
#endif
|
||||
|
||||
#ifdef CAP_PREAD
|
||||
/* Existence of CAP_PREAD implies new-style CAP_SEEK semantics */
|
||||
#define CAP_SEEK_ASWAS 0
|
||||
#else
|
||||
/* Old-style CAP_SEEK semantics */
|
||||
#define CAP_SEEK_ASWAS CAP_SEEK
|
||||
#define CAP_PREAD CAP_READ
|
||||
#define CAP_PWRITE CAP_WRITE
|
||||
#endif
|
||||
|
||||
#ifndef CAP_MMAP_R
|
||||
#define CAP_MMAP_R (CAP_READ|CAP_MMAP)
|
||||
#define CAP_MMAP_W (CAP_WRITE|CAP_MMAP)
|
||||
#define CAP_MMAP_X (CAP_MAPEXEC|CAP_MMAP)
|
||||
#define CAP_MMAP_RW (CAP_MMAP_R|CAP_MMAP_W)
|
||||
#define CAP_MMAP_RX (CAP_MMAP_R|CAP_MMAP_X)
|
||||
#define CAP_MMAP_WX (CAP_MMAP_W|CAP_MMAP_X)
|
||||
#define CAP_MMAP_RWX (CAP_MMAP_R|CAP_MMAP_W|CAP_MMAP_X)
|
||||
#endif
|
||||
|
||||
#ifndef CAP_MKFIFOAT
|
||||
#define CAP_MKFIFOAT CAP_MKFIFO
|
||||
#endif
|
||||
|
||||
#ifndef CAP_MKNODAT
|
||||
#define CAP_MKNODAT CAP_MKFIFOAT
|
||||
#endif
|
||||
|
||||
#ifndef CAP_MKDIRAT
|
||||
#define CAP_MKDIRAT CAP_MKDIR
|
||||
#endif
|
||||
|
||||
#ifndef CAP_UNLINKAT
|
||||
#define CAP_UNLINKAT CAP_RMDIR
|
||||
#endif
|
||||
|
||||
#ifndef CAP_SOCK_CLIENT
|
||||
#define CAP_SOCK_CLIENT \
|
||||
(CAP_CONNECT | CAP_GETPEERNAME | CAP_GETSOCKNAME | CAP_GETSOCKOPT | \
|
||||
CAP_PEELOFF | CAP_READ | CAP_WRITE | CAP_SETSOCKOPT | CAP_SHUTDOWN)
|
||||
#endif
|
||||
|
||||
#ifndef CAP_SOCK_SERVER
|
||||
#define CAP_SOCK_SERVER \
|
||||
(CAP_ACCEPT | CAP_BIND | CAP_GETPEERNAME | CAP_GETSOCKNAME | \
|
||||
CAP_GETSOCKOPT | CAP_LISTEN | CAP_PEELOFF | CAP_READ | CAP_WRITE | \
|
||||
CAP_SETSOCKOPT | CAP_SHUTDOWN)
|
||||
#endif
|
||||
|
||||
#ifndef CAP_EVENT
|
||||
#define CAP_EVENT CAP_POLL_EVENT
|
||||
#endif
|
||||
|
||||
/************************************************************
|
||||
* Define new-style API functions in terms of old-style API
|
||||
* functions if absent.
|
||||
************************************************************/
|
||||
#ifndef HAVE_CAP_RIGHTS_GET
|
||||
/* Define cap_rights_get() in terms of old-style cap_getrights() */
|
||||
inline int cap_rights_get(int fd, cap_rights_t *rights) {
|
||||
return cap_getrights(fd, rights);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_CAP_RIGHTS_LIMIT
|
||||
/* Define cap_rights_limit() in terms of old-style cap_new() and dup2() */
|
||||
#include <unistd.h>
|
||||
inline int cap_rights_limit(int fd, const cap_rights_t *rights) {
|
||||
int cap = cap_new(fd, *rights);
|
||||
if (cap < 0) return cap;
|
||||
int rc = dup2(cap, fd);
|
||||
if (rc < 0) return rc;
|
||||
close(cap);
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#ifdef CAP_RIGHTS_VERSION
|
||||
/* New-style Capsicum API extras for debugging */
|
||||
static inline void cap_rights_describe(const cap_rights_t *rights, char *buffer) {
|
||||
int ii;
|
||||
@@ -151,24 +21,14 @@ static inline void cap_rights_describe(const cap_rights_t *rights, char *buffer)
|
||||
#ifdef __cplusplus
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <string>
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, cap_rights_t rights) {
|
||||
for (int ii = 0; ii < (CAP_RIGHTS_VERSION+2); ii++) {
|
||||
os << std::hex << std::setw(16) << std::setfill('0') << (unsigned long long)rights.cr_rights[ii] << " ";
|
||||
}
|
||||
return os;
|
||||
}
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
static inline void cap_rights_describe(const cap_rights_t *rights, char *buffer) {
|
||||
sprintf(buffer, "0x%016llx", (*rights));
|
||||
}
|
||||
|
||||
#endif /* new/old style rights manipulation */
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include <string>
|
||||
extern std::string capsicum_test_bindir;
|
||||
#endif
|
||||
|
||||
|
||||
@@ -111,13 +111,8 @@ void InitRights() {
|
||||
cap_rights_init(&(fcntl_rights[1]), CAP_READ, CAP_WRITE);
|
||||
cap_rights_init(&(fcntl_rights[2]), CAP_FCNTL);
|
||||
cap_rights_init(&(fcntl_rights[3]), CAP_FLOCK);
|
||||
#ifdef CAP_FSIGNAL
|
||||
cap_rights_init(&(fcntl_rights[4]), CAP_EVENT, CAP_FSIGNAL);
|
||||
cap_rights_init(&(fcntl_rights[5]), CAP_FLOCK, CAP_FSIGNAL);
|
||||
#else
|
||||
cap_rights_init(&(fcntl_rights[4]), 0);
|
||||
cap_rights_init(&(fcntl_rights[5]), 0);
|
||||
#endif
|
||||
#ifdef CAP_NOTIFY
|
||||
cap_rights_init(&(fcntl_rights[6]), CAP_NOTIFY);
|
||||
#else
|
||||
@@ -176,13 +171,11 @@ TEST(Fcntl, Commands) {
|
||||
EXPECT_OK(cap_rights_get(newfd, &rights));
|
||||
EXPECT_RIGHTS_EQ(&(fcntl_rights[0]), &rights);
|
||||
close(newfd);
|
||||
#ifdef HAVE_F_DUP2FD
|
||||
EXPECT_OK(fcntl(caps[0], F_DUP2FD, newfd));
|
||||
// dup2()'ed FD should have same rights.
|
||||
EXPECT_OK(cap_rights_get(newfd, &rights));
|
||||
EXPECT_RIGHTS_EQ(&(fcntl_rights[0]), &rights);
|
||||
close(newfd);
|
||||
#endif
|
||||
|
||||
EXPECT_OK(fcntl(caps[0], F_GETFD, 0));
|
||||
EXPECT_OK(fcntl(caps[0], F_SETFD, 0));
|
||||
@@ -258,7 +251,6 @@ TEST(Fcntl, WriteLock) {
|
||||
unlink(TmpFile("cap_fcntl_readlock"));
|
||||
}
|
||||
|
||||
#ifdef HAVE_CAP_FCNTLS_LIMIT
|
||||
TEST(Fcntl, SubRightNormalFD) {
|
||||
int fd = open(TmpFile("cap_fcntl_subrightnorm"), O_RDWR|O_CREAT, 0644);
|
||||
EXPECT_OK(fd);
|
||||
@@ -273,7 +265,7 @@ TEST(Fcntl, SubRightNormalFD) {
|
||||
cap_rights_t rights;
|
||||
EXPECT_OK(cap_rights_get(fd, &rights));
|
||||
cap_rights_t all;
|
||||
CAP_SET_ALL(&all);
|
||||
CAP_ALL(&all);
|
||||
EXPECT_RIGHTS_EQ(&all, &rights);
|
||||
cap_fcntl_t fcntls;
|
||||
EXPECT_OK(cap_fcntls_get(fd, &fcntls));
|
||||
@@ -408,4 +400,3 @@ TEST(Fcntl, OWNSubRights) {
|
||||
|
||||
close(sock);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -36,7 +36,6 @@ TEST(Ioctl, Basic) {
|
||||
close(fd_no);
|
||||
}
|
||||
|
||||
#ifdef HAVE_CAP_IOCTLS_LIMIT
|
||||
TEST(Ioctl, SubRightNormalFD) {
|
||||
int fd = open("/etc/passwd", O_RDONLY);
|
||||
EXPECT_OK(fd);
|
||||
@@ -53,7 +52,7 @@ TEST(Ioctl, SubRightNormalFD) {
|
||||
cap_rights_t rights;
|
||||
EXPECT_OK(cap_rights_get(fd, &rights));
|
||||
cap_rights_t all;
|
||||
CAP_SET_ALL(&all);
|
||||
CAP_ALL(&all);
|
||||
EXPECT_RIGHTS_EQ(&all, &rights);
|
||||
cap_ioctl_t ioctls[16];
|
||||
memset(ioctls, 0, sizeof(ioctls));
|
||||
@@ -186,7 +185,6 @@ TEST(Ioctl, SubRights) {
|
||||
close(fd);
|
||||
}
|
||||
|
||||
#ifdef CAP_IOCTLS_LIMIT_MAX
|
||||
TEST(Ioctl, TooManySubRights) {
|
||||
int fd = open("/etc/passwd", O_RDONLY);
|
||||
EXPECT_OK(fd);
|
||||
@@ -207,28 +205,3 @@ TEST(Ioctl, TooManySubRights) {
|
||||
|
||||
close(fd);
|
||||
}
|
||||
#else
|
||||
TEST(Ioctl, ManySubRights) {
|
||||
int fd = open("/etc/passwd", O_RDONLY);
|
||||
EXPECT_OK(fd);
|
||||
|
||||
const int nioctls = 150000;
|
||||
cap_ioctl_t* ioctls = (cap_ioctl_t*)calloc(nioctls, sizeof(cap_ioctl_t));
|
||||
for (int ii = 0; ii < nioctls; ii++) {
|
||||
ioctls[ii] = ii + 1;
|
||||
}
|
||||
|
||||
cap_rights_t rights_ioctl;
|
||||
cap_rights_init(&rights_ioctl, CAP_IOCTL);
|
||||
EXPECT_OK(cap_rights_limit(fd, &rights_ioctl));
|
||||
|
||||
EXPECT_OK(cap_ioctls_limit(fd, ioctls, nioctls));
|
||||
// Limit to a subset; if this takes a long time then there's an
|
||||
// O(N^2) implementation of the ioctl list comparison.
|
||||
EXPECT_OK(cap_ioctls_limit(fd, ioctls, nioctls - 1));
|
||||
|
||||
close(fd);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -494,7 +494,7 @@ TEST(Linux, FanotifyIfRoot) {
|
||||
// only have rights that are a subset of those for the original
|
||||
// monitored directory file descriptor.
|
||||
cap_rights_t rights;
|
||||
CAP_SET_ALL(&rights);
|
||||
CAL_ALL(&rights);
|
||||
EXPECT_OK(cap_rights_get(ev.fd, &rights));
|
||||
EXPECT_RIGHTS_IN(&rights, &r_rslstat);
|
||||
#endif
|
||||
|
||||
@@ -57,15 +57,11 @@ FORK_TEST(Openat, Relative) {
|
||||
int etc_cap_base = dup(etc);
|
||||
EXPECT_OK(etc_cap_base);
|
||||
EXPECT_OK(cap_rights_limit(etc_cap_base, &r_base));
|
||||
#ifdef HAVE_CAP_FCNTLS_LIMIT
|
||||
// Also limit fcntl(2) subrights.
|
||||
EXPECT_OK(cap_fcntls_limit(etc_cap_base, CAP_FCNTL_GETFL));
|
||||
#endif
|
||||
#ifdef HAVE_CAP_IOCTLS_LIMIT
|
||||
// Also limit ioctl(2) subrights.
|
||||
cap_ioctl_t ioctl_nread = FIONREAD;
|
||||
EXPECT_OK(cap_ioctls_limit(etc_cap_base, &ioctl_nread, 1));
|
||||
#endif
|
||||
|
||||
// openat(2) with regular file descriptors in non-capability mode
|
||||
// Should Just Work (tm).
|
||||
@@ -93,12 +89,9 @@ FORK_TEST(Openat, Relative) {
|
||||
cap_rights_t rights;
|
||||
EXPECT_OK(cap_rights_get(fd, &rights));
|
||||
EXPECT_RIGHTS_IN(&rights, &r_base);
|
||||
#ifdef HAVE_CAP_FCNTLS_LIMIT
|
||||
cap_fcntl_t fcntls;
|
||||
EXPECT_OK(cap_fcntls_get(fd, &fcntls));
|
||||
EXPECT_EQ((cap_fcntl_t)CAP_FCNTL_GETFL, fcntls);
|
||||
#endif
|
||||
#ifdef HAVE_CAP_IOCTLS_LIMIT
|
||||
cap_ioctl_t ioctls[16];
|
||||
ssize_t nioctls;
|
||||
memset(ioctls, 0, sizeof(ioctls));
|
||||
@@ -106,7 +99,6 @@ FORK_TEST(Openat, Relative) {
|
||||
EXPECT_OK(nioctls);
|
||||
EXPECT_EQ(1, nioctls);
|
||||
EXPECT_EQ((cap_ioctl_t)FIONREAD, ioctls[0]);
|
||||
#endif
|
||||
close(fd);
|
||||
|
||||
// Enter capability mode; now ALL lookups are strictly relative.
|
||||
@@ -270,10 +262,8 @@ class OpenatTest : public ::testing::Test {
|
||||
EXPECT_OPENAT_FAIL_TRAVERSAL(sub_fd_, "../subdir/bottomfile", O_RDONLY|oflag);
|
||||
EXPECT_OPENAT_FAIL_TRAVERSAL(sub_fd_, "..", O_RDONLY|oflag);
|
||||
|
||||
#ifdef HAVE_OPENAT_INTERMEDIATE_DOTDOT
|
||||
// OK for dotdot lookups that don't escape the top directory
|
||||
EXPECT_OPEN_OK(openat(dir_fd_, "subdir/../topfile", O_RDONLY|oflag));
|
||||
#endif
|
||||
|
||||
// Check that we can't escape the top directory by the cunning
|
||||
// ruse of going via a subdirectory.
|
||||
@@ -341,11 +331,6 @@ FORK_TEST_F(OpenatTest, InCapabilityMode) {
|
||||
EXPECT_OPENAT_FAIL_TRAVERSAL(sub_fd_, "/etc/passwd", O_RDONLY);
|
||||
}
|
||||
|
||||
#if !defined(O_RESOLVE_BENEATH) && defined(O_BENEATH)
|
||||
#define O_RESOLVE_BENEATH O_BENEATH
|
||||
#endif
|
||||
|
||||
#ifdef O_RESOLVE_BENEATH
|
||||
TEST_F(OpenatTest, WithFlag) {
|
||||
CheckPolicing(O_RESOLVE_BENEATH);
|
||||
|
||||
@@ -363,4 +348,3 @@ FORK_TEST_F(OpenatTest, WithFlagInCapabilityMode) {
|
||||
EXPECT_OK(cap_enter()); // Enter capability mode
|
||||
CheckPolicing(O_RESOLVE_BENEATH);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -20,13 +20,6 @@
|
||||
#include "syscalls.h"
|
||||
#include "capsicum-test.h"
|
||||
|
||||
#ifndef __WALL
|
||||
// Linux requires __WALL in order for waitpid(specific_pid,...) to
|
||||
// see and reap any specific pid. Define this to nothing for platforms
|
||||
// (FreeBSD) where it doesn't exist, to reduce macroing.
|
||||
#define __WALL 0
|
||||
#endif
|
||||
|
||||
//------------------------------------------------
|
||||
// Utilities for the tests.
|
||||
|
||||
@@ -40,7 +33,6 @@ static pid_t pdwait4_(int pd, int *status, int options, struct rusage *ru) {
|
||||
if (rc < 0) {
|
||||
return rc;
|
||||
}
|
||||
options |= __WALL;
|
||||
return wait4(pid, status, options, ru);
|
||||
#endif
|
||||
}
|
||||
@@ -55,17 +47,13 @@ static void print_stat(FILE *f, const struct stat *stat) {
|
||||
fprintf(f,
|
||||
"{ .st_dev=%ld, st_ino=%ld, st_mode=%04o, st_nlink=%ld, st_uid=%d, st_gid=%d,\n"
|
||||
" .st_rdev=%ld, .st_size=%ld, st_blksize=%ld, .st_block=%ld,\n "
|
||||
#ifdef HAVE_STAT_BIRTHTIME
|
||||
".st_birthtime=%ld, "
|
||||
#endif
|
||||
".st_atime=%ld, .st_mtime=%ld, .st_ctime=%ld}\n",
|
||||
(long)stat->st_dev, (long)stat->st_ino, stat->st_mode,
|
||||
(long)stat->st_nlink, stat->st_uid, stat->st_gid,
|
||||
(long)stat->st_rdev, (long)stat->st_size, (long)stat->st_blksize,
|
||||
(long)stat->st_blocks,
|
||||
#ifdef HAVE_STAT_BIRTHTIME
|
||||
(long)stat->st_birthtime,
|
||||
#endif
|
||||
(long)stat->st_atime, (long)stat->st_mtime, (long)stat->st_ctime);
|
||||
}
|
||||
|
||||
@@ -83,7 +71,7 @@ void CheckChildFinished(pid_t pid, bool signaled=false) {
|
||||
int rc;
|
||||
int status = 0;
|
||||
do {
|
||||
rc = waitpid(pid, &status, __WALL);
|
||||
rc = waitpid(pid, &status, 0);
|
||||
if (rc < 0) {
|
||||
fprintf(stderr, "Warning: waitpid error %s (%d)\n", strerror(errno), errno);
|
||||
ADD_FAILURE() << "Failed to wait for child";
|
||||
@@ -170,7 +158,7 @@ TEST(Pdfork, InvalidFlag) {
|
||||
}
|
||||
EXPECT_EQ(-1, pid);
|
||||
EXPECT_EQ(EINVAL, errno);
|
||||
if (pid > 0) waitpid(pid, NULL, __WALL);
|
||||
if (pid > 0) waitpid(pid, NULL, 0);
|
||||
}
|
||||
|
||||
TEST(Pdfork, TimeCheck) {
|
||||
@@ -188,21 +176,17 @@ TEST(Pdfork, TimeCheck) {
|
||||
exit(HasFailure());
|
||||
}
|
||||
|
||||
#ifdef HAVE_PROCDESC_FSTAT
|
||||
// Parent process. Ensure that [acm]times have been set correctly.
|
||||
struct stat stat;
|
||||
memset(&stat, 0, sizeof(stat));
|
||||
EXPECT_OK(fstat(pd, &stat));
|
||||
if (verbose) print_stat(stderr, &stat);
|
||||
|
||||
#ifdef HAVE_STAT_BIRTHTIME
|
||||
EXPECT_GE(now, stat.st_birthtime);
|
||||
EXPECT_EQ(stat.st_birthtime, stat.st_atime);
|
||||
#endif
|
||||
EXPECT_LT((now - stat.st_atime), 2);
|
||||
EXPECT_EQ(stat.st_atime, stat.st_ctime);
|
||||
EXPECT_EQ(stat.st_ctime, stat.st_mtime);
|
||||
#endif
|
||||
|
||||
// Wait for the child to finish.
|
||||
pid_t pd_pid = -1;
|
||||
@@ -339,7 +323,7 @@ class PipePdforkBase : public ::testing::Test {
|
||||
}
|
||||
if (pid_ > 0) {
|
||||
kill(pid_, SIGKILL);
|
||||
waitpid(pid_, NULL, __WALL|WNOHANG);
|
||||
waitpid(pid_, NULL, WNOHANG);
|
||||
}
|
||||
// Check signal expectations.
|
||||
EXPECT_FALSE(had_signal[SIGCHLD]);
|
||||
@@ -448,7 +432,7 @@ TEST_F(PipePdfork, PollMultiple) {
|
||||
} else {
|
||||
// Parent: wait on process D.
|
||||
int rc = 0;
|
||||
waitpid(doppel, &rc, __WALL);
|
||||
waitpid(doppel, &rc, 0);
|
||||
EXPECT_TRUE(WIFEXITED(rc));
|
||||
EXPECT_EQ(0, WEXITSTATUS(rc));
|
||||
// Also wait on process B.
|
||||
@@ -495,30 +479,12 @@ TEST_F(PipePdfork, ChildExit) {
|
||||
pid_ = 0;
|
||||
}
|
||||
|
||||
#ifdef HAVE_PROC_FDINFO
|
||||
TEST_F(PipePdfork, FdInfo) {
|
||||
char buffer[1024];
|
||||
sprintf(buffer, "/proc/%d/fdinfo/%d", getpid_(), pd_);
|
||||
int procfd = open(buffer, O_RDONLY);
|
||||
EXPECT_OK(procfd);
|
||||
|
||||
EXPECT_OK(read(procfd, buffer, sizeof(buffer)));
|
||||
// The fdinfo should include the file pos of the underlying file
|
||||
EXPECT_NE((char*)NULL, strstr(buffer, "pos:\t0")) << buffer;
|
||||
// ...and the underlying pid
|
||||
char pidline[256];
|
||||
sprintf(pidline, "pid:\t%d", pid_);
|
||||
EXPECT_NE((char*)NULL, strstr(buffer, pidline)) << buffer;
|
||||
close(procfd);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Closing a normal process descriptor terminates the underlying process.
|
||||
TEST_F(PipePdfork, Close) {
|
||||
sighandler_t original = signal(SIGCHLD, handle_signal);
|
||||
EXPECT_PID_ALIVE(pid_);
|
||||
int status;
|
||||
EXPECT_EQ(0, waitpid(pid_, &status, __WALL|WNOHANG));
|
||||
EXPECT_EQ(0, waitpid(pid_, &status, WNOHANG));
|
||||
|
||||
EXPECT_OK(close(pd_));
|
||||
pd_ = -1;
|
||||
@@ -526,7 +492,7 @@ TEST_F(PipePdfork, Close) {
|
||||
EXPECT_PID_DEAD(pid_);
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
EXPECT_EQ(-1, waitpid(pid_, NULL, __WALL));
|
||||
EXPECT_EQ(-1, waitpid(pid_, NULL, 0));
|
||||
EXPECT_EQ(errno, ECHILD);
|
||||
#else
|
||||
// Having closed the process descriptor means that pdwait4(pd) now doesn't work.
|
||||
@@ -535,7 +501,7 @@ TEST_F(PipePdfork, Close) {
|
||||
EXPECT_EQ(EBADF, errno);
|
||||
|
||||
// Closing all process descriptors means the the child can only be reaped via pid.
|
||||
EXPECT_EQ(pid_, waitpid(pid_, &status, __WALL|WNOHANG));
|
||||
EXPECT_EQ(pid_, waitpid(pid_, &status, WNOHANG));
|
||||
#endif
|
||||
signal(SIGCHLD, original);
|
||||
}
|
||||
@@ -551,7 +517,7 @@ TEST_F(PipePdfork, CloseLast) {
|
||||
|
||||
EXPECT_PID_ALIVE(pid_);
|
||||
int status;
|
||||
EXPECT_EQ(0, waitpid(pid_, &status, __WALL|WNOHANG));
|
||||
EXPECT_EQ(0, waitpid(pid_, &status, WNOHANG));
|
||||
|
||||
// Can no longer pdwait4() the closed process descriptor...
|
||||
EXPECT_EQ(-1, pdwait4_(pd_, &status, WNOHANG, NULL));
|
||||
@@ -621,7 +587,7 @@ TEST_F(PipePdfork, WaitPidThenPd) {
|
||||
TerminateChild();
|
||||
int status;
|
||||
// If we waitpid(pid) first...
|
||||
int rc = waitpid(pid_, &status, __WALL);
|
||||
int rc = waitpid(pid_, &status, 0);
|
||||
EXPECT_OK(rc);
|
||||
EXPECT_EQ(pid_, rc);
|
||||
|
||||
@@ -640,7 +606,7 @@ TEST_F(PipePdfork, WaitPdThenPid) {
|
||||
EXPECT_EQ(pid_, rc);
|
||||
|
||||
// ...the zombie is reaped and cannot subsequently waitpid(pid).
|
||||
EXPECT_EQ(-1, waitpid(pid_, &status, __WALL));
|
||||
EXPECT_EQ(-1, waitpid(pid_, &status, 0));
|
||||
EXPECT_EQ(ECHILD, errno);
|
||||
}
|
||||
|
||||
@@ -721,7 +687,7 @@ TEST(Pdfork, PdkillOtherSignal) {
|
||||
|
||||
// Child's exit status confirms whether it received the signal.
|
||||
int status;
|
||||
int rc = waitpid(pid, &status, __WALL);
|
||||
int rc = waitpid(pid, &status, 0);
|
||||
EXPECT_OK(rc);
|
||||
EXPECT_EQ(pid, rc);
|
||||
EXPECT_TRUE(WIFEXITED(status)) << "status: 0x" << std::hex << status;
|
||||
@@ -810,7 +776,7 @@ TEST_F(PipePdfork, NoSigchld) {
|
||||
TerminateChild();
|
||||
int rc = 0;
|
||||
// Can waitpid() for the specific pid of the pdfork()ed child.
|
||||
EXPECT_EQ(pid_, waitpid(pid_, &rc, __WALL));
|
||||
EXPECT_EQ(pid_, waitpid(pid_, &rc, 0));
|
||||
EXPECT_TRUE(WIFEXITED(rc)) << "0x" << std::hex << rc;
|
||||
EXPECT_FALSE(had_signal[SIGCHLD]);
|
||||
signal(SIGCHLD, original);
|
||||
@@ -826,19 +792,18 @@ TEST_F(PipePdforkDaemon, NoPDSigchld) {
|
||||
EXPECT_OK(close(pd_));
|
||||
TerminateChild();
|
||||
#ifdef __FreeBSD__
|
||||
EXPECT_EQ(-1, waitpid(pid_, NULL, __WALL));
|
||||
EXPECT_EQ(-1, waitpid(pid_, NULL, 0));
|
||||
EXPECT_EQ(errno, ECHILD);
|
||||
#else
|
||||
int rc = 0;
|
||||
// Can waitpid() for the specific pid of the pdfork()ed child.
|
||||
EXPECT_EQ(pid_, waitpid(pid_, &rc, __WALL));
|
||||
EXPECT_EQ(pid_, waitpid(pid_, &rc, 0));
|
||||
EXPECT_TRUE(WIFEXITED(rc)) << "0x" << std::hex << rc;
|
||||
#endif
|
||||
EXPECT_FALSE(had_signal[SIGCHLD]);
|
||||
signal(SIGCHLD, original);
|
||||
}
|
||||
|
||||
#ifdef HAVE_PROCDESC_FSTAT
|
||||
TEST_F(PipePdfork, ModeBits) {
|
||||
// Owner rwx bits indicate liveness of child
|
||||
struct stat stat;
|
||||
@@ -855,7 +820,6 @@ TEST_F(PipePdfork, ModeBits) {
|
||||
if (verbose) print_stat(stderr, &stat);
|
||||
EXPECT_EQ(0, (int)(stat.st_mode & S_IRWXU));
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST_F(PipePdfork, WildcardWait) {
|
||||
TerminateChild();
|
||||
@@ -1087,7 +1051,7 @@ TEST_F(PipePdfork, PassProcessDescriptor) {
|
||||
|
||||
// wait for child2
|
||||
int status;
|
||||
EXPECT_EQ(child2, waitpid(child2, &status, __WALL));
|
||||
EXPECT_EQ(child2, waitpid(child2, &status, 0));
|
||||
rc = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
|
||||
EXPECT_EQ(0, rc);
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
#include "capsicum.h"
|
||||
#include "capsicum-test.h"
|
||||
|
||||
#ifdef HAVE_SCTP
|
||||
static cap_rights_t r_ro;
|
||||
static cap_rights_t r_wo;
|
||||
static cap_rights_t r_rw;
|
||||
@@ -180,12 +179,10 @@ TEST(Sctp, Socket) {
|
||||
EXPECT_OK(rc2);
|
||||
int peeled = std::max(rc1, rc2);
|
||||
if (peeled > 0) {
|
||||
#ifdef CAP_FROM_PEELOFF
|
||||
// Peeled off FD should have same rights as original socket.
|
||||
cap_rights_t rights;
|
||||
EXPECT_OK(cap_rights_get(peeled, &rights));
|
||||
EXPECT_RIGHTS_EQ(&r_all, &rights);
|
||||
#endif
|
||||
close(peeled);
|
||||
}
|
||||
} else if (buffer[0] == DO_TERM) {
|
||||
@@ -212,4 +209,3 @@ TEST(Sctp, Socket) {
|
||||
close(cap_sock_all);
|
||||
close(cap_sock_all_nopeel);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -73,7 +73,6 @@ FORK_TEST_ON(Select, LotsOFileDescriptors, TmpFile("cap_select")) {
|
||||
ret = select(maxfd+1, &rset, &wset, NULL, &tv);
|
||||
EXPECT_NOTCAPABLE(ret);
|
||||
|
||||
#ifdef HAVE_PSELECT
|
||||
// And again with pselect
|
||||
struct timespec ts;
|
||||
ts.tv_sec = 0;
|
||||
@@ -93,7 +92,6 @@ FORK_TEST_ON(Select, LotsOFileDescriptors, TmpFile("cap_select")) {
|
||||
AddFDToSet(&wset, cap_rw, maxfd);
|
||||
ret = pselect(maxfd+1, &rset, &wset, NULL, &ts, NULL);
|
||||
EXPECT_NOTCAPABLE(ret);
|
||||
#endif
|
||||
}
|
||||
|
||||
FORK_TEST_ON(Poll, LotsOFileDescriptors, TmpFile("cap_poll")) {
|
||||
@@ -129,7 +127,6 @@ FORK_TEST_ON(Poll, LotsOFileDescriptors, TmpFile("cap_poll")) {
|
||||
EXPECT_OK(poll(cap_fd, kCapCount + 2, 10));
|
||||
EXPECT_NE(0, (cap_fd[kCapCount + 1].revents & POLLNVAL));
|
||||
|
||||
#ifdef HAVE_PPOLL
|
||||
// And again with ppoll
|
||||
struct timespec ts;
|
||||
ts.tv_sec = 0;
|
||||
@@ -138,5 +135,4 @@ FORK_TEST_ON(Poll, LotsOFileDescriptors, TmpFile("cap_poll")) {
|
||||
// Now also include the capability with no CAP_EVENT.
|
||||
EXPECT_OK(ppoll(cap_fd, kCapCount + 2, &ts, NULL));
|
||||
EXPECT_NE(0, (cap_fd[kCapCount + 1].revents & POLLNVAL));
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -13,16 +13,9 @@
|
||||
|
||||
#include "capsicum.h"
|
||||
|
||||
#ifdef __linux__
|
||||
// glibc on Linux caches getpid() return value.
|
||||
int getpid_(void) { return syscall(__NR_getpid); }
|
||||
#else
|
||||
#define getpid_ getpid
|
||||
#endif
|
||||
|
||||
static int seen_sigchld = 0;
|
||||
static void handle_signal(int x) {
|
||||
fprintf(stderr, "[%d] received SIGCHLD\n", getpid_());
|
||||
fprintf(stderr, "[%d] received SIGCHLD\n", getpid());
|
||||
seen_sigchld = 1;
|
||||
}
|
||||
|
||||
@@ -38,7 +31,7 @@ int main(int argc, char *argv[]) {
|
||||
cap_rights_init(&r_rws, CAP_READ, CAP_WRITE, CAP_SEEK);
|
||||
int cap_fd = dup(STDOUT_FILENO);
|
||||
int rc = cap_rights_limit(cap_fd, &r_rws);
|
||||
fprintf(stderr, "[%d] cap_fd=%d\n", getpid_(), cap_fd);
|
||||
fprintf(stderr, "[%d] cap_fd=%d\n", getpid(), cap_fd);
|
||||
if (rc < 0) fprintf(stderr, "*** cap_rights_limit() failed: errno=%d %s\n", errno, strerror(errno));
|
||||
|
||||
/* cap_rights_get() available? */
|
||||
@@ -47,13 +40,13 @@ int main(int argc, char *argv[]) {
|
||||
rc = cap_rights_get(cap_fd, &rights);
|
||||
char buffer[256];
|
||||
cap_rights_describe(&rights, buffer);
|
||||
fprintf(stderr, "[%d] cap_rights_get(cap_fd=%d) rc=%d rights=%s\n", getpid_(), cap_fd, rc, buffer);
|
||||
fprintf(stderr, "[%d] cap_rights_get(cap_fd=%d) rc=%d rights=%s\n", getpid(), cap_fd, rc, buffer);
|
||||
if (rc < 0) fprintf(stderr, "*** cap_rights_get() failed: errno=%d %s\n", errno, strerror(errno));
|
||||
|
||||
/* fstat() policed? */
|
||||
struct stat buf;
|
||||
rc = fstat(cap_fd, &buf);
|
||||
fprintf(stderr, "[%d] fstat(cap_fd=%d) rc=%d errno=%d\n", getpid_(), cap_fd, rc, errno);
|
||||
fprintf(stderr, "[%d] fstat(cap_fd=%d) rc=%d errno=%d\n", getpid(), cap_fd, rc, errno);
|
||||
if (rc != -1) fprintf(stderr, "*** fstat() unexpectedly succeeded\n");
|
||||
|
||||
/* pdfork() available? */
|
||||
@@ -64,26 +57,26 @@ int main(int argc, char *argv[]) {
|
||||
if (rc == 0) { /* child */
|
||||
int count = 0;
|
||||
while (count < 20) {
|
||||
fprintf(stderr, " [%d] child alive, parent is ppid=%d\n", getpid_(), getppid());
|
||||
fprintf(stderr, " [%d] child alive, parent is ppid=%d\n", getpid(), getppid());
|
||||
sleep(1);
|
||||
}
|
||||
fprintf(stderr, " [%d] child exit(0)\n", getpid_());
|
||||
fprintf(stderr, " [%d] child exit(0)\n", getpid());
|
||||
exit(0);
|
||||
}
|
||||
fprintf(stderr, "[%d] pdfork() rc=%d pd=%d\n", getpid_(), rc, pd);
|
||||
fprintf(stderr, "[%d] pdfork() rc=%d pd=%d\n", getpid(), rc, pd);
|
||||
|
||||
/* pdgetpid() available? */
|
||||
pid_t actual_pid = rc;
|
||||
pid_t got_pid = -1;
|
||||
rc = pdgetpid(pd, &got_pid);
|
||||
if (rc < 0) fprintf(stderr, "*** pdgetpid(pd=%d) failed: errno=%d %s\n", pd, errno, strerror(errno));
|
||||
fprintf(stderr, "[%d] pdgetpid(pd=%d)=%d, pdfork returned %d\n", getpid_(), pd, got_pid, actual_pid);
|
||||
fprintf(stderr, "[%d] pdgetpid(pd=%d)=%d, pdfork returned %d\n", getpid(), pd, got_pid, actual_pid);
|
||||
|
||||
sleep(lifetime);
|
||||
|
||||
/* pdkill() available? */
|
||||
rc = pdkill(pd, SIGKILL);
|
||||
fprintf(stderr, "[%d] pdkill(pd=%d, SIGKILL) -> rc=%d\n", getpid_(), pd, rc);
|
||||
fprintf(stderr, "[%d] pdkill(pd=%d, SIGKILL) -> rc=%d\n", getpid(), pd, rc);
|
||||
if (rc < 0) fprintf(stderr, "*** pdkill() failed: errno=%d %s\n", errno, strerror(errno));
|
||||
usleep(50000); /* Allow time for death and signals */
|
||||
|
||||
@@ -93,40 +86,38 @@ int main(int argc, char *argv[]) {
|
||||
rc = wait4(-1, &status, WNOHANG, NULL);
|
||||
if (rc > 0) fprintf(stderr, "*** wait4(-1, ...) unexpectedly found child %d\n", rc);
|
||||
|
||||
fprintf(stderr, "[%d] forking off a child process to check cap_enter()\n", getpid_());
|
||||
fprintf(stderr, "[%d] forking off a child process to check cap_enter()\n", getpid());
|
||||
pid_t child = fork();
|
||||
if (child == 0) { /* child */
|
||||
/* cap_getmode() / cap_enter() available? */
|
||||
unsigned int cap_mode = -1;
|
||||
rc = cap_getmode(&cap_mode);
|
||||
fprintf(stderr, " [%d] cap_getmode() -> rc=%d, cap_mode=%d\n", getpid_(), rc, cap_mode);
|
||||
fprintf(stderr, " [%d] cap_getmode() -> rc=%d, cap_mode=%d\n", getpid(), rc, cap_mode);
|
||||
if (rc < 0) fprintf(stderr, "*** cap_getmode() failed: errno=%d %s\n", errno, strerror(errno));
|
||||
|
||||
rc = cap_enter();
|
||||
fprintf(stderr, " [%d] cap_enter() -> rc=%d\n", getpid_(), rc);
|
||||
fprintf(stderr, " [%d] cap_enter() -> rc=%d\n", getpid(), rc);
|
||||
if (rc < 0) fprintf(stderr, "*** cap_enter() failed: errno=%d %s\n", errno, strerror(errno));
|
||||
|
||||
rc = cap_getmode(&cap_mode);
|
||||
fprintf(stderr, " [%d] cap_getmode() -> rc=%d, cap_mode=%d\n", getpid_(), rc, cap_mode);
|
||||
fprintf(stderr, " [%d] cap_getmode() -> rc=%d, cap_mode=%d\n", getpid(), rc, cap_mode);
|
||||
if (rc < 0) fprintf(stderr, "*** cap_getmode() failed: errno=%d %s\n", errno, strerror(errno));
|
||||
|
||||
/* open disallowed? */
|
||||
rc = open("/etc/passwd", O_RDONLY);
|
||||
fprintf(stderr, " [%d] open('/etc/passwd') -> rc=%d, errno=%d\n", getpid_(), rc, errno);
|
||||
fprintf(stderr, " [%d] open('/etc/passwd') -> rc=%d, errno=%d\n", getpid(), rc, errno);
|
||||
if (rc != -1) fprintf(stderr, "*** open() unexpectedly succeeded\n");
|
||||
#ifdef ECAPMODE
|
||||
if (errno != ECAPMODE) fprintf(stderr, "*** open() failed with errno %d not ECAPMODE\n", errno);
|
||||
#endif
|
||||
exit(0);
|
||||
}
|
||||
rc = wait4(child, &status, 0, NULL);
|
||||
fprintf(stderr, "[%d] child %d exited with status %x\n", getpid_(), child, status);
|
||||
fprintf(stderr, "[%d] child %d exited with status %x\n", getpid(), child, status);
|
||||
|
||||
/* fexecve() available? */
|
||||
char* argv_pass[] = {(char*)"/bin/ls", "-l", "smoketest", NULL};
|
||||
char* null_envp[] = {NULL};
|
||||
int ls_bin = open("/bin/ls", O_RDONLY);
|
||||
fprintf(stderr, "[%d] about to fexecve('/bin/ls', '-l', 'smoketest')\n", getpid_());
|
||||
fprintf(stderr, "[%d] about to fexecve('/bin/ls', '-l', 'smoketest')\n", getpid());
|
||||
rc = fexecve(ls_bin, argv_pass, null_envp);
|
||||
/* should never reach here */
|
||||
fprintf(stderr, "*** fexecve(fd=%d) failed: rc=%d errno=%d %s\n", ls_bin, rc, errno, strerror(errno));
|
||||
|
||||
@@ -106,13 +106,11 @@ TEST(Socket, UnixDomain) {
|
||||
int conn_fd = accept(cap_sock_all, (struct sockaddr *)&un, &len);
|
||||
EXPECT_OK(conn_fd);
|
||||
|
||||
#ifdef CAP_FROM_ACCEPT
|
||||
// New connection should also be a capability.
|
||||
cap_rights_t rights;
|
||||
cap_rights_init(&rights, 0);
|
||||
EXPECT_OK(cap_rights_get(conn_fd, &rights));
|
||||
EXPECT_RIGHTS_IN(&rights, &r_all);
|
||||
#endif
|
||||
|
||||
// Wait for the child.
|
||||
int status;
|
||||
@@ -223,13 +221,11 @@ TEST(Socket, TCP) {
|
||||
int conn_fd = accept(cap_sock_all, (struct sockaddr *)&addr, &len);
|
||||
EXPECT_OK(conn_fd);
|
||||
|
||||
#ifdef CAP_FROM_ACCEPT
|
||||
// New connection should also be a capability.
|
||||
cap_rights_t rights;
|
||||
cap_rights_init(&rights, 0);
|
||||
EXPECT_OK(cap_rights_get(conn_fd, &rights));
|
||||
EXPECT_RIGHTS_IN(&rights, &r_all);
|
||||
#endif
|
||||
|
||||
// Wait for the child.
|
||||
int status;
|
||||
|
||||
@@ -5,11 +5,6 @@
|
||||
#ifndef __SYSCALLS_H__
|
||||
#define __SYSCALLS_H__
|
||||
|
||||
/************************************************************
|
||||
* FreeBSD
|
||||
************************************************************/
|
||||
#ifdef __FreeBSD__
|
||||
|
||||
/* Map umount2 (Linux) syscall to unmount (FreeBSD) syscall */
|
||||
#define umount2(T, F) unmount(T, F)
|
||||
|
||||
@@ -108,11 +103,9 @@ inline long ptrace_(int request, pid_t pid, void *addr, void *data) {
|
||||
#define connect_ connect
|
||||
|
||||
/* Features available */
|
||||
#if __FreeBSD_version >= 1000000
|
||||
#define HAVE_CHFLAGSAT
|
||||
#define HAVE_BINDAT
|
||||
#define HAVE_CONNECTAT
|
||||
#endif
|
||||
#define HAVE_CHFLAGS
|
||||
#define HAVE_GETFSSTAT
|
||||
#define HAVE_REVOKE
|
||||
@@ -132,141 +125,4 @@ inline long ptrace_(int request, pid_t pid, void *addr, void *data) {
|
||||
/* FreeBSD effectively only allows root to call sched_setscheduler */
|
||||
#define SCHED_SETSCHEDULER_REQUIRES_ROOT 1
|
||||
|
||||
#endif /* FreeBSD */
|
||||
|
||||
/************************************************************
|
||||
* Linux
|
||||
************************************************************/
|
||||
#ifdef __linux__
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/sendfile.h>
|
||||
#include <sys/statfs.h>
|
||||
#include <sys/xattr.h>
|
||||
#include <sys/mount.h>
|
||||
#include <linux/net.h>
|
||||
|
||||
/* profil(2) has a first argument of unsigned short* */
|
||||
#define profil_arg1_t unsigned short
|
||||
|
||||
static inline int getdents_(unsigned int fd, void *dirp, unsigned int count) {
|
||||
return syscall(__NR_getdents, fd, dirp, count);
|
||||
}
|
||||
/* A sample mount(2) call */
|
||||
static inline int bogus_mount_() {
|
||||
return mount("/dev/bogus", "/bogus", "debugfs", MS_RDONLY, "");
|
||||
}
|
||||
|
||||
/* libc's getpid() wrapper caches the pid value, and doesn't invalidate
|
||||
* the cached value on pdfork(), so directly syscall. */
|
||||
static inline pid_t getpid_() {
|
||||
return syscall(__NR_getpid);
|
||||
}
|
||||
static inline int execveat(int fd, const char *path,
|
||||
char *const argv[], char *const envp[], int flags) {
|
||||
return syscall(__NR_execveat, fd, path, argv, envp, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* Linux glibc includes an fexecve() function, implemented via the /proc
|
||||
* filesystem. Bypass this and go directly to the execveat(2) syscall.
|
||||
*/
|
||||
static inline int fexecve_(int fd, char *const argv[], char *const envp[]) {
|
||||
return execveat(fd, "", argv, envp, AT_EMPTY_PATH);
|
||||
}
|
||||
/*
|
||||
* Linux glibc attempts to be clever and intercepts various uid/gid functions.
|
||||
* Bypass by calling the syscalls directly.
|
||||
*/
|
||||
static inline gid_t getegid_(void) { return syscall(__NR_getegid); }
|
||||
static inline gid_t getgid_(void) { return syscall(__NR_getgid); }
|
||||
static inline uid_t geteuid_(void) { return syscall(__NR_geteuid); }
|
||||
static inline uid_t getuid_(void) { return syscall(__NR_getuid); }
|
||||
static inline int getgroups_(int size, gid_t list[]) { return syscall(__NR_getgroups, size, list); }
|
||||
static inline int getrlimit_(int resource, struct rlimit *rlim) {
|
||||
return syscall(__NR_getrlimit, resource, rlim);
|
||||
}
|
||||
|
||||
/*
|
||||
* Linux glibc for i386 consumes the errno returned from the raw socketcall(2) operation,
|
||||
* so use the raw syscall for those operations that are disallowed in capability mode.
|
||||
*/
|
||||
#ifdef __NR_bind
|
||||
#define bind_ bind
|
||||
#else
|
||||
static inline int bind_(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
|
||||
unsigned long args[3] = {(unsigned long)sockfd, (unsigned long)(intptr_t)addr, (unsigned long)addrlen};
|
||||
return syscall(__NR_socketcall, SYS_BIND, args);
|
||||
}
|
||||
#endif
|
||||
#ifdef __NR_connect
|
||||
#define connect_ connect
|
||||
#else
|
||||
static inline int connect_(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
|
||||
unsigned long args[3] = {(unsigned long)sockfd, (unsigned long)(intptr_t)addr, (unsigned long)addrlen};
|
||||
return syscall(__NR_socketcall, SYS_CONNECT, args);
|
||||
}
|
||||
#endif
|
||||
|
||||
#define mincore_ mincore
|
||||
#define sendfile_ sendfile
|
||||
#define flistxattr_ flistxattr
|
||||
#define fgetxattr_ fgetxattr
|
||||
#define fsetxattr_ fsetxattr
|
||||
#define fremovexattr_ fremovexattr
|
||||
#define mq_notify_ mq_notify
|
||||
#define mq_open_ mq_open
|
||||
#define mq_setattr_ mq_setattr
|
||||
#define mq_getattr_ mq_getattr
|
||||
#define mq_timedreceive_ mq_timedreceive
|
||||
#define mq_timedsend_ mq_timedsend
|
||||
#define mq_unlink_ mq_unlink
|
||||
#define mq_close_ mq_close
|
||||
#define ptrace_ ptrace
|
||||
#define PTRACE_PEEKDATA_ PTRACE_PEEKDATA
|
||||
|
||||
/* Features available */
|
||||
#define HAVE_DUP3
|
||||
#define HAVE_PIPE2
|
||||
#include <sys/fsuid.h> /* for setfsgid()/setfsuid() */
|
||||
#define HAVE_SETFSUID
|
||||
#define HAVE_SETFSGID
|
||||
#define HAVE_READAHEAD
|
||||
#define HAVE_SEND_RECV_MMSG
|
||||
#define HAVE_SYNCFS
|
||||
#define HAVE_SYNC_FILE_RANGE
|
||||
#include <sys/uio.h> /* for vmsplice */
|
||||
#define HAVE_TEE
|
||||
#define HAVE_SPLICE
|
||||
#define HAVE_VMSPLICE
|
||||
#define HAVE_PSELECT
|
||||
#define HAVE_PPOLL
|
||||
#define HAVE_EXECVEAT
|
||||
#define HAVE_SYSCALL
|
||||
#define HAVE_MKNOD_REG
|
||||
#define HAVE_MKNOD_SOCKET
|
||||
/*
|
||||
* O_BENEATH is arch-specific, via <asm/fcntl.h>; however we cannot include both that file
|
||||
* and the normal <fcntl.h> as they have some clashing definitions. Bypass by directly
|
||||
* defining O_BENEATH, using the current proposed x86 value. (This will therefore not
|
||||
* work for non-x86, and may need changing in future if a different value gets merged.)
|
||||
*/
|
||||
#ifndef O_BENEATH
|
||||
#define O_BENEATH 040000000 /* no / or .. in openat path */
|
||||
#endif
|
||||
|
||||
|
||||
/* Linux allows anyone to call mlock[all]/munlock[all] */
|
||||
#define MLOCK_REQUIRES_ROOT 0
|
||||
/* Linux allows anyone to call sched_setscheduler */
|
||||
#define SCHED_SETSCHEDULER_REQUIRES_ROOT 1
|
||||
|
||||
#endif /* Linux */
|
||||
|
||||
#endif /*__SYSCALLS_H__*/
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include "capsicum.h"
|
||||
#include "capsicum-test.h"
|
||||
|
||||
#ifdef HAVE_SYSCTL
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
// Certain sysctls are permitted in capability mode, but most are not. Test
|
||||
@@ -12,4 +11,3 @@ TEST(Sysctl, Capability) {
|
||||
size_t len = sizeof(ii);
|
||||
EXPECT_OK(sysctl(oid, 2, &ii, &len, NULL, 0));
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -6,16 +6,7 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
#include <sys/procdesc.h>
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
#include <sys/syscall.h>
|
||||
int pdfork(int *fd, int flags) {
|
||||
return syscall(__NR_pdfork, fd, flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
int main() {
|
||||
int procfd;
|
||||
|
||||
Reference in New Issue
Block a user