Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 18 Apr 2018 21:31:13 +0000 (UTC)
From:      Konstantin Belousov <kib@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r332740 - in head: lib/libc/sys sys/compat/freebsd32 sys/kern sys/sys tests/sys/kern
Message-ID:  <201804182131.w3ILVDtB018055@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: kib
Date: Wed Apr 18 21:31:13 2018
New Revision: 332740
URL: https://svnweb.freebsd.org/changeset/base/332740

Log:
  Add PROC_PDEATHSIG_SET to procctl interface.
  
  Allow processes to request the delivery of a signal upon death of
  their parent process.  Supposed consumer of the feature is PostgreSQL.
  
  Submitted by:	Thomas Munro
  Reviewed by:	jilles, mjg
  MFC after:	2 weeks
  Differential revision:	https://reviews.freebsd.org/D15106

Added:
  head/tests/sys/kern/pdeathsig.c   (contents, props changed)
  head/tests/sys/kern/pdeathsig_helper.c   (contents, props changed)
Modified:
  head/lib/libc/sys/procctl.2
  head/sys/compat/freebsd32/freebsd32_misc.c
  head/sys/kern/kern_exec.c
  head/sys/kern/kern_exit.c
  head/sys/kern/kern_procctl.c
  head/sys/kern/kern_thread.c
  head/sys/sys/proc.h
  head/sys/sys/procctl.h
  head/tests/sys/kern/Makefile

Modified: head/lib/libc/sys/procctl.2
==============================================================================
--- head/lib/libc/sys/procctl.2	Wed Apr 18 20:31:42 2018	(r332739)
+++ head/lib/libc/sys/procctl.2	Wed Apr 18 21:31:13 2018	(r332740)
@@ -29,7 +29,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd November 21, 2017
+.Dd April 18, 2018
 .Dt PROCCTL 2
 .Os
 .Sh NAME
@@ -391,6 +391,37 @@ otherwise.
 See the note about sysctl
 .Dv kern.trap_enotcap
 above, which gives independent global control of signal delivery.
+.It Dv PROC_PDEATHSIG_SET
+Request the delivery of a signal when the parent of the calling
+process exits.
+.Fa idtype
+must be
+.Dv P_PID
+and
+.Fa id
+must be the either caller's pid or zero, with no difference in effect.
+The value is cleared for child processes
+and when executing set-user-ID or set-group-ID binaries.
+.Fa arg
+must point to a value of type
+.Vt int
+indicating the signal
+that should be delivered to the caller.
+Use zero to cancel a previously requested signal delivery.
+.It Dv PROC_PDEATHSIG_GET
+Query the current signal number that will be delivered when the parent
+of the calling process exits.
+.Fa idtype
+must be
+.Dv P_PID
+and
+.Fa id
+must be the either caller's pid or zero, with no difference in effect.
+.Fa arg
+must point to a memory location that can hold a value of type
+.Vt int .
+If signal delivery has not been requested, it will contain zero
+on return.
 .El
 .Sh NOTES
 Disabling tracing on a process should not be considered a security
@@ -487,6 +518,15 @@ parameter for the
 or
 .Dv PROC_TRAPCAP_CTL
 request is invalid.
+.It Bq Er EINVAL
+The
+.Dv PROC_PDEATHSIG_SET
+or
+.Dv PROC_PDEATHSIG_GET
+request referenced an unsupported
+.Fa id ,
+.Fa idtype
+or invalid signal number.
 .El
 .Sh SEE ALSO
 .Xr dtrace 1 ,
@@ -506,3 +546,8 @@ function appeared in
 The reaper facility is based on a similar feature of Linux and
 DragonflyBSD, and first appeared in
 .Fx 10.2 .
+The
+.Dv PROC_PDEATHSIG_SET
+facility is based on the prctl(PR_SET_PDEATHSIG, ...) feature of Linux,
+and first appeared in
+.Fx 12.0 .

Modified: head/sys/compat/freebsd32/freebsd32_misc.c
==============================================================================
--- head/sys/compat/freebsd32/freebsd32_misc.c	Wed Apr 18 20:31:42 2018	(r332739)
+++ head/sys/compat/freebsd32/freebsd32_misc.c	Wed Apr 18 21:31:13 2018	(r332740)
@@ -3352,7 +3352,7 @@ freebsd32_procctl(struct thread *td, struct freebsd32_
 	union {
 		struct procctl_reaper_pids32 rp;
 	} x32;
-	int error, error1, flags;
+	int error, error1, flags, signum;
 
 	switch (uap->com) {
 	case PROC_SPROTECT:
@@ -3390,6 +3390,15 @@ freebsd32_procctl(struct thread *td, struct freebsd32_
 	case PROC_TRAPCAP_STATUS:
 		data = &flags;
 		break;
+	case PROC_PDEATHSIG_SET:
+		error = copyin(uap->data, &signum, sizeof(signum));
+		if (error != 0)
+			return (error);
+		data = &signum;
+		break;
+	case PROC_PDEATHSIG_GET:
+		data = &signum;
+		break;
 	default:
 		return (EINVAL);
 	}
@@ -3409,6 +3418,10 @@ freebsd32_procctl(struct thread *td, struct freebsd32_
 	case PROC_TRAPCAP_STATUS:
 		if (error == 0)
 			error = copyout(&flags, uap->data, sizeof(flags));
+		break;
+	case PROC_PDEATHSIG_GET:
+		if (error == 0)
+			error = copyout(&signum, uap->data, sizeof(signum));
 		break;
 	}
 	return (error);

Modified: head/sys/kern/kern_exec.c
==============================================================================
--- head/sys/kern/kern_exec.c	Wed Apr 18 20:31:42 2018	(r332739)
+++ head/sys/kern/kern_exec.c	Wed Apr 18 21:31:13 2018	(r332740)
@@ -522,6 +522,10 @@ interpret:
 	credential_changing |= will_transition;
 #endif
 
+	/* Don't inherit PROC_PDEATHSIG_SET value if setuid/setgid. */
+	if (credential_changing)
+		imgp->proc->p_pdeathsig = 0;
+
 	if (credential_changing &&
 #ifdef CAPABILITY_MODE
 	    ((oldcred->cr_flags & CRED_FLAG_CAPMODE) == 0) &&

Modified: head/sys/kern/kern_exit.c
==============================================================================
--- head/sys/kern/kern_exit.c	Wed Apr 18 20:31:42 2018	(r332739)
+++ head/sys/kern/kern_exit.c	Wed Apr 18 21:31:13 2018	(r332740)
@@ -480,6 +480,12 @@ exit1(struct thread *td, int rval, int signo)
 				PROC_LOCK(q->p_reaper);
 				pksignal(q->p_reaper, SIGCHLD, ksi1);
 				PROC_UNLOCK(q->p_reaper);
+			} else if (q->p_pdeathsig > 0) {
+				/*
+				 * The child asked to received a signal
+				 * when we exit.
+				 */
+				kern_psignal(q, q->p_pdeathsig);
 			}
 		} else {
 			/*
@@ -520,6 +526,13 @@ exit1(struct thread *td, int rval, int signo)
 	 */
 	while ((q = LIST_FIRST(&p->p_orphans)) != NULL) {
 		PROC_LOCK(q);
+		/*
+		 * If we are the real parent of this process
+		 * but it has been reparented to a debugger, then
+		 * check if it asked for a signal when we exit.
+		 */
+		if (q->p_pdeathsig > 0)
+			kern_psignal(q, q->p_pdeathsig);
 		CTR2(KTR_PTRACE, "exit: pid %d, clearing orphan %d", p->p_pid,
 		    q->p_pid);
 		clear_orphan(q);

Modified: head/sys/kern/kern_procctl.c
==============================================================================
--- head/sys/kern/kern_procctl.c	Wed Apr 18 20:31:42 2018	(r332739)
+++ head/sys/kern/kern_procctl.c	Wed Apr 18 21:31:13 2018	(r332740)
@@ -431,7 +431,7 @@ sys_procctl(struct thread *td, struct procctl_args *ua
 		struct procctl_reaper_pids rp;
 		struct procctl_reaper_kill rk;
 	} x;
-	int error, error1, flags;
+	int error, error1, flags, signum;
 
 	switch (uap->com) {
 	case PROC_SPROTECT:
@@ -467,6 +467,15 @@ sys_procctl(struct thread *td, struct procctl_args *ua
 	case PROC_TRAPCAP_STATUS:
 		data = &flags;
 		break;
+	case PROC_PDEATHSIG_SET:
+		error = copyin(uap->data, &signum, sizeof(signum));
+		if (error != 0)
+			return (error);
+		data = &signum;
+		break;
+	case PROC_PDEATHSIG_GET:
+		data = &signum;
+		break;
 	default:
 		return (EINVAL);
 	}
@@ -486,6 +495,10 @@ sys_procctl(struct thread *td, struct procctl_args *ua
 		if (error == 0)
 			error = copyout(&flags, uap->data, sizeof(flags));
 		break;
+	case PROC_PDEATHSIG_GET:
+		if (error == 0)
+			error = copyout(&signum, uap->data, sizeof(signum));
+		break;
 	}
 	return (error);
 }
@@ -527,6 +540,7 @@ kern_procctl(struct thread *td, idtype_t idtype, id_t 
 	struct pgrp *pg;
 	struct proc *p;
 	int error, first_error, ok;
+	int signum;
 	bool tree_locked;
 
 	switch (com) {
@@ -537,8 +551,31 @@ kern_procctl(struct thread *td, idtype_t idtype, id_t 
 	case PROC_REAP_KILL:
 	case PROC_TRACE_STATUS:
 	case PROC_TRAPCAP_STATUS:
+	case PROC_PDEATHSIG_SET:
+	case PROC_PDEATHSIG_GET:
 		if (idtype != P_PID)
 			return (EINVAL);
+	}
+
+	switch (com) {
+	case PROC_PDEATHSIG_SET:
+		signum = *(int *)data;
+		p = td->td_proc;
+		if ((id != 0 && id != p->p_pid) ||
+		    (signum != 0 && !_SIG_VALID(signum)))
+			return (EINVAL);
+		PROC_LOCK(p);
+		p->p_pdeathsig = signum;
+		PROC_UNLOCK(p);
+		return (0);
+	case PROC_PDEATHSIG_GET:
+		p = td->td_proc;
+		if (id != 0 && id != p->p_pid)
+			return (EINVAL);
+		PROC_LOCK(p);
+		*(int *)data = p->p_pdeathsig;
+		PROC_UNLOCK(p);
+		return (0);
 	}
 
 	switch (com) {

Modified: head/sys/kern/kern_thread.c
==============================================================================
--- head/sys/kern/kern_thread.c	Wed Apr 18 20:31:42 2018	(r332739)
+++ head/sys/kern/kern_thread.c	Wed Apr 18 21:31:13 2018	(r332740)
@@ -91,7 +91,7 @@ _Static_assert(offsetof(struct proc, p_pid) == 0xbc,
     "struct proc KBI p_pid");
 _Static_assert(offsetof(struct proc, p_filemon) == 0x3d0,
     "struct proc KBI p_filemon");
-_Static_assert(offsetof(struct proc, p_comm) == 0x3e0,
+_Static_assert(offsetof(struct proc, p_comm) == 0x3e4,
     "struct proc KBI p_comm");
 _Static_assert(offsetof(struct proc, p_emuldata) == 0x4b8,
     "struct proc KBI p_emuldata");
@@ -111,9 +111,9 @@ _Static_assert(offsetof(struct proc, p_pid) == 0x74,
     "struct proc KBI p_pid");
 _Static_assert(offsetof(struct proc, p_filemon) == 0x27c,
     "struct proc KBI p_filemon");
-_Static_assert(offsetof(struct proc, p_comm) == 0x288,
+_Static_assert(offsetof(struct proc, p_comm) == 0x28c,
     "struct proc KBI p_comm");
-_Static_assert(offsetof(struct proc, p_emuldata) == 0x314,
+_Static_assert(offsetof(struct proc, p_emuldata) == 0x318,
     "struct proc KBI p_emuldata");
 #endif
 

Modified: head/sys/sys/proc.h
==============================================================================
--- head/sys/sys/proc.h	Wed Apr 18 20:31:42 2018	(r332739)
+++ head/sys/sys/proc.h	Wed Apr 18 21:31:13 2018	(r332740)
@@ -624,6 +624,7 @@ struct proc {
 	u_int		p_treeflag;	/* (e) P_TREE flags */
 	int		p_pendingexits; /* (c) Count of pending thread exits. */
 	struct filemon	*p_filemon;	/* (c) filemon-specific data. */
+	int		p_pdeathsig;	/* (c) Signal from parent on exit. */
 /* End area that is zeroed on creation. */
 #define	p_endzero	p_magic
 

Modified: head/sys/sys/procctl.h
==============================================================================
--- head/sys/sys/procctl.h	Wed Apr 18 20:31:42 2018	(r332739)
+++ head/sys/sys/procctl.h	Wed Apr 18 21:31:13 2018	(r332740)
@@ -51,6 +51,8 @@
 #define	PROC_TRACE_STATUS	8	/* query tracing status */
 #define	PROC_TRAPCAP_CTL	9	/* trap capability errors */
 #define	PROC_TRAPCAP_STATUS	10	/* query trap capability status */
+#define	PROC_PDEATHSIG_SET	11	/* set parent death signal */
+#define	PROC_PDEATHSIG_GET	12	/* get parent death signal */
 
 /* Operations for PROC_SPROTECT (passed in integer arg). */
 #define	PPROT_OP(x)	((x) & 0xf)

Modified: head/tests/sys/kern/Makefile
==============================================================================
--- head/tests/sys/kern/Makefile	Wed Apr 18 20:31:42 2018	(r332739)
+++ head/tests/sys/kern/Makefile	Wed Apr 18 21:31:13 2018	(r332740)
@@ -16,11 +16,13 @@ ATF_TESTS_C+=	unix_seqpacket_test
 ATF_TESTS_C+=	unix_passfd_test
 TEST_METADATA.unix_seqpacket_test+=	timeout="15"
 ATF_TESTS_C+=	waitpid_nohang
+ATF_TESTS_C+=	pdeathsig
 
 ATF_TESTS_SH+=	coredump_phnum_test
 
 BINDIR=		${TESTSDIR}
 PROGS+=		coredump_phnum_helper
+PROGS+=		pdeathsig_helper
 
 CFLAGS.sys_getrandom+=			-I${SRCTOP}/sys/contrib/zstd/lib
 LIBADD.sys_getrandom+=			zstd

Added: head/tests/sys/kern/pdeathsig.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/tests/sys/kern/pdeathsig.c	Wed Apr 18 21:31:13 2018	(r332740)
@@ -0,0 +1,343 @@
+/*-
+ * Copyright (c) 2018 Thomas Munro
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <assert.h>
+#include <atf-c.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/procctl.h>
+#include <sys/ptrace.h>
+#include <sys/signal.h>
+#include <sys/types.h>
+
+static void
+dummy_signal_handler(int signum)
+{
+}
+
+ATF_TC_WITHOUT_HEAD(arg_validation);
+ATF_TC_BODY(arg_validation, tc)
+{
+	int signum;
+	int rc;
+
+	/* bad signal */
+	signum = 8888;
+	rc = procctl(P_PID, 0, PROC_PDEATHSIG_SET, &signum);
+	ATF_CHECK_EQ(-1, rc);
+	ATF_CHECK_EQ(EINVAL, errno);
+
+	/* bad id type */
+	signum = SIGINFO;
+	rc = procctl(8888, 0, PROC_PDEATHSIG_SET, &signum);
+	ATF_CHECK_EQ(-1, rc);
+	ATF_CHECK_EQ(EINVAL, errno);
+
+	/* bad id (pid that doesn't match mine or zero) */
+	signum = SIGINFO;
+	rc = procctl(P_PID, (((getpid() + 1) % 10) + 100),
+		     PROC_PDEATHSIG_SET, &signum);
+	ATF_CHECK_EQ(-1, rc);
+	ATF_CHECK_EQ(EINVAL, errno);
+
+	/* null pointer */
+	signum = SIGINFO;
+	rc = procctl(P_PID, 0, PROC_PDEATHSIG_SET, NULL);
+	ATF_CHECK_EQ(-1, rc);
+	ATF_CHECK_EQ(EFAULT, errno);
+
+	/* good (pid == 0) */
+	signum = SIGINFO;
+	rc = procctl(P_PID, 0, PROC_PDEATHSIG_SET, &signum);
+	ATF_CHECK_EQ(0, rc);
+
+	/* good (pid == my pid) */
+	signum = SIGINFO;
+	rc = procctl(P_PID, getpid(), PROC_PDEATHSIG_SET, &signum);
+	ATF_CHECK_EQ(0, rc);
+
+	/* check that we can read the signal number back */
+	signum = 0xdeadbeef;
+	rc = procctl(P_PID, 0, PROC_PDEATHSIG_GET, &signum);
+	ATF_CHECK_EQ(0, rc);
+	ATF_CHECK_EQ(SIGINFO, signum);
+}
+
+ATF_TC_WITHOUT_HEAD(fork_no_inherit);
+ATF_TC_BODY(fork_no_inherit, tc)
+{
+	int status;
+	int signum;
+	int rc;
+
+	/* request a signal on parent death in the parent */
+	signum = SIGINFO;
+	rc = procctl(P_PID, 0, PROC_PDEATHSIG_SET, &signum);
+
+	rc = fork();
+	ATF_REQUIRE(rc != -1);
+	if (rc == 0) {
+		/* check that we didn't inherit the setting */
+		signum = 0xdeadbeef;
+		rc = procctl(P_PID, 0, PROC_PDEATHSIG_GET, &signum);
+		assert(rc == 0);
+		assert(signum == 0);
+		_exit(0);
+	}
+
+	/* wait for the child to exit successfully */
+	waitpid(rc, &status, 0);
+	ATF_CHECK_EQ(0, status);
+}
+
+ATF_TC_WITHOUT_HEAD(exec_inherit);
+ATF_TC_BODY(exec_inherit, tc)
+{
+	int status;
+	int rc;
+
+	rc = fork();
+	ATF_REQUIRE(rc != -1);
+	if (rc == 0) {
+		char exec_path[1024];
+		int signum;
+
+		/* compute the path of the helper executable */
+		snprintf(exec_path, sizeof(exec_path), "%s/pdeathsig_helper",
+			 atf_tc_get_config_var(tc, "srcdir"));
+
+		/* request a signal on parent death and register a handler */
+		signum = SIGINFO;
+		rc = procctl(P_PID, 0, PROC_PDEATHSIG_SET, &signum);
+		assert(rc == 0);
+
+		/* execute helper program: it asserts that it has the setting */
+		rc = execl(exec_path, exec_path, NULL);
+		assert(rc == 0);
+		_exit(0);
+	}
+
+	/* wait for the child to exit successfully */
+	waitpid(rc, &status, 0);
+	ATF_CHECK_EQ(0, status);
+}
+
+ATF_TC_WITHOUT_HEAD(signal_delivered);
+ATF_TC_BODY(signal_delivered, tc)
+{
+	sigset_t sigset;
+	int signum;
+	int rc;
+	int pipe_ca[2];
+	int pipe_cb[2];
+	char buffer;
+
+	rc = pipe(pipe_ca);
+	ATF_REQUIRE(rc == 0);
+	rc = pipe(pipe_cb);
+	ATF_REQUIRE(rc == 0);
+
+	rc = fork();
+	ATF_REQUIRE(rc != -1);
+	if (rc == 0) {
+		rc = fork();
+		assert(rc >= 0);
+		if (rc == 0) {
+			/* process C */
+			signum = SIGINFO;
+
+			/* block signals so we can handle them synchronously */
+			rc = sigfillset(&sigset);
+			assert(rc == 0);
+			rc = sigprocmask(SIG_SETMASK, &sigset, NULL);
+			assert(rc == 0);
+
+			/* register a dummy handler or the kernel will not queue it */
+			signal(signum, dummy_signal_handler);
+
+			/* request a signal on death of our parent B */
+			rc = procctl(P_PID, 0, PROC_PDEATHSIG_SET, &signum);
+			assert(rc == 0);
+
+			/* tell B that we're ready for it to exit now */
+			rc = write(pipe_cb[1], ".", 1);
+			assert(rc == 1);
+
+			/* wait for B to die and signal us... */
+			signum = 0xdeadbeef;
+			rc = sigwait(&sigset, &signum);
+			assert(rc == 0);
+			assert(signum == SIGINFO);
+
+			/* tell A the test passed */
+			rc = write(pipe_ca[1], ".", 1);
+			assert(rc == 1);
+			_exit(0);
+		}
+
+		/* process B */
+
+		/* wait for C to tell us it is ready for us to exit */
+		rc = read(pipe_cb[0], &buffer, 1);
+		assert(rc == 1);
+
+		/* now we exit so that C gets a signal */
+		_exit(0);
+	}
+	/* process A */
+
+	/* wait for C to tell us the test passed */
+	rc = read(pipe_ca[0], &buffer, 1);
+	ATF_CHECK_EQ(1, rc);
+}
+
+ATF_TC_WITHOUT_HEAD(signal_delivered_ptrace);
+ATF_TC_BODY(signal_delivered_ptrace, tc)
+{
+	sigset_t sigset;
+	int signum;
+	int rc;
+	int pipe_ca[2];
+	int pipe_db[2];
+	int pipe_cd[2];
+	char buffer;
+	int status;
+
+	rc = pipe(pipe_ca);
+	ATF_REQUIRE(rc == 0);
+	rc = pipe(pipe_db);
+	ATF_REQUIRE(rc == 0);
+	rc = pipe(pipe_cd);
+	ATF_REQUIRE(rc == 0);
+
+	rc = fork();
+	ATF_REQUIRE(rc != -1);
+	if (rc == 0) {
+		pid_t c_pid;
+
+		/* process B */
+
+		rc = fork();
+		assert(rc >= 0);
+		if (rc == 0) {
+			/* process C */
+			signum = SIGINFO;
+
+			/* block signals so we can handle them synchronously */
+			rc = sigfillset(&sigset);
+			assert(rc == 0);
+			rc = sigprocmask(SIG_SETMASK, &sigset, NULL);
+			assert(rc == 0);
+
+			/* register a dummy handler or the kernel will not queue it */
+			signal(signum, dummy_signal_handler);
+
+			/* request a signal on parent death and register a handler */
+			rc = procctl(P_PID, 0, PROC_PDEATHSIG_SET, &signum);
+			assert(rc == 0);
+
+			/* tell D we are ready for it to attach */
+			rc = write(pipe_cd[1], ".", 1);
+			assert(rc == 1);
+
+			/* wait for B to die and signal us... */
+			signum = 0xdeadbeef;
+			rc = sigwait(&sigset, &signum);
+			assert(rc == 0);
+			assert(signum == SIGINFO);
+
+			/* tell A the test passed */
+			rc = write(pipe_ca[1], ".", 1);
+			assert(rc == 1);
+			_exit(0);
+		}
+		c_pid = rc;
+
+
+		/* fork another process to ptrace C */
+		rc = fork();
+		assert(rc >= 0);
+		if (rc == 0) {
+
+			/* process D */
+			rc = ptrace(PT_ATTACH, c_pid, 0, 0);
+			assert(rc == 0);
+
+			waitpid(c_pid, &status, 0);
+			assert(WIFSTOPPED(status));
+			assert(WSTOPSIG(status) == SIGSTOP);
+
+			rc = ptrace(PT_CONTINUE, c_pid, (caddr_t) 1, 0);
+			assert(rc == 0);
+
+			/* tell B that we're ready for it to exit now */
+			rc = write(pipe_db[1], ".", 1);
+			assert(rc == 1);
+
+			waitpid(c_pid, &status, 0);
+			assert(WIFSTOPPED(status));
+			assert(WSTOPSIG(status) == SIGINFO);
+
+			rc = ptrace(PT_CONTINUE, c_pid, (caddr_t) 1,
+				    WSTOPSIG(status));
+			assert(rc == 0);
+
+			ptrace(PT_DETACH, c_pid, 0, 0);
+
+			_exit(0);
+		}
+
+		/* wait for D to tell us it is ready for us to exit */
+		rc = read(pipe_db[0], &buffer, 1);
+		assert(rc == 1);
+
+		/* now we exit so that C gets a signal */
+		_exit(0);
+	}
+
+	/* process A */
+
+	/* wait for C to tell us the test passed */
+	rc = read(pipe_ca[0], &buffer, 1);
+	ATF_CHECK_EQ(1, rc);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+	ATF_TP_ADD_TC(tp, arg_validation);
+	ATF_TP_ADD_TC(tp, fork_no_inherit);
+	ATF_TP_ADD_TC(tp, exec_inherit);
+	ATF_TP_ADD_TC(tp, signal_delivered);
+	ATF_TP_ADD_TC(tp, signal_delivered_ptrace);
+	return (atf_no_error());
+}

Added: head/tests/sys/kern/pdeathsig_helper.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/tests/sys/kern/pdeathsig_helper.c	Wed Apr 18 21:31:13 2018	(r332740)
@@ -0,0 +1,50 @@
+/*-
+ * Copyright (c) 2018 Thomas Munro
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <assert.h>
+#include <signal.h>
+#include <sys/procctl.h>
+
+int main(int argc, char **argv)
+{
+        int signum;
+        int rc;
+
+	/*
+	 * This program is executed by the pdeathsig test
+	 * to check if the PROC_PDEATHSIG_SET setting was
+	 * inherited.
+	 */
+        signum = 0xdeadbeef;
+        rc = procctl(P_PID, 0, PROC_PDEATHSIG_GET, &signum);
+        assert(rc == 0);
+        assert(signum == SIGINFO);
+
+        return 0;
+}



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201804182131.w3ILVDtB018055>