1*75996a40Skre /* $NetBSD: sys_sig.c,v 1.58 2024/07/14 05:10:40 kre Exp $ */
2b07ec3fcSad
3b07ec3fcSad /*-
4284c2b9aSad * Copyright (c) 2006, 2007, 2008 The NetBSD Foundation, Inc.
5b07ec3fcSad * All rights reserved.
6b07ec3fcSad *
7b07ec3fcSad * This code is derived from software contributed to The NetBSD Foundation
8b07ec3fcSad * by Andrew Doran.
9b07ec3fcSad *
10b07ec3fcSad * Redistribution and use in source and binary forms, with or without
11b07ec3fcSad * modification, are permitted provided that the following conditions
12b07ec3fcSad * are met:
13b07ec3fcSad * 1. Redistributions of source code must retain the above copyright
14b07ec3fcSad * notice, this list of conditions and the following disclaimer.
15b07ec3fcSad * 2. Redistributions in binary form must reproduce the above copyright
16b07ec3fcSad * notice, this list of conditions and the following disclaimer in the
17b07ec3fcSad * documentation and/or other materials provided with the distribution.
18b07ec3fcSad *
19b07ec3fcSad * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20b07ec3fcSad * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21b07ec3fcSad * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22b07ec3fcSad * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23b07ec3fcSad * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24b07ec3fcSad * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25b07ec3fcSad * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26b07ec3fcSad * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27b07ec3fcSad * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28b07ec3fcSad * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29b07ec3fcSad * POSSIBILITY OF SUCH DAMAGE.
30b07ec3fcSad */
31b07ec3fcSad
32b07ec3fcSad /*
33b07ec3fcSad * Copyright (c) 1982, 1986, 1989, 1991, 1993
34b07ec3fcSad * The Regents of the University of California. All rights reserved.
35b07ec3fcSad * (c) UNIX System Laboratories, Inc.
36b07ec3fcSad * All or some portions of this file are derived from material licensed
37b07ec3fcSad * to the University of California by American Telephone and Telegraph
38b07ec3fcSad * Co. or Unix System Laboratories, Inc. and are reproduced herein with
39b07ec3fcSad * the permission of UNIX System Laboratories, Inc.
40b07ec3fcSad *
41b07ec3fcSad * Redistribution and use in source and binary forms, with or without
42b07ec3fcSad * modification, are permitted provided that the following conditions
43b07ec3fcSad * are met:
44b07ec3fcSad * 1. Redistributions of source code must retain the above copyright
45b07ec3fcSad * notice, this list of conditions and the following disclaimer.
46b07ec3fcSad * 2. Redistributions in binary form must reproduce the above copyright
47b07ec3fcSad * notice, this list of conditions and the following disclaimer in the
48b07ec3fcSad * documentation and/or other materials provided with the distribution.
49b07ec3fcSad * 3. Neither the name of the University nor the names of its contributors
50b07ec3fcSad * may be used to endorse or promote products derived from this software
51b07ec3fcSad * without specific prior written permission.
52b07ec3fcSad *
53b07ec3fcSad * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54b07ec3fcSad * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55b07ec3fcSad * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56b07ec3fcSad * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57b07ec3fcSad * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58b07ec3fcSad * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59b07ec3fcSad * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60b07ec3fcSad * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61b07ec3fcSad * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62b07ec3fcSad * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63b07ec3fcSad * SUCH DAMAGE.
64b07ec3fcSad *
65b07ec3fcSad * @(#)kern_sig.c 8.14 (Berkeley) 5/14/95
66b07ec3fcSad */
67b07ec3fcSad
68b07ec3fcSad #include <sys/cdefs.h>
69*75996a40Skre __KERNEL_RCSID(0, "$NetBSD: sys_sig.c,v 1.58 2024/07/14 05:10:40 kre Exp $");
70db70f181Schristos
71db70f181Schristos #include "opt_dtrace.h"
72b07ec3fcSad
73b07ec3fcSad #include <sys/param.h>
74b07ec3fcSad #include <sys/kernel.h>
75b07ec3fcSad #include <sys/signalvar.h>
76b07ec3fcSad #include <sys/proc.h>
77b07ec3fcSad #include <sys/pool.h>
78b07ec3fcSad #include <sys/syscallargs.h>
79b07ec3fcSad #include <sys/kauth.h>
80b07ec3fcSad #include <sys/wait.h>
81b07ec3fcSad #include <sys/kmem.h>
8292ce8c6aSad #include <sys/module.h>
83db70f181Schristos #include <sys/sdt.h>
847b0f5c9eSpgoyette #include <sys/compat_stub.h>
85db70f181Schristos
86db70f181Schristos SDT_PROVIDER_DECLARE(proc);
87db70f181Schristos SDT_PROBE_DEFINE2(proc, kernel, , signal__clear,
88db70f181Schristos "int", /* signal */
89db70f181Schristos "ksiginfo_t *"); /* signal-info */
90b07ec3fcSad
91b07ec3fcSad int
sys___sigaction_sigtramp(struct lwp * l,const struct sys___sigaction_sigtramp_args * uap,register_t * retval)923c74cdf1Srmind sys___sigaction_sigtramp(struct lwp *l,
933c74cdf1Srmind const struct sys___sigaction_sigtramp_args *uap, register_t *retval)
94b07ec3fcSad {
957e2790cfSdsl /* {
96b07ec3fcSad syscallarg(int) signum;
97b07ec3fcSad syscallarg(const struct sigaction *) nsa;
98b07ec3fcSad syscallarg(struct sigaction *) osa;
99b07ec3fcSad syscallarg(void *) tramp;
100b07ec3fcSad syscallarg(int) vers;
1017e2790cfSdsl } */
102b07ec3fcSad struct sigaction nsa, osa;
103b07ec3fcSad int error;
104b07ec3fcSad
105b07ec3fcSad if (SCARG(uap, nsa)) {
106b07ec3fcSad error = copyin(SCARG(uap, nsa), &nsa, sizeof(nsa));
107b07ec3fcSad if (error)
108b07ec3fcSad return (error);
109b07ec3fcSad }
110b07ec3fcSad error = sigaction1(l, SCARG(uap, signum),
111b07ec3fcSad SCARG(uap, nsa) ? &nsa : 0, SCARG(uap, osa) ? &osa : 0,
112b07ec3fcSad SCARG(uap, tramp), SCARG(uap, vers));
113b07ec3fcSad if (error)
114b07ec3fcSad return (error);
115b07ec3fcSad if (SCARG(uap, osa)) {
116b07ec3fcSad error = copyout(&osa, SCARG(uap, osa), sizeof(osa));
117b07ec3fcSad if (error)
118b07ec3fcSad return (error);
119b07ec3fcSad }
1203c74cdf1Srmind return 0;
121b07ec3fcSad }
122b07ec3fcSad
123b07ec3fcSad /*
124b07ec3fcSad * Manipulate signal mask. Note that we receive new mask, not pointer, and
125b07ec3fcSad * return old mask as return value; the library stub does the rest.
126b07ec3fcSad */
127b07ec3fcSad int
sys___sigprocmask14(struct lwp * l,const struct sys___sigprocmask14_args * uap,register_t * retval)1283c74cdf1Srmind sys___sigprocmask14(struct lwp *l, const struct sys___sigprocmask14_args *uap,
1293c74cdf1Srmind register_t *retval)
130b07ec3fcSad {
1317e2790cfSdsl /* {
132b07ec3fcSad syscallarg(int) how;
133b07ec3fcSad syscallarg(const sigset_t *) set;
134b07ec3fcSad syscallarg(sigset_t *) oset;
1357e2790cfSdsl } */
136b07ec3fcSad struct proc *p = l->l_proc;
137b07ec3fcSad sigset_t nss, oss;
138b07ec3fcSad int error;
139b07ec3fcSad
140b07ec3fcSad if (SCARG(uap, set)) {
141b07ec3fcSad error = copyin(SCARG(uap, set), &nss, sizeof(nss));
142b07ec3fcSad if (error)
1433c74cdf1Srmind return error;
144b07ec3fcSad }
145284c2b9aSad mutex_enter(p->p_lock);
146b07ec3fcSad error = sigprocmask1(l, SCARG(uap, how),
147b07ec3fcSad SCARG(uap, set) ? &nss : 0, SCARG(uap, oset) ? &oss : 0);
148284c2b9aSad mutex_exit(p->p_lock);
149b07ec3fcSad if (error)
1503c74cdf1Srmind return error;
151b07ec3fcSad if (SCARG(uap, oset)) {
152b07ec3fcSad error = copyout(&oss, SCARG(uap, oset), sizeof(oss));
153b07ec3fcSad if (error)
1543c74cdf1Srmind return error;
155b07ec3fcSad }
1563c74cdf1Srmind return 0;
157b07ec3fcSad }
158b07ec3fcSad
159b07ec3fcSad int
sys___sigpending14(struct lwp * l,const struct sys___sigpending14_args * uap,register_t * retval)1603c74cdf1Srmind sys___sigpending14(struct lwp *l, const struct sys___sigpending14_args *uap,
1613c74cdf1Srmind register_t *retval)
162b07ec3fcSad {
1637e2790cfSdsl /* {
164b07ec3fcSad syscallarg(sigset_t *) set;
1657e2790cfSdsl } */
166b07ec3fcSad sigset_t ss;
167b07ec3fcSad
168b07ec3fcSad sigpending1(l, &ss);
1693c74cdf1Srmind return copyout(&ss, SCARG(uap, set), sizeof(ss));
170b07ec3fcSad }
171b07ec3fcSad
172b07ec3fcSad /*
173b07ec3fcSad * Suspend process until signal, providing mask to be set in the meantime.
174b07ec3fcSad * Note nonstandard calling convention: libc stub passes mask, not pointer,
175b07ec3fcSad * to save a copyin.
176b07ec3fcSad */
177b07ec3fcSad int
sys___sigsuspend14(struct lwp * l,const struct sys___sigsuspend14_args * uap,register_t * retval)1783c74cdf1Srmind sys___sigsuspend14(struct lwp *l, const struct sys___sigsuspend14_args *uap,
1793c74cdf1Srmind register_t *retval)
180b07ec3fcSad {
1817e2790cfSdsl /* {
182b07ec3fcSad syscallarg(const sigset_t *) set;
1837e2790cfSdsl } */
184b07ec3fcSad sigset_t ss;
185b07ec3fcSad int error;
186b07ec3fcSad
187b07ec3fcSad if (SCARG(uap, set)) {
188b07ec3fcSad error = copyin(SCARG(uap, set), &ss, sizeof(ss));
189b07ec3fcSad if (error)
1903c74cdf1Srmind return error;
1913c74cdf1Srmind }
1923c74cdf1Srmind return sigsuspend1(l, SCARG(uap, set) ? &ss : 0);
193b07ec3fcSad }
194b07ec3fcSad
195b07ec3fcSad int
sys___sigaltstack14(struct lwp * l,const struct sys___sigaltstack14_args * uap,register_t * retval)1963c74cdf1Srmind sys___sigaltstack14(struct lwp *l, const struct sys___sigaltstack14_args *uap,
1973c74cdf1Srmind register_t *retval)
198b07ec3fcSad {
1997e2790cfSdsl /* {
200b07ec3fcSad syscallarg(const struct sigaltstack *) nss;
201b07ec3fcSad syscallarg(struct sigaltstack *) oss;
2027e2790cfSdsl } */
2030a15a2c8Sthorpej stack_t nss, oss;
204b07ec3fcSad int error;
205b07ec3fcSad
206b07ec3fcSad if (SCARG(uap, nss)) {
207b07ec3fcSad error = copyin(SCARG(uap, nss), &nss, sizeof(nss));
208b07ec3fcSad if (error)
2093c74cdf1Srmind return error;
210b07ec3fcSad }
211b07ec3fcSad error = sigaltstack1(l,
212b07ec3fcSad SCARG(uap, nss) ? &nss : 0, SCARG(uap, oss) ? &oss : 0);
213b07ec3fcSad if (error)
2143c74cdf1Srmind return error;
215b07ec3fcSad if (SCARG(uap, oss)) {
216b07ec3fcSad error = copyout(&oss, SCARG(uap, oss), sizeof(oss));
217b07ec3fcSad if (error)
2183c74cdf1Srmind return error;
219b07ec3fcSad }
2203c74cdf1Srmind return 0;
221b07ec3fcSad }
222b07ec3fcSad
2235f7e4ad4Smartin int
kill1(struct lwp * l,pid_t pid,ksiginfo_t * ksi,register_t * retval)2243d70c4b4Schristos kill1(struct lwp *l, pid_t pid, ksiginfo_t *ksi, register_t *retval)
2253d70c4b4Schristos {
2263d70c4b4Schristos int error;
2273d70c4b4Schristos struct proc *p;
2283d70c4b4Schristos
2293d70c4b4Schristos if ((u_int)ksi->ksi_signo >= NSIG)
2303c74cdf1Srmind return EINVAL;
2313d70c4b4Schristos
232ccc5092eSmartin if (pid != l->l_proc->p_pid) {
2333d70c4b4Schristos if (ksi->ksi_pid != l->l_proc->p_pid)
2343d70c4b4Schristos return EPERM;
2353d70c4b4Schristos
2363d70c4b4Schristos if (ksi->ksi_uid != kauth_cred_geteuid(l->l_cred))
2373d70c4b4Schristos return EPERM;
2383d70c4b4Schristos
2393d70c4b4Schristos switch (ksi->ksi_code) {
2403d70c4b4Schristos case SI_USER:
2413d70c4b4Schristos case SI_QUEUE:
2423d70c4b4Schristos break;
2433d70c4b4Schristos default:
2443d70c4b4Schristos return EPERM;
2453d70c4b4Schristos }
246ccc5092eSmartin }
2473d70c4b4Schristos
2483d70c4b4Schristos if (pid > 0) {
249b07ec3fcSad /* kill single process */
2500eaaa024Sad mutex_enter(&proc_lock);
251c296146aSchristos p = proc_find_raw(pid);
252c296146aSchristos if (p == NULL || (p->p_stat != SACTIVE && p->p_stat != SSTOP)) {
2530eaaa024Sad mutex_exit(&proc_lock);
254c296146aSchristos /* IEEE Std 1003.1-2001: return success for zombies */
255c296146aSchristos return p ? 0 : ESRCH;
2566d70f903Sad }
257284c2b9aSad mutex_enter(p->p_lock);
258b07ec3fcSad error = kauth_authorize_process(l->l_cred,
2593d70c4b4Schristos KAUTH_PROCESS_SIGNAL, p, KAUTH_ARG(ksi->ksi_signo),
260b07ec3fcSad NULL, NULL);
2613d70c4b4Schristos if (!error && ksi->ksi_signo) {
262c10c4abeSchristos error = kpsignal2(p, ksi);
263b07ec3fcSad }
264284c2b9aSad mutex_exit(p->p_lock);
2650eaaa024Sad mutex_exit(&proc_lock);
2663c74cdf1Srmind return error;
267b07ec3fcSad }
2683d70c4b4Schristos
2693d70c4b4Schristos switch (pid) {
270b07ec3fcSad case -1: /* broadcast signal */
2713d70c4b4Schristos return killpg1(l, ksi, 0, 1);
272b07ec3fcSad case 0: /* signal own process group */
2733d70c4b4Schristos return killpg1(l, ksi, 0, 0);
274b07ec3fcSad default: /* negative explicit process group */
275*75996a40Skre if (pid <= INT_MIN)
276*75996a40Skre return ESRCH;
2773d70c4b4Schristos return killpg1(l, ksi, -pid, 0);
278b07ec3fcSad }
279b07ec3fcSad /* NOTREACHED */
280b07ec3fcSad }
281b07ec3fcSad
282b07ec3fcSad int
sys_sigqueueinfo(struct lwp * l,const struct sys_sigqueueinfo_args * uap,register_t * retval)2833d70c4b4Schristos sys_sigqueueinfo(struct lwp *l, const struct sys_sigqueueinfo_args *uap,
2843d70c4b4Schristos register_t *retval)
2853d70c4b4Schristos {
2863d70c4b4Schristos /* {
2873d70c4b4Schristos syscallarg(pid_t int) pid;
2883d70c4b4Schristos syscallarg(const siginfo_t *) info;
2893d70c4b4Schristos } */
2903d70c4b4Schristos ksiginfo_t ksi;
2913d70c4b4Schristos int error;
2923d70c4b4Schristos
2933d70c4b4Schristos KSI_INIT(&ksi);
2943d70c4b4Schristos
2953d70c4b4Schristos if ((error = copyin(&SCARG(uap, info)->_info, &ksi.ksi_info,
2963d70c4b4Schristos sizeof(ksi.ksi_info))) != 0)
2973d70c4b4Schristos return error;
2983d70c4b4Schristos
2993d70c4b4Schristos return kill1(l, SCARG(uap, pid), &ksi, retval);
3003d70c4b4Schristos }
3013d70c4b4Schristos
3023d70c4b4Schristos int
sys_kill(struct lwp * l,const struct sys_kill_args * uap,register_t * retval)3033d70c4b4Schristos sys_kill(struct lwp *l, const struct sys_kill_args *uap, register_t *retval)
3043d70c4b4Schristos {
3053d70c4b4Schristos /* {
3063d70c4b4Schristos syscallarg(pid_t) pid;
3073d70c4b4Schristos syscallarg(int) signum;
3083d70c4b4Schristos } */
3093d70c4b4Schristos ksiginfo_t ksi;
3103d70c4b4Schristos
3113d70c4b4Schristos KSI_INIT(&ksi);
3123d70c4b4Schristos
3133d70c4b4Schristos ksi.ksi_signo = SCARG(uap, signum);
3143d70c4b4Schristos ksi.ksi_code = SI_USER;
3153d70c4b4Schristos ksi.ksi_pid = l->l_proc->p_pid;
3163d70c4b4Schristos ksi.ksi_uid = kauth_cred_geteuid(l->l_cred);
3173d70c4b4Schristos
3183d70c4b4Schristos return kill1(l, SCARG(uap, pid), &ksi, retval);
3193d70c4b4Schristos }
3203d70c4b4Schristos
3213d70c4b4Schristos int
sys_getcontext(struct lwp * l,const struct sys_getcontext_args * uap,register_t * retval)3223c74cdf1Srmind sys_getcontext(struct lwp *l, const struct sys_getcontext_args *uap,
3233c74cdf1Srmind register_t *retval)
324b07ec3fcSad {
3257e2790cfSdsl /* {
326b07ec3fcSad syscallarg(struct __ucontext *) ucp;
3277e2790cfSdsl } */
328b07ec3fcSad struct proc *p = l->l_proc;
329b07ec3fcSad ucontext_t uc;
330b07ec3fcSad
33113011308Sjoerg memset(&uc, 0, sizeof(uc));
33213011308Sjoerg
333284c2b9aSad mutex_enter(p->p_lock);
334b07ec3fcSad getucontext(l, &uc);
335284c2b9aSad mutex_exit(p->p_lock);
336b07ec3fcSad
3373c74cdf1Srmind return copyout(&uc, SCARG(uap, ucp), sizeof (*SCARG(uap, ucp)));
338b07ec3fcSad }
339b07ec3fcSad
340b07ec3fcSad int
sys_setcontext(struct lwp * l,const struct sys_setcontext_args * uap,register_t * retval)3413c74cdf1Srmind sys_setcontext(struct lwp *l, const struct sys_setcontext_args *uap,
3423c74cdf1Srmind register_t *retval)
343b07ec3fcSad {
3447e2790cfSdsl /* {
345b07ec3fcSad syscallarg(const ucontext_t *) ucp;
3467e2790cfSdsl } */
347b07ec3fcSad struct proc *p = l->l_proc;
348b07ec3fcSad ucontext_t uc;
349b07ec3fcSad int error;
350b07ec3fcSad
351b07ec3fcSad error = copyin(SCARG(uap, ucp), &uc, sizeof (uc));
352b07ec3fcSad if (error)
3533c74cdf1Srmind return error;
3543c74cdf1Srmind if ((uc.uc_flags & _UC_CPU) == 0)
3553c74cdf1Srmind return EINVAL;
356284c2b9aSad mutex_enter(p->p_lock);
357b07ec3fcSad error = setucontext(l, &uc);
358284c2b9aSad mutex_exit(p->p_lock);
359b07ec3fcSad if (error)
3603c74cdf1Srmind return error;
361b07ec3fcSad
3623c74cdf1Srmind return EJUSTRETURN;
363b07ec3fcSad }
364b07ec3fcSad
365b07ec3fcSad /*
366b07ec3fcSad * sigtimedwait(2) system call, used also for implementation
367b07ec3fcSad * of sigwaitinfo() and sigwait().
368b07ec3fcSad *
369b07ec3fcSad * This only handles single LWP in signal wait. libpthread provides
370f0a7346dSsnj * its own sigtimedwait() wrapper to DTRT WRT individual threads.
371b07ec3fcSad */
372b07ec3fcSad int
sys_____sigtimedwait50(struct lwp * l,const struct sys_____sigtimedwait50_args * uap,register_t * retval)373461a86f9Schristos sys_____sigtimedwait50(struct lwp *l,
374461a86f9Schristos const struct sys_____sigtimedwait50_args *uap, register_t *retval)
375b07ec3fcSad {
376b07ec3fcSad
377d8bca0f2Schristos return sigtimedwait1(l, uap, retval, copyin, copyout, copyin, copyout);
378b07ec3fcSad }
379b07ec3fcSad
380b07ec3fcSad int
sigaction1(struct lwp * l,int signum,const struct sigaction * nsa,struct sigaction * osa,const void * tramp,int vers)381b07ec3fcSad sigaction1(struct lwp *l, int signum, const struct sigaction *nsa,
382b07ec3fcSad struct sigaction *osa, const void *tramp, int vers)
383b07ec3fcSad {
384b07ec3fcSad struct proc *p;
385b07ec3fcSad struct sigacts *ps;
386b07ec3fcSad sigset_t tset;
387b07ec3fcSad int prop, error;
388b07ec3fcSad ksiginfoq_t kq;
3899d09ecfaSad static bool v0v1valid;
390b07ec3fcSad
391b07ec3fcSad if (signum <= 0 || signum >= NSIG)
3923c74cdf1Srmind return EINVAL;
393b07ec3fcSad
394b07ec3fcSad p = l->l_proc;
395b07ec3fcSad error = 0;
396b07ec3fcSad ksiginfo_queue_init(&kq);
397b07ec3fcSad
398b07ec3fcSad /*
3995fd6947dSthorpej * Trampoline ABI version __SIGTRAMP_SIGCODE_VERSION (0) is reserved
4005fd6947dSthorpej * for the legacy kernel provided on-stack trampoline. Conversely,
4015fd6947dSthorpej * if we are using a non-0 ABI version, we must have a trampoline.
4025fd6947dSthorpej * Only validate the vers if a new sigaction was supplied and there
4035fd6947dSthorpej * was an actual handler specified (not SIG_IGN or SIG_DFL), which
4045fd6947dSthorpej * don't require a trampoline. Emulations use legacy kernel
4055fd6947dSthorpej * trampolines with version 0, alternatively check for that too.
40692ce8c6aSad *
4075fd6947dSthorpej * If version < __SIGTRAMP_SIGINFO_VERSION_MIN (usually 2), we try
4085fd6947dSthorpej * to autoload the compat module. Note that we interlock with the
4095fd6947dSthorpej * unload check in compat_modcmd() using kernconfig_lock. If the
4105fd6947dSthorpej * autoload fails, we don't try it again for this process.
411b07ec3fcSad */
412b9e9a610Schristos if (nsa != NULL && nsa->sa_handler != SIG_IGN
413b9e9a610Schristos && nsa->sa_handler != SIG_DFL) {
4145fd6947dSthorpej if (__predict_false(vers < __SIGTRAMP_SIGINFO_VERSION_MIN)) {
4155fd6947dSthorpej if (vers == __SIGTRAMP_SIGCODE_VERSION &&
416b4e9c61bSryo p->p_sigctx.ps_sigcode != NULL) {
417b4e9c61bSryo /*
418b4e9c61bSryo * if sigcode is used for this emulation,
419b4e9c61bSryo * version 0 is allowed.
420b4e9c61bSryo */
4215fd6947dSthorpej }
4225fd6947dSthorpej #ifdef __HAVE_STRUCT_SIGCONTEXT
4235fd6947dSthorpej else if (p->p_flag & PK_32) {
424e0435021Sthorpej /*
425e0435021Sthorpej * The 32-bit compat module will have
426e0435021Sthorpej * pre-validated this for us.
427e0435021Sthorpej */
4285fd6947dSthorpej v0v1valid = true;
429b4e9c61bSryo } else if ((p->p_lflag & PL_SIGCOMPAT) == 0) {
43023d5409eSpgoyette kernconfig_lock();
431a87c3088Spgoyette (void)module_autoload("compat_16",
4329d09ecfaSad MODULE_CLASS_ANY);
4337b0f5c9eSpgoyette if (sendsig_sigcontext_16_hook.hooked) {
4349d09ecfaSad /*
4359d09ecfaSad * We need to remember if the
4369d09ecfaSad * sigcontext method may be useable,
4379d09ecfaSad * because libc may use it even
4389d09ecfaSad * if siginfo is available.
4399d09ecfaSad */
4409d09ecfaSad v0v1valid = true;
44192ce8c6aSad }
4420eaaa024Sad mutex_enter(&proc_lock);
4439d09ecfaSad /*
4449d09ecfaSad * Prevent unload of compat module while
4459d09ecfaSad * this process remains.
4469d09ecfaSad */
44792ce8c6aSad p->p_lflag |= PL_SIGCOMPAT;
4480eaaa024Sad mutex_exit(&proc_lock);
44923d5409eSpgoyette kernconfig_unlock();
45092ce8c6aSad }
4515fd6947dSthorpej #endif /* __HAVE_STRUCT_SIGCONTEXT */
452131cc4dfSchristos }
45392ce8c6aSad
4549d09ecfaSad switch (vers) {
4555fd6947dSthorpej case __SIGTRAMP_SIGCODE_VERSION:
4565fd6947dSthorpej /* kernel supplied trampoline. */
457b4e9c61bSryo if (tramp != NULL ||
458b4e9c61bSryo (p->p_sigctx.ps_sigcode == NULL && !v0v1valid)) {
45992ce8c6aSad return EINVAL;
46092ce8c6aSad }
4619d09ecfaSad break;
4625fd6947dSthorpej #ifdef __HAVE_STRUCT_SIGCONTEXT
4635fd6947dSthorpej case __SIGTRAMP_SIGCONTEXT_VERSION_MIN ...
4645fd6947dSthorpej __SIGTRAMP_SIGCONTEXT_VERSION_MAX:
4659d09ecfaSad /* sigcontext, user supplied trampoline. */
4669d09ecfaSad if (tramp == NULL || !v0v1valid) {
46792ce8c6aSad return EINVAL;
468b07ec3fcSad }
4699d09ecfaSad break;
4705fd6947dSthorpej #endif /* __HAVE_STRUCT_SIGCONTEXT */
4715fd6947dSthorpej case __SIGTRAMP_SIGINFO_VERSION_MIN ...
4725fd6947dSthorpej __SIGTRAMP_SIGINFO_VERSION_MAX:
4739d09ecfaSad /* siginfo, user supplied trampoline. */
4749d09ecfaSad if (tramp == NULL) {
4759d09ecfaSad return EINVAL;
4769d09ecfaSad }
4779d09ecfaSad break;
4789d09ecfaSad default:
4795fd6947dSthorpej /* Invalid trampoline version. */
4809d09ecfaSad return EINVAL;
4819d09ecfaSad }
4829d09ecfaSad }
483b07ec3fcSad
484284c2b9aSad mutex_enter(p->p_lock);
485b07ec3fcSad
486b07ec3fcSad ps = p->p_sigacts;
487b07ec3fcSad if (osa)
48866e967efSmaxv sigaction_copy(osa, &SIGACTION_PS(ps, signum));
489b07ec3fcSad if (!nsa)
490b07ec3fcSad goto out;
491b07ec3fcSad
492b07ec3fcSad prop = sigprop[signum];
493b07ec3fcSad if ((nsa->sa_flags & ~SA_ALLBITS) || (prop & SA_CANTMASK)) {
494b07ec3fcSad error = EINVAL;
495b07ec3fcSad goto out;
496b07ec3fcSad }
497b07ec3fcSad
49866e967efSmaxv sigaction_copy(&SIGACTION_PS(ps, signum), nsa);
499b07ec3fcSad ps->sa_sigdesc[signum].sd_tramp = tramp;
500b07ec3fcSad ps->sa_sigdesc[signum].sd_vers = vers;
501b07ec3fcSad sigminusset(&sigcantmask, &SIGACTION_PS(ps, signum).sa_mask);
502b07ec3fcSad
503b07ec3fcSad if ((prop & SA_NORESET) != 0)
504b07ec3fcSad SIGACTION_PS(ps, signum).sa_flags &= ~SA_RESETHAND;
505b07ec3fcSad
506b07ec3fcSad if (signum == SIGCHLD) {
507b07ec3fcSad if (nsa->sa_flags & SA_NOCLDSTOP)
508b07ec3fcSad p->p_sflag |= PS_NOCLDSTOP;
509b07ec3fcSad else
510b07ec3fcSad p->p_sflag &= ~PS_NOCLDSTOP;
511b07ec3fcSad if (nsa->sa_flags & SA_NOCLDWAIT) {
512b07ec3fcSad /*
513b07ec3fcSad * Paranoia: since SA_NOCLDWAIT is implemented by
514b07ec3fcSad * reparenting the dying child to PID 1 (and trust
515b07ec3fcSad * it to reap the zombie), PID 1 itself is forbidden
516b07ec3fcSad * to set SA_NOCLDWAIT.
517b07ec3fcSad */
518b07ec3fcSad if (p->p_pid == 1)
519934634a1Spavel p->p_flag &= ~PK_NOCLDWAIT;
520b07ec3fcSad else
521934634a1Spavel p->p_flag |= PK_NOCLDWAIT;
522b07ec3fcSad } else
523934634a1Spavel p->p_flag &= ~PK_NOCLDWAIT;
524b07ec3fcSad
525b07ec3fcSad if (nsa->sa_handler == SIG_IGN) {
526b07ec3fcSad /*
527b07ec3fcSad * Paranoia: same as above.
528b07ec3fcSad */
529b07ec3fcSad if (p->p_pid == 1)
530934634a1Spavel p->p_flag &= ~PK_CLDSIGIGN;
531b07ec3fcSad else
532934634a1Spavel p->p_flag |= PK_CLDSIGIGN;
533b07ec3fcSad } else
534934634a1Spavel p->p_flag &= ~PK_CLDSIGIGN;
535b07ec3fcSad }
536b07ec3fcSad
537b07ec3fcSad if ((nsa->sa_flags & SA_NODEFER) == 0)
538b07ec3fcSad sigaddset(&SIGACTION_PS(ps, signum).sa_mask, signum);
539b07ec3fcSad else
540b07ec3fcSad sigdelset(&SIGACTION_PS(ps, signum).sa_mask, signum);
541b07ec3fcSad
542b07ec3fcSad /*
543b07ec3fcSad * Set bit in p_sigctx.ps_sigignore for signals that are set to
544b07ec3fcSad * SIG_IGN, and for signals set to SIG_DFL where the default is to
545b07ec3fcSad * ignore. However, don't put SIGCONT in p_sigctx.ps_sigignore, as
546b07ec3fcSad * we have to restart the process.
547b07ec3fcSad */
548b07ec3fcSad if (nsa->sa_handler == SIG_IGN ||
549b07ec3fcSad (nsa->sa_handler == SIG_DFL && (prop & SA_IGNORE) != 0)) {
550b07ec3fcSad /* Never to be seen again. */
551b07ec3fcSad sigemptyset(&tset);
552b07ec3fcSad sigaddset(&tset, signum);
553b07ec3fcSad sigclearall(p, &tset, &kq);
554b07ec3fcSad if (signum != SIGCONT) {
555b07ec3fcSad /* Easier in psignal */
556b07ec3fcSad sigaddset(&p->p_sigctx.ps_sigignore, signum);
557b07ec3fcSad }
558b07ec3fcSad sigdelset(&p->p_sigctx.ps_sigcatch, signum);
559b07ec3fcSad } else {
560b07ec3fcSad sigdelset(&p->p_sigctx.ps_sigignore, signum);
561b07ec3fcSad if (nsa->sa_handler == SIG_DFL)
562b07ec3fcSad sigdelset(&p->p_sigctx.ps_sigcatch, signum);
563b07ec3fcSad else
564b07ec3fcSad sigaddset(&p->p_sigctx.ps_sigcatch, signum);
565b07ec3fcSad }
566b07ec3fcSad
567b07ec3fcSad /*
568b07ec3fcSad * Previously held signals may now have become visible. Ensure that
569b07ec3fcSad * we check for them before returning to userspace.
570b07ec3fcSad */
571a76d1d29Sad if (sigispending(l, 0)) {
572b07ec3fcSad lwp_lock(l);
573934634a1Spavel l->l_flag |= LW_PENDSIG;
574725adb2aSad lwp_need_userret(l);
575b07ec3fcSad lwp_unlock(l);
576a76d1d29Sad }
577b07ec3fcSad out:
578284c2b9aSad mutex_exit(p->p_lock);
579b07ec3fcSad ksiginfo_queue_drain(&kq);
580b07ec3fcSad
5813c74cdf1Srmind return error;
582b07ec3fcSad }
583b07ec3fcSad
584b07ec3fcSad int
sigprocmask1(struct lwp * l,int how,const sigset_t * nss,sigset_t * oss)585b07ec3fcSad sigprocmask1(struct lwp *l, int how, const sigset_t *nss, sigset_t *oss)
586b07ec3fcSad {
587ad12c770Srmind sigset_t *mask = &l->l_sigmask;
588ad12c770Srmind bool more;
589b07ec3fcSad
590ad12c770Srmind KASSERT(mutex_owned(l->l_proc->p_lock));
591b07ec3fcSad
592ad12c770Srmind if (oss) {
593fc7511b0Swrstuden *oss = *mask;
594ad12c770Srmind }
595ad12c770Srmind
596ad12c770Srmind if (nss == NULL) {
597ad12c770Srmind return 0;
598ad12c770Srmind }
599ad12c770Srmind
600b07ec3fcSad switch (how) {
601b07ec3fcSad case SIG_BLOCK:
602fc7511b0Swrstuden sigplusset(nss, mask);
603ad12c770Srmind more = false;
604b07ec3fcSad break;
605b07ec3fcSad case SIG_UNBLOCK:
606fc7511b0Swrstuden sigminusset(nss, mask);
607ad12c770Srmind more = true;
608b07ec3fcSad break;
609b07ec3fcSad case SIG_SETMASK:
610fc7511b0Swrstuden *mask = *nss;
611ad12c770Srmind more = true;
612b07ec3fcSad break;
613b07ec3fcSad default:
614ad12c770Srmind return EINVAL;
615b07ec3fcSad }
616fc7511b0Swrstuden sigminusset(&sigcantmask, mask);
617a76d1d29Sad if (more && sigispending(l, 0)) {
618b07ec3fcSad /*
619b07ec3fcSad * Check for pending signals on return to user.
620b07ec3fcSad */
621b07ec3fcSad lwp_lock(l);
622934634a1Spavel l->l_flag |= LW_PENDSIG;
623725adb2aSad lwp_need_userret(l);
624b07ec3fcSad lwp_unlock(l);
625b07ec3fcSad }
6263c74cdf1Srmind return 0;
627b07ec3fcSad }
628b07ec3fcSad
629b07ec3fcSad void
sigpending1(struct lwp * l,sigset_t * ss)630b07ec3fcSad sigpending1(struct lwp *l, sigset_t *ss)
631b07ec3fcSad {
632b07ec3fcSad struct proc *p = l->l_proc;
633b07ec3fcSad
634284c2b9aSad mutex_enter(p->p_lock);
635b07ec3fcSad *ss = l->l_sigpend.sp_set;
636b07ec3fcSad sigplusset(&p->p_sigpend.sp_set, ss);
637284c2b9aSad mutex_exit(p->p_lock);
638b07ec3fcSad }
639b07ec3fcSad
640e2543d03Schristos void
sigsuspendsetup(struct lwp * l,const sigset_t * ss)641e2543d03Schristos sigsuspendsetup(struct lwp *l, const sigset_t *ss)
642b07ec3fcSad {
6433c74cdf1Srmind struct proc *p = l->l_proc;
644b07ec3fcSad
645b07ec3fcSad /*
646e2543d03Schristos * When returning from sigsuspend/pselect/pollts, we want
647b07ec3fcSad * the old mask to be restored after the
648b07ec3fcSad * signal handler has finished. Thus, we
649b07ec3fcSad * save it here and mark the sigctx structure
650b07ec3fcSad * to indicate this.
651b07ec3fcSad */
652284c2b9aSad mutex_enter(p->p_lock);
653b07ec3fcSad l->l_sigrestore = 1;
654b07ec3fcSad l->l_sigoldmask = l->l_sigmask;
655b07ec3fcSad l->l_sigmask = *ss;
656b07ec3fcSad sigminusset(&sigcantmask, &l->l_sigmask);
657b07ec3fcSad
658b07ec3fcSad /* Check for pending signals when sleeping. */
659a76d1d29Sad if (sigispending(l, 0)) {
660b07ec3fcSad lwp_lock(l);
661934634a1Spavel l->l_flag |= LW_PENDSIG;
662725adb2aSad lwp_need_userret(l);
663b07ec3fcSad lwp_unlock(l);
664a76d1d29Sad }
665284c2b9aSad mutex_exit(p->p_lock);
666b07ec3fcSad }
667b07ec3fcSad
6680b60c7beSchristos void
sigsuspendteardown(struct lwp * l)6690b60c7beSchristos sigsuspendteardown(struct lwp *l)
6700b60c7beSchristos {
6710b60c7beSchristos struct proc *p = l->l_proc;
6720b60c7beSchristos
6730b60c7beSchristos mutex_enter(p->p_lock);
67441ceba00Schristos /* Check for pending signals when sleeping. */
6750b60c7beSchristos if (l->l_sigrestore) {
67641ceba00Schristos if (sigispending(l, 0)) {
67741ceba00Schristos lwp_lock(l);
67841ceba00Schristos l->l_flag |= LW_PENDSIG;
679725adb2aSad lwp_need_userret(l);
68041ceba00Schristos lwp_unlock(l);
68141ceba00Schristos } else {
6820b60c7beSchristos l->l_sigrestore = 0;
6830b60c7beSchristos l->l_sigmask = l->l_sigoldmask;
6840b60c7beSchristos }
68541ceba00Schristos }
6860b60c7beSchristos mutex_exit(p->p_lock);
6870b60c7beSchristos }
6880b60c7beSchristos
689e2543d03Schristos int
sigsuspend1(struct lwp * l,const sigset_t * ss)690e2543d03Schristos sigsuspend1(struct lwp *l, const sigset_t *ss)
691e2543d03Schristos {
692e2543d03Schristos
693e2543d03Schristos if (ss)
694e2543d03Schristos sigsuspendsetup(l, ss);
695e2543d03Schristos
6964f3d5a9cSthorpej while (kpause("pause", true, 0, NULL) == 0)
697b07ec3fcSad ;
698b07ec3fcSad
699b07ec3fcSad /* always return EINTR rather than ERESTART... */
7003c74cdf1Srmind return EINTR;
701b07ec3fcSad }
702b07ec3fcSad
703b07ec3fcSad int
sigaltstack1(struct lwp * l,const stack_t * nss,stack_t * oss)7040a15a2c8Sthorpej sigaltstack1(struct lwp *l, const stack_t *nss, stack_t *oss)
705b07ec3fcSad {
706b07ec3fcSad struct proc *p = l->l_proc;
707b07ec3fcSad int error = 0;
708b07ec3fcSad
709284c2b9aSad mutex_enter(p->p_lock);
710b07ec3fcSad
711b07ec3fcSad if (oss)
712b07ec3fcSad *oss = l->l_sigstk;
713b07ec3fcSad
714b07ec3fcSad if (nss) {
715b07ec3fcSad if (nss->ss_flags & ~SS_ALLBITS)
716b07ec3fcSad error = EINVAL;
717b07ec3fcSad else if (nss->ss_flags & SS_DISABLE) {
718b07ec3fcSad if (l->l_sigstk.ss_flags & SS_ONSTACK)
719b07ec3fcSad error = EINVAL;
720b07ec3fcSad } else if (nss->ss_size < MINSIGSTKSZ)
721b07ec3fcSad error = ENOMEM;
722b07ec3fcSad
723b07ec3fcSad if (!error)
724b07ec3fcSad l->l_sigstk = *nss;
725b07ec3fcSad }
726b07ec3fcSad
727284c2b9aSad mutex_exit(p->p_lock);
728b07ec3fcSad
7293c74cdf1Srmind return error;
730b07ec3fcSad }
731b07ec3fcSad
732b07ec3fcSad int
sigtimedwait1(struct lwp * l,const struct sys_____sigtimedwait50_args * uap,register_t * retval,copyin_t fetchss,copyout_t storeinf,copyin_t fetchts,copyout_t storets)733654415b2Spooka sigtimedwait1(struct lwp *l, const struct sys_____sigtimedwait50_args *uap,
734d8bca0f2Schristos register_t *retval, copyin_t fetchss, copyout_t storeinf, copyin_t fetchts,
735d8bca0f2Schristos copyout_t storets)
736b07ec3fcSad {
7377e2790cfSdsl /* {
738b07ec3fcSad syscallarg(const sigset_t *) set;
739b07ec3fcSad syscallarg(siginfo_t *) info;
740b07ec3fcSad syscallarg(struct timespec *) timeout;
7417e2790cfSdsl } */
742b07ec3fcSad struct proc *p = l->l_proc;
7433c74cdf1Srmind int error, signum, timo;
744b07ec3fcSad struct timespec ts, tsstart, tsnow;
745ebd0ab14Srmind ksiginfo_t ksi;
746b07ec3fcSad
747b07ec3fcSad /*
748b07ec3fcSad * Calculate timeout, if it was specified.
7497c5d63e1Sapb *
7507c5d63e1Sapb * NULL pointer means an infinite timeout.
7517c5d63e1Sapb * {.tv_sec = 0, .tv_nsec = 0} means do not block.
752b07ec3fcSad */
753b07ec3fcSad if (SCARG(uap, timeout)) {
7543c74cdf1Srmind error = (*fetchts)(SCARG(uap, timeout), &ts, sizeof(ts));
7556e1db6ceSchristos if (error)
7566e1db6ceSchristos return error;
757b07ec3fcSad
7586e1db6ceSchristos if ((error = itimespecfix(&ts)) != 0)
7596e1db6ceSchristos return error;
760b07ec3fcSad
7616e1db6ceSchristos timo = tstohz(&ts);
762f92c0e46Sapb if (timo == 0) {
763f92c0e46Sapb if (ts.tv_sec == 0 && ts.tv_nsec == 0)
764f92c0e46Sapb timo = -1; /* do not block */
765f92c0e46Sapb else
766f92c0e46Sapb timo = 1; /* the shortest possible timeout */
767f92c0e46Sapb }
768b07ec3fcSad
769b07ec3fcSad /*
770b07ec3fcSad * Remember current uptime, it would be used in
771b07ec3fcSad * ECANCELED/ERESTART case.
772b07ec3fcSad */
773b07ec3fcSad getnanouptime(&tsstart);
7743c74cdf1Srmind } else {
7753c74cdf1Srmind memset(&tsstart, 0, sizeof(tsstart)); /* XXXgcc */
776f92c0e46Sapb timo = 0; /* infinite timeout */
777b07ec3fcSad }
778b07ec3fcSad
779d8bca0f2Schristos error = (*fetchss)(SCARG(uap, set), &l->l_sigwaitset,
780b07ec3fcSad sizeof(l->l_sigwaitset));
7813c74cdf1Srmind if (error)
7823c74cdf1Srmind return error;
783b07ec3fcSad
784b07ec3fcSad /*
785b07ec3fcSad * Silently ignore SA_CANTMASK signals. psignal1() would ignore
786b07ec3fcSad * SA_CANTMASK signals in waitset, we do this only for the below
787b07ec3fcSad * siglist check.
788b07ec3fcSad */
789b07ec3fcSad sigminusset(&sigcantmask, &l->l_sigwaitset);
790b07ec3fcSad
7916bb18810Smaxv memset(&ksi.ksi_info, 0, sizeof(ksi.ksi_info));
7926bb18810Smaxv
793284c2b9aSad mutex_enter(p->p_lock);
794b07ec3fcSad
7953c74cdf1Srmind /* Check for pending signals in the process, if no - then in LWP. */
796ebd0ab14Srmind if ((signum = sigget(&p->p_sigpend, &ksi, 0, &l->l_sigwaitset)) == 0)
797ebd0ab14Srmind signum = sigget(&l->l_sigpend, &ksi, 0, &l->l_sigwaitset);
798b07ec3fcSad
799b07ec3fcSad if (signum != 0) {
8003c74cdf1Srmind /* If found a pending signal, just copy it out to the user. */
801284c2b9aSad mutex_exit(p->p_lock);
802b07ec3fcSad goto out;
803b07ec3fcSad }
804b07ec3fcSad
805f92c0e46Sapb if (timo < 0) {
806f92c0e46Sapb /* If not allowed to block, return an error */
807f92c0e46Sapb mutex_exit(p->p_lock);
808f92c0e46Sapb return EAGAIN;
809f92c0e46Sapb }
810f92c0e46Sapb
811b07ec3fcSad /*
8123c74cdf1Srmind * Set up the sigwait list and wait for signal to arrive.
8133c74cdf1Srmind * We can either be woken up or time out.
814b07ec3fcSad */
815ebd0ab14Srmind l->l_sigwaited = &ksi;
816b07ec3fcSad LIST_INSERT_HEAD(&p->p_sigwaiters, l, l_sigwaiter);
817284c2b9aSad error = cv_timedwait_sig(&l->l_sigcv, p->p_lock, timo);
818b07ec3fcSad
819b07ec3fcSad /*
8203c74cdf1Srmind * Need to find out if we woke as a result of _lwp_wakeup() or a
821b07ec3fcSad * signal outside our wait set.
822b07ec3fcSad */
823b07ec3fcSad if (l->l_sigwaited != NULL) {
824b07ec3fcSad if (error == EINTR) {
8253c74cdf1Srmind /* Wakeup via _lwp_wakeup(). */
826b07ec3fcSad error = ECANCELED;
827b07ec3fcSad } else if (!error) {
8283c74cdf1Srmind /* Spurious wakeup - arrange for syscall restart. */
829b07ec3fcSad error = ERESTART;
830b07ec3fcSad }
831b07ec3fcSad l->l_sigwaited = NULL;
832b07ec3fcSad LIST_REMOVE(l, l_sigwaiter);
833b07ec3fcSad }
834284c2b9aSad mutex_exit(p->p_lock);
835b07ec3fcSad
836b07ec3fcSad /*
837b07ec3fcSad * If the sleep was interrupted (either by signal or wakeup), update
838b07ec3fcSad * the timeout and copyout new value back. It would be used when
839b07ec3fcSad * the syscall would be restarted or called again.
840b07ec3fcSad */
841b07ec3fcSad if (timo && (error == ERESTART || error == ECANCELED)) {
842b07ec3fcSad getnanouptime(&tsnow);
843b07ec3fcSad
8443c74cdf1Srmind /* Compute how much time has passed since start. */
845b07ec3fcSad timespecsub(&tsnow, &tsstart, &tsnow);
8463c74cdf1Srmind
847e81d387dSandvar /* Subtract passed time from timeout. */
848b07ec3fcSad timespecsub(&ts, &tsnow, &ts);
849b07ec3fcSad
850b07ec3fcSad if (ts.tv_sec < 0)
851b07ec3fcSad error = EAGAIN;
852b07ec3fcSad else {
8533c74cdf1Srmind /* Copy updated timeout to userland. */
8543c74cdf1Srmind error = (*storets)(&ts, SCARG(uap, timeout),
855b07ec3fcSad sizeof(ts));
856b07ec3fcSad }
857b07ec3fcSad }
8583c74cdf1Srmind out:
859b07ec3fcSad /*
860b07ec3fcSad * If a signal from the wait set arrived, copy it to userland.
861b07ec3fcSad * Copy only the used part of siginfo, the padding part is
862b07ec3fcSad * left unchanged (userland is not supposed to touch it anyway).
863b07ec3fcSad */
8648239dc73Sdrochner if (error == 0 && SCARG(uap, info)) {
8653c74cdf1Srmind error = (*storeinf)(&ksi.ksi_info, SCARG(uap, info),
866ebd0ab14Srmind sizeof(ksi.ksi_info));
8673c74cdf1Srmind }
868db70f181Schristos if (error == 0) {
8698239dc73Sdrochner *retval = ksi.ksi_info._signo;
870db70f181Schristos SDT_PROBE(proc, kernel, , signal__clear, *retval,
871db70f181Schristos &ksi, 0, 0, 0);
872db70f181Schristos }
873b07ec3fcSad return error;
874b07ec3fcSad }
875