Module Name: src Committed By: kamil Date: Fri Apr 5 22:58:53 UTC 2019
Modified Files: src/tests/lib/libc/sys: t_ptrace_wait.c Log Message: Add __clone(2) tests in t_ptrace_wait* The __clone(2) API is a variation of fork(2)/vfork(2) operations. New tests: - clone_signalignored - clone_signalmasked - clone_vm_signalignored - clone_vm_signalmasked - clone_fs_signalignored - clone_fs_signalmasked - clone_files_signalignored - clone_files_signalmasked - clone_vfork_signalignored - clone_vfork_signalmasked All new tests pass. CLONE_SIGHAND tests are right now disabled as they cannot reuse the shared signal operations (wait(2)) to wait for a clonee. Another nit is that wait(2) must be used right now with WALLSIG as for some reason the default variation doesn't work. To generate a diff of this commit: cvs rdiff -u -r1.102 -r1.103 src/tests/lib/libc/sys/t_ptrace_wait.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/tests/lib/libc/sys/t_ptrace_wait.c diff -u src/tests/lib/libc/sys/t_ptrace_wait.c:1.102 src/tests/lib/libc/sys/t_ptrace_wait.c:1.103 --- src/tests/lib/libc/sys/t_ptrace_wait.c:1.102 Wed Apr 3 08:19:46 2019 +++ src/tests/lib/libc/sys/t_ptrace_wait.c Fri Apr 5 22:58:53 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: t_ptrace_wait.c,v 1.102 2019/04/03 08:19:46 kamil Exp $ */ +/* $NetBSD: t_ptrace_wait.c,v 1.103 2019/04/05 22:58:53 kamil Exp $ */ /*- * Copyright (c) 2016, 2017, 2018, 2019 The NetBSD Foundation, Inc. @@ -27,7 +27,7 @@ */ #include <sys/cdefs.h> -__RCSID("$NetBSD: t_ptrace_wait.c,v 1.102 2019/04/03 08:19:46 kamil Exp $"); +__RCSID("$NetBSD: t_ptrace_wait.c,v 1.103 2019/04/05 22:58:53 kamil Exp $"); #include <sys/param.h> #include <sys/types.h> @@ -6295,6 +6295,383 @@ ATF_TC_BODY(syscallemu1, tc) TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0)); } +/// ---------------------------------------------------------------------------- + +#if defined(TWAIT_HAVE_PID) +static int +clone_func(void *arg) +{ + int ret; + + ret = (int)(intptr_t)arg; + + return ret; +} + +static void +clone_body(int flags, bool masked, bool ignored) +{ + const int exitval = 5; + const int exitval2 = 15; + const int sigval = SIGSTOP; + pid_t child, child2 = 0, wpid; +#if defined(TWAIT_HAVE_STATUS) + int status; +#endif + ptrace_state_t state; + const int slen = sizeof(state); + ptrace_event_t event; + const int elen = sizeof(event); + struct sigaction sa; + struct ptrace_siginfo info; + sigset_t intmask; + struct kinfo_proc2 kp; + size_t len = sizeof(kp); + + int name[6]; + const size_t namelen = __arraycount(name); + ki_sigset_t kp_sigmask; + ki_sigset_t kp_sigignore; + + const size_t stack_size = 1024 * 1024; + void *stack, *stack_base; + + stack = malloc(stack_size); + ATF_REQUIRE(stack != NULL); + +#ifdef __MACHINE_STACK_GROWS_UP + stack_base = stack; +#else + stack_base = (char *)stack + stack_size; +#endif + + SYSCALL_REQUIRE((child = fork()) != -1); + if (child == 0) { + DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid()); + FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1); + + if (masked) { + sigemptyset(&intmask); + sigaddset(&intmask, SIGTRAP); + sigprocmask(SIG_BLOCK, &intmask, NULL); + } + + if (ignored) { + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = SIG_IGN; + sigemptyset(&sa.sa_mask); + FORKEE_ASSERT(sigaction(SIGTRAP, &sa, NULL) != -1); + } + DPRINTF("Before raising %s from child\n", strsignal(sigval)); + FORKEE_ASSERT(raise(sigval) == 0); + + DPRINTF("Before forking process PID=%d flags=%#x\n", getpid(), + flags); + SYSCALL_REQUIRE((child2 = __clone(clone_func, stack_base, + flags|SIGCHLD, (void *)(intptr_t)exitval2)) != -1); + + DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), + child2); + + // XXX WALLSIG? + FORKEE_REQUIRE_SUCCESS + (wpid = TWAIT_GENERIC(child2, &status, WALLSIG), child2); + + forkee_status_exited(status, exitval2); + + DPRINTF("Before exiting of the child process\n"); + _exit(exitval); + } + DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child); + + DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME); + TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child); + + validate_status_stopped(status, sigval); + + DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n"); + SYSCALL_REQUIRE( + ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1); + + DPRINTF("Before checking siginfo_t\n"); + ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval); + ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP); + + name[0] = CTL_KERN, + name[1] = KERN_PROC2, + name[2] = KERN_PROC_PID; + name[3] = child; + name[4] = sizeof(kp); + name[5] = 1; + + FORKEE_ASSERT_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0); + + if (masked) + kp_sigmask = kp.p_sigmask; + + if (ignored) + kp_sigignore = kp.p_sigignore; + + DPRINTF("Set PTRACE_FORK | PTRACE_VFORK | PTRACE_VFORK_DONE in " + "EVENT_MASK for the child %d\n", child); + event.pe_set_event = PTRACE_FORK | PTRACE_VFORK | PTRACE_VFORK_DONE; + SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1); + + DPRINTF("Before resuming the child process where it left off and " + "without signal to be sent\n"); + SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1); + + DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME, + child); + TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), + child); + + validate_status_stopped(status, SIGTRAP); + + ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0); + + if (masked) { + DPRINTF("kp_sigmask=" + "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" + PRIx32 "\n", + kp_sigmask.__bits[0], kp_sigmask.__bits[1], + kp_sigmask.__bits[2], kp_sigmask.__bits[3]); + + DPRINTF("kp.p_sigmask=" + "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" + PRIx32 "\n", + kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1], + kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]); + + ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask, + sizeof(kp_sigmask))); + } + + if (ignored) { + DPRINTF("kp_sigignore=" + "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" + PRIx32 "\n", + kp_sigignore.__bits[0], kp_sigignore.__bits[1], + kp_sigignore.__bits[2], kp_sigignore.__bits[3]); + + DPRINTF("kp.p_sigignore=" + "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" + PRIx32 "\n", + kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1], + kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]); + + ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore, + sizeof(kp_sigignore))); + } + + SYSCALL_REQUIRE( + ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1); + DPRINTF("state.pe_report_event=%#x pid=%d\n", state.pe_report_event, + child2); + if (!(flags & CLONE_VFORK)) { + ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_FORK, + PTRACE_FORK); + } else { + ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_VFORK, + PTRACE_VFORK); + } + + child2 = state.pe_other_pid; + DPRINTF("Reported ptrace event with forkee %d\n", child2); + + DPRINTF("Before calling %s() for the forkee %d of the child " + "%d\n", TWAIT_FNAME, child2, child); + TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child2, &status, 0), + child2); + + validate_status_stopped(status, SIGTRAP); + + name[3] = child2; + ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0); + + if (masked) { + DPRINTF("kp_sigmask=" + "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" + PRIx32 "\n", + kp_sigmask.__bits[0], kp_sigmask.__bits[1], + kp_sigmask.__bits[2], kp_sigmask.__bits[3]); + + DPRINTF("kp.p_sigmask=" + "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" + PRIx32 "\n", + kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1], + kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]); + + ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask, + sizeof(kp_sigmask))); + } + + if (ignored) { + DPRINTF("kp_sigignore=" + "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" + PRIx32 "\n", + kp_sigignore.__bits[0], kp_sigignore.__bits[1], + kp_sigignore.__bits[2], kp_sigignore.__bits[3]); + + DPRINTF("kp.p_sigignore=" + "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" + PRIx32 "\n", + kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1], + kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]); + + ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore, + sizeof(kp_sigignore))); + } + + SYSCALL_REQUIRE( + ptrace(PT_GET_PROCESS_STATE, child2, &state, slen) != -1); + if (!(flags & CLONE_VFORK)) { + ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_FORK, + PTRACE_FORK); + } else { + ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_VFORK, + PTRACE_VFORK); + } + + ATF_REQUIRE_EQ(state.pe_other_pid, child); + + DPRINTF("Before resuming the forkee process where it left off " + "and without signal to be sent\n"); + SYSCALL_REQUIRE( + ptrace(PT_CONTINUE, child2, (void *)1, 0) != -1); + + DPRINTF("Before resuming the child process where it left off " + "and without signal to be sent\n"); + SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1); + + if (flags & CLONE_VFORK) { + DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME, + child); + TWAIT_REQUIRE_SUCCESS( + wpid = TWAIT_GENERIC(child, &status, 0), child); + + validate_status_stopped(status, SIGTRAP); + + name[3] = child; + ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0); + + /* + * SIGCHLD is now pending in the signal queue and + * the kernel presents it to userland as a masked signal. + */ + sigdelset((sigset_t *)&kp.p_sigmask, SIGCHLD); + + if (masked) { + DPRINTF("kp_sigmask=" + "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" + PRIx32 "\n", + kp_sigmask.__bits[0], kp_sigmask.__bits[1], + kp_sigmask.__bits[2], kp_sigmask.__bits[3]); + + DPRINTF("kp.p_sigmask=" + "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" + PRIx32 "\n", + kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1], + kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]); + + ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask, + sizeof(kp_sigmask))); + } + + if (ignored) { + DPRINTF("kp_sigignore=" + "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" + PRIx32 "\n", + kp_sigignore.__bits[0], kp_sigignore.__bits[1], + kp_sigignore.__bits[2], kp_sigignore.__bits[3]); + + DPRINTF("kp.p_sigignore=" + "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" + PRIx32 "\n", + kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1], + kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]); + + ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore, + sizeof(kp_sigignore))); + } + + SYSCALL_REQUIRE( + ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1); + ATF_REQUIRE_EQ(state.pe_report_event, PTRACE_VFORK_DONE); + + child2 = state.pe_other_pid; + DPRINTF("Reported PTRACE_VFORK_DONE event with forkee %d\n", + child2); + + DPRINTF("Before resuming the child process where it left off " + "and without signal to be sent\n"); + SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1); + } + + DPRINTF("Before calling %s() for the forkee - expected exited" + "\n", TWAIT_FNAME); + TWAIT_REQUIRE_SUCCESS( + wpid = TWAIT_GENERIC(child2, &status, 0), child2); + + validate_status_exited(status, exitval2); + + DPRINTF("Before calling %s() for the forkee - expected no " + "process\n", TWAIT_FNAME); + TWAIT_REQUIRE_FAILURE(ECHILD, + wpid = TWAIT_GENERIC(child2, &status, 0)); + + DPRINTF("Before calling %s() for the child - expected stopped " + "SIGCHLD\n", TWAIT_FNAME); + TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child); + + validate_status_stopped(status, SIGCHLD); + + DPRINTF("Before resuming the child process where it left off and " + "without signal to be sent\n"); + SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1); + + DPRINTF("Before calling %s() for the child - expected exited\n", + TWAIT_FNAME); + TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child); + + validate_status_exited(status, exitval); + + DPRINTF("Before calling %s() for the child - expected no process\n", + TWAIT_FNAME); + TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0)); +} + +#define CLONE_TEST(name,flags,masked,ignored) \ +ATF_TC(name); \ +ATF_TC_HEAD(name, tc) \ +{ \ + atf_tc_set_md_var(tc, "descr", "Verify that clone(%s) is caught"\ + " regardless of signal %s%s", \ + #flags, masked ? "masked" : "", ignored ? "ignored" : ""); \ +} \ + \ +ATF_TC_BODY(name, tc) \ +{ \ + \ + clone_body(flags, masked, ignored); \ +} + +CLONE_TEST(clone_signalignored, 0, true, false) +CLONE_TEST(clone_signalmasked, 0, false, true) +CLONE_TEST(clone_vm_signalignored, CLONE_VM, true, false) +CLONE_TEST(clone_vm_signalmasked, CLONE_VM, false, true) +CLONE_TEST(clone_fs_signalignored, CLONE_FS, true, false) +CLONE_TEST(clone_fs_signalmasked, CLONE_FS, false, true) +CLONE_TEST(clone_files_signalignored, CLONE_FILES, true, false) +CLONE_TEST(clone_files_signalmasked, CLONE_FILES, false, true) +//CLONE_TEST(clone_sighand_signalignored, CLONE_SIGHAND, true, false) // XXX +//CLONE_TEST(clone_sighand_signalmasked, CLONE_SIGHAND, false, true) // XXX +CLONE_TEST(clone_vfork_signalignored, CLONE_VFORK, true, false) +CLONE_TEST(clone_vfork_signalmasked, CLONE_VFORK, false, true) +#endif + +/// ---------------------------------------------------------------------------- + #include "t_ptrace_amd64_wait.h" #include "t_ptrace_i386_wait.h" #include "t_ptrace_x86_wait.h" @@ -6634,6 +7011,19 @@ ATF_TP_ADD_TCS(tp) ATF_TP_ADD_TC(tp, syscallemu1); + ATF_TP_ADD_TC_HAVE_PID(tp, clone_signalignored); + ATF_TP_ADD_TC_HAVE_PID(tp, clone_signalmasked); + ATF_TP_ADD_TC_HAVE_PID(tp, clone_vm_signalignored); + ATF_TP_ADD_TC_HAVE_PID(tp, clone_vm_signalmasked); + ATF_TP_ADD_TC_HAVE_PID(tp, clone_fs_signalignored); + ATF_TP_ADD_TC_HAVE_PID(tp, clone_fs_signalmasked); + ATF_TP_ADD_TC_HAVE_PID(tp, clone_files_signalignored); + ATF_TP_ADD_TC_HAVE_PID(tp, clone_files_signalmasked); +// ATF_TP_ADD_TC_HAVE_PID(tp, clone_sighand_signalignored); // XXX +// ATF_TP_ADD_TC_HAVE_PID(tp, clone_sighand_signalmasked); // XXX + ATF_TP_ADD_TC_HAVE_PID(tp, clone_vfork_signalignored); + ATF_TP_ADD_TC_HAVE_PID(tp, clone_vfork_signalmasked); + ATF_TP_ADD_TCS_PTRACE_WAIT_AMD64(); ATF_TP_ADD_TCS_PTRACE_WAIT_I386(); ATF_TP_ADD_TCS_PTRACE_WAIT_X86();