summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorngie <ngie@FreeBSD.org>2015-08-10 18:27:54 +0000
committerngie <ngie@FreeBSD.org>2015-08-10 18:27:54 +0000
commit87dee474091dcb77b80fce8618161cceef3301cf (patch)
tree24ec3a6ecad18df23b771aeb0231f5cf475c3390 /tests
parent823f826ddd1301e2ed5bd22a4d3f6b5a38061c36 (diff)
parent9033c894a1c694d3e946571d9e57c05349a235eb (diff)
downloadFreeBSD-src-87dee474091dcb77b80fce8618161cceef3301cf.zip
FreeBSD-src-87dee474091dcb77b80fce8618161cceef3301cf.tar.gz
MFhead @ r286584
Diffstat (limited to 'tests')
-rw-r--r--tests/sys/kern/ptrace_test.c581
-rw-r--r--tests/sys/kern/unix_seqpacket_test.c60
-rw-r--r--tests/sys/vm/Makefile2
-rw-r--r--tests/sys/vm/mmap_test.c129
4 files changed, 674 insertions, 98 deletions
diff --git a/tests/sys/kern/ptrace_test.c b/tests/sys/kern/ptrace_test.c
index a64262a..c10c097 100644
--- a/tests/sys/kern/ptrace_test.c
+++ b/tests/sys/kern/ptrace_test.c
@@ -50,7 +50,7 @@ __FBSDID("$FreeBSD$");
#exp " not met"); \
} while (0)
-static void __dead2
+static __dead2 void
child_fail_require(const char *file, int line, const char *str)
{
char buf[128];
@@ -60,6 +60,58 @@ child_fail_require(const char *file, int line, const char *str)
_exit(32);
}
+static void
+trace_me(void)
+{
+
+ /* Attach the parent process as a tracer of this process. */
+ CHILD_REQUIRE(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ /* Trigger a stop. */
+ raise(SIGSTOP);
+}
+
+static void
+attach_child(pid_t pid)
+{
+ pid_t wpid;
+ int status;
+
+ ATF_REQUIRE(ptrace(PT_ATTACH, pid, NULL, 0) == 0);
+
+ wpid = waitpid(pid, &status, 0);
+ ATF_REQUIRE(wpid == pid);
+ ATF_REQUIRE(WIFSTOPPED(status));
+ ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP);
+}
+
+static void
+wait_for_zombie(pid_t pid)
+{
+
+ /*
+ * Wait for a process to exit. This is kind of gross, but
+ * there is not a better way.
+ */
+ for (;;) {
+ struct kinfo_proc kp;
+ size_t len;
+ int mib[4];
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_PID;
+ mib[3] = pid;
+ len = sizeof(kp);
+ if (sysctl(mib, nitems(mib), &kp, &len, NULL, 0) == -1) {
+ /* The KERN_PROC_PID sysctl fails for zombies. */
+ ATF_REQUIRE(errno == ESRCH);
+ break;
+ }
+ usleep(5000);
+ }
+}
+
/*
* Verify that a parent debugger process "sees" the exit of a debugged
* process exactly once when attached via PT_TRACE_ME.
@@ -73,10 +125,7 @@ ATF_TC_BODY(ptrace__parent_wait_after_trace_me, tc)
ATF_REQUIRE((child = fork()) != -1);
if (child == 0) {
/* Child process. */
- CHILD_REQUIRE(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
-
- /* Trigger a stop. */
- raise(SIGSTOP);
+ trace_me();
exit(1);
}
@@ -131,13 +180,7 @@ ATF_TC_BODY(ptrace__parent_wait_after_attach, tc)
/* Parent process. */
/* Attach to the child process. */
- ATF_REQUIRE(ptrace(PT_ATTACH, child, NULL, 0) == 0);
-
- /* The first wait() should report the SIGSTOP from PT_ATTACH. */
- wpid = waitpid(child, &status, 0);
- ATF_REQUIRE(wpid == child);
- ATF_REQUIRE(WIFSTOPPED(status));
- ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP);
+ attach_child(child);
/* Continue the child ignoring the SIGSTOP. */
ATF_REQUIRE(ptrace(PT_CONTINUE, child, (caddr_t)1, 0) != -1);
@@ -223,27 +266,7 @@ ATF_TC_BODY(ptrace__parent_sees_exit_after_child_debugger, tc)
ATF_REQUIRE(read(cpipe[0], &c, sizeof(c)) == 0);
close(cpipe[0]);
- /*
- * Wait for the child to exit. This is kind of gross, but
- * there is not a better way.
- */
- for (;;) {
- struct kinfo_proc kp;
- size_t len;
- int mib[4];
-
- mib[0] = CTL_KERN;
- mib[1] = KERN_PROC;
- mib[2] = KERN_PROC_PID;
- mib[3] = child;
- len = sizeof(kp);
- if (sysctl(mib, nitems(mib), &kp, &len, NULL, 0) == -1) {
- /* The KERN_PROC_PID sysctl fails for zombies. */
- ATF_REQUIRE(errno == ESRCH);
- break;
- }
- usleep(5000);
- }
+ wait_for_zombie(child);
/*
* This wait should return a pid of 0 to indicate no status to
@@ -357,27 +380,7 @@ ATF_TC_BODY(ptrace__parent_sees_exit_after_unrelated_debugger, tc)
ATF_REQUIRE(read(cpipe[0], &c, sizeof(c)) == 0);
close(cpipe[0]);
- /*
- * Wait for the child to exit. This is kind of gross, but
- * there is not a better way.
- */
- for (;;) {
- struct kinfo_proc kp;
- size_t len;
- int mib[4];
-
- mib[0] = CTL_KERN;
- mib[1] = KERN_PROC;
- mib[2] = KERN_PROC_PID;
- mib[3] = child;
- len = sizeof(kp);
- if (sysctl(mib, nitems(mib), &kp, &len, NULL, 0) == -1) {
- /* The KERN_PROC_PID sysctl fails for zombies. */
- ATF_REQUIRE(errno == ESRCH);
- break;
- }
- usleep(5000);
- }
+ wait_for_zombie(child);
/*
* This wait should return a pid of 0 to indicate no status to
@@ -401,6 +404,468 @@ ATF_TC_BODY(ptrace__parent_sees_exit_after_unrelated_debugger, tc)
ATF_REQUIRE(WEXITSTATUS(status) == 1);
}
+/*
+ * The parent process should always act the same regardless of how the
+ * debugger is attached to it.
+ */
+static __dead2 void
+follow_fork_parent(void)
+{
+ pid_t fpid, wpid;
+ int status;
+
+ CHILD_REQUIRE((fpid = fork()) != -1);
+
+ if (fpid == 0)
+ /* Child */
+ exit(2);
+
+ wpid = waitpid(fpid, &status, 0);
+ CHILD_REQUIRE(wpid == fpid);
+ CHILD_REQUIRE(WIFEXITED(status));
+ CHILD_REQUIRE(WEXITSTATUS(status) == 2);
+
+ exit(1);
+}
+
+/*
+ * Helper routine for follow fork tests. This waits for two stops
+ * that report both "sides" of a fork. It returns the pid of the new
+ * child process.
+ */
+static pid_t
+handle_fork_events(pid_t parent)
+{
+ struct ptrace_lwpinfo pl;
+ bool fork_reported[2];
+ pid_t child, wpid;
+ int i, status;
+
+ fork_reported[0] = false;
+ fork_reported[1] = false;
+ child = -1;
+
+ /*
+ * Each process should report a fork event. The parent should
+ * report a PL_FLAG_FORKED event, and the child should report
+ * a PL_FLAG_CHILD event.
+ */
+ for (i = 0; i < 2; i++) {
+ wpid = wait(&status);
+ ATF_REQUIRE(wpid > 0);
+ ATF_REQUIRE(WIFSTOPPED(status));
+
+ ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl,
+ sizeof(pl)) != -1);
+ ATF_REQUIRE((pl.pl_flags & (PL_FLAG_FORKED | PL_FLAG_CHILD)) !=
+ 0);
+ ATF_REQUIRE((pl.pl_flags & (PL_FLAG_FORKED | PL_FLAG_CHILD)) !=
+ (PL_FLAG_FORKED | PL_FLAG_CHILD));
+ if (pl.pl_flags & PL_FLAG_CHILD) {
+ ATF_REQUIRE(wpid != parent);
+ ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP);
+ ATF_REQUIRE(!fork_reported[1]);
+ if (child == -1)
+ child = wpid;
+ else
+ ATF_REQUIRE(child == wpid);
+ fork_reported[1] = true;
+ } else {
+ ATF_REQUIRE(wpid == parent);
+ ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP);
+ ATF_REQUIRE(!fork_reported[0]);
+ if (child == -1)
+ child = pl.pl_child_pid;
+ else
+ ATF_REQUIRE(child == pl.pl_child_pid);
+ fork_reported[0] = true;
+ }
+ }
+
+ return (child);
+}
+
+/*
+ * Verify that a new child process is stopped after a followed fork and
+ * that the traced parent sees the exit of the child after the debugger
+ * when both processes remain attached to the debugger.
+ */
+ATF_TC_WITHOUT_HEAD(ptrace__follow_fork_both_attached);
+ATF_TC_BODY(ptrace__follow_fork_both_attached, tc)
+{
+ pid_t children[0], fpid, wpid;
+ int status;
+
+ ATF_REQUIRE((fpid = fork()) != -1);
+ if (fpid == 0) {
+ trace_me();
+ follow_fork_parent();
+ }
+
+ /* Parent process. */
+ children[0] = fpid;
+
+ /* The first wait() should report the stop from SIGSTOP. */
+ wpid = waitpid(children[0], &status, 0);
+ ATF_REQUIRE(wpid == children[0]);
+ ATF_REQUIRE(WIFSTOPPED(status));
+ ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP);
+
+ ATF_REQUIRE(ptrace(PT_FOLLOW_FORK, children[0], NULL, 1) != -1);
+
+ /* Continue the child ignoring the SIGSTOP. */
+ ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1);
+
+ children[1] = handle_fork_events(children[0]);
+ ATF_REQUIRE(children[1] > 0);
+
+ ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1);
+ ATF_REQUIRE(ptrace(PT_CONTINUE, children[1], (caddr_t)1, 0) != -1);
+
+ /*
+ * The child can't exit until the grandchild reports status, so the
+ * grandchild should report its exit first to the debugger.
+ */
+ wpid = wait(&status);
+ ATF_REQUIRE(wpid == children[1]);
+ ATF_REQUIRE(WIFEXITED(status));
+ ATF_REQUIRE(WEXITSTATUS(status) == 2);
+
+ wpid = wait(&status);
+ ATF_REQUIRE(wpid == children[0]);
+ ATF_REQUIRE(WIFEXITED(status));
+ ATF_REQUIRE(WEXITSTATUS(status) == 1);
+
+ wpid = wait(&status);
+ ATF_REQUIRE(wpid == -1);
+ ATF_REQUIRE(errno == ECHILD);
+}
+
+/*
+ * Verify that a new child process is stopped after a followed fork
+ * and that the traced parent sees the exit of the child when the new
+ * child process is detached after it reports its fork.
+ */
+ATF_TC_WITHOUT_HEAD(ptrace__follow_fork_child_detached);
+ATF_TC_BODY(ptrace__follow_fork_child_detached, tc)
+{
+ pid_t children[0], fpid, wpid;
+ int status;
+
+ ATF_REQUIRE((fpid = fork()) != -1);
+ if (fpid == 0) {
+ trace_me();
+ follow_fork_parent();
+ }
+
+ /* Parent process. */
+ children[0] = fpid;
+
+ /* The first wait() should report the stop from SIGSTOP. */
+ wpid = waitpid(children[0], &status, 0);
+ ATF_REQUIRE(wpid == children[0]);
+ ATF_REQUIRE(WIFSTOPPED(status));
+ ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP);
+
+ ATF_REQUIRE(ptrace(PT_FOLLOW_FORK, children[0], NULL, 1) != -1);
+
+ /* Continue the child ignoring the SIGSTOP. */
+ ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1);
+
+ children[1] = handle_fork_events(children[0]);
+ ATF_REQUIRE(children[1] > 0);
+
+ ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1);
+ ATF_REQUIRE(ptrace(PT_DETACH, children[1], (caddr_t)1, 0) != -1);
+
+ /*
+ * Should not see any status from the grandchild now, only the
+ * child.
+ */
+ wpid = wait(&status);
+ ATF_REQUIRE(wpid == children[0]);
+ ATF_REQUIRE(WIFEXITED(status));
+ ATF_REQUIRE(WEXITSTATUS(status) == 1);
+
+ wpid = wait(&status);
+ ATF_REQUIRE(wpid == -1);
+ ATF_REQUIRE(errno == ECHILD);
+}
+
+/*
+ * Verify that a new child process is stopped after a followed fork
+ * and that the traced parent sees the exit of the child when the
+ * traced parent is detached after the fork.
+ */
+ATF_TC_WITHOUT_HEAD(ptrace__follow_fork_parent_detached);
+ATF_TC_BODY(ptrace__follow_fork_parent_detached, tc)
+{
+ pid_t children[0], fpid, wpid;
+ int status;
+
+ ATF_REQUIRE((fpid = fork()) != -1);
+ if (fpid == 0) {
+ trace_me();
+ follow_fork_parent();
+ }
+
+ /* Parent process. */
+ children[0] = fpid;
+
+ /* The first wait() should report the stop from SIGSTOP. */
+ wpid = waitpid(children[0], &status, 0);
+ ATF_REQUIRE(wpid == children[0]);
+ ATF_REQUIRE(WIFSTOPPED(status));
+ ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP);
+
+ ATF_REQUIRE(ptrace(PT_FOLLOW_FORK, children[0], NULL, 1) != -1);
+
+ /* Continue the child ignoring the SIGSTOP. */
+ ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1);
+
+ children[1] = handle_fork_events(children[0]);
+ ATF_REQUIRE(children[1] > 0);
+
+ ATF_REQUIRE(ptrace(PT_DETACH, children[0], (caddr_t)1, 0) != -1);
+ ATF_REQUIRE(ptrace(PT_CONTINUE, children[1], (caddr_t)1, 0) != -1);
+
+ /*
+ * The child can't exit until the grandchild reports status, so the
+ * grandchild should report its exit first to the debugger.
+ *
+ * Even though the child process is detached, it is still a
+ * child of the debugger, so it will still report it's exit
+ * after the grandchild.
+ */
+ wpid = wait(&status);
+ ATF_REQUIRE(wpid == children[1]);
+ ATF_REQUIRE(WIFEXITED(status));
+ ATF_REQUIRE(WEXITSTATUS(status) == 2);
+
+ wpid = wait(&status);
+ ATF_REQUIRE(wpid == children[0]);
+ ATF_REQUIRE(WIFEXITED(status));
+ ATF_REQUIRE(WEXITSTATUS(status) == 1);
+
+ wpid = wait(&status);
+ ATF_REQUIRE(wpid == -1);
+ ATF_REQUIRE(errno == ECHILD);
+}
+
+static void
+attach_fork_parent(int cpipe[2])
+{
+ pid_t fpid;
+
+ close(cpipe[0]);
+
+ /* Double-fork to disassociate from the debugger. */
+ CHILD_REQUIRE((fpid = fork()) != -1);
+ if (fpid != 0)
+ exit(3);
+
+ /* Send the pid of the disassociated child to the debugger. */
+ fpid = getpid();
+ CHILD_REQUIRE(write(cpipe[1], &fpid, sizeof(fpid)) == sizeof(fpid));
+
+ /* Wait for the debugger to attach. */
+ CHILD_REQUIRE(read(cpipe[1], &fpid, sizeof(fpid)) == 0);
+}
+
+/*
+ * Verify that a new child process is stopped after a followed fork and
+ * that the traced parent sees the exit of the child after the debugger
+ * when both processes remain attached to the debugger. In this test
+ * the parent that forks is not a direct child of the debugger.
+ */
+ATF_TC_WITHOUT_HEAD(ptrace__follow_fork_both_attached_unrelated_debugger);
+ATF_TC_BODY(ptrace__follow_fork_both_attached_unrelated_debugger, tc)
+{
+ pid_t children[0], fpid, wpid;
+ int cpipe[2], status;
+
+ ATF_REQUIRE(pipe(cpipe) == 0);
+ ATF_REQUIRE((fpid = fork()) != -1);
+ if (fpid == 0) {
+ attach_fork_parent(cpipe);
+ follow_fork_parent();
+ }
+
+ /* Parent process. */
+ close(cpipe[1]);
+
+ /* Wait for the direct child to exit. */
+ wpid = waitpid(fpid, &status, 0);
+ ATF_REQUIRE(wpid == fpid);
+ ATF_REQUIRE(WIFEXITED(status));
+ ATF_REQUIRE(WEXITSTATUS(status) == 3);
+
+ /* Read the pid of the fork parent. */
+ ATF_REQUIRE(read(cpipe[0], &children[0], sizeof(children[0])) ==
+ sizeof(children[0]));
+
+ /* Attach to the fork parent. */
+ attach_child(children[0]);
+
+ ATF_REQUIRE(ptrace(PT_FOLLOW_FORK, children[0], NULL, 1) != -1);
+
+ /* Continue the fork parent ignoring the SIGSTOP. */
+ ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1);
+
+ /* Signal the fork parent to continue. */
+ close(cpipe[0]);
+
+ children[1] = handle_fork_events(children[0]);
+ ATF_REQUIRE(children[1] > 0);
+
+ ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1);
+ ATF_REQUIRE(ptrace(PT_CONTINUE, children[1], (caddr_t)1, 0) != -1);
+
+ /*
+ * The fork parent can't exit until the child reports status,
+ * so the child should report its exit first to the debugger.
+ */
+ wpid = wait(&status);
+ ATF_REQUIRE(wpid == children[1]);
+ ATF_REQUIRE(WIFEXITED(status));
+ ATF_REQUIRE(WEXITSTATUS(status) == 2);
+
+ wpid = wait(&status);
+ ATF_REQUIRE(wpid == children[0]);
+ ATF_REQUIRE(WIFEXITED(status));
+ ATF_REQUIRE(WEXITSTATUS(status) == 1);
+
+ wpid = wait(&status);
+ ATF_REQUIRE(wpid == -1);
+ ATF_REQUIRE(errno == ECHILD);
+}
+
+/*
+ * Verify that a new child process is stopped after a followed fork
+ * and that the traced parent sees the exit of the child when the new
+ * child process is detached after it reports its fork. In this test
+ * the parent that forks is not a direct child of the debugger.
+ */
+ATF_TC_WITHOUT_HEAD(ptrace__follow_fork_child_detached_unrelated_debugger);
+ATF_TC_BODY(ptrace__follow_fork_child_detached_unrelated_debugger, tc)
+{
+ pid_t children[0], fpid, wpid;
+ int cpipe[2], status;
+
+ ATF_REQUIRE(pipe(cpipe) == 0);
+ ATF_REQUIRE((fpid = fork()) != -1);
+ if (fpid == 0) {
+ attach_fork_parent(cpipe);
+ follow_fork_parent();
+ }
+
+ /* Parent process. */
+ close(cpipe[1]);
+
+ /* Wait for the direct child to exit. */
+ wpid = waitpid(fpid, &status, 0);
+ ATF_REQUIRE(wpid == fpid);
+ ATF_REQUIRE(WIFEXITED(status));
+ ATF_REQUIRE(WEXITSTATUS(status) == 3);
+
+ /* Read the pid of the fork parent. */
+ ATF_REQUIRE(read(cpipe[0], &children[0], sizeof(children[0])) ==
+ sizeof(children[0]));
+
+ /* Attach to the fork parent. */
+ attach_child(children[0]);
+
+ ATF_REQUIRE(ptrace(PT_FOLLOW_FORK, children[0], NULL, 1) != -1);
+
+ /* Continue the fork parent ignoring the SIGSTOP. */
+ ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1);
+
+ /* Signal the fork parent to continue. */
+ close(cpipe[0]);
+
+ children[1] = handle_fork_events(children[0]);
+ ATF_REQUIRE(children[1] > 0);
+
+ ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1);
+ ATF_REQUIRE(ptrace(PT_DETACH, children[1], (caddr_t)1, 0) != -1);
+
+ /*
+ * Should not see any status from the child now, only the fork
+ * parent.
+ */
+ wpid = wait(&status);
+ ATF_REQUIRE(wpid == children[0]);
+ ATF_REQUIRE(WIFEXITED(status));
+ ATF_REQUIRE(WEXITSTATUS(status) == 1);
+
+ wpid = wait(&status);
+ ATF_REQUIRE(wpid == -1);
+ ATF_REQUIRE(errno == ECHILD);
+}
+
+/*
+ * Verify that a new child process is stopped after a followed fork
+ * and that the traced parent sees the exit of the child when the
+ * traced parent is detached after the fork. In this test the parent
+ * that forks is not a direct child of the debugger.
+ */
+ATF_TC_WITHOUT_HEAD(ptrace__follow_fork_parent_detached_unrelated_debugger);
+ATF_TC_BODY(ptrace__follow_fork_parent_detached_unrelated_debugger, tc)
+{
+ pid_t children[0], fpid, wpid;
+ int cpipe[2], status;
+
+ ATF_REQUIRE(pipe(cpipe) == 0);
+ ATF_REQUIRE((fpid = fork()) != -1);
+ if (fpid == 0) {
+ attach_fork_parent(cpipe);
+ follow_fork_parent();
+ }
+
+ /* Parent process. */
+ close(cpipe[1]);
+
+ /* Wait for the direct child to exit. */
+ wpid = waitpid(fpid, &status, 0);
+ ATF_REQUIRE(wpid == fpid);
+ ATF_REQUIRE(WIFEXITED(status));
+ ATF_REQUIRE(WEXITSTATUS(status) == 3);
+
+ /* Read the pid of the fork parent. */
+ ATF_REQUIRE(read(cpipe[0], &children[0], sizeof(children[0])) ==
+ sizeof(children[0]));
+
+ /* Attach to the fork parent. */
+ attach_child(children[0]);
+
+ ATF_REQUIRE(ptrace(PT_FOLLOW_FORK, children[0], NULL, 1) != -1);
+
+ /* Continue the fork parent ignoring the SIGSTOP. */
+ ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1);
+
+ /* Signal the fork parent to continue. */
+ close(cpipe[0]);
+
+ children[1] = handle_fork_events(children[0]);
+ ATF_REQUIRE(children[1] > 0);
+
+ ATF_REQUIRE(ptrace(PT_DETACH, children[0], (caddr_t)1, 0) != -1);
+ ATF_REQUIRE(ptrace(PT_CONTINUE, children[1], (caddr_t)1, 0) != -1);
+
+ /*
+ * Should not see any status from the fork parent now, only
+ * the child.
+ */
+ wpid = wait(&status);
+ ATF_REQUIRE(wpid == children[1]);
+ ATF_REQUIRE(WIFEXITED(status));
+ ATF_REQUIRE(WEXITSTATUS(status) == 2);
+
+ wpid = wait(&status);
+ ATF_REQUIRE(wpid == -1);
+ ATF_REQUIRE(errno == ECHILD);
+}
+
ATF_TP_ADD_TCS(tp)
{
@@ -408,6 +873,14 @@ ATF_TP_ADD_TCS(tp)
ATF_TP_ADD_TC(tp, ptrace__parent_wait_after_attach);
ATF_TP_ADD_TC(tp, ptrace__parent_sees_exit_after_child_debugger);
ATF_TP_ADD_TC(tp, ptrace__parent_sees_exit_after_unrelated_debugger);
+ ATF_TP_ADD_TC(tp, ptrace__follow_fork_both_attached);
+ ATF_TP_ADD_TC(tp, ptrace__follow_fork_child_detached);
+ ATF_TP_ADD_TC(tp, ptrace__follow_fork_parent_detached);
+ ATF_TP_ADD_TC(tp, ptrace__follow_fork_both_attached_unrelated_debugger);
+ ATF_TP_ADD_TC(tp,
+ ptrace__follow_fork_child_detached_unrelated_debugger);
+ ATF_TP_ADD_TC(tp,
+ ptrace__follow_fork_parent_detached_unrelated_debugger);
return (atf_no_error());
}
diff --git a/tests/sys/kern/unix_seqpacket_test.c b/tests/sys/kern/unix_seqpacket_test.c
index ccbacaf..986b70e 100644
--- a/tests/sys/kern/unix_seqpacket_test.c
+++ b/tests/sys/kern/unix_seqpacket_test.c
@@ -751,35 +751,79 @@ ATF_TC_BODY(send_recv_with_connect, tc)
ATF_TC_WITHOUT_HEAD(shutdown_send);
ATF_TC_BODY(shutdown_send, tc)
{
- int s;
- const char data[] = "data";
+ struct sockaddr_un sun;
+ /* ATF's isolation mechanisms will guarantee uniqueness of this file */
+ const char *path = "sock";
+ const char *data = "data";
ssize_t ssize;
+ int s, err, s2;
s = socket(PF_LOCAL, SOCK_SEQPACKET, 0);
ATF_REQUIRE(s >= 0);
- ATF_CHECK_EQ(0, shutdown(s, SHUT_RDWR));
+
+ bzero(&sun, sizeof(sun));
+ sun.sun_family = AF_LOCAL;
+ sun.sun_len = sizeof(sun);
+ strlcpy(sun.sun_path, path, sizeof(sun.sun_path));
+ err = bind(s, (struct sockaddr *)&sun, sizeof(sun));
+ err = listen(s, -1);
+ ATF_CHECK_EQ(0, err);
+
+ /* Create the other socket */
+ s2 = socket(PF_LOCAL, SOCK_SEQPACKET, 0);
+ ATF_REQUIRE(s2 >= 0);
+ err = connect(s2, (struct sockaddr*)&sun, sizeof(sun));
+ if (err != 0) {
+ perror("connect");
+ atf_tc_fail("connect(2) failed");
+ }
+
+ ATF_CHECK_EQ(0, shutdown(s2, SHUT_RDWR));
/* USE MSG_NOSIGNAL so we don't get SIGPIPE */
- ssize = send(s, data, sizeof(data), MSG_EOR | MSG_NOSIGNAL);
+ ssize = send(s2, data, sizeof(data), MSG_EOR | MSG_NOSIGNAL);
ATF_CHECK_EQ(EPIPE, errno);
ATF_CHECK_EQ(-1, ssize);
close(s);
+ close(s2);
}
/* send(2) should cause SIGPIPE on a shutdown socket */
ATF_TC_WITHOUT_HEAD(shutdown_send_sigpipe);
ATF_TC_BODY(shutdown_send_sigpipe, tc)
{
- int s;
- const char data[] = "data";
+ struct sockaddr_un sun;
+ /* ATF's isolation mechanisms will guarantee uniqueness of this file */
+ const char *path = "sock";
+ const char *data = "data";
ssize_t ssize;
+ int s, err, s2;
s = socket(PF_LOCAL, SOCK_SEQPACKET, 0);
ATF_REQUIRE(s >= 0);
- ATF_CHECK_EQ(0, shutdown(s, SHUT_RDWR));
+
+ bzero(&sun, sizeof(sun));
+ sun.sun_family = AF_LOCAL;
+ sun.sun_len = sizeof(sun);
+ strlcpy(sun.sun_path, path, sizeof(sun.sun_path));
+ err = bind(s, (struct sockaddr *)&sun, sizeof(sun));
+ err = listen(s, -1);
+ ATF_CHECK_EQ(0, err);
+
+ /* Create the other socket */
+ s2 = socket(PF_LOCAL, SOCK_SEQPACKET, 0);
+ ATF_REQUIRE(s2 >= 0);
+ err = connect(s2, (struct sockaddr*)&sun, sizeof(sun));
+ if (err != 0) {
+ perror("connect");
+ atf_tc_fail("connect(2) failed");
+ }
+
+ ATF_CHECK_EQ(0, shutdown(s2, SHUT_RDWR));
ATF_REQUIRE(SIG_ERR != signal(SIGPIPE, shutdown_send_sigpipe_handler));
- ssize = send(s, data, sizeof(data), MSG_EOR);
+ ssize = send(s2, data, sizeof(data), MSG_EOR);
ATF_CHECK_EQ(1, got_sigpipe);
close(s);
+ close(s2);
}
/* nonblocking send(2) and recv(2) a single short record */
diff --git a/tests/sys/vm/Makefile b/tests/sys/vm/Makefile
index 1795eef..08fbb21 100644
--- a/tests/sys/vm/Makefile
+++ b/tests/sys/vm/Makefile
@@ -2,6 +2,6 @@
TESTSDIR= ${TESTSBASE}/sys/vm
-TAP_TESTS_C+= mmap_test
+ATF_TESTS_C+= mmap_test
.include <bsd.test.mk>
diff --git a/tests/sys/vm/mmap_test.c b/tests/sys/vm/mmap_test.c
index 7591a09..00abeb6 100644
--- a/tests/sys/vm/mmap_test.c
+++ b/tests/sys/vm/mmap_test.c
@@ -29,16 +29,18 @@
#include <sys/param.h>
#include <sys/mman.h>
#include <sys/sysctl.h>
-#include <sys/types.h>
+#include <atf-c.h>
#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
#include <stdio.h>
-#include <string.h>
+#include <stdlib.h>
static const struct {
void *addr;
int ok[2]; /* Depending on security.bsd.map_at_zero {0, !=0}. */
-} tests[] = {
+} map_at_zero_tests[] = {
{ (void *)0, { 0, 1 } }, /* Test sysctl. */
{ (void *)1, { 0, 0 } },
{ (void *)(PAGE_SIZE - 1), { 0, 0 } },
@@ -52,54 +54,111 @@ static const struct {
#define MAP_AT_ZERO "security.bsd.map_at_zero"
-int
-main(void)
+ATF_TC_WITHOUT_HEAD(mmap__map_at_zero);
+ATF_TC_BODY(mmap__map_at_zero, tc)
{
void *p;
size_t len;
- int i, error, mib[3], map_at_zero;
-
- error = 0;
-
- /* Get the current sysctl value of security.bsd.map_at_zero. */
- len = sizeof(mib) / sizeof(*mib);
- if (sysctlnametomib(MAP_AT_ZERO, mib, &len) == -1) {
- printf("1..0 # SKIP: sysctlnametomib(\"%s\") failed: %s\n",
- MAP_AT_ZERO, strerror(errno));
- return (0);
- }
+ unsigned int i;
+ int map_at_zero;
len = sizeof(map_at_zero);
- if (sysctl(mib, 3, &map_at_zero, &len, NULL, 0) == -1) {
- printf("1..0 # SKIP: sysctl for %s failed: %s\n", MAP_AT_ZERO,
+ if (sysctlbyname(MAP_AT_ZERO, &map_at_zero, &len, NULL, 0) == -1) {
+ atf_tc_skip("sysctl for %s failed: %s\n", MAP_AT_ZERO,
strerror(errno));
- return (0);
+ return;
}
/* Normalize to 0 or 1 for array access. */
map_at_zero = !!map_at_zero;
- printf("1..%zu\n", nitems(tests));
- for (i = 0; i < (int)nitems(tests); i++) {
- p = mmap((void *)tests[i].addr, PAGE_SIZE,
+ for (i = 0; i < nitems(map_at_zero_tests); i++) {
+ p = mmap((void *)map_at_zero_tests[i].addr, PAGE_SIZE,
PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANON | MAP_FIXED,
-1, 0);
if (p == MAP_FAILED) {
- if (tests[i].ok[map_at_zero] != 0)
- error++;
- printf("%sok %d # mmap(%p, ...) failed\n",
- tests[i].ok[map_at_zero] == 0 ? "" : "not ",
- i + 1,
- tests[i].addr);
+ ATF_CHECK_MSG(map_at_zero_tests[i].ok[map_at_zero] == 0,
+ "mmap(%p, ...) failed", map_at_zero_tests[i].addr);
} else {
- if (tests[i].ok[map_at_zero] != 1)
- error++;
- printf("%sok %d # mmap(%p, ...) succeeded: p=%p\n",
- tests[i].ok[map_at_zero] == 1 ? "" : "not ",
- i + 1,
- tests[i].addr, p);
+ ATF_CHECK_MSG(map_at_zero_tests[i].ok[map_at_zero] == 1,
+ "mmap(%p, ...) succeeded: p=%p\n",
+ map_at_zero_tests[i].addr, p);
}
}
+}
+
+static void
+checked_mmap(int prot, int flags, int fd, int error, const char *msg)
+{
+ void *p;
+
+ p = mmap(NULL, getpagesize(), prot, flags, fd, 0);
+ if (p == MAP_FAILED) {
+ if (error == 0)
+ ATF_CHECK_MSG(0, "%s failed with errno %d", msg,
+ errno);
+ else
+ ATF_CHECK_EQ_MSG(error, errno,
+ "%s failed with wrong errno %d (expected %d)", msg,
+ errno, error);
+ } else {
+ ATF_CHECK_MSG(error == 0, "%s succeeded", msg);
+ munmap(p, getpagesize());
+ }
+}
+
+ATF_TC_WITHOUT_HEAD(mmap__bad_arguments);
+ATF_TC_BODY(mmap__bad_arguments, tc)
+{
+ int fd;
+
+ ATF_REQUIRE((fd = shm_open(SHM_ANON, O_RDWR, 0644)) >= 0);
+ ATF_REQUIRE(ftruncate(fd, getpagesize()) == 0);
+
+ /* These should work. */
+ checked_mmap(PROT_READ | PROT_WRITE, MAP_ANON, -1, 0,
+ "simple MAP_ANON");
+ checked_mmap(PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0,
+ "simple shm fd shared");
+ checked_mmap(PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0,
+ "simple shm fd private");
+
+ /* Extra PROT flags. */
+ checked_mmap(PROT_READ | PROT_WRITE | 0x100000, MAP_ANON, -1, EINVAL,
+ "MAP_ANON with extra PROT flags");
+ checked_mmap(0xffff, MAP_SHARED, fd, EINVAL,
+ "shm fd with garbage PROT");
+
+ /* Undefined flag. */
+ checked_mmap(PROT_READ | PROT_WRITE, MAP_ANON | MAP_RESERVED0080, -1,
+ EINVAL, "Undefined flag");
+
+ /* Both MAP_SHARED and MAP_PRIVATE */
+ checked_mmap(PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE |
+ MAP_SHARED, -1, EINVAL, "MAP_ANON with both SHARED and PRIVATE");
+ checked_mmap(PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_SHARED, fd,
+ EINVAL, "shm fd with both SHARED and PRIVATE");
+
+ /* At least one of MAP_SHARED or MAP_PRIVATE without ANON */
+ checked_mmap(PROT_READ | PROT_WRITE, 0, fd, EINVAL,
+ "shm fd without sharing flag");
+
+ /* MAP_ANON with either sharing flag (impacts fork). */
+ checked_mmap(PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0,
+ "shared MAP_ANON");
+ checked_mmap(PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0,
+ "private MAP_ANON");
+
+ /* MAP_ANON should require an fd of -1. */
+ checked_mmap(PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, 0, EINVAL,
+ "MAP_ANON with fd != -1");
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, mmap__map_at_zero);
+ ATF_TP_ADD_TC(tp, mmap__bad_arguments);
- return (error != 0);
+ return (atf_no_error());
}
OpenPOWER on IntegriCloud