Date: Tue, 17 Oct 2017 19:01:02 +0000 (UTC) From: Bryan Drewery <bdrewery@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r324701 - head/tests/sys/kern Message-ID: <201710171901.v9HJ12OM088566@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
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);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201710171901.v9HJ12OM088566>