diff options
-rw-r--r-- | lib/libc/sys/procctl.2 | 47 | ||||
-rw-r--r-- | sys/compat/freebsd32/freebsd32_misc.c | 15 | ||||
-rw-r--r-- | sys/kern/kern_exec.c | 4 | ||||
-rw-r--r-- | sys/kern/kern_exit.c | 13 | ||||
-rw-r--r-- | sys/kern/kern_fork.c | 1 | ||||
-rw-r--r-- | sys/kern/kern_procctl.c | 39 | ||||
-rw-r--r-- | sys/sys/proc.h | 1 | ||||
-rw-r--r-- | sys/sys/procctl.h | 2 | ||||
-rw-r--r-- | tests/sys/kern/Makefile | 3 | ||||
-rw-r--r-- | tests/sys/kern/pdeathsig.c | 336 | ||||
-rw-r--r-- | tests/sys/kern/pdeathsig_helper.c | 50 |
11 files changed, 508 insertions, 3 deletions
diff --git a/lib/libc/sys/procctl.2 b/lib/libc/sys/procctl.2 index 9d90f56..4b1d2ba 100644 --- a/lib/libc/sys/procctl.2 +++ b/lib/libc/sys/procctl.2 @@ -29,7 +29,7 @@ .\" .\" $FreeBSD$ .\" -.Dd November 21, 2017 +.Dd April 20, 2018 .Dt PROCCTL 2 .Os .Sh NAME @@ -391,6 +391,37 @@ otherwise. See the note about sysctl .Dv kern.trap_enocap above, which gives independent global control of signal delivery. +.It Dv PROC_PDEATHSIG_CTL +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_STATUS +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_CTL +or +.Dv PROC_PDEATHSIG_STATUS +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_CTL +facility is based on the prctl(PR_SET_PDEATHSIG, ...) feature of Linux, +and first appeared in +.Fx 12.0 . diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c index ad8d07c..ffb50d5 100644 --- a/sys/compat/freebsd32/freebsd32_misc.c +++ b/sys/compat/freebsd32/freebsd32_misc.c @@ -3057,7 +3057,7 @@ freebsd32_procctl(struct thread *td, struct freebsd32_procctl_args *uap) union { struct procctl_reaper_pids32 rp; } x32; - int error, error1, flags; + int error, error1, flags, signum; switch (uap->com) { case PROC_SPROTECT: @@ -3095,6 +3095,15 @@ freebsd32_procctl(struct thread *td, struct freebsd32_procctl_args *uap) case PROC_TRAPCAP_STATUS: data = &flags; break; + case PROC_PDEATHSIG_CTL: + error = copyin(uap->data, &signum, sizeof(signum)); + if (error != 0) + return (error); + data = &signum; + break; + case PROC_PDEATHSIG_STATUS: + data = &signum; + break; default: return (EINVAL); } @@ -3115,6 +3124,10 @@ freebsd32_procctl(struct thread *td, struct freebsd32_procctl_args *uap) if (error == 0) error = copyout(&flags, uap->data, sizeof(flags)); break; + case PROC_PDEATHSIG_STATUS: + if (error == 0) + error = copyout(&signum, uap->data, sizeof(signum)); + break; } return (error); } diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c index 400b7ee..518af5c 100644 --- a/sys/kern/kern_exec.c +++ b/sys/kern/kern_exec.c @@ -520,6 +520,10 @@ interpret: credential_changing |= will_transition; #endif + /* Don't inherit PROC_PDEATHSIG_CTL 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) && diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c index 8c496a0..546d0de 100644 --- a/sys/kern/kern_exit.c +++ b/sys/kern/kern_exit.c @@ -479,6 +479,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 { /* @@ -519,6 +525,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); diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c index 301dbfb..62f2033 100644 --- a/sys/kern/kern_fork.c +++ b/sys/kern/kern_fork.c @@ -425,6 +425,7 @@ do_fork(struct thread *td, struct fork_req *fr, struct proc *p2, struct thread * bzero(&p2->p_startzero, __rangeof(struct proc, p_startzero, p_endzero)); p2->p_ptevents = 0; + p2->p_pdeathsig = 0; /* Tell the prison that we exist. */ prison_proc_hold(p2->p_ucred->cr_prison); diff --git a/sys/kern/kern_procctl.c b/sys/kern/kern_procctl.c index dddc6b9..4c3569a 100644 --- a/sys/kern/kern_procctl.c +++ b/sys/kern/kern_procctl.c @@ -431,7 +431,7 @@ sys_procctl(struct thread *td, struct procctl_args *uap) 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 *uap) case PROC_TRAPCAP_STATUS: data = &flags; break; + case PROC_PDEATHSIG_CTL: + error = copyin(uap->data, &signum, sizeof(signum)); + if (error != 0) + return (error); + data = &signum; + break; + case PROC_PDEATHSIG_STATUS: + data = &signum; + break; default: return (EINVAL); } @@ -486,6 +495,10 @@ sys_procctl(struct thread *td, struct procctl_args *uap) if (error == 0) error = copyout(&flags, uap->data, sizeof(flags)); break; + case PROC_PDEATHSIG_STATUS: + 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 id, int com, void *data) struct pgrp *pg; struct proc *p; int error, first_error, ok; + int signum; bool tree_locked; switch (com) { @@ -537,11 +551,34 @@ kern_procctl(struct thread *td, idtype_t idtype, id_t id, int com, void *data) case PROC_REAP_KILL: case PROC_TRACE_STATUS: case PROC_TRAPCAP_STATUS: + case PROC_PDEATHSIG_CTL: + case PROC_PDEATHSIG_STATUS: if (idtype != P_PID) return (EINVAL); } switch (com) { + case PROC_PDEATHSIG_CTL: + 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_STATUS: + 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) { case PROC_SPROTECT: case PROC_REAP_STATUS: case PROC_REAP_GETPIDS: diff --git a/sys/sys/proc.h b/sys/sys/proc.h index 553a881..d5ba0f4 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -674,6 +674,7 @@ struct proc { uint64_t p_elf_flags; /* (x) ELF flags */ sigqueue_t p_sigqueue; /* (c) Sigs not delivered to a td. */ #define p_siglist p_sigqueue.sq_signals + int p_pdeathsig; /* (c) Signal from parent on exit. */ }; #define p_session p_pgrp->pg_session diff --git a/sys/sys/procctl.h b/sys/sys/procctl.h index 8c938c5..1bed970 100644 --- a/sys/sys/procctl.h +++ b/sys/sys/procctl.h @@ -49,6 +49,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_CTL 11 /* set parent death signal */ +#define PROC_PDEATHSIG_STATUS 12 /* get parent death signal */ /* Operations for PROC_SPROTECT (passed in integer arg). */ #define PPROT_OP(x) ((x) & 0xf) diff --git a/tests/sys/kern/Makefile b/tests/sys/kern/Makefile index a3bffef..93e5aa8 100644 --- a/tests/sys/kern/Makefile +++ b/tests/sys/kern/Makefile @@ -15,6 +15,9 @@ 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 + +PROGS+= pdeathsig_helper LIBADD.ptrace_test+= pthread LIBADD.unix_seqpacket_test+= pthread diff --git a/tests/sys/kern/pdeathsig.c b/tests/sys/kern/pdeathsig.c new file mode 100644 index 0000000..a69720d --- /dev/null +++ b/tests/sys/kern/pdeathsig.c @@ -0,0 +1,336 @@ +/*- + * 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_CTL, &signum); + ATF_CHECK_EQ(-1, rc); + ATF_CHECK_EQ(EINVAL, errno); + + /* bad id type */ + signum = SIGINFO; + rc = procctl(8888, 0, PROC_PDEATHSIG_CTL, &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_CTL, &signum); + ATF_CHECK_EQ(-1, rc); + ATF_CHECK_EQ(EINVAL, errno); + + /* null pointer */ + signum = SIGINFO; + rc = procctl(P_PID, 0, PROC_PDEATHSIG_CTL, NULL); + ATF_CHECK_EQ(-1, rc); + ATF_CHECK_EQ(EFAULT, errno); + + /* good (pid == 0) */ + signum = SIGINFO; + rc = procctl(P_PID, 0, PROC_PDEATHSIG_CTL, &signum); + ATF_CHECK_EQ(0, rc); + + /* good (pid == my pid) */ + signum = SIGINFO; + rc = procctl(P_PID, getpid(), PROC_PDEATHSIG_CTL, &signum); + ATF_CHECK_EQ(0, rc); + + /* check that we can read the signal number back */ + signum = 0xdeadbeef; + rc = procctl(P_PID, 0, PROC_PDEATHSIG_STATUS, &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_CTL, &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_STATUS, &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_CTL, &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_CTL, &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]; + char buffer; + int status; + + rc = pipe(pipe_ca); + ATF_REQUIRE(rc == 0); + rc = pipe(pipe_db); + 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_CTL, &signum); + assert(rc == 0); + + /* 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()); +} diff --git a/tests/sys/kern/pdeathsig_helper.c b/tests/sys/kern/pdeathsig_helper.c new file mode 100644 index 0000000..e1a8252 --- /dev/null +++ b/tests/sys/kern/pdeathsig_helper.c @@ -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_CTL setting was + * inherited. + */ + signum = 0xdeadbeef; + rc = procctl(P_PID, 0, PROC_PDEATHSIG_STATUS, &signum); + assert(rc == 0); + assert(signum == SIGINFO); + + return 0; +} |