Author: bdrewery
Date: Tue Oct 17 19:01:01 2017
New Revision: 324701
URL: https://svnweb.freebsd.org/changeset/base/324701

Log:
  Add a test for r324671 along with some other masked tests.
  
  MFC after:    1 week
  Sponsored by: Dell EMC Isilon

Modified:
  head/tests/sys/kern/ptrace_test.c

Modified: head/tests/sys/kern/ptrace_test.c
==============================================================================
--- head/tests/sys/kern/ptrace_test.c   Tue Oct 17 18:00:01 2017        
(r324700)
+++ head/tests/sys/kern/ptrace_test.c   Tue Oct 17 19:01:01 2017        
(r324701)
@@ -2402,7 +2402,107 @@ ATF_TC_BODY(ptrace__PT_CONTINUE_with_signal_full_sigqu
        ATF_REQUIRE(errno == ECHILD);
 }
 
+static sem_t sigusr1_sem;
+static int got_usr1;
+
+static void
+sigusr1_sempost_handler(int sig __unused)
+{
+
+       got_usr1++;
+       CHILD_REQUIRE(sem_post(&sigusr1_sem) == 0);
+}
+
 /*
+ * Verify that even if the signal queue is full for a child process,
+ * and the signal is masked, a PT_CONTINUE with a signal will not
+ * result in loss of that signal.
+ */
+ATF_TC_WITHOUT_HEAD(ptrace__PT_CONTINUE_with_signal_masked_full_sigqueue);
+ATF_TC_BODY(ptrace__PT_CONTINUE_with_signal_masked_full_sigqueue, tc)
+{
+       struct ptrace_lwpinfo pl;
+       pid_t fpid, wpid;
+       int status, err;
+       int max_pending_per_proc;
+       size_t len;
+       int i;
+       sigset_t sigmask;
+
+       ATF_REQUIRE(signal(SIGUSR2, handler) != SIG_ERR);
+       ATF_REQUIRE(sem_init(&sigusr1_sem, 0, 0) == 0);
+       ATF_REQUIRE(signal(SIGUSR1, sigusr1_sempost_handler) != SIG_ERR);
+
+       got_usr1 = 0;
+       ATF_REQUIRE((fpid = fork()) != -1);
+       if (fpid == 0) {
+               CHILD_REQUIRE(sigemptyset(&sigmask) == 0);
+               CHILD_REQUIRE(sigaddset(&sigmask, SIGUSR1) == 0);
+               CHILD_REQUIRE(sigprocmask(SIG_BLOCK, &sigmask, NULL) == 0);
+
+               trace_me();
+               CHILD_REQUIRE(got_usr1 == 0);
+
+               /* Allow the pending SIGUSR1 in now. */
+               CHILD_REQUIRE(sigprocmask(SIG_UNBLOCK, &sigmask, NULL) == 0);
+               /* Wait to receive the SIGUSR1. */
+               do {
+                       err = sem_wait(&sigusr1_sem);
+                       CHILD_REQUIRE(err == 0 || errno == EINTR);
+               } while (err != 0 && errno == EINTR);
+               CHILD_REQUIRE(got_usr1 == 1);
+               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);
+
+       len = sizeof(max_pending_per_proc);
+       ATF_REQUIRE(sysctlbyname("kern.sigqueue.max_pending_per_proc",
+           &max_pending_per_proc, &len, NULL, 0) == 0);
+
+       /* Fill the signal queue. */
+       for (i = 0; i < max_pending_per_proc; ++i)
+               ATF_REQUIRE(kill(fpid, SIGUSR2) == 0);
+
+       /* Continue with signal. */
+       ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, SIGUSR1) == 0);
+
+       /* Collect and ignore all of the SIGUSR2. */
+       for (i = 0; i < max_pending_per_proc; ++i) {
+               wpid = waitpid(fpid, &status, 0);
+               ATF_REQUIRE(wpid == fpid);
+               ATF_REQUIRE(WIFSTOPPED(status));
+               ATF_REQUIRE(WSTOPSIG(status) == SIGUSR2);
+               ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0);
+       }
+
+       /* Now our PT_CONTINUE'd SIGUSR1 should cause a stop after unmask. */
+       wpid = waitpid(fpid, &status, 0);
+       ATF_REQUIRE(wpid == fpid);
+       ATF_REQUIRE(WIFSTOPPED(status));
+       ATF_REQUIRE(WSTOPSIG(status) == SIGUSR1);
+       ATF_REQUIRE(ptrace(PT_LWPINFO, fpid, (caddr_t)&pl, sizeof(pl)) != -1);
+       ATF_REQUIRE(pl.pl_siginfo.si_signo == SIGUSR1);
+
+       /* Continue the child, ignoring the SIGUSR1. */
+       ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0);
+
+       /* The last wait() should report exit after receiving SIGUSR1. */
+       wpid = waitpid(fpid, &status, 0);
+       ATF_REQUIRE(wpid == fpid);
+       ATF_REQUIRE(WIFEXITED(status));
+       ATF_REQUIRE(WEXITSTATUS(status) == 1);
+
+       wpid = wait(&status);
+       ATF_REQUIRE(wpid == -1);
+       ATF_REQUIRE(errno == ECHILD);
+}
+
+/*
  * Verify that, after stopping due to a signal, that signal can be
  * replaced with another signal.
  */
@@ -2674,15 +2774,6 @@ ATF_TC_BODY(ptrace__PT_CONTINUE_with_signal_kqueue, tc
        ATF_REQUIRE(errno == ECHILD);
 }
 
-static sem_t sigusr1_sem;
-
-static void
-sigusr1_sempost_handler(int sig __unused)
-{
-
-       CHILD_REQUIRE(sem_post(&sigusr1_sem) == 0);
-}
-
 static void *
 signal_thread(void *arg)
 {
@@ -2718,6 +2809,148 @@ signal_thread(void *arg)
 }
 
 /*
+ * Verify that a traced process with blocked signal received the
+ * signal from kill() once unmasked.
+ */
+ATF_TC_WITHOUT_HEAD(ptrace__killed_with_sigmask);
+ATF_TC_BODY(ptrace__killed_with_sigmask, tc)
+{
+       struct ptrace_lwpinfo pl;
+       pid_t fpid, wpid;
+       int status, err;
+       sigset_t sigmask;
+
+       ATF_REQUIRE(sem_init(&sigusr1_sem, 0, 0) == 0);
+       ATF_REQUIRE(signal(SIGUSR1, sigusr1_sempost_handler) != SIG_ERR);
+       got_usr1 = 0;
+
+       ATF_REQUIRE((fpid = fork()) != -1);
+       if (fpid == 0) {
+               CHILD_REQUIRE(sigemptyset(&sigmask) == 0);
+               CHILD_REQUIRE(sigaddset(&sigmask, SIGUSR1) == 0);
+               CHILD_REQUIRE(sigprocmask(SIG_BLOCK, &sigmask, NULL) == 0);
+
+               trace_me();
+               CHILD_REQUIRE(got_usr1 == 0);
+
+               /* Allow the pending SIGUSR1 in now. */
+               CHILD_REQUIRE(sigprocmask(SIG_UNBLOCK, &sigmask, NULL) == 0);
+               /* Wait to receive a SIGUSR1. */
+               do {
+                       err = sem_wait(&sigusr1_sem);
+                       CHILD_REQUIRE(err == 0 || errno == EINTR);
+               } while (err != 0 && errno == EINTR);
+               CHILD_REQUIRE(got_usr1 == 1);
+               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, fpid, (caddr_t)&pl, sizeof(pl)) != -1);
+       ATF_REQUIRE(pl.pl_siginfo.si_signo == SIGSTOP);
+
+       /* Send blocked SIGUSR1 which should cause a stop. */
+       ATF_REQUIRE(kill(fpid, SIGUSR1) == 0);
+
+       /* Continue the child ignoring the SIGSTOP. */
+       ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0);
+
+       /* The next wait() should report the kill(SIGUSR1) was received. */
+       wpid = waitpid(fpid, &status, 0);
+       ATF_REQUIRE(wpid == fpid);
+       ATF_REQUIRE(WIFSTOPPED(status));
+       ATF_REQUIRE(WSTOPSIG(status) == SIGUSR1);
+       ATF_REQUIRE(ptrace(PT_LWPINFO, fpid, (caddr_t)&pl, sizeof(pl)) != -1);
+       ATF_REQUIRE(pl.pl_siginfo.si_signo == SIGUSR1);
+
+       /* Continue the child, allowing in the SIGUSR1. */
+       ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, SIGUSR1) == 0);
+
+       /* The last wait() should report normal exit with code 1. */
+       wpid = waitpid(fpid, &status, 0);
+       ATF_REQUIRE(wpid == fpid);
+       ATF_REQUIRE(WIFEXITED(status));
+       ATF_REQUIRE(WEXITSTATUS(status) == 1);
+
+       wpid = wait(&status);
+       ATF_REQUIRE(wpid == -1);
+       ATF_REQUIRE(errno == ECHILD);
+}
+
+/*
+ * Verify that a traced process with blocked signal received the
+ * signal from PT_CONTINUE once unmasked.
+ */
+ATF_TC_WITHOUT_HEAD(ptrace__PT_CONTINUE_with_sigmask);
+ATF_TC_BODY(ptrace__PT_CONTINUE_with_sigmask, tc)
+{
+       struct ptrace_lwpinfo pl;
+       pid_t fpid, wpid;
+       int status, err;
+       sigset_t sigmask;
+
+       ATF_REQUIRE(sem_init(&sigusr1_sem, 0, 0) == 0);
+       ATF_REQUIRE(signal(SIGUSR1, sigusr1_sempost_handler) != SIG_ERR);
+       got_usr1 = 0;
+
+       ATF_REQUIRE((fpid = fork()) != -1);
+       if (fpid == 0) {
+               CHILD_REQUIRE(sigemptyset(&sigmask) == 0);
+               CHILD_REQUIRE(sigaddset(&sigmask, SIGUSR1) == 0);
+               CHILD_REQUIRE(sigprocmask(SIG_BLOCK, &sigmask, NULL) == 0);
+
+               trace_me();
+               CHILD_REQUIRE(got_usr1 == 0);
+
+               /* Allow the pending SIGUSR1 in now. */
+               CHILD_REQUIRE(sigprocmask(SIG_UNBLOCK, &sigmask, NULL) == 0);
+               /* Wait to receive a SIGUSR1. */
+               do {
+                       err = sem_wait(&sigusr1_sem);
+                       CHILD_REQUIRE(err == 0 || errno == EINTR);
+               } while (err != 0 && errno == EINTR);
+
+               CHILD_REQUIRE(got_usr1 == 1);
+               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, fpid, (caddr_t)&pl, sizeof(pl)) != -1);
+       ATF_REQUIRE(pl.pl_siginfo.si_signo == SIGSTOP);
+
+       /* Continue the child replacing SIGSTOP with SIGUSR1. */
+       ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, SIGUSR1) == 0);
+
+       /* The next wait() should report the SIGUSR1 was received. */
+       wpid = waitpid(fpid, &status, 0);
+       ATF_REQUIRE(wpid == fpid);
+       ATF_REQUIRE(WIFSTOPPED(status));
+       ATF_REQUIRE(WSTOPSIG(status) == SIGUSR1);
+       ATF_REQUIRE(ptrace(PT_LWPINFO, fpid, (caddr_t)&pl, sizeof(pl)) != -1);
+       ATF_REQUIRE(pl.pl_siginfo.si_signo == SIGUSR1);
+
+       /* Continue the child, ignoring the SIGUSR1. */
+       ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0);
+
+       /* The last wait() should report normal exit with code 1. */
+       wpid = waitpid(fpid, &status, 0);
+       ATF_REQUIRE(wpid == fpid);
+       ATF_REQUIRE(WIFEXITED(status));
+       ATF_REQUIRE(WEXITSTATUS(status) == 1);
+
+       wpid = wait(&status);
+       ATF_REQUIRE(wpid == -1);
+       ATF_REQUIRE(errno == ECHILD);
+}
+
+/*
  * Verify that if ptrace stops due to a signal but continues with
  * a different signal that the new signal is routed to a thread
  * that can accept it, and that that thread is awakened by the signal
@@ -3183,10 +3416,13 @@ ATF_TP_ADD_TCS(tp)
        ATF_TP_ADD_TC(tp,
            ptrace__PT_CONTINUE_with_signal_system_call_entry_and_exit);
        ATF_TP_ADD_TC(tp, ptrace__PT_CONTINUE_with_signal_full_sigqueue);
+       ATF_TP_ADD_TC(tp, ptrace__PT_CONTINUE_with_signal_masked_full_sigqueue);
        ATF_TP_ADD_TC(tp, ptrace__PT_CONTINUE_change_sig);
        ATF_TP_ADD_TC(tp, ptrace__PT_CONTINUE_with_sigtrap_system_call_entry);
        ATF_TP_ADD_TC(tp, ptrace__PT_CONTINUE_with_signal_mix);
        ATF_TP_ADD_TC(tp, ptrace__PT_CONTINUE_with_signal_kqueue);
+       ATF_TP_ADD_TC(tp, ptrace__killed_with_sigmask);
+       ATF_TP_ADD_TC(tp, ptrace__PT_CONTINUE_with_sigmask);
        ATF_TP_ADD_TC(tp, ptrace__PT_CONTINUE_with_signal_thread_sigmask);
        ATF_TP_ADD_TC(tp, ptrace__parent_terminate_with_pending_sigstop1);
        ATF_TP_ADD_TC(tp, ptrace__parent_terminate_with_pending_sigstop2);
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to