xref: /netbsd-src/sys/kern/sys_sig.c (revision 75996a401adf173278b026a036cd3ac0756959c7)
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