aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--GNUmakefile4
-rw-r--r--capability-fd.cc23
-rw-r--r--capmode.cc126
-rw-r--r--capsicum-test.cc88
-rw-r--r--capsicum-test.h36
-rw-r--r--makefile2
-rw-r--r--openat.cc1
-rw-r--r--procdesc.cc241
-rw-r--r--socket.cc18
9 files changed, 411 insertions, 128 deletions
diff --git a/GNUmakefile b/GNUmakefile
index d7133ca3b386..426eb49cdfa1 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -4,6 +4,10 @@ OS:=$(shell uname)
ARCH?=64
ARCHFLAG=-m$(ARCH)
+ifeq ($(OS),FreeBSD)
+EXTRA_LIBS=-lprocstat
+endif
+
ifeq ($(OS),Linux)
PROCESSOR:=$(shell uname -p)
diff --git a/capability-fd.cc b/capability-fd.cc
index a454d54aa86a..f255c6425cdd 100644
--- a/capability-fd.cc
+++ b/capability-fd.cc
@@ -486,6 +486,7 @@ FORK_TEST_ON(Capability, Mmap, TmpFile("cap_mmap_operations")) {
// Given a file descriptor, create a capability with specific rights and
// make sure only those rights work.
#define TRY_FILE_OPS(fd, ...) do { \
+ SCOPED_TRACE(#__VA_ARGS__); \
cap_rights_t rights; \
cap_rights_init(&rights, __VA_ARGS__); \
TryFileOps((fd), rights); \
@@ -1019,6 +1020,8 @@ FORK_TEST_ON(Capability, SocketTransfer, TmpFile("cap_fd_transfer")) {
if (child == 0) {
// Child: enter cap mode
EXPECT_OK(cap_enter());
+ // Child: send startup notification
+ SEND_INT_MESSAGE(sock_fds[0], MSG_CHILD_STARTED);
// Child: wait to receive FD over socket
int rc = recvmsg(sock_fds[0], &mh, 0);
@@ -1036,10 +1039,12 @@ FORK_TEST_ON(Capability, SocketTransfer, TmpFile("cap_fd_transfer")) {
EXPECT_RIGHTS_EQ(&r_rs, &rights);
TryReadWrite(cap_fd);
+ // Child: acknowledge that we have received and tested the file descriptor
+ SEND_INT_MESSAGE(sock_fds[0], MSG_CHILD_FD_RECEIVED);
+
// Child: wait for a normal read
- int val;
- read(sock_fds[0], &val, sizeof(val));
- exit(0);
+ AWAIT_INT_MESSAGE(sock_fds[0], MSG_PARENT_REQUEST_CHILD_EXIT);
+ exit(testing::Test::HasFailure());
}
int fd = open(TmpFile("cap_fd_transfer"), O_RDWR | O_CREAT, 0644);
@@ -1054,6 +1059,9 @@ FORK_TEST_ON(Capability, SocketTransfer, TmpFile("cap_fd_transfer")) {
// Confirm we can do the right operations on the capability
TryReadWrite(cap_fd);
+ // Wait for child to start up:
+ AWAIT_INT_MESSAGE(sock_fds[1], MSG_CHILD_STARTED);
+
// Send the file descriptor over the pipe to the sub-process
mh.msg_controllen = CMSG_LEN(sizeof(int));
cmptr = CMSG_FIRSTHDR(&mh);
@@ -1063,13 +1071,14 @@ FORK_TEST_ON(Capability, SocketTransfer, TmpFile("cap_fd_transfer")) {
*(int *)CMSG_DATA(cmptr) = cap_fd;
buffer1[0] = 0;
iov[0].iov_len = 1;
- sleep(3);
int rc = sendmsg(sock_fds[1], &mh, 0);
EXPECT_OK(rc);
- sleep(1); // Ensure subprocess runs
- int zero = 0;
- write(sock_fds[1], &zero, sizeof(zero));
+ // Check that the child received the message
+ AWAIT_INT_MESSAGE(sock_fds[1], MSG_CHILD_FD_RECEIVED);
+
+ // Tell the child to exit
+ SEND_INT_MESSAGE(sock_fds[1], MSG_PARENT_REQUEST_CHILD_EXIT);
}
TEST(Capability, SyscallAt) {
diff --git a/capmode.cc b/capmode.cc
index 567773f319d9..c274f5e1c9f3 100644
--- a/capmode.cc
+++ b/capmode.cc
@@ -528,6 +528,8 @@ TEST(Capmode, Abort) {
FORK_TEST_F(WithFiles, AllowedMiscSyscalls) {
umask(022);
mode_t um_before = umask(022);
+ int pipefds[2];
+ EXPECT_OK(pipe(pipefds));
EXPECT_OK(cap_enter()); // Enter capability mode.
mode_t um = umask(022);
@@ -540,13 +542,19 @@ FORK_TEST_F(WithFiles, AllowedMiscSyscalls) {
pid_t pid = fork();
EXPECT_OK(pid);
if (pid == 0) {
- // Child: almost immediately exit.
- sleep(1);
+ // Child: wait for an exit message from parent (so we can test waitpid).
+ EXPECT_OK(close(pipefds[0]));
+ SEND_INT_MESSAGE(pipefds[1], MSG_CHILD_STARTED);
+ AWAIT_INT_MESSAGE(pipefds[1], MSG_PARENT_REQUEST_CHILD_EXIT);
exit(0);
} else if (pid > 0) {
+ EXPECT_OK(close(pipefds[1]));
+ AWAIT_INT_MESSAGE(pipefds[0], MSG_CHILD_STARTED);
errno = 0;
EXPECT_CAPMODE(ptrace_(PTRACE_PEEKDATA_, pid, &pid, NULL));
- EXPECT_CAPMODE(waitpid(pid, NULL, 0));
+ EXPECT_CAPMODE(waitpid(pid, NULL, WNOHANG));
+ SEND_INT_MESSAGE(pipefds[0], MSG_PARENT_REQUEST_CHILD_EXIT);
+ if (verbose) fprintf(stderr, " child finished\n");
}
// No error return from sync(2) to test, but check errno remains unset.
@@ -568,68 +576,136 @@ FORK_TEST_F(WithFiles, AllowedMiscSyscalls) {
}
void *thread_fn(void *p) {
- int delay = *(int *)p;
- sleep(delay);
+ 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_CAPMODE(open("/dev/null", O_RDWR));
- return NULL;
+ // Return whether there have been any failures to the main thread.
+ void *rval = (void *)(intptr_t)testing::Test::HasFailure();
+ if (verbose) fprintf(stderr, " thread finished: %p\n", rval);
+ return rval;
}
// Check that restrictions are the same in subprocesses and threads
FORK_TEST(Capmode, NewThread) {
// Fire off a new thread before entering capability mode
pthread_t early_thread;
- int one = 1; // second
- EXPECT_OK(pthread_create(&early_thread, NULL, thread_fn, &one));
+ void *thread_rval;
+ // Create two pipes, one for synchronization with the threads, the other to
+ // synchronize with the children (since we can't use waitpid after cap_enter).
+ // Note: Could use pdfork+pdwait instead, but that is tested in procdesc.cc.
+ int thread_pipe[2];
+ EXPECT_OK(pipe(thread_pipe));
+ int proc_pipe[2];
+ EXPECT_OK(pipe(proc_pipe));
+ EXPECT_OK(pthread_create(&early_thread, NULL, thread_fn,
+ (void *)(intptr_t)thread_pipe[1]));
// Fire off a new process before entering capability mode.
+ if (verbose) fprintf(stderr, " starting second child (non-capability mode)\n");
int early_child = fork();
EXPECT_OK(early_child);
if (early_child == 0) {
- // Child: wait and then confirm this process is unaffect by capability mode in the parent.
- sleep(1);
+ if (verbose) fprintf(stderr, " first child started\n");
+ EXPECT_OK(close(proc_pipe[0]));
+ // Child: wait and then confirm this process is unaffected by capability mode in the parent.
+ AWAIT_INT_MESSAGE(proc_pipe[1], MSG_PARENT_CHILD_SHOULD_RUN);
int fd = open("/dev/null", O_RDWR);
EXPECT_OK(fd);
close(fd);
- exit(0);
+ // Notify the parent of success/failure.
+ int rval = (int)testing::Test::HasFailure();
+ SEND_INT_MESSAGE(proc_pipe[1], rval);
+ if (verbose) fprintf(stderr, " first child finished: %d\n", rval);
+ exit(rval);
}
EXPECT_OK(cap_enter()); // Enter capability mode.
+ // At this point the current process has both a child process and a
+ // child thread that were created before entering capability mode.
+ // - The child process is unaffected by capability mode.
+ // - The child thread is affected by capability mode.
+ SEND_INT_MESSAGE(proc_pipe[0], MSG_PARENT_CHILD_SHOULD_RUN);
+
// Do an allowed syscall.
EXPECT_OK(getpid_());
+ // Wait for the first child to exit (should get a zero exit code message).
+ AWAIT_INT_MESSAGE(proc_pipe[0], 0);
+
+ // The child processes/threads return HasFailure(), so we depend on no prior errors.
+ ASSERT_FALSE(testing::Test::HasFailure())
+ << "Cannot continue test with pre-existing failures.";
+ // Now that we're in capability mode, if we create a second child process
+ // it will be affected by capability mode.
+ if (verbose) fprintf(stderr, " starting second child (in capability mode)\n");
int child = fork();
EXPECT_OK(child);
if (child == 0) {
+ 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_CAPMODE(open("/dev/null", O_RDWR));
- exit(0);
+ // Notify the parent of success/failure.
+ int rval = (int)testing::Test::HasFailure();
+ SEND_INT_MESSAGE(proc_pipe[1], rval);
+ if (verbose) fprintf(stderr, " second child finished: %d\n", rval);
+ exit(rval);
}
- // Don't (can't) wait for either child.
-
+ // Now tell the early_started thread that it can run. We expect it to also
+ // be affected by capability mode since it's per-process not per-thread.
+ // Note: it is important that we don't allow the thread to run before fork(),
+ // since that could result in fork() being called while the thread holds one
+ // of the gtest-internal mutexes, so the child process deadlocks.
+ SEND_INT_MESSAGE(thread_pipe[0], MSG_PARENT_CHILD_SHOULD_RUN);
// Wait for the early-started thread.
- EXPECT_OK(pthread_join(early_thread, NULL));
+ EXPECT_OK(pthread_join(early_thread, &thread_rval));
+ EXPECT_FALSE((bool)(intptr_t)thread_rval) << "thread returned failure";
- // Fire off a new thread.
+ // Wait for the second child to exit (should get a zero exit code message).
+ AWAIT_INT_MESSAGE(proc_pipe[0], 0);
+
+ // Fire off a new (second) child thread, which is also affected by capability mode.
+ ASSERT_FALSE(testing::Test::HasFailure())
+ << "Cannot continue test with pre-existing failures.";
pthread_t child_thread;
- int zero = 0; // seconds
- EXPECT_OK(pthread_create(&child_thread, NULL, thread_fn, &zero));
- EXPECT_OK(pthread_join(child_thread, NULL));
+ EXPECT_OK(pthread_create(&child_thread, NULL, thread_fn,
+ (void *)(intptr_t)thread_pipe[1]));
+ SEND_INT_MESSAGE(thread_pipe[0], MSG_PARENT_CHILD_SHOULD_RUN);
+ EXPECT_OK(pthread_join(child_thread, &thread_rval));
+ EXPECT_FALSE((bool)(intptr_t)thread_rval) << "thread returned failure";
// Fork a subprocess which fires off a new thread.
+ ASSERT_FALSE(testing::Test::HasFailure())
+ << "Cannot continue test with pre-existing failures.";
+ if (verbose) fprintf(stderr, " starting third child (in capability mode)\n");
child = fork();
EXPECT_OK(child);
if (child == 0) {
+ if (verbose) fprintf(stderr, " third child started\n");
+ EXPECT_OK(close(proc_pipe[0]));
pthread_t child_thread2;
- EXPECT_OK(pthread_create(&child_thread2, NULL, thread_fn, &zero));
- EXPECT_OK(pthread_join(child_thread2, NULL));
- exit(0);
+ EXPECT_OK(pthread_create(&child_thread2, NULL, thread_fn,
+ (void *)(intptr_t)thread_pipe[1]));
+ SEND_INT_MESSAGE(thread_pipe[0], MSG_PARENT_CHILD_SHOULD_RUN);
+ EXPECT_OK(pthread_join(child_thread2, &thread_rval));
+ EXPECT_FALSE((bool)(intptr_t)thread_rval) << "thread returned failure";
+ // Notify the parent of success/failure.
+ int rval = (int)testing::Test::HasFailure();
+ SEND_INT_MESSAGE(proc_pipe[1], rval);
+ if (verbose) fprintf(stderr, " third child finished: %d\n", rval);
+ exit(rval);
}
- // Sleep for a bit to allow the subprocess to finish.
- sleep(2);
+ // Wait for the third child to exit (should get a zero exit code message).
+ AWAIT_INT_MESSAGE(proc_pipe[0], 0);
+ close(proc_pipe[0]);
+ close(proc_pipe[1]);
+ close(thread_pipe[0]);
+ close(thread_pipe[1]);
}
-static int had_signal = 0;
+static volatile sig_atomic_t had_signal = 0;
static void handle_signal(int) { had_signal = 1; }
FORK_TEST(Capmode, SelfKill) {
diff --git a/capsicum-test.cc b/capsicum-test.cc
index 6adb222ec055..dedad464a4d9 100644
--- a/capsicum-test.cc
+++ b/capsicum-test.cc
@@ -1,5 +1,15 @@
#include "capsicum-test.h"
+#ifdef __FreeBSD__
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <sys/user.h>
+#include <libprocstat.h>
+#endif
+
#include <stdio.h>
#include <string.h>
#include <signal.h>
@@ -48,31 +58,59 @@ char ProcessState(int pid) {
return '?';
#endif
#ifdef __FreeBSD__
- char buffer[1024];
- snprintf(buffer, sizeof(buffer), "ps -p %d -o state | grep -v STAT", pid);
- sig_t original = signal(SIGCHLD, SIG_IGN);
- FILE* cmd = popen(buffer, "r");
- usleep(50000); // allow any pending SIGCHLD signals to arrive
- signal(SIGCHLD, original);
- int result = fgetc(cmd);
- fclose(cmd);
- // Map FreeBSD codes to Linux codes.
- switch (result) {
- case EOF:
- return '\0';
- case 'D': // disk wait
- case 'R': // runnable
- case 'S': // sleeping
- case 'T': // stopped
- case 'Z': // zombie
- return result;
- case 'W': // idle interrupt thread
- return 'S';
- case 'I': // idle
- return 'S';
- case 'L': // waiting to acquire lock
- default:
- return '?';
+ // 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;
+ int name[4];
+ name[0] = CTL_KERN;
+ name[1] = KERN_PROC;
+ name[2] = KERN_PROC_PID;
+ name[3] = pid;
+ if (sysctl(name, nitems(name), NULL, &len, NULL, 0) < 0 && errno == ESRCH) {
+ if (verbose) fprintf(stderr, "Process %d does not exist\n", pid);
+ return '\0'; // No such process.
+ }
+ unsigned int count = 0;
+ struct procstat *prstat = procstat_open_sysctl();
+ EXPECT_NE(NULL, prstat) << "procstat_open_sysctl failed.";
+ errno = 0;
+ struct kinfo_proc *p = procstat_getprocs(prstat, KERN_PROC_PID, pid, &count);
+ if (p == NULL || count == 0) {
+ if (verbose) fprintf(stderr, "procstat_getprocs failed with %p/%d: %s\n", p, count, strerror(errno));
+ procstat_close(prstat);
+ return '\0';
+ }
+ char result = '\0';
+ // See state() in bin/ps/print.c
+ switch (p->ki_stat) {
+ case SSTOP:
+ result = 'T';
+ break;
+ case SSLEEP:
+ if (p->ki_tdflags & TDF_SINTR) /* interruptable (long) */
+ result = 'S';
+ else
+ result = 'D';
+ break;
+ case SRUN:
+ case SIDL:
+ result = 'R';
+ break;
+ case SWAIT:
+ case SLOCK:
+ // We treat SWAIT/SLOCK as 'S' here (instead of 'W'/'L').
+ result = 'S';
+ break;
+ case SZOMB:
+ result = 'Z';
+ break;
+ default:
+ result = '?';
+ break;
}
+ procstat_freeprocs(prstat, p);
+ procstat_close(prstat);
+ if (verbose) fprintf(stderr, "Process %d in state '%c'\n", pid, result);
+ return result;
#endif
}
diff --git a/capsicum-test.h b/capsicum-test.h
index 808840f4280e..7433814b31c8 100644
--- a/capsicum-test.h
+++ b/capsicum-test.h
@@ -140,15 +140,17 @@ const char *TmpFile(const char *pathname);
// Expect a syscall to fail with the given error.
#define EXPECT_SYSCALL_FAIL(E, C) \
do { \
+ SCOPED_TRACE(#C); \
EXPECT_GT(0, C); \
- EXPECT_EQ(E, errno); \
+ EXPECT_EQ(E, errno) << "expected '" << strerror(E) \
+ << "' but got '" << strerror(errno) << "'"; \
} while (0)
// Expect a syscall to fail with anything other than the given error.
#define EXPECT_SYSCALL_FAIL_NOT(E, C) \
do { \
EXPECT_GT(0, C); \
- EXPECT_NE(E, errno); \
+ EXPECT_NE(E, errno) << strerror(E); \
} while (0)
// Expect a void syscall to fail with anything other than the given error.
@@ -163,7 +165,8 @@ const char *TmpFile(const char *pathname);
// code is OS-specific.
#ifdef O_BENEATH
#define EXPECT_OPENAT_FAIL_TRAVERSAL(fd, path, flags) \
- do { \
+ do { \
+ SCOPED_TRACE(GTEST_STRINGIFY_(openat((fd), (path), (flags)))); \
const int result = openat((fd), (path), (flags)); \
if (((flags) & O_BENEATH) == O_BENEATH) { \
EXPECT_SYSCALL_FAIL(E_NO_TRAVERSE_O_BENEATH, result); \
@@ -175,6 +178,7 @@ const char *TmpFile(const char *pathname);
#else
#define EXPECT_OPENAT_FAIL_TRAVERSAL(fd, path, flags) \
do { \
+ SCOPED_TRACE(GTEST_STRINGIFY_(openat((fd), (path), (flags)))); \
const int result = openat((fd), (path), (flags)); \
EXPECT_SYSCALL_FAIL(E_NO_TRAVERSE_CAPABILITY, result); \
if (result >= 0) { close(result); } \
@@ -200,7 +204,8 @@ const char *TmpFile(const char *pathname);
int rc = C; \
EXPECT_GT(0, rc); \
EXPECT_TRUE(errno == ECAPMODE || errno == ENOTCAPABLE) \
- << #C << " did not fail with ECAPMODE/ENOTCAPABLE but " << errno; \
+ << #C << " did not fail with ECAPMODE/ENOTCAPABLE but " << errno \
+ << "(" << strerror(errno) << ")"; \
} while (0)
// Ensure that 'rights' are a subset of 'max'.
@@ -244,6 +249,29 @@ char ProcessState(int pid);
#define EXPECT_PID_ZOMBIE(pid) EXPECT_PID_REACHES_STATES(pid, 'Z', 'Z');
#define EXPECT_PID_GONE(pid) EXPECT_PID_REACHES_STATES(pid, '\0', '\0');
+enum {
+ // Magic numbers for messages sent by child processes.
+ MSG_CHILD_STARTED = 1234,
+ MSG_CHILD_FD_RECEIVED = 4321,
+ // Magic numbers for messages sent by parent processes.
+ MSG_PARENT_REQUEST_CHILD_EXIT = 9999,
+ MSG_PARENT_CLOSED_FD = 10000,
+ MSG_PARENT_CHILD_SHOULD_RUN = 10001,
+};
+
+#define SEND_INT_MESSAGE(fd, message) \
+ do { \
+ int _msg = message; \
+ EXPECT_EQ(sizeof(_msg), (size_t)write(fd, &_msg, sizeof(_msg))); \
+ } while (0)
+
+#define AWAIT_INT_MESSAGE(fd, expected) \
+ do { \
+ int _msg = 0; \
+ EXPECT_EQ(sizeof(_msg), (size_t)read(fd, &_msg, sizeof(_msg))); \
+ EXPECT_EQ(expected, _msg); \
+ } while (0)
+
// Mark a test that can only be run as root.
#define GTEST_SKIP_IF_NOT_ROOT() \
if (getuid() != 0) { GTEST_SKIP() << "requires root"; }
diff --git a/makefile b/makefile
index 7b95e1927927..ad697f160e2e 100644
--- a/makefile
+++ b/makefile
@@ -8,7 +8,7 @@ CXXFLAGS+=$(ARCHFLAG) -Wall -g $(GTEST_INCS) $(GTEST_FLAGS) --std=c++11
CFLAGS+=$(ARCHFLAG) -Wall -g
capsicum-test: $(OBJECTS) libgtest.a $(LOCAL_LIBS)
- $(CXX) $(CXXFLAGS) -g -o $@ $(OBJECTS) libgtest.a -lpthread -lrt $(LIBSCTP) $(LIBCAPRIGHTS)
+ $(CXX) $(CXXFLAGS) -g -o $@ $(OBJECTS) libgtest.a -lpthread -lrt $(LIBSCTP) $(LIBCAPRIGHTS) $(EXTRA_LIBS)
# Small statically-linked program for fexecve tests
# (needs to be statically linked so that execve()ing it
diff --git a/openat.cc b/openat.cc
index ca7e39772f9a..1f48909037bf 100644
--- a/openat.cc
+++ b/openat.cc
@@ -11,6 +11,7 @@
// Check an open call works and close the resulting fd.
#define EXPECT_OPEN_OK(f) do { \
+ SCOPED_TRACE(#f); \
int _fd = f; \
EXPECT_OK(_fd); \
close(_fd); \
diff --git a/procdesc.cc b/procdesc.cc
index 11274ce9e866..105546cabfb2 100644
--- a/procdesc.cc
+++ b/procdesc.cc
@@ -27,10 +27,6 @@
#define __WALL 0
#endif
-// TODO(drysdale): it would be nice to use proper synchronization between
-// processes, rather than synchronization-via-sleep; faster too.
-
-
//------------------------------------------------
// Utilities for the tests.
@@ -73,7 +69,10 @@ static void print_stat(FILE *f, const struct stat *stat) {
(long)stat->st_atime, (long)stat->st_mtime, (long)stat->st_ctime);
}
-static std::map<int,bool> had_signal;
+static volatile sig_atomic_t had_signal[NSIG];
+void clear_had_signals() {
+ memset(const_cast<sig_atomic_t *>(had_signal), 0, sizeof(had_signal));
+}
static void handle_signal(int x) {
had_signal[x] = true;
}
@@ -109,7 +108,9 @@ void CheckChildFinished(pid_t pid, bool signaled=false) {
TEST(Pdfork, Simple) {
int pd = -1;
+ int pipefds[2];
pid_t parent = getpid_();
+ EXPECT_OK(pipe(pipefds));
int pid = pdfork(&pd, 0);
EXPECT_OK(pid);
if (pid == 0) {
@@ -117,19 +118,29 @@ TEST(Pdfork, Simple) {
EXPECT_EQ(-1, pd);
EXPECT_NE(parent, getpid_());
EXPECT_EQ(parent, getppid());
- sleep(1);
- exit(0);
+ close(pipefds[0]);
+ SEND_INT_MESSAGE(pipefds[1], MSG_CHILD_STARTED);
+ if (verbose) fprintf(stderr, "Child waiting for exit message\n");
+ // Terminate once the parent has completed the checks
+ AWAIT_INT_MESSAGE(pipefds[1], MSG_PARENT_REQUEST_CHILD_EXIT);
+ exit(testing::Test::HasFailure());
}
- usleep(100); // ensure the child has a chance to run
+ close(pipefds[1]);
+ // Ensure the child has started.
+ AWAIT_INT_MESSAGE(pipefds[0], MSG_CHILD_STARTED);
+
EXPECT_NE(-1, pd);
EXPECT_PID_ALIVE(pid);
int pid_got;
EXPECT_OK(pdgetpid(pd, &pid_got));
EXPECT_EQ(pid, pid_got);
- // Wait long enough for the child to exit().
- sleep(2);
+ // Tell the child to exit and wait until it is a zombie.
+ SEND_INT_MESSAGE(pipefds[0], MSG_PARENT_REQUEST_CHILD_EXIT);
+ // EXPECT_PID_ZOMBIE waits for up to ~500ms, that should be enough time for
+ // the child to exit successfully.
EXPECT_PID_ZOMBIE(pid);
+ close(pipefds[0]);
// Wait for the the child.
int status;
@@ -223,7 +234,10 @@ TEST(Pdfork, NonProcessDescriptor) {
close(fd);
}
-static void *SubThreadMain(void *) {
+static void *SubThreadMain(void *arg) {
+ // Notify the main thread that we have started
+ if (verbose) fprintf(stderr, " subthread started: pipe=%p\n", arg);
+ SEND_INT_MESSAGE((int)(intptr_t)arg, MSG_CHILD_STARTED);
while (true) {
if (verbose) fprintf(stderr, " subthread: \"I aten't dead\"\n");
usleep(100000);
@@ -233,11 +247,28 @@ static void *SubThreadMain(void *) {
static void *ThreadMain(void *) {
int pd;
+ int pipefds[2];
+ EXPECT_EQ(0, pipe(pipefds));
pid_t child = pdfork(&pd, 0);
if (child == 0) {
- // Child: start a subthread then loop
+ close(pipefds[0]);
+ // Child: start a subthread then loop.
pthread_t child_subthread;
- EXPECT_OK(pthread_create(&child_subthread, NULL, SubThreadMain, NULL));
+ // Wait for the subthread startup using another pipe.
+ int thread_pipefds[2];
+ EXPECT_EQ(0, pipe(thread_pipefds));
+ EXPECT_OK(pthread_create(&child_subthread, NULL, SubThreadMain,
+ (void *)(intptr_t)thread_pipefds[0]));
+ if (verbose) {
+ fprintf(stderr, " pdforked process %d: waiting for subthread.\n",
+ getpid());
+ }
+ AWAIT_INT_MESSAGE(thread_pipefds[1], MSG_CHILD_STARTED);
+ close(thread_pipefds[0]);
+ close(thread_pipefds[1]);
+ // Child: Notify parent that all threads have started
+ if (verbose) fprintf(stderr, " pdforked process %d: subthread started\n", getpid());
+ SEND_INT_MESSAGE(pipefds[1], MSG_CHILD_STARTED);
while (true) {
if (verbose) fprintf(stderr, " pdforked process %d: \"I aten't dead\"\n", getpid());
usleep(100000);
@@ -245,7 +276,9 @@ static void *ThreadMain(void *) {
exit(0);
}
if (verbose) fprintf(stderr, " thread generated pd %d\n", pd);
- sleep(2);
+ close(pipefds[1]);
+ AWAIT_INT_MESSAGE(pipefds[0], MSG_CHILD_STARTED);
+ if (verbose) fprintf(stderr, "[%d] got child startup message\n", getpid_());
// Pass the process descriptor back to the main thread.
return reinterpret_cast<void *>(pd);
@@ -278,7 +311,7 @@ TEST(Pdfork, FromThread) {
class PipePdforkBase : public ::testing::Test {
public:
PipePdforkBase(int pdfork_flags) : pd_(-1), pid_(-1) {
- had_signal.clear();
+ clear_had_signals();
int pipes[2];
EXPECT_OK(pipe(pipes));
pipe_ = pipes[1];
@@ -356,24 +389,34 @@ TEST_F(PipePdfork, Poll) {
// Can multiple processes poll on the same descriptor?
TEST_F(PipePdfork, PollMultiple) {
+ int pipefds[2];
+ EXPECT_EQ(0, pipe(pipefds));
int child = fork();
EXPECT_OK(child);
if (child == 0) {
- // Child: wait to give time for setup, then write to the pipe (which will
- // induce exit of the pdfork()ed process) and exit.
- sleep(1);
+ close(pipefds[0]);
+ // Child: wait for parent to acknowledge startup
+ SEND_INT_MESSAGE(pipefds[1], MSG_CHILD_STARTED);
+ // Child: wait for two messages from the parent and the forked process
+ // before telling the other process to terminate.
+ if (verbose) fprintf(stderr, "[%d] waiting for read 1\n", getpid_());
+ AWAIT_INT_MESSAGE(pipefds[1], MSG_PARENT_REQUEST_CHILD_EXIT);
+ if (verbose) fprintf(stderr, "[%d] waiting for read 2\n", getpid_());
+ AWAIT_INT_MESSAGE(pipefds[1], MSG_PARENT_REQUEST_CHILD_EXIT);
TerminateChild();
- exit(0);
+ if (verbose) fprintf(stderr, "[%d] about to exit\n", getpid_());
+ exit(testing::Test::HasFailure());
}
- usleep(100); // ensure the child has a chance to run
-
+ close(pipefds[1]);
+ AWAIT_INT_MESSAGE(pipefds[0], MSG_CHILD_STARTED);
+ if (verbose) fprintf(stderr, "[%d] got child startup message\n", getpid_());
// Fork again
int doppel = fork();
EXPECT_OK(doppel);
// We now have:
// pid A: main process, here
// |--pid B: pdfork()ed process, blocked on read()
- // |--pid C: fork()ed process, in sleep(1) above
+ // |--pid C: fork()ed process, in read() above
// +--pid D: doppel process, here
// Both A and D execute the following code.
@@ -384,12 +427,18 @@ TEST_F(PipePdfork, PollMultiple) {
fdp.revents = 0;
EXPECT_EQ(0, poll(&fdp, 1, 0));
+ // Both A and D ask C to exit, allowing it to do so.
+ if (verbose) fprintf(stderr, "[%d] telling child to exit\n", getpid_());
+ SEND_INT_MESSAGE(pipefds[0], MSG_PARENT_REQUEST_CHILD_EXIT);
+ close(pipefds[0]);
+
// Now, wait (indefinitely) for activity on the process descriptor.
// We expect:
- // - pid C will finish its sleep, write to the pipe and exit
+ // - pid C will finish its two read() calls, write to the pipe and exit.
// - pid B will unblock from read(), and exit
// - this will generate an event on the process descriptor...
// - ...in both process A and process D.
+ if (verbose) fprintf(stderr, "[%d] waiting for child to exit\n", getpid_());
EXPECT_EQ(1, poll(&fdp, 1, 2000));
EXPECT_TRUE(fdp.revents & POLLHUP);
@@ -522,6 +571,7 @@ TEST_F(PipePdfork, CloseLast) {
FORK_TEST(Pdfork, OtherUserIfRoot) {
GTEST_SKIP_IF_NOT_ROOT();
int pd;
+ int status;
pid_t pid = pdfork(&pd, 0);
EXPECT_OK(pid);
if (pid == 0) {
@@ -542,15 +592,29 @@ FORK_TEST(Pdfork, OtherUserIfRoot) {
EXPECT_EQ(EPERM, errno);
EXPECT_PID_ALIVE(pid);
- // Succeed with pdkill though.
+ // Ideally, we should be able to send signals via a process descriptor even
+ // if it's owned by another user, but this is not implementated on FreeBSD.
+#ifdef __FreeBSD__
+ // On FreeBSD, pdkill() still performs all the same checks that kill() does
+ // and therefore cannot be used to send a signal to a process with another
+ // UID unless we are root.
+ EXPECT_SYSCALL_FAIL(EBADF, pdkill(pid, SIGKILL));
+ EXPECT_PID_ALIVE(pid);
+ // However, the process will be killed when we close the process descriptor.
+ EXPECT_OK(close(pd));
+ EXPECT_PID_GONE(pid);
+ // Can't pdwait4() after close() since close() reparents the child to a reaper (init)
+ EXPECT_SYSCALL_FAIL(EBADF, pdwait4_(pd, &status, WNOHANG, NULL));
+#else
+ // Sending a signal with pdkill() should be permitted though.
EXPECT_OK(pdkill(pd, SIGKILL));
EXPECT_PID_ZOMBIE(pid);
- int status;
int rc = pdwait4_(pd, &status, WNOHANG, NULL);
EXPECT_OK(rc);
EXPECT_EQ(pid, rc);
EXPECT_TRUE(WIFSIGNALED(status));
+#endif
}
TEST_F(PipePdfork, WaitPidThenPd) {
@@ -624,18 +688,27 @@ TEST_F(PipePdforkDaemon, Pdkill) {
TEST(Pdfork, PdkillOtherSignal) {
int pd = -1;
+ int pipefds[2];
+ EXPECT_EQ(0, pipe(pipefds));
int pid = pdfork(&pd, 0);
EXPECT_OK(pid);
if (pid == 0) {
- // Child: watch for SIGUSR1 forever.
- had_signal.clear();
+ // Child: tell the parent that we have started before entering the loop,
+ // and importantly only do so once we have registered the SIGUSR1 handler.
+ close(pipefds[0]);
+ clear_had_signals();
signal(SIGUSR1, handle_signal);
+ SEND_INT_MESSAGE(pipefds[1], MSG_CHILD_STARTED);
+ // Child: watch for SIGUSR1 forever.
while (!had_signal[SIGUSR1]) {
usleep(100000);
}
exit(123);
}
- sleep(1);
+ // Wait for child to start
+ close(pipefds[1]);
+ AWAIT_INT_MESSAGE(pipefds[0], MSG_CHILD_STARTED);
+ close(pipefds[0]);
// Send an invalid signal.
EXPECT_EQ(-1, pdkill(pd, 0xFFFF));
@@ -651,14 +724,15 @@ TEST(Pdfork, PdkillOtherSignal) {
int rc = waitpid(pid, &status, __WALL);
EXPECT_OK(rc);
EXPECT_EQ(pid, rc);
- EXPECT_TRUE(WIFEXITED(status)) << "0x" << std::hex << rc;
+ EXPECT_TRUE(WIFEXITED(status)) << "status: 0x" << std::hex << status;
EXPECT_EQ(123, WEXITSTATUS(status));
}
pid_t PdforkParentDeath(int pdfork_flags) {
// Set up:
// pid A: main process, here
- // +--pid B: fork()ed process, sleep(4)s then exits
+ // +--pid B: fork()ed process, starts a child process with pdfork() then
+ // waits for parent to send a shutdown message.
// +--pid C: pdfork()ed process, looping forever
int sock_fds[2];
EXPECT_OK(socketpair(AF_UNIX, SOCK_STREAM, 0, sock_fds));
@@ -668,27 +742,45 @@ pid_t PdforkParentDeath(int pdfork_flags) {
if (child == 0) {
int pd;
if (verbose) fprintf(stderr, " [%d] child about to pdfork()...\n", getpid_());
+ int pipefds[2]; // for startup notification
+ EXPECT_OK(pipe(pipefds));
pid_t grandchild = pdfork(&pd, pdfork_flags);
if (grandchild == 0) {
+ close(pipefds[0]);
+ pid_t grandchildPid = getpid_();
+ EXPECT_EQ(sizeof(grandchildPid), (size_t)write(pipefds[1], &grandchildPid, sizeof(grandchildPid)));
while (true) {
- if (verbose) fprintf(stderr, " [%d] grandchild: \"I aten't dead\"\n", getpid_());
+ if (verbose) fprintf(stderr, " [%d] grandchild: \"I aten't dead\"\n", grandchildPid);
sleep(1);
}
}
+ close(pipefds[1]);
if (verbose) fprintf(stderr, " [%d] pdfork()ed grandchild %d, sending ID to parent\n", getpid_(), grandchild);
- // send grandchild pid to parent
- write(sock_fds[1], &grandchild, sizeof(grandchild));
- sleep(4);
+ // Wait for grandchild to start.
+ pid_t grandchild2;
+ EXPECT_EQ(sizeof(grandchild2), (size_t)read(pipefds[0], &grandchild2, sizeof(grandchild2)));
+ EXPECT_EQ(grandchild, grandchild2) << "received invalid grandchild pid";
+ if (verbose) fprintf(stderr, " [%d] grandchild %d has started successfully\n", getpid_(), grandchild);
+ close(pipefds[0]);
+
+ // Send grandchild pid to parent.
+ EXPECT_EQ(sizeof(grandchild), (size_t)write(sock_fds[1], &grandchild, sizeof(grandchild)));
+ if (verbose) fprintf(stderr, " [%d] sent grandchild pid %d to parent\n", getpid_(), grandchild);
+ // Wait for parent to acknowledge the message.
+ AWAIT_INT_MESSAGE(sock_fds[1], MSG_PARENT_REQUEST_CHILD_EXIT);
+ if (verbose) fprintf(stderr, " [%d] parent acknowledged grandchild pid %d\n", getpid_(), grandchild);
if (verbose) fprintf(stderr, " [%d] child terminating\n", getpid_());
- exit(0);
+ exit(testing::Test::HasFailure());
}
if (verbose) fprintf(stderr, "[%d] fork()ed child is %d\n", getpid_(), child);
pid_t grandchild;
read(sock_fds[0], &grandchild, sizeof(grandchild));
- if (verbose) fprintf(stderr, "[%d] receive grandchild id %d\n", getpid_(), grandchild);
+ if (verbose) fprintf(stderr, "[%d] received grandchild id %d\n", getpid_(), grandchild);
EXPECT_PID_ALIVE(child);
EXPECT_PID_ALIVE(grandchild);
- sleep(6);
+ // Tell child to exit.
+ if (verbose) fprintf(stderr, "[%d] telling child %d to exit\n", getpid_(), child);
+ SEND_INT_MESSAGE(sock_fds[0], MSG_PARENT_REQUEST_CHILD_EXIT);
// Child dies, closing its process descriptor for the grandchild.
EXPECT_PID_DEAD(child);
CheckChildFinished(child);
@@ -713,7 +805,7 @@ TEST(Pdfork, BagpussDaemon) {
// The exit of a pdfork()ed process should not generate SIGCHLD.
TEST_F(PipePdfork, NoSigchld) {
- had_signal.clear();
+ clear_had_signals();
sighandler_t original = signal(SIGCHLD, handle_signal);
TerminateChild();
int rc = 0;
@@ -728,7 +820,7 @@ TEST_F(PipePdfork, NoSigchld) {
// all been closed should generate SIGCHLD. The child process needs
// PD_DAEMON to survive the closure of the process descriptors.
TEST_F(PipePdforkDaemon, NoPDSigchld) {
- had_signal.clear();
+ clear_had_signals();
sighandler_t original = signal(SIGCHLD, handle_signal);
EXPECT_OK(close(pd_));
@@ -766,10 +858,8 @@ TEST_F(PipePdfork, ModeBits) {
#endif
TEST_F(PipePdfork, WildcardWait) {
- // TODO(FreeBSD): make wildcard wait ignore pdfork()ed children
- // https://bugs.freebsd.org/201054
TerminateChild();
- sleep(1); // Ensure child is truly dead.
+ EXPECT_PID_ZOMBIE(pid_); // Ensure child is truly dead.
// Wildcard waitpid(-1) should not see the pdfork()ed child because
// there is still a process descriptor for it.
@@ -782,21 +872,30 @@ TEST_F(PipePdfork, WildcardWait) {
}
FORK_TEST(Pdfork, Pdkill) {
- had_signal.clear();
+ clear_had_signals();
int pd;
+ int pipefds[2];
+ EXPECT_OK(pipe(pipefds));
pid_t pid = pdfork(&pd, 0);
EXPECT_OK(pid);
if (pid == 0) {
- // Child: set a SIGINT handler and sleep.
- had_signal.clear();
+ // Child: set a SIGINT handler, notify the parent and sleep.
+ close(pipefds[0]);
+ clear_had_signals();
signal(SIGINT, handle_signal);
+ if (verbose) fprintf(stderr, "[%d] child started\n", getpid_());
+ SEND_INT_MESSAGE(pipefds[1], MSG_CHILD_STARTED);
if (verbose) fprintf(stderr, "[%d] child about to sleep(10)\n", getpid_());
- int left = sleep(10);
- if (verbose) fprintf(stderr, "[%d] child slept, %d sec left, had[SIGINT]=%d\n",
- getpid_(), left, had_signal[SIGINT]);
- // Expect this sleep to be interrupted by the signal (and so left > 0).
- exit(left == 0);
+ // Note: we could receive the SIGINT just before sleep(), so we use a loop
+ // with a short delay instead of one long sleep().
+ for (int i = 0; i < 50 && !had_signal[SIGINT]; i++) {
+ usleep(100000);
+ }
+ if (verbose) fprintf(stderr, "[%d] child slept, had[SIGINT]=%d\n",
+ getpid_(), (int)had_signal[SIGINT]);
+ // Return non-zero if we didn't see SIGINT.
+ exit(had_signal[SIGINT] ? 0 : 99);
}
// Parent: get child's PID.
@@ -804,9 +903,12 @@ FORK_TEST(Pdfork, Pdkill) {
EXPECT_OK(pdgetpid(pd, &pd_pid));
EXPECT_EQ(pid, pd_pid);
- // Interrupt the child after a second.
- sleep(1);
+ // Interrupt the child once it's registered the SIGINT handler.
+ close(pipefds[1]);
+ if (verbose) fprintf(stderr, "[%d] waiting for child\n", getpid_());
+ AWAIT_INT_MESSAGE(pipefds[0], MSG_CHILD_STARTED);
EXPECT_OK(pdkill(pd, SIGINT));
+ if (verbose) fprintf(stderr, "[%d] sent SIGINT\n", getpid_());
// Make sure the child finished properly (caught signal then exited).
CheckChildFinished(pid);
@@ -814,19 +916,28 @@ FORK_TEST(Pdfork, Pdkill) {
FORK_TEST(Pdfork, PdkillSignal) {
int pd;
+ int pipefds[2];
+ EXPECT_OK(pipe(pipefds));
pid_t pid = pdfork(&pd, 0);
EXPECT_OK(pid);
if (pid == 0) {
- // Child: sleep. No SIGINT handler.
- if (verbose) fprintf(stderr, "[%d] child about to sleep(10)\n", getpid_());
- int left = sleep(10);
- if (verbose) fprintf(stderr, "[%d] child slept, %d sec left\n", getpid_(), left);
+ close(pipefds[0]);
+ if (verbose) fprintf(stderr, "[%d] child started\n", getpid_());
+ SEND_INT_MESSAGE(pipefds[1], MSG_CHILD_STARTED);
+ // Child: wait for shutdown message. No SIGINT handler. The message should
+ // never be received, since SIGINT should terminate the process.
+ if (verbose) fprintf(stderr, "[%d] child about to read()\n", getpid_());
+ AWAIT_INT_MESSAGE(pipefds[1], MSG_PARENT_REQUEST_CHILD_EXIT);
+ fprintf(stderr, "[%d] child read() returned unexpectedly\n", getpid_());
exit(99);
}
-
+ // Wait for child to start before signalling.
+ if (verbose) fprintf(stderr, "[%d] waiting for child\n", getpid_());
+ close(pipefds[1]);
+ AWAIT_INT_MESSAGE(pipefds[0], MSG_CHILD_STARTED);
// Kill the child (as it doesn't handle SIGINT).
- sleep(1);
+ if (verbose) fprintf(stderr, "[%d] sending SIGINT\n", getpid_());
EXPECT_OK(pdkill(pd, SIGINT));
// Make sure the child finished properly (terminated by signal).
@@ -922,7 +1033,7 @@ TEST_F(PipePdfork, PassProcessDescriptor) {
if (child2 == 0) {
// Child: close our copy of the original process descriptor.
close(pd_);
-
+ SEND_INT_MESSAGE(sock_fds[0], MSG_CHILD_STARTED);
// Child: wait to receive process descriptor over socket
if (verbose) fprintf(stderr, " [%d] child of %d waiting for process descriptor on socket\n", getpid_(), getppid());
int rc = recvmsg(sock_fds[0], &mh, 0);
@@ -934,13 +1045,16 @@ TEST_F(PipePdfork, PassProcessDescriptor) {
cmptr = CMSG_NXTHDR(&mh, cmptr);
EXPECT_TRUE(cmptr == NULL);
if (verbose) fprintf(stderr, " [%d] got process descriptor %d on socket\n", getpid_(), pd);
+ SEND_INT_MESSAGE(sock_fds[0], MSG_CHILD_FD_RECEIVED);
// Child: confirm we can do pd*() operations on the process descriptor
pid_t other;
EXPECT_OK(pdgetpid(pd, &other));
if (verbose) fprintf(stderr, " [%d] process descriptor %d is pid %d\n", getpid_(), pd, other);
- sleep(2);
+ // Wait until the parent has closed the process descriptor.
+ AWAIT_INT_MESSAGE(sock_fds[0], MSG_PARENT_CLOSED_FD);
+
if (verbose) fprintf(stderr, " [%d] close process descriptor %d\n", getpid_(), pd);
close(pd);
@@ -949,7 +1063,8 @@ TEST_F(PipePdfork, PassProcessDescriptor) {
exit(HasFailure());
}
- usleep(1000); // Ensure subprocess runs
+ // Wait until the child has started.
+ AWAIT_INT_MESSAGE(sock_fds[1], MSG_CHILD_STARTED);
// Send the process descriptor over the pipe to the sub-process
mh.msg_controllen = CMSG_LEN(sizeof(int));
@@ -960,13 +1075,15 @@ TEST_F(PipePdfork, PassProcessDescriptor) {
*(int *)CMSG_DATA(cmptr) = pd_;
buffer1[0] = 0;
iov[0].iov_len = 1;
- sleep(1);
if (verbose) fprintf(stderr, "[%d] send process descriptor %d on socket\n", getpid_(), pd_);
int rc = sendmsg(sock_fds[1], &mh, 0);
EXPECT_OK(rc);
+ // Wait until the child has received the process descriptor.
+ AWAIT_INT_MESSAGE(sock_fds[1], MSG_CHILD_FD_RECEIVED);
if (verbose) fprintf(stderr, "[%d] close process descriptor %d\n", getpid_(), pd_);
close(pd_); // Not last open process descriptor
+ SEND_INT_MESSAGE(sock_fds[1], MSG_PARENT_CLOSED_FD);
// wait for child2
int status;
diff --git a/socket.cc b/socket.cc
index a80cd3ae5e7e..b68af49f85e6 100644
--- a/socket.cc
+++ b/socket.cc
@@ -20,10 +20,13 @@ TEST(Socket, UnixDomain) {
cap_rights_t r_all;
cap_rights_init(&r_all, CAP_READ, CAP_WRITE, CAP_SOCK_CLIENT, CAP_SOCK_SERVER);
+ int pipefds[2];
+ EXPECT_EQ(0, pipe(pipefds));
pid_t child = fork();
if (child == 0) {
// Child process: wait for server setup
- sleep(1);
+ close(pipefds[0]);
+ AWAIT_INT_MESSAGE(pipefds[1], MSG_PARENT_CHILD_SHOULD_RUN);
// Create sockets
int sock = socket(AF_UNIX, SOCK_STREAM, 0);
@@ -94,7 +97,9 @@ TEST(Socket, UnixDomain) {
len = sizeof(value);
EXPECT_OK(getsockopt(cap_sock_all, SOL_SOCKET, SO_DEBUG, &value, &len));
- // Accept the incoming connection
+ // Tell the child process that we are ready and accept the incoming connection.
+ EXPECT_OK(close(pipefds[1]));
+ SEND_INT_MESSAGE(pipefds[0], MSG_PARENT_CHILD_SHOULD_RUN);
len = sizeof(un);
memset(&un, 0, sizeof(un));
EXPECT_NOTCAPABLE(accept(cap_sock_rw, (struct sockaddr *)&un, &len));
@@ -153,11 +158,14 @@ TEST(Socket, TCP) {
getsockname(cap_sock_all, (struct sockaddr *)&addr, &len);
int port = ntohs(addr.sin_port);
+ int pipefds[2];
+ EXPECT_EQ(0, pipe(pipefds));
// Now we know the port involved, fork off a child.
pid_t child = fork();
if (child == 0) {
// Child process: wait for server setup
- sleep(1);
+ close(pipefds[0]);
+ AWAIT_INT_MESSAGE(pipefds[1], MSG_PARENT_CHILD_SHOULD_RUN);
// Create sockets
int sock = socket(AF_INET, SOCK_STREAM, 0);
@@ -206,7 +214,9 @@ TEST(Socket, TCP) {
len = sizeof(value);
EXPECT_OK(getsockopt(cap_sock_all, SOL_SOCKET, SO_REUSEPORT, &value, &len));
- // Accept the incoming connection
+ // Tell the child process that we are ready and accept the incoming connection.
+ EXPECT_OK(close(pipefds[1]));
+ SEND_INT_MESSAGE(pipefds[0], MSG_PARENT_CHILD_SHOULD_RUN);
len = sizeof(addr);
memset(&addr, 0, sizeof(addr));
EXPECT_NOTCAPABLE(accept(cap_sock_rw, (struct sockaddr *)&addr, &len));