aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorJohn Baldwin <jhb@FreeBSD.org>2018-12-10 19:39:24 +0000
committerJohn Baldwin <jhb@FreeBSD.org>2018-12-10 19:39:24 +0000
commitc5786670acf18432b16d0e9ded171149adc12d70 (patch)
tree6a9b6ac5229300c6ac42f39bc3f8f12a7c4b6c04 /tests
parenta895c1c28ad1b241f7d49c1694c6d40fddbfddcd (diff)
downloadsrc-c5786670acf18432b16d0e9ded171149adc12d70.tar.gz
src-c5786670acf18432b16d0e9ded171149adc12d70.zip
Don't report stale signal information for non-signal events in ptrace_lwpinfo.
Once a signal's siginfo was copied to 'td_si' as part of the signal exchange in issignal(), it was never cleared. This caused future thread events that are reported as SIGTRAP events without signal information to report the stale siginfo in 'td_si'. For example, if a debugger created a new process and used SIGSTOP to stop it after PT_ATTACH, future system call entry / exit events would set PL_FLAG_SI with the SIGSTOP siginfo in pl_siginfo. This broke 'catch syscall' in current versions of gdb as it assumed PL_FLAG_SI with SIGTRAP indicates a breakpoint or single step trap. Reviewed by: kib MFC after: 1 week Differential Revision: https://reviews.freebsd.org/D18487
Notes
Notes: svn path=/head/; revision=341800
Diffstat (limited to 'tests')
-rw-r--r--tests/sys/kern/ptrace_test.c73
1 files changed, 73 insertions, 0 deletions
diff --git a/tests/sys/kern/ptrace_test.c b/tests/sys/kern/ptrace_test.c
index 9589bb62922a..8bca329449fd 100644
--- a/tests/sys/kern/ptrace_test.c
+++ b/tests/sys/kern/ptrace_test.c
@@ -3772,6 +3772,78 @@ ATF_TC_BODY(ptrace__PT_CONTINUE_different_thread, tc)
}
#endif
+/*
+ * Verify that PT_LWPINFO doesn't return stale siginfo.
+ */
+ATF_TC_WITHOUT_HEAD(ptrace__PT_LWPINFO_stale_siginfo);
+ATF_TC_BODY(ptrace__PT_LWPINFO_stale_siginfo, tc)
+{
+ struct ptrace_lwpinfo pl;
+ pid_t fpid, wpid;
+ int events, status;
+
+ ATF_REQUIRE((fpid = fork()) != -1);
+ if (fpid == 0) {
+ trace_me();
+ raise(SIGABRT);
+ 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_CONTINUE, fpid, (caddr_t)1, 0) == 0);
+
+ /* The next stop should report the SIGABRT in the child body. */
+ wpid = waitpid(fpid, &status, 0);
+ ATF_REQUIRE(wpid == fpid);
+ ATF_REQUIRE(WIFSTOPPED(status));
+ ATF_REQUIRE(WSTOPSIG(status) == SIGABRT);
+
+ ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1);
+ ATF_REQUIRE(pl.pl_flags & PL_FLAG_SI);
+ ATF_REQUIRE(pl.pl_siginfo.si_signo == SIGABRT);
+
+ /*
+ * Continue the process ignoring the signal, but enabling
+ * syscall traps.
+ */
+ ATF_REQUIRE(ptrace(PT_SYSCALL, fpid, (caddr_t)1, 0) == 0);
+
+ /*
+ * The next stop should report a system call entry from
+ * exit(). PL_FLAGS_SI should not be set.
+ */
+ 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_SCE);
+ ATF_REQUIRE((pl.pl_flags & PL_FLAG_SI) == 0);
+
+ /* Disable syscall tracing and continue the child to let it exit. */
+ ATF_REQUIRE(ptrace(PT_GET_EVENT_MASK, fpid, (caddr_t)&events,
+ sizeof(events)) == 0);
+ events &= ~PTRACE_SYSCALL;
+ ATF_REQUIRE(ptrace(PT_SET_EVENT_MASK, fpid, (caddr_t)&events,
+ sizeof(events)) == 0);
+ ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0);
+
+ /* The last event should be for the child process's exit. */
+ wpid = waitpid(fpid, &status, 0);
+ ATF_REQUIRE(WIFEXITED(status));
+ ATF_REQUIRE(WEXITSTATUS(status) == 1);
+
+ wpid = wait(&status);
+ ATF_REQUIRE(wpid == -1);
+ ATF_REQUIRE(errno == ECHILD);
+}
+
ATF_TP_ADD_TCS(tp)
{
@@ -3831,6 +3903,7 @@ ATF_TP_ADD_TCS(tp)
#if defined(HAVE_BREAKPOINT) && defined(SKIP_BREAK)
ATF_TP_ADD_TC(tp, ptrace__PT_CONTINUE_different_thread);
#endif
+ ATF_TP_ADD_TC(tp, ptrace__PT_LWPINFO_stale_siginfo);
return (atf_no_error());
}