Introduce new interface in ptrace(2) - PT_GET_SIGMASK and PT_SET_SIGMASK
Add new interface to add ability to get/set signal mask of a tracee. It has been inspired by Linux PTRACE_GETSIGMASK and PTRACE_SETSIGMASK, but adapted for NetBSD API. This interface is used for checkpointing software to set/restore context of a process including signal mask like criu or just to track this property in reverse-execution software like Record and Replay Framework (rr). Add new ATF tests for this interface ==================================== getsigmask1: Verify that plain PT_SET_SIGMASK can be called getsigmask2: Verify that PT_SET_SIGMASK reports correct mask from tracee setsigmask1: Verify that plain PT_SET_SIGMASK can be called with empty mask setsigmask2: Verify that sigmask is preserved between PT_GET_SIGMASK and PT_SET_SIGMASK setsigmask3: Verify that sigmask is preserved between PT_GET_SIGMASK, process resumed and PT_SET_SIGMASK setsigmask4: Verify that new sigmask is visible in tracee Kernel ABI bump delayed as there are more interfaces to come in ptrace(2). Sponsored by <The NetBSD Foundation>
This commit is contained in:
parent
ac46406cfc
commit
61aff29627
@ -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
|
||||
|
@ -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 <sys/cdefs.h>
|
||||
__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;
|
||||
|
@ -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/ptrace.h> /* 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 {
|
||||
|
@ -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 <sys/cdefs.h>
|
||||
__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 <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
@ -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();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user