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:
Alan Somers
2026-01-29 13:39:20 -07:00
parent dc9a8d300b
commit fba81b33aa
22 changed files with 55 additions and 937 deletions
+8 -40
View File
@@ -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`).
-140
View File
@@ -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
+5 -65
View File
@@ -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);
+4 -47
View File
@@ -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();
-18
View File
@@ -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__*/
-40
View File
@@ -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__*/
-103
View File
@@ -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__*/
-19
View File
@@ -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();
}
-23
View File
@@ -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 -144
View File
@@ -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
+1 -10
View File
@@ -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
+1 -28
View File
@@ -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
+1 -1
View File
@@ -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
-16
View File
@@ -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
+15 -51
View File
@@ -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);
-4
View File
@@ -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
-4
View File
@@ -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
}
+16 -25
View File
@@ -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));
-4
View File
@@ -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;
-144
View File
@@ -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__*/
-2
View File
@@ -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
-9
View File
@@ -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;