summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorRenato Botelho <renato@netgate.com>2015-11-03 09:45:44 -0200
committerRenato Botelho <renato@netgate.com>2015-11-03 09:45:44 -0200
commitc7275b999acdea9746ff095cf10188b4a3d09b7a (patch)
treea95eeaad8a2157ed3641d93c98bdc108bcd728d4 /tests
parent2b0a9fbf7a64ff2e54d03cebd5bc2d787026eaf8 (diff)
parentfe49fc6e1c94b6c41d1d3844ca219a76da3c70dc (diff)
downloadFreeBSD-src-c7275b999acdea9746ff095cf10188b4a3d09b7a.zip
FreeBSD-src-c7275b999acdea9746ff095cf10188b4a3d09b7a.tar.gz
Merge branch 'stable/10' into devel
Diffstat (limited to 'tests')
-rw-r--r--tests/sys/Makefile1
-rw-r--r--tests/sys/kern/Makefile1
-rw-r--r--tests/sys/kern/ptrace_test.c259
-rw-r--r--tests/sys/vfs/Makefile7
-rwxr-xr-xtests/sys/vfs/trailing_slash.sh42
5 files changed, 295 insertions, 15 deletions
diff --git a/tests/sys/Makefile b/tests/sys/Makefile
index 066c918..0f20aa6 100644
--- a/tests/sys/Makefile
+++ b/tests/sys/Makefile
@@ -12,6 +12,7 @@ TESTS_SUBDIRS+= kqueue
TESTS_SUBDIRS+= mqueue
TESTS_SUBDIRS+= netinet
TESTS_SUBDIRS+= opencrypto
+TESTS_SUBDIRS+= vfs
TESTS_SUBDIRS+= vm
# Items not integrated into kyua runs by default
diff --git a/tests/sys/kern/Makefile b/tests/sys/kern/Makefile
index bf6aa0d..c345e5d 100644
--- a/tests/sys/kern/Makefile
+++ b/tests/sys/kern/Makefile
@@ -7,6 +7,7 @@ ATF_TESTS_C+= ptrace_test
ATF_TESTS_C+= unix_seqpacket_test
TEST_METADATA.unix_seqpacket_test+= timeout="15"
+LDADD.ptrace_test+= -lpthread
LDADD.unix_seqpacket_test+= -lpthread
WARNS?= 5
diff --git a/tests/sys/kern/ptrace_test.c b/tests/sys/kern/ptrace_test.c
index c10c097..1731698 100644
--- a/tests/sys/kern/ptrace_test.c
+++ b/tests/sys/kern/ptrace_test.c
@@ -29,10 +29,12 @@ __FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <sys/ptrace.h>
+#include <sys/syscall.h>
#include <sys/sysctl.h>
#include <sys/user.h>
#include <sys/wait.h>
#include <errno.h>
+#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
@@ -409,12 +411,15 @@ ATF_TC_BODY(ptrace__parent_sees_exit_after_unrelated_debugger, tc)
* debugger is attached to it.
*/
static __dead2 void
-follow_fork_parent(void)
+follow_fork_parent(bool use_vfork)
{
pid_t fpid, wpid;
int status;
- CHILD_REQUIRE((fpid = fork()) != -1);
+ if (use_vfork)
+ CHILD_REQUIRE((fpid = vfork()) != -1);
+ else
+ CHILD_REQUIRE((fpid = fork()) != -1);
if (fpid == 0)
/* Child */
@@ -434,7 +439,7 @@ follow_fork_parent(void)
* child process.
*/
static pid_t
-handle_fork_events(pid_t parent)
+handle_fork_events(pid_t parent, struct ptrace_lwpinfo *ppl)
{
struct ptrace_lwpinfo pl;
bool fork_reported[2];
@@ -469,6 +474,8 @@ handle_fork_events(pid_t parent)
child = wpid;
else
ATF_REQUIRE(child == wpid);
+ if (ppl != NULL)
+ ppl[1] = pl;
fork_reported[1] = true;
} else {
ATF_REQUIRE(wpid == parent);
@@ -478,6 +485,8 @@ handle_fork_events(pid_t parent)
child = pl.pl_child_pid;
else
ATF_REQUIRE(child == pl.pl_child_pid);
+ if (ppl != NULL)
+ ppl[0] = pl;
fork_reported[0] = true;
}
}
@@ -499,7 +508,7 @@ ATF_TC_BODY(ptrace__follow_fork_both_attached, tc)
ATF_REQUIRE((fpid = fork()) != -1);
if (fpid == 0) {
trace_me();
- follow_fork_parent();
+ follow_fork_parent(false);
}
/* Parent process. */
@@ -516,7 +525,7 @@ ATF_TC_BODY(ptrace__follow_fork_both_attached, tc)
/* 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]);
+ children[1] = handle_fork_events(children[0], NULL);
ATF_REQUIRE(children[1] > 0);
ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1);
@@ -555,7 +564,7 @@ ATF_TC_BODY(ptrace__follow_fork_child_detached, tc)
ATF_REQUIRE((fpid = fork()) != -1);
if (fpid == 0) {
trace_me();
- follow_fork_parent();
+ follow_fork_parent(false);
}
/* Parent process. */
@@ -572,7 +581,7 @@ ATF_TC_BODY(ptrace__follow_fork_child_detached, tc)
/* 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]);
+ children[1] = handle_fork_events(children[0], NULL);
ATF_REQUIRE(children[1] > 0);
ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1);
@@ -606,7 +615,7 @@ ATF_TC_BODY(ptrace__follow_fork_parent_detached, tc)
ATF_REQUIRE((fpid = fork()) != -1);
if (fpid == 0) {
trace_me();
- follow_fork_parent();
+ follow_fork_parent(false);
}
/* Parent process. */
@@ -623,7 +632,7 @@ ATF_TC_BODY(ptrace__follow_fork_parent_detached, tc)
/* 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]);
+ children[1] = handle_fork_events(children[0], NULL);
ATF_REQUIRE(children[1] > 0);
ATF_REQUIRE(ptrace(PT_DETACH, children[0], (caddr_t)1, 0) != -1);
@@ -688,7 +697,7 @@ ATF_TC_BODY(ptrace__follow_fork_both_attached_unrelated_debugger, tc)
ATF_REQUIRE((fpid = fork()) != -1);
if (fpid == 0) {
attach_fork_parent(cpipe);
- follow_fork_parent();
+ follow_fork_parent(false);
}
/* Parent process. */
@@ -715,7 +724,7 @@ ATF_TC_BODY(ptrace__follow_fork_both_attached_unrelated_debugger, tc)
/* Signal the fork parent to continue. */
close(cpipe[0]);
- children[1] = handle_fork_events(children[0]);
+ children[1] = handle_fork_events(children[0], NULL);
ATF_REQUIRE(children[1] > 0);
ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1);
@@ -756,7 +765,7 @@ ATF_TC_BODY(ptrace__follow_fork_child_detached_unrelated_debugger, tc)
ATF_REQUIRE((fpid = fork()) != -1);
if (fpid == 0) {
attach_fork_parent(cpipe);
- follow_fork_parent();
+ follow_fork_parent(false);
}
/* Parent process. */
@@ -783,7 +792,7 @@ ATF_TC_BODY(ptrace__follow_fork_child_detached_unrelated_debugger, tc)
/* Signal the fork parent to continue. */
close(cpipe[0]);
- children[1] = handle_fork_events(children[0]);
+ children[1] = handle_fork_events(children[0], NULL);
ATF_REQUIRE(children[1] > 0);
ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1);
@@ -819,7 +828,7 @@ ATF_TC_BODY(ptrace__follow_fork_parent_detached_unrelated_debugger, tc)
ATF_REQUIRE((fpid = fork()) != -1);
if (fpid == 0) {
attach_fork_parent(cpipe);
- follow_fork_parent();
+ follow_fork_parent(false);
}
/* Parent process. */
@@ -846,7 +855,7 @@ ATF_TC_BODY(ptrace__follow_fork_parent_detached_unrelated_debugger, tc)
/* Signal the fork parent to continue. */
close(cpipe[0]);
- children[1] = handle_fork_events(children[0]);
+ children[1] = handle_fork_events(children[0], NULL);
ATF_REQUIRE(children[1] > 0);
ATF_REQUIRE(ptrace(PT_DETACH, children[0], (caddr_t)1, 0) != -1);
@@ -866,6 +875,223 @@ ATF_TC_BODY(ptrace__follow_fork_parent_detached_unrelated_debugger, tc)
ATF_REQUIRE(errno == ECHILD);
}
+/*
+ * Verify that pl_syscall_code in struct ptrace_lwpinfo for a new
+ * child process created via fork() reports the correct value.
+ */
+ATF_TC_WITHOUT_HEAD(ptrace__new_child_pl_syscall_code_fork);
+ATF_TC_BODY(ptrace__new_child_pl_syscall_code_fork, tc)
+{
+ struct ptrace_lwpinfo pl[2];
+ pid_t children[2], fpid, wpid;
+ int status;
+
+ ATF_REQUIRE((fpid = fork()) != -1);
+ if (fpid == 0) {
+ trace_me();
+ follow_fork_parent(false);
+ }
+
+ /* 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);
+
+ /* Wait for both halves of the fork event to get reported. */
+ children[1] = handle_fork_events(children[0], pl);
+ ATF_REQUIRE(children[1] > 0);
+
+ ATF_REQUIRE((pl[0].pl_flags & PL_FLAG_SCX) != 0);
+ ATF_REQUIRE((pl[1].pl_flags & PL_FLAG_SCX) != 0);
+ ATF_REQUIRE(pl[0].pl_syscall_code == SYS_fork);
+ ATF_REQUIRE(pl[0].pl_syscall_code == pl[1].pl_syscall_code);
+ ATF_REQUIRE(pl[0].pl_syscall_narg == pl[1].pl_syscall_narg);
+
+ 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 pl_syscall_code in struct ptrace_lwpinfo for a new
+ * child process created via vfork() reports the correct value.
+ */
+ATF_TC_WITHOUT_HEAD(ptrace__new_child_pl_syscall_code_vfork);
+ATF_TC_BODY(ptrace__new_child_pl_syscall_code_vfork, tc)
+{
+ struct ptrace_lwpinfo pl[2];
+ pid_t children[2], fpid, wpid;
+ int status;
+
+ ATF_REQUIRE((fpid = fork()) != -1);
+ if (fpid == 0) {
+ trace_me();
+ follow_fork_parent(true);
+ }
+
+ /* 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);
+
+ /* Wait for both halves of the fork event to get reported. */
+ children[1] = handle_fork_events(children[0], pl);
+ ATF_REQUIRE(children[1] > 0);
+
+ ATF_REQUIRE((pl[0].pl_flags & PL_FLAG_SCX) != 0);
+ ATF_REQUIRE((pl[1].pl_flags & PL_FLAG_SCX) != 0);
+ ATF_REQUIRE(pl[0].pl_syscall_code == SYS_vfork);
+ ATF_REQUIRE(pl[0].pl_syscall_code == pl[1].pl_syscall_code);
+ ATF_REQUIRE(pl[0].pl_syscall_narg == pl[1].pl_syscall_narg);
+
+ 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);
+}
+
+static void *
+simple_thread(void *arg __unused)
+{
+
+ pthread_exit(NULL);
+}
+
+/*
+ * Verify that pl_syscall_code in struct ptrace_lwpinfo for a new
+ * thread reports the correct value.
+ */
+ATF_TC_WITHOUT_HEAD(ptrace__new_child_pl_syscall_code_thread);
+ATF_TC_BODY(ptrace__new_child_pl_syscall_code_thread, tc)
+{
+ struct ptrace_lwpinfo pl;
+ pid_t fpid, wpid;
+ lwpid_t main;
+ int status;
+
+ ATF_REQUIRE((fpid = fork()) != -1);
+ if (fpid == 0) {
+ pthread_t thread;
+
+ trace_me();
+
+ CHILD_REQUIRE(pthread_create(&thread, NULL, simple_thread,
+ NULL) == 0);
+ CHILD_REQUIRE(pthread_join(thread, NULL) == 0);
+ exit(1);
+ }
+
+ /* The first wait() should report the stop from SIGSTOP. */
+ wpid = waitpid(fpid, &status, 0);
+ ATF_REQUIRE(wpid == fpid);
+ ATF_REQUIRE(WIFSTOPPED(status));
+ ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP);
+
+ ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl,
+ sizeof(pl)) != -1);
+ main = pl.pl_lwpid;
+
+ /*
+ * Continue the child ignoring the SIGSTOP and tracing all
+ * system call exits.
+ */
+ ATF_REQUIRE(ptrace(PT_TO_SCX, fpid, (caddr_t)1, 0) != -1);
+
+ /*
+ * Wait for the new thread to arrive. pthread_create() might
+ * invoke any number of system calls. For now we just wait
+ * for the new thread to arrive and make sure it reports a
+ * valid system call code. If ptrace grows thread event
+ * reporting then this test can be made more precise.
+ */
+ for (;;) {
+ wpid = waitpid(fpid, &status, 0);
+ ATF_REQUIRE(wpid == fpid);
+ ATF_REQUIRE(WIFSTOPPED(status));
+ ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP);
+
+ ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl,
+ sizeof(pl)) != -1);
+ ATF_REQUIRE((pl.pl_flags & PL_FLAG_SCX) != 0);
+ ATF_REQUIRE(pl.pl_syscall_code != 0);
+ if (pl.pl_lwpid != main)
+ /* New thread seen. */
+ break;
+
+ ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0);
+ }
+
+ /* Wait for the child to exit. */
+ ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0);
+ for (;;) {
+ wpid = waitpid(fpid, &status, 0);
+ ATF_REQUIRE(wpid == fpid);
+ if (WIFEXITED(status))
+ break;
+
+ ATF_REQUIRE(WIFSTOPPED(status));
+ ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP);
+ ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0);
+ }
+
+ ATF_REQUIRE(WEXITSTATUS(status) == 1);
+
+ wpid = wait(&status);
+ ATF_REQUIRE(wpid == -1);
+ ATF_REQUIRE(errno == ECHILD);
+}
+
ATF_TP_ADD_TCS(tp)
{
@@ -881,6 +1107,9 @@ ATF_TP_ADD_TCS(tp)
ptrace__follow_fork_child_detached_unrelated_debugger);
ATF_TP_ADD_TC(tp,
ptrace__follow_fork_parent_detached_unrelated_debugger);
+ ATF_TP_ADD_TC(tp, ptrace__new_child_pl_syscall_code_fork);
+ ATF_TP_ADD_TC(tp, ptrace__new_child_pl_syscall_code_vfork);
+ ATF_TP_ADD_TC(tp, ptrace__new_child_pl_syscall_code_thread);
return (atf_no_error());
}
diff --git a/tests/sys/vfs/Makefile b/tests/sys/vfs/Makefile
new file mode 100644
index 0000000..48f5226
--- /dev/null
+++ b/tests/sys/vfs/Makefile
@@ -0,0 +1,7 @@
+# $FreeBSD$
+
+TESTSDIR= ${TESTSBASE}/sys/vfs
+
+PLAIN_TESTS_SH+= trailing_slash
+
+.include <bsd.test.mk>
diff --git a/tests/sys/vfs/trailing_slash.sh b/tests/sys/vfs/trailing_slash.sh
new file mode 100755
index 0000000..b1b8523
--- /dev/null
+++ b/tests/sys/vfs/trailing_slash.sh
@@ -0,0 +1,42 @@
+#!/bin/sh
+#
+# $FreeBSD$
+#
+# Tests vfs_lookup()'s handling of trailing slashes for symlinks that
+# point to files. See kern/21768 for details. Fixed in r193028.
+#
+
+testfile="/tmp/testfile-$$"
+testlink="/tmp/testlink-$$"
+
+tests="
+$testfile:$testlink:$testfile:0
+$testfile:$testlink:$testfile/:1
+$testfile:$testlink:$testlink:0
+$testfile:$testlink:$testlink/:1
+$testfile/:$testlink:$testlink:1
+$testfile/:$testlink:$testlink/:1
+"
+
+touch $testfile || exit 1
+trap "rm $testfile $testlink" EXIT
+
+set $tests
+echo "1..$#"
+n=1
+for testspec ; do
+ (
+ IFS=:
+ set $testspec
+ unset IFS
+ ln -fs "$1" "$2" || exit 1
+ cat "$3" >/dev/null 2>&1
+ ret=$?
+ if [ "$ret" -eq "$4" ] ; then
+ echo "ok $n"
+ else
+ echo "fail $n - expected $4, got $ret"
+ fi
+ )
+ n=$((n+1))
+done
OpenPOWER on IntegriCloud