aboutsummaryrefslogtreecommitdiff
path: root/tests/sys/kern/ptrace_test.c
diff options
context:
space:
mode:
Diffstat (limited to 'tests/sys/kern/ptrace_test.c')
-rw-r--r--tests/sys/kern/ptrace_test.c187
1 files changed, 183 insertions, 4 deletions
diff --git a/tests/sys/kern/ptrace_test.c b/tests/sys/kern/ptrace_test.c
index 675d90e144ae..d36dfe951e20 100644
--- a/tests/sys/kern/ptrace_test.c
+++ b/tests/sys/kern/ptrace_test.c
@@ -28,13 +28,13 @@
#include <sys/elf.h>
#include <sys/event.h>
#include <sys/file.h>
+#include <sys/mman.h>
#include <sys/time.h>
#include <sys/procctl.h>
#include <sys/procdesc.h>
#include <sys/ptrace.h>
#include <sys/procfs.h>
#include <sys/queue.h>
-#include <sys/runq.h>
#include <sys/syscall.h>
#include <sys/sysctl.h>
#include <sys/user.h>
@@ -2027,7 +2027,7 @@ ATF_TC_BODY(ptrace__PT_KILL_competing_signal, tc)
sched_get_priority_min(SCHED_FIFO)) / 2;
CHILD_REQUIRE(pthread_setschedparam(pthread_self(),
SCHED_FIFO, &sched_param) == 0);
- sched_param.sched_priority -= RQ_PPQ;
+ sched_param.sched_priority -= 1;
CHILD_REQUIRE(pthread_setschedparam(t, SCHED_FIFO,
&sched_param) == 0);
@@ -2130,7 +2130,7 @@ ATF_TC_BODY(ptrace__PT_KILL_competing_stop, tc)
sched_get_priority_min(SCHED_FIFO)) / 2;
CHILD_REQUIRE(pthread_setschedparam(pthread_self(),
SCHED_FIFO, &sched_param) == 0);
- sched_param.sched_priority -= RQ_PPQ;
+ sched_param.sched_priority -= 1;
CHILD_REQUIRE(pthread_setschedparam(t, SCHED_FIFO,
&sched_param) == 0);
@@ -4161,6 +4161,53 @@ ATF_TC_BODY(ptrace__syscall_args, tc)
}
/*
+ * Check that syscall info is available whenever kernel has valid td_sa.
+ * Assumes that libc nanosleep(2) is the plain syscall wrapper.
+ */
+ATF_TC_WITHOUT_HEAD(ptrace__syscall_args_anywhere);
+ATF_TC_BODY(ptrace__syscall_args_anywhere, tc)
+{
+ struct timespec rqt;
+ struct ptrace_lwpinfo lwpi;
+ register_t args[8];
+ pid_t debuggee, wpid;
+ int error, status;
+
+ debuggee = fork();
+ ATF_REQUIRE(debuggee >= 0);
+ if (debuggee == 0) {
+ rqt.tv_sec = 100000;
+ rqt.tv_nsec = 0;
+ for (;;)
+ nanosleep(&rqt, NULL);
+ _exit(0);
+ }
+
+ /* Give the debuggee some time to go to sleep. */
+ sleep(2);
+ error = ptrace(PT_ATTACH, debuggee, 0, 0);
+ ATF_REQUIRE(error == 0);
+ wpid = waitpid(debuggee, &status, 0);
+ REQUIRE_EQ(wpid, debuggee);
+ ATF_REQUIRE(WIFSTOPPED(status));
+ REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
+
+ error = ptrace(PT_LWPINFO, debuggee, (caddr_t)&lwpi, sizeof(lwpi));
+ ATF_REQUIRE(error == 0);
+ ATF_REQUIRE(lwpi.pl_syscall_code == SYS_nanosleep);
+ ATF_REQUIRE(lwpi.pl_syscall_narg == 2);
+ error = ptrace(PT_GET_SC_ARGS, debuggee, (caddr_t)&args[0],
+ lwpi.pl_syscall_narg * sizeof(register_t));
+ ATF_REQUIRE(error == 0);
+ ATF_REQUIRE(args[0] == (register_t)&rqt);
+ ATF_REQUIRE(args[1] == 0);
+
+ error = ptrace(PT_DETACH, debuggee, 0, 0);
+ ATF_REQUIRE(error == 0);
+ kill(SIGKILL, debuggee);
+}
+
+/*
* Verify that when the process is traced that it isn't reparent
* to the init process when we close all process descriptors.
*/
@@ -4331,7 +4378,10 @@ ATF_TC_BODY(ptrace__PT_SC_REMOTE_getpid, tc)
exit(0);
}
- attach_child(fpid);
+ wpid = waitpid(fpid, &status, 0);
+ REQUIRE_EQ(wpid, fpid);
+ ATF_REQUIRE(WIFSTOPPED(status));
+ REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
pscr.pscr_syscall = SYS_getpid;
pscr.pscr_nargs = 0;
@@ -4414,6 +4464,132 @@ ATF_TC_BODY(ptrace__reap_kill_stopped, tc)
REQUIRE_EQ(-1, prk.rk_fpid);
}
+struct child_res {
+ struct timespec sleep_time;
+ int nanosleep_res;
+ int nanosleep_errno;
+};
+
+static const long nsec = 1000000000L;
+static const struct timespec ten_sec = {
+ .tv_sec = 10,
+ .tv_nsec = 0,
+};
+static const struct timespec twelve_sec = {
+ .tv_sec = 12,
+ .tv_nsec = 0,
+};
+
+ATF_TC_WITHOUT_HEAD(ptrace__PT_ATTACH_no_EINTR);
+ATF_TC_BODY(ptrace__PT_ATTACH_no_EINTR, tc)
+{
+ struct child_res *shm;
+ struct timespec rqt, now, wake;
+ pid_t debuggee;
+ int status;
+
+ shm = mmap(NULL, sizeof(*shm), PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_ANON, -1, 0);
+ ATF_REQUIRE(shm != MAP_FAILED);
+
+ ATF_REQUIRE((debuggee = fork()) != -1);
+ if (debuggee == 0) {
+ rqt.tv_sec = 10;
+ rqt.tv_nsec = 0;
+ clock_gettime(CLOCK_MONOTONIC_PRECISE, &now);
+ errno = 0;
+ shm->nanosleep_res = nanosleep(&rqt, NULL);
+ shm->nanosleep_errno = errno;
+ clock_gettime(CLOCK_MONOTONIC_PRECISE, &wake);
+ timespecsub(&wake, &now, &shm->sleep_time);
+ _exit(0);
+ }
+
+ /* Give the debuggee some time to go to sleep. */
+ sleep(2);
+ REQUIRE_EQ(ptrace(PT_ATTACH, debuggee, 0, 0), 0);
+ REQUIRE_EQ(waitpid(debuggee, &status, 0), debuggee);
+ ATF_REQUIRE(WIFSTOPPED(status));
+ REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
+
+ REQUIRE_EQ(ptrace(PT_DETACH, debuggee, 0, 0), 0);
+ REQUIRE_EQ(waitpid(debuggee, &status, 0), debuggee);
+ ATF_REQUIRE(WIFEXITED(status));
+ REQUIRE_EQ(WEXITSTATUS(status), 0);
+
+ ATF_REQUIRE(shm->nanosleep_res == 0);
+ ATF_REQUIRE(shm->nanosleep_errno == 0);
+ ATF_REQUIRE(timespeccmp(&shm->sleep_time, &ten_sec, >=));
+ ATF_REQUIRE(timespeccmp(&shm->sleep_time, &twelve_sec, <=));
+}
+
+ATF_TC_WITHOUT_HEAD(ptrace__PT_DETACH_continued);
+ATF_TC_BODY(ptrace__PT_DETACH_continued, tc)
+{
+ char buf[256];
+ pid_t debuggee, debugger;
+ int dpipe[2] = {-1, -1}, status;
+
+ /* Setup the debuggee's pipe, which we'll use to let it terminate. */
+ ATF_REQUIRE(pipe(dpipe) == 0);
+ ATF_REQUIRE((debuggee = fork()) != -1);
+
+ if (debuggee == 0) {
+ ssize_t readsz;
+
+ /*
+ * The debuggee will just absorb everything until the parent
+ * closes it. In the process, we expect it to get SIGSTOP'd,
+ * then ptrace(2)d and finally, it should resume after we detach
+ * and the parent will be notified.
+ */
+ close(dpipe[1]);
+ while ((readsz = read(dpipe[0], buf, sizeof(buf))) != 0) {
+ if (readsz > 0 || errno == EINTR)
+ continue;
+ _exit(1);
+ }
+
+ _exit(0);
+ }
+
+ close(dpipe[0]);
+
+ ATF_REQUIRE(kill(debuggee, SIGSTOP) == 0);
+ REQUIRE_EQ(waitpid(debuggee, &status, WUNTRACED), debuggee);
+ ATF_REQUIRE(WIFSTOPPED(status));
+
+ /* Child is stopped, enter the debugger to attach/detach. */
+ ATF_REQUIRE((debugger = fork()) != -1);
+ if (debugger == 0) {
+ REQUIRE_EQ(ptrace(PT_ATTACH, debuggee, 0, 0), 0);
+ REQUIRE_EQ(waitpid(debuggee, &status, 0), debuggee);
+ ATF_REQUIRE(WIFSTOPPED(status));
+ REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
+
+ REQUIRE_EQ(ptrace(PT_DETACH, debuggee, 0, 0), 0);
+ _exit(0);
+ }
+
+ REQUIRE_EQ(waitpid(debugger, &status, 0), debugger);
+ ATF_REQUIRE(WIFEXITED(status));
+ REQUIRE_EQ(WEXITSTATUS(status), 0);
+
+ REQUIRE_EQ(waitpid(debuggee, &status, WCONTINUED), debuggee);
+ ATF_REQUIRE(WIFCONTINUED(status));
+
+ /*
+ * Closing the pipe will trigger the debuggee to exit now that the
+ * child has resumed following detach.
+ */
+ close(dpipe[1]);
+
+ REQUIRE_EQ(waitpid(debuggee, &status, 0), debuggee);
+ ATF_REQUIRE(WIFEXITED(status));
+ REQUIRE_EQ(WEXITSTATUS(status), 0);
+
+}
+
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, ptrace__parent_wait_after_trace_me);
@@ -4476,11 +4652,14 @@ ATF_TP_ADD_TCS(tp)
#endif
ATF_TP_ADD_TC(tp, ptrace__PT_LWPINFO_stale_siginfo);
ATF_TP_ADD_TC(tp, ptrace__syscall_args);
+ ATF_TP_ADD_TC(tp, ptrace__syscall_args_anywhere);
ATF_TP_ADD_TC(tp, ptrace__proc_reparent);
ATF_TP_ADD_TC(tp, ptrace__procdesc_wait_child);
ATF_TP_ADD_TC(tp, ptrace__procdesc_reparent_wait_child);
ATF_TP_ADD_TC(tp, ptrace__PT_SC_REMOTE_getpid);
ATF_TP_ADD_TC(tp, ptrace__reap_kill_stopped);
+ ATF_TP_ADD_TC(tp, ptrace__PT_ATTACH_no_EINTR);
+ ATF_TP_ADD_TC(tp, ptrace__PT_DETACH_continued);
return (atf_no_error());
}