diff --git a/lib/libc/sys/ptrace.2 b/lib/libc/sys/ptrace.2 index 859aa0d3c2e8..2a8d33121408 100644 --- a/lib/libc/sys/ptrace.2 +++ b/lib/libc/sys/ptrace.2 @@ -1,7 +1,7 @@ -.\" $NetBSD: ptrace.2,v 1.58 2017/01/27 12:52:39 wiz Exp $ +.\" $NetBSD: ptrace.2,v 1.59 2017/02/12 06:09:53 kamil Exp $ .\" .\" This file is in the public domain. -.Dd January 25, 2016 +.Dd February 12, 2016 .Dt PTRACE 2 .Os .Sh NAME @@ -514,6 +514,31 @@ The .Fa data argument should be set to .Li sizeof(struct ptrace_siginfo) . +.It Dv PT_SET_SIGMASK +This request loads the traced process' signal mask from +.Dq Li "sigset_t" +(defined in +.In sys/sigtypes.h ) +pointed to by +.Fa addr . +The +.Fa data +argument contains the LWP ID of the thread whose registers are to +be written. +If zero is supplied, the first thread of the process is written. +.It Dv PT_GET_SIGMASK +This request is the converse of +.Dv PT_SET_SIGMASK ; +it reads the traced process' signal mask into +.Dq Li "sigset_t" +(defined in +.In sys/sigtypes.h ) +pointed to by +.Fa addr . +The +.Fa data +argument contains the LWP ID of the thread whose mask is to be read. +If zero is supplied, the first thread of the process is read. .El .Pp Additionally, the following requests exist but are diff --git a/sys/kern/sys_ptrace_common.c b/sys/kern/sys_ptrace_common.c index 64f61bf12019..1313a5ef5e99 100644 --- a/sys/kern/sys_ptrace_common.c +++ b/sys/kern/sys_ptrace_common.c @@ -1,4 +1,4 @@ -/* $NetBSD: sys_ptrace_common.c,v 1.13 2017/02/11 19:32:41 kamil Exp $ */ +/* $NetBSD: sys_ptrace_common.c,v 1.14 2017/02/12 06:09:52 kamil Exp $ */ /*- * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc. @@ -118,7 +118,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: sys_ptrace_common.c,v 1.13 2017/02/11 19:32:41 kamil Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sys_ptrace_common.c,v 1.14 2017/02/12 06:09:52 kamil Exp $"); #ifdef _KERNEL_OPT #include "opt_ptrace.h" @@ -212,6 +212,8 @@ ptrace_listener_cb(kauth_cred_t cred, kauth_action_t action, void *cookie, case PT_GET_PROCESS_STATE: case PT_SET_SIGINFO: case PT_GET_SIGINFO: + case PT_SET_SIGMASK: + case PT_GET_SIGMASK: #ifdef __HAVE_PTRACE_MACHDEP PTRACE_MACHDEP_REQUEST_CASES #endif @@ -406,6 +408,8 @@ do_ptrace(struct ptrace_methods *ptm, struct lwp *l, int req, pid_t pid, case PT_IO: case PT_SET_SIGINFO: case PT_GET_SIGINFO: + case PT_SET_SIGMASK: + case PT_GET_SIGMASK: #ifdef PT_GETREGS case PT_GETREGS: #endif @@ -1039,6 +1043,35 @@ do_ptrace(struct ptrace_methods *ptm, struct lwp *l, int req, pid_t pid, break; + case PT_SET_SIGMASK: + write = 1; + + case PT_GET_SIGMASK: + /* write = 0 done above. */ + + tmp = data; + if (tmp != 0 && t->p_nlwps > 1) { + lwp_delref(lt); + mutex_enter(t->p_lock); + lt = lwp_find(t, tmp); + if (lt == NULL) { + mutex_exit(t->p_lock); + error = ESRCH; + break; + } + lwp_addref(lt); + mutex_exit(t->p_lock); + } + + if (!process_validregs(lt)) + error = EINVAL; + else if (write == 1) + error = copyin(addr, <->l_sigmask, sizeof(sigset_t)); + else + error = copyout(<->l_sigmask, addr, sizeof(sigset_t)); + + break; + #ifdef PT_SETREGS case PT_SETREGS: write = 1; diff --git a/sys/sys/ptrace.h b/sys/sys/ptrace.h index 55ca4097e093..82d43532496f 100644 --- a/sys/sys/ptrace.h +++ b/sys/sys/ptrace.h @@ -1,4 +1,4 @@ -/* $NetBSD: ptrace.h,v 1.55 2017/01/16 21:35:59 kamil Exp $ */ +/* $NetBSD: ptrace.h,v 1.56 2017/02/12 06:09:52 kamil Exp $ */ /*- * Copyright (c) 1984, 1993 @@ -55,6 +55,8 @@ #define PT_GET_PROCESS_STATE 18 /* get process state, defined below */ #define PT_SET_SIGINFO 19 /* set signal state, defined below */ #define PT_GET_SIGINFO 20 /* get signal state, defined below */ +#define PT_SET_SIGMASK 21 /* set signal mask */ +#define PT_GET_SIGMASK 22 /* get signal mask */ #define PT_FIRSTMACH 32 /* for machine-specific requests */ #include /* machine-specific requests, if any */ @@ -80,7 +82,9 @@ /* 17 */ "PT_GET_EVENT_MASK", \ /* 18 */ "PT_GET_PROCESS_STATE", \ /* 19 */ "PT_SET_SIGINFO", \ -/* 20 */ "PT_GET_SIGINFO", +/* 20 */ "PT_GET_SIGINFO", \ +/* 20 */ "PT_GET_SIGMASK", \ +/* 20 */ "PT_GET_SIGMASK", /* PT_{G,S}EVENT_MASK */ typedef struct ptrace_event { diff --git a/tests/kernel/t_ptrace_wait.c b/tests/kernel/t_ptrace_wait.c index 9d08c0e9648d..f2a3b2a2ee88 100644 --- a/tests/kernel/t_ptrace_wait.c +++ b/tests/kernel/t_ptrace_wait.c @@ -1,4 +1,4 @@ -/* $NetBSD: t_ptrace_wait.c,v 1.69 2017/01/27 16:43:07 kamil Exp $ */ +/* $NetBSD: t_ptrace_wait.c,v 1.70 2017/02/12 06:09:52 kamil Exp $ */ /*- * Copyright (c) 2016 The NetBSD Foundation, Inc. @@ -27,7 +27,7 @@ */ #include -__RCSID("$NetBSD: t_ptrace_wait.c,v 1.69 2017/01/27 16:43:07 kamil Exp $"); +__RCSID("$NetBSD: t_ptrace_wait.c,v 1.70 2017/02/12 06:09:52 kamil Exp $"); #include #include @@ -6583,6 +6583,370 @@ ATF_TC_BODY(signal10, tc) TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0)); } +ATF_TC(getsigmask1); +ATF_TC_HEAD(getsigmask1, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Verify that plain PT_SET_SIGMASK can be called"); +} + +ATF_TC_BODY(getsigmask1, tc) +{ + const int exitval = 5; + const int sigval = SIGSTOP; + pid_t child, wpid; +#if defined(TWAIT_HAVE_STATUS) + int status; +#endif + sigset_t mask; + + printf("Before forking process PID=%d\n", getpid()); + ATF_REQUIRE((child = fork()) != -1); + if (child == 0) { + printf("Before calling PT_TRACE_ME from child %d\n", getpid()); + FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1); + + printf("Before raising %s from child\n", strsignal(sigval)); + FORKEE_ASSERT(raise(sigval) == 0); + + printf("Before exiting of the child process\n"); + _exit(exitval); + } + printf("Parent process PID=%d, child's PID=%d\n", getpid(), child); + + printf("Before calling %s() for the child\n", TWAIT_FNAME); + TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child); + + validate_status_stopped(status, sigval); + + printf("Before calling PT_GET_SIGMASK\n"); + ATF_REQUIRE(ptrace(PT_GET_SIGMASK, child, &mask, 0) != -1); + + printf("Before resuming the child process where it left off and " + "without signal to be sent\n"); + ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1); + + printf("Before calling %s() for the child\n", TWAIT_FNAME); + TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child); + + validate_status_exited(status, exitval); + + printf("Before calling %s() for the child\n", TWAIT_FNAME); + TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0)); +} + +ATF_TC(getsigmask2); +ATF_TC_HEAD(getsigmask2, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Verify that PT_SET_SIGMASK reports correct mask from tracee"); +} + +ATF_TC_BODY(getsigmask2, tc) +{ + const int exitval = 5; + const int sigval = SIGSTOP; + const int sigmasked = SIGTRAP; + pid_t child, wpid; +#if defined(TWAIT_HAVE_STATUS) + int status; +#endif + sigset_t mask; + sigset_t expected_mask; + ATF_REQUIRE(sigemptyset(&mask) == 0); + ATF_REQUIRE(sigemptyset(&expected_mask) == 0); + ATF_REQUIRE(sigaddset(&expected_mask, sigmasked) == 0); + + printf("Before forking process PID=%d\n", getpid()); + ATF_REQUIRE((child = fork()) != -1); + if (child == 0) { + printf("Before calling PT_TRACE_ME from child %d\n", getpid()); + FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1); + + sigaddset(&mask, sigmasked); + sigprocmask(SIG_BLOCK, &mask, NULL); + + printf("Before raising %s from child\n", strsignal(sigval)); + FORKEE_ASSERT(raise(sigval) == 0); + + printf("Before exiting of the child process\n"); + _exit(exitval); + } + printf("Parent process PID=%d, child's PID=%d\n", getpid(), child); + + printf("Before calling %s() for the child\n", TWAIT_FNAME); + TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child); + + validate_status_stopped(status, sigval); + + printf("Before calling PT_GET_SIGMASK\n"); + ATF_REQUIRE(ptrace(PT_GET_SIGMASK, child, &mask, 0) != -1); + + ATF_REQUIRE(memcmp(&mask, &expected_mask, sizeof(sigset_t)) == 0); + + printf("Before resuming the child process where it left off and " + "without signal to be sent\n"); + ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1); + + printf("Before calling %s() for the child\n", TWAIT_FNAME); + TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child); + + validate_status_exited(status, exitval); + + printf("Before calling %s() for the child\n", TWAIT_FNAME); + TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0)); +} + +ATF_TC(setsigmask1); +ATF_TC_HEAD(setsigmask1, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Verify that plain PT_SET_SIGMASK can be called with empty mask"); +} + +ATF_TC_BODY(setsigmask1, tc) +{ + const int exitval = 5; + const int sigval = SIGSTOP; + pid_t child, wpid; +#if defined(TWAIT_HAVE_STATUS) + int status; +#endif + sigset_t mask; + ATF_REQUIRE(sigemptyset(&mask) == 0); + + printf("Before forking process PID=%d\n", getpid()); + ATF_REQUIRE((child = fork()) != -1); + if (child == 0) { + printf("Before calling PT_TRACE_ME from child %d\n", getpid()); + FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1); + + printf("Before raising %s from child\n", strsignal(sigval)); + FORKEE_ASSERT(raise(sigval) == 0); + + printf("Before exiting of the child process\n"); + _exit(exitval); + } + printf("Parent process PID=%d, child's PID=%d\n", getpid(), child); + + printf("Before calling %s() for the child\n", TWAIT_FNAME); + TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child); + + validate_status_stopped(status, sigval); + + printf("Before calling PT_SET_SIGMASK for empty mask\n"); + ATF_REQUIRE(ptrace(PT_SET_SIGMASK, child, &mask, 0) != -1); + + printf("Before resuming the child process where it left off and " + "without signal to be sent\n"); + ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1); + + printf("Before calling %s() for the child\n", TWAIT_FNAME); + TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child); + + validate_status_exited(status, exitval); + + printf("Before calling %s() for the child\n", TWAIT_FNAME); + TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0)); +} + +ATF_TC(setsigmask2); +ATF_TC_HEAD(setsigmask2, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Verify that sigmask is preserved between PT_GET_SIGMASK and " + "PT_SET_SIGMASK"); +} + +ATF_TC_BODY(setsigmask2, tc) +{ + const int exitval = 5; + const int sigval = SIGSTOP; + pid_t child, wpid; +#if defined(TWAIT_HAVE_STATUS) + int status; +#endif + sigset_t new_mask; + sigset_t mask; + ATF_REQUIRE(sigemptyset(&new_mask) == 0); + ATF_REQUIRE(sigemptyset(&mask) == 0); + ATF_REQUIRE(sigaddset(&mask, SIGINT) == 0); + + printf("Before forking process PID=%d\n", getpid()); + ATF_REQUIRE((child = fork()) != -1); + if (child == 0) { + printf("Before calling PT_TRACE_ME from child %d\n", getpid()); + FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1); + + printf("Before raising %s from child\n", strsignal(sigval)); + FORKEE_ASSERT(raise(sigval) == 0); + + printf("Before exiting of the child process\n"); + _exit(exitval); + } + printf("Parent process PID=%d, child's PID=%d\n", getpid(), child); + + printf("Before calling %s() for the child\n", TWAIT_FNAME); + TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child); + + validate_status_stopped(status, sigval); + + printf("Before calling PT_SET_SIGMASK for new mask with SIGINT\n"); + ATF_REQUIRE(ptrace(PT_SET_SIGMASK, child, &mask, 0) != -1); + + printf("Before calling PT_GET_SIGMASK to store it in new_mask\n"); + ATF_REQUIRE(ptrace(PT_GET_SIGMASK, child, &new_mask, 0) != -1); + + ATF_REQUIRE(memcmp(&mask, &new_mask, sizeof(sigset_t)) == 0); + + printf("Before resuming the child process where it left off and " + "without signal to be sent\n"); + ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1); + + printf("Before calling %s() for the child\n", TWAIT_FNAME); + TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child); + + validate_status_exited(status, exitval); + + printf("Before calling %s() for the child\n", TWAIT_FNAME); + TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0)); +} + +ATF_TC(setsigmask3); +ATF_TC_HEAD(setsigmask3, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Verify that sigmask is preserved between PT_GET_SIGMASK, process " + "resumed and PT_SET_SIGMASK"); +} + +ATF_TC_BODY(setsigmask3, tc) +{ + const int exitval = 5; + const int sigval = SIGSTOP; + pid_t child, wpid; +#if defined(TWAIT_HAVE_STATUS) + int status; +#endif + sigset_t new_mask; + sigset_t mask; + ATF_REQUIRE(sigemptyset(&new_mask) == 0); + ATF_REQUIRE(sigemptyset(&mask) == 0); + ATF_REQUIRE(sigaddset(&mask, SIGINT) == 0); + + printf("Before forking process PID=%d\n", getpid()); + ATF_REQUIRE((child = fork()) != -1); + if (child == 0) { + printf("Before calling PT_TRACE_ME from child %d\n", getpid()); + FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1); + + printf("Before raising %s from child\n", strsignal(sigval)); + FORKEE_ASSERT(raise(sigval) == 0); + + printf("Before raising %s from child\n", strsignal(sigval)); + FORKEE_ASSERT(raise(sigval) == 0); + + printf("Before exiting of the child process\n"); + _exit(exitval); + } + printf("Parent process PID=%d, child's PID=%d\n", getpid(), child); + + printf("Before calling %s() for the child\n", TWAIT_FNAME); + TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child); + + validate_status_stopped(status, sigval); + + printf("Before calling PT_SET_SIGMASK for new mask with SIGINT\n"); + ATF_REQUIRE(ptrace(PT_SET_SIGMASK, child, &mask, 0) != -1); + + printf("Before resuming the child process where it left off and " + "without signal to be sent\n"); + ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1); + + printf("Before calling %s() for the child\n", TWAIT_FNAME); + TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child); + + validate_status_stopped(status, sigval); + + printf("Before calling PT_GET_SIGMASK to store it in new_mask\n"); + ATF_REQUIRE(ptrace(PT_GET_SIGMASK, child, &new_mask, 0) != -1); + + ATF_REQUIRE(memcmp(&mask, &new_mask, sizeof(sigset_t)) == 0); + + printf("Before resuming the child process where it left off and " + "without signal to be sent\n"); + ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1); + + printf("Before calling %s() for the child\n", TWAIT_FNAME); + TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child); + + validate_status_exited(status, exitval); + + printf("Before calling %s() for the child\n", TWAIT_FNAME); + TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0)); +} + +ATF_TC(setsigmask4); +ATF_TC_HEAD(setsigmask4, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Verify that new sigmask is visible in tracee"); +} + +ATF_TC_BODY(setsigmask4, tc) +{ + const int exitval = 5; + const int sigval = SIGSTOP; + pid_t child, wpid; +#if defined(TWAIT_HAVE_STATUS) + int status; +#endif + sigset_t mask; + sigset_t expected_mask; + ATF_REQUIRE(sigemptyset(&mask) == 0); + ATF_REQUIRE(sigemptyset(&expected_mask) == 0); + ATF_REQUIRE(sigaddset(&expected_mask, SIGINT) == 0); + + printf("Before forking process PID=%d\n", getpid()); + ATF_REQUIRE((child = fork()) != -1); + if (child == 0) { + printf("Before calling PT_TRACE_ME from child %d\n", getpid()); + FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1); + + printf("Before raising %s from child\n", strsignal(sigval)); + FORKEE_ASSERT(raise(sigval) == 0); + + sigprocmask(0, NULL, &mask); + + FORKEE_ASSERT + (memcmp(&mask, &expected_mask, sizeof(sigset_t)) == 0); + + printf("Before exiting of the child process\n"); + _exit(exitval); + } + printf("Parent process PID=%d, child's PID=%d\n", getpid(), child); + + printf("Before calling %s() for the child\n", TWAIT_FNAME); + TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child); + + validate_status_stopped(status, sigval); + + printf("Before calling PT_SET_SIGMASK for new mask with SIGINT\n"); + ATF_REQUIRE(ptrace(PT_SET_SIGMASK, child, &expected_mask, 0) != -1); + + printf("Before resuming the child process where it left off and " + "without signal to be sent\n"); + ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1); + + printf("Before calling %s() for the child\n", TWAIT_FNAME); + TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child); + + validate_status_exited(status, exitval); + + printf("Before calling %s() for the child\n", TWAIT_FNAME); + TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0)); +} + ATF_TP_ADD_TCS(tp) { setvbuf(stdout, NULL, _IONBF, 0); @@ -6696,5 +7060,13 @@ ATF_TP_ADD_TCS(tp) ATF_TP_ADD_TC(tp, signal9); ATF_TP_ADD_TC(tp, signal10); + ATF_TP_ADD_TC(tp, getsigmask1); + ATF_TP_ADD_TC(tp, getsigmask2); + + ATF_TP_ADD_TC(tp, setsigmask1); + ATF_TP_ADD_TC(tp, setsigmask2); + ATF_TP_ADD_TC(tp, setsigmask3); + ATF_TP_ADD_TC(tp, setsigmask4); + return atf_no_error(); }