xref: /freebsd/sys/compat/linux/linux_signal.c (revision 227d01c1bc7caf2e838ee6eef1e6a3cc81d79d1b)
1c21dee17SSøren Schmidt /*-
20ba1b365SEd Maste  * SPDX-License-Identifier: BSD-2-Clause
37f2d13d6SPedro F. Giffuni  *
49a14aa01SUlrich Spörlein  * Copyright (c) 1994-1995 Søren Schmidt
5c21dee17SSøren Schmidt  * All rights reserved.
6c21dee17SSøren Schmidt  *
7c21dee17SSøren Schmidt  * Redistribution and use in source and binary forms, with or without
8c21dee17SSøren Schmidt  * modification, are permitted provided that the following conditions
9c21dee17SSøren Schmidt  * are met:
10c21dee17SSøren Schmidt  * 1. Redistributions of source code must retain the above copyright
110ba1b365SEd Maste  *    notice, this list of conditions and the following disclaimer.
12c21dee17SSøren Schmidt  * 2. Redistributions in binary form must reproduce the above copyright
13c21dee17SSøren Schmidt  *    notice, this list of conditions and the following disclaimer in the
14c21dee17SSøren Schmidt  *    documentation and/or other materials provided with the distribution.
15c21dee17SSøren Schmidt  *
160ba1b365SEd Maste  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
170ba1b365SEd Maste  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
180ba1b365SEd Maste  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
190ba1b365SEd Maste  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
200ba1b365SEd Maste  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
210ba1b365SEd Maste  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
220ba1b365SEd Maste  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
230ba1b365SEd Maste  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
240ba1b365SEd Maste  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
250ba1b365SEd Maste  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
260ba1b365SEd Maste  * SUCH DAMAGE.
27c21dee17SSøren Schmidt  */
28c21dee17SSøren Schmidt 
2993107373SDmitry Chagin #include "opt_ktrace.h"
3093107373SDmitry Chagin 
31c21dee17SSøren Schmidt #include <sys/param.h>
3230c6d982SEdward Tomasz Napierala #include <sys/ktr.h>
33fb919e4dSMark Murray #include <sys/lock.h>
34fb919e4dSMark Murray #include <sys/mutex.h>
35c21dee17SSøren Schmidt #include <sys/proc.h>
36c21dee17SSøren Schmidt #include <sys/signalvar.h>
37d8e53d94SDmitry Chagin #include <sys/sx.h>
38206a5d3aSIan Dowse #include <sys/syscallsubr.h>
39fb919e4dSMark Murray #include <sys/sysproto.h>
4093107373SDmitry Chagin #ifdef KTRACE
4193107373SDmitry Chagin #include <sys/ktrace.h>
4293107373SDmitry Chagin #endif
43c21dee17SSøren Schmidt 
44aa8b2011SKonstantin Belousov #include <security/audit/audit.h>
45aa8b2011SKonstantin Belousov 
461997c537SDavid E. O'Brien #ifdef COMPAT_LINUX32
474af27623STim J. Robbins #include <machine/../linux32/linux.h>
484af27623STim J. Robbins #include <machine/../linux32/linux32_proto.h>
491997c537SDavid E. O'Brien #else
501997c537SDavid E. O'Brien #include <machine/../linux/linux.h>
511997c537SDavid E. O'Brien #include <machine/../linux/linux_proto.h>
524af27623STim J. Robbins #endif
539c1045ffSDmitry Chagin #include <compat/linux/linux_mib.h>
54ba9ef45bSMarcel Moolenaar #include <compat/linux/linux_signal.h>
55c8a79231SDmitry Chagin #include <compat/linux/linux_time.h>
56ba9ef45bSMarcel Moolenaar #include <compat/linux/linux_util.h>
579b44bfc5SAlexander Leidinger #include <compat/linux/linux_emul.h>
5881338031SDmitry Chagin #include <compat/linux/linux_misc.h>
5981338031SDmitry Chagin 
606201a50dSDmitry Chagin static int	linux_pksignal(struct thread *td, int pid, int sig,
6181338031SDmitry Chagin 		    ksiginfo_t *ksi);
626201a50dSDmitry Chagin static int	linux_psignal(struct thread *td, int pid, int sig);
636201a50dSDmitry Chagin static int	linux_tdksignal(struct thread *td, lwpid_t tid,
646201a50dSDmitry Chagin 		    int tgid, int sig, ksiginfo_t *ksi);
656201a50dSDmitry Chagin static int	linux_tdsignal(struct thread *td, lwpid_t tid,
666201a50dSDmitry Chagin 		    int tgid, int sig);
67a6f85b12SDmitry Chagin static void	sicode_to_lsicode(int sig, int si_code, int *lsi_code);
68db4a1f33SDmitry Chagin static int	linux_common_rt_sigtimedwait(struct thread *,
69db4a1f33SDmitry Chagin 		    l_sigset_t *, struct timespec *, l_siginfo_t *,
70db4a1f33SDmitry Chagin 		    l_size_t);
71fe4ed1e7SDmitry Chagin 
72a1ebcbfbSPeter Wemm static void
linux_to_bsd_sigaction(l_sigaction_t * lsa,struct sigaction * bsa)735002a60fSMarcel Moolenaar linux_to_bsd_sigaction(l_sigaction_t *lsa, struct sigaction *bsa)
74d66a5066SPeter Wemm {
75d5629eb2SEdward Tomasz Napierala 	unsigned long flags;
76956d3333SMarcel Moolenaar 
77956d3333SMarcel Moolenaar 	linux_to_bsd_sigset(&lsa->lsa_mask, &bsa->sa_mask);
784af27623STim J. Robbins 	bsa->sa_handler = PTRIN(lsa->lsa_handler);
79d66a5066SPeter Wemm 	bsa->sa_flags = 0;
80d5629eb2SEdward Tomasz Napierala 
81d5629eb2SEdward Tomasz Napierala 	flags = lsa->lsa_flags;
82d5629eb2SEdward Tomasz Napierala 	if (lsa->lsa_flags & LINUX_SA_NOCLDSTOP) {
83d5629eb2SEdward Tomasz Napierala 		flags &= ~LINUX_SA_NOCLDSTOP;
84d66a5066SPeter Wemm 		bsa->sa_flags |= SA_NOCLDSTOP;
85d5629eb2SEdward Tomasz Napierala 	}
86d5629eb2SEdward Tomasz Napierala 	if (lsa->lsa_flags & LINUX_SA_NOCLDWAIT) {
87d5629eb2SEdward Tomasz Napierala 		flags &= ~LINUX_SA_NOCLDWAIT;
8806ebbe77SMarcel Moolenaar 		bsa->sa_flags |= SA_NOCLDWAIT;
89d5629eb2SEdward Tomasz Napierala 	}
90d5629eb2SEdward Tomasz Napierala 	if (lsa->lsa_flags & LINUX_SA_SIGINFO) {
91d5629eb2SEdward Tomasz Napierala 		flags &= ~LINUX_SA_SIGINFO;
9206ebbe77SMarcel Moolenaar 		bsa->sa_flags |= SA_SIGINFO;
93d5629eb2SEdward Tomasz Napierala #ifdef notyet
94d5629eb2SEdward Tomasz Napierala 		/*
95d5629eb2SEdward Tomasz Napierala 		 * XXX: We seem to be missing code to convert
96d5629eb2SEdward Tomasz Napierala 		 *      some of the fields in ucontext_t.
97d5629eb2SEdward Tomasz Napierala 		 */
98d5629eb2SEdward Tomasz Napierala 		linux_msg(curthread,
99d5629eb2SEdward Tomasz Napierala 		    "partially unsupported sigaction flag SA_SIGINFO");
100d5629eb2SEdward Tomasz Napierala #endif
101d5629eb2SEdward Tomasz Napierala 	}
102d5629eb2SEdward Tomasz Napierala 	if (lsa->lsa_flags & LINUX_SA_RESTORER) {
103d5629eb2SEdward Tomasz Napierala 		flags &= ~LINUX_SA_RESTORER;
1043eaf271dSEdward Tomasz Napierala 		/*
1053eaf271dSEdward Tomasz Napierala 		 * We ignore the lsa_restorer and always use our own signal
1063eaf271dSEdward Tomasz Napierala 		 * trampoline instead.  It looks like SA_RESTORER is obsolete
1073eaf271dSEdward Tomasz Napierala 		 * in Linux too - it doesn't seem to be used at all on arm64.
1083eaf271dSEdward Tomasz Napierala 		 * In any case: see Linux sigreturn(2).
1093eaf271dSEdward Tomasz Napierala 		 */
110d5629eb2SEdward Tomasz Napierala 	}
111d5629eb2SEdward Tomasz Napierala 	if (lsa->lsa_flags & LINUX_SA_ONSTACK) {
112d5629eb2SEdward Tomasz Napierala 		flags &= ~LINUX_SA_ONSTACK;
113d66a5066SPeter Wemm 		bsa->sa_flags |= SA_ONSTACK;
114d5629eb2SEdward Tomasz Napierala 	}
115d5629eb2SEdward Tomasz Napierala 	if (lsa->lsa_flags & LINUX_SA_RESTART) {
116d5629eb2SEdward Tomasz Napierala 		flags &= ~LINUX_SA_RESTART;
117d66a5066SPeter Wemm 		bsa->sa_flags |= SA_RESTART;
118d5629eb2SEdward Tomasz Napierala 	}
1199bc42c18SEdward Tomasz Napierala 	if (lsa->lsa_flags & LINUX_SA_INTERRUPT) {
1209bc42c18SEdward Tomasz Napierala 		flags &= ~LINUX_SA_INTERRUPT;
1219bc42c18SEdward Tomasz Napierala 		/* Documented to be a "historical no-op". */
1229bc42c18SEdward Tomasz Napierala 	}
123d5629eb2SEdward Tomasz Napierala 	if (lsa->lsa_flags & LINUX_SA_ONESHOT) {
124d5629eb2SEdward Tomasz Napierala 		flags &= ~LINUX_SA_ONESHOT;
125d66a5066SPeter Wemm 		bsa->sa_flags |= SA_RESETHAND;
126d5629eb2SEdward Tomasz Napierala 	}
127d5629eb2SEdward Tomasz Napierala 	if (lsa->lsa_flags & LINUX_SA_NOMASK) {
128d5629eb2SEdward Tomasz Napierala 		flags &= ~LINUX_SA_NOMASK;
129d66a5066SPeter Wemm 		bsa->sa_flags |= SA_NODEFER;
130d66a5066SPeter Wemm 	}
131d66a5066SPeter Wemm 
132d5629eb2SEdward Tomasz Napierala 	if (flags != 0)
133d5629eb2SEdward Tomasz Napierala 		linux_msg(curthread, "unsupported sigaction flag %#lx", flags);
134d5629eb2SEdward Tomasz Napierala }
135d5629eb2SEdward Tomasz Napierala 
136a1ebcbfbSPeter Wemm static void
bsd_to_linux_sigaction(struct sigaction * bsa,l_sigaction_t * lsa)1375002a60fSMarcel Moolenaar bsd_to_linux_sigaction(struct sigaction *bsa, l_sigaction_t *lsa)
138d66a5066SPeter Wemm {
139956d3333SMarcel Moolenaar 
140956d3333SMarcel Moolenaar 	bsd_to_linux_sigset(&bsa->sa_mask, &lsa->lsa_mask);
1411997c537SDavid E. O'Brien #ifdef COMPAT_LINUX32
1424af27623STim J. Robbins 	lsa->lsa_handler = (uintptr_t)bsa->sa_handler;
1434af27623STim J. Robbins #else
1448f437f44SMartin Cracauer 	lsa->lsa_handler = bsa->sa_handler;
1454af27623STim J. Robbins #endif
1464af27623STim J. Robbins 	lsa->lsa_restorer = 0;		/* unsupported */
1478f437f44SMartin Cracauer 	lsa->lsa_flags = 0;
148d66a5066SPeter Wemm 	if (bsa->sa_flags & SA_NOCLDSTOP)
1498f437f44SMartin Cracauer 		lsa->lsa_flags |= LINUX_SA_NOCLDSTOP;
15006ebbe77SMarcel Moolenaar 	if (bsa->sa_flags & SA_NOCLDWAIT)
15106ebbe77SMarcel Moolenaar 		lsa->lsa_flags |= LINUX_SA_NOCLDWAIT;
15206ebbe77SMarcel Moolenaar 	if (bsa->sa_flags & SA_SIGINFO)
15306ebbe77SMarcel Moolenaar 		lsa->lsa_flags |= LINUX_SA_SIGINFO;
154d66a5066SPeter Wemm 	if (bsa->sa_flags & SA_ONSTACK)
1558f437f44SMartin Cracauer 		lsa->lsa_flags |= LINUX_SA_ONSTACK;
156d66a5066SPeter Wemm 	if (bsa->sa_flags & SA_RESTART)
1578f437f44SMartin Cracauer 		lsa->lsa_flags |= LINUX_SA_RESTART;
158d66a5066SPeter Wemm 	if (bsa->sa_flags & SA_RESETHAND)
1598f437f44SMartin Cracauer 		lsa->lsa_flags |= LINUX_SA_ONESHOT;
160d66a5066SPeter Wemm 	if (bsa->sa_flags & SA_NODEFER)
1618f437f44SMartin Cracauer 		lsa->lsa_flags |= LINUX_SA_NOMASK;
162d66a5066SPeter Wemm }
163c21dee17SSøren Schmidt 
164ba9ef45bSMarcel Moolenaar int
linux_do_sigaction(struct thread * td,int linux_sig,l_sigaction_t * linux_nsa,l_sigaction_t * linux_osa)165b40ce416SJulian Elischer linux_do_sigaction(struct thread *td, int linux_sig, l_sigaction_t *linux_nsa,
1665002a60fSMarcel Moolenaar 		   l_sigaction_t *linux_osa)
16706ebbe77SMarcel Moolenaar {
168206a5d3aSIan Dowse 	struct sigaction act, oact, *nsa, *osa;
169206a5d3aSIan Dowse 	int error, sig;
17006ebbe77SMarcel Moolenaar 
171687c23beSAlexander Leidinger 	if (!LINUX_SIG_VALID(linux_sig))
172956d3333SMarcel Moolenaar 		return (EINVAL);
173*227d01c1SDmitry Chagin 	sig = linux_to_bsd_signal(linux_sig);
17406ebbe77SMarcel Moolenaar 
175206a5d3aSIan Dowse 	osa = (linux_osa != NULL) ? &oact : NULL;
176956d3333SMarcel Moolenaar 	if (linux_nsa != NULL) {
177206a5d3aSIan Dowse 		nsa = &act;
178ec99e322SMarcel Moolenaar 		linux_to_bsd_sigaction(linux_nsa, nsa);
17993107373SDmitry Chagin #ifdef KTRACE
18093107373SDmitry Chagin 		if (KTRPOINT(td, KTR_STRUCT))
18193107373SDmitry Chagin 			linux_ktrsigset(&linux_nsa->lsa_mask,
18293107373SDmitry Chagin 			    sizeof(linux_nsa->lsa_mask));
18393107373SDmitry Chagin #endif
184*227d01c1SDmitry Chagin 		if ((sig == SIGKILL || sig == SIGSTOP) &&
185*227d01c1SDmitry Chagin 		    nsa->sa_handler == SIG_DFL)
186*227d01c1SDmitry Chagin 			return (EINVAL);
187206a5d3aSIan Dowse 	} else
18806ebbe77SMarcel Moolenaar 		nsa = NULL;
189956d3333SMarcel Moolenaar 
190206a5d3aSIan Dowse 	error = kern_sigaction(td, sig, nsa, osa, 0);
19155731437SDmitry Chagin 	if (error != 0)
192956d3333SMarcel Moolenaar 		return (error);
19306ebbe77SMarcel Moolenaar 
19493107373SDmitry Chagin 	if (linux_osa != NULL) {
195ec99e322SMarcel Moolenaar 		bsd_to_linux_sigaction(osa, linux_osa);
19693107373SDmitry Chagin #ifdef KTRACE
19793107373SDmitry Chagin 		if (KTRPOINT(td, KTR_STRUCT))
19893107373SDmitry Chagin 			linux_ktrsigset(&linux_osa->lsa_mask,
19993107373SDmitry Chagin 			    sizeof(linux_osa->lsa_mask));
20093107373SDmitry Chagin #endif
20193107373SDmitry Chagin 	}
202956d3333SMarcel Moolenaar 	return (0);
20306ebbe77SMarcel Moolenaar }
20406ebbe77SMarcel Moolenaar 
20530c6d982SEdward Tomasz Napierala int
linux_sigaltstack(struct thread * td,struct linux_sigaltstack_args * uap)20630c6d982SEdward Tomasz Napierala linux_sigaltstack(struct thread *td, struct linux_sigaltstack_args *uap)
20730c6d982SEdward Tomasz Napierala {
20830c6d982SEdward Tomasz Napierala 	stack_t ss, oss;
20930c6d982SEdward Tomasz Napierala 	l_stack_t lss;
21030c6d982SEdward Tomasz Napierala 	int error;
21130c6d982SEdward Tomasz Napierala 
21230c6d982SEdward Tomasz Napierala 	memset(&lss, 0, sizeof(lss));
21330c6d982SEdward Tomasz Napierala 	LINUX_CTR2(sigaltstack, "%p, %p", uap->uss, uap->uoss);
21430c6d982SEdward Tomasz Napierala 
21530c6d982SEdward Tomasz Napierala 	if (uap->uss != NULL) {
2162722e515SDmitry Chagin 		error = copyin(uap->uss, &lss, sizeof(lss));
21730c6d982SEdward Tomasz Napierala 		if (error != 0)
21830c6d982SEdward Tomasz Napierala 			return (error);
21930c6d982SEdward Tomasz Napierala 
22030c6d982SEdward Tomasz Napierala 		ss.ss_sp = PTRIN(lss.ss_sp);
22130c6d982SEdward Tomasz Napierala 		ss.ss_size = lss.ss_size;
22230c6d982SEdward Tomasz Napierala 		ss.ss_flags = linux_to_bsd_sigaltstack(lss.ss_flags);
22330c6d982SEdward Tomasz Napierala 	}
22430c6d982SEdward Tomasz Napierala 	error = kern_sigaltstack(td, (uap->uss != NULL) ? &ss : NULL,
22530c6d982SEdward Tomasz Napierala 	    (uap->uoss != NULL) ? &oss : NULL);
22630c6d982SEdward Tomasz Napierala 	if (error == 0 && uap->uoss != NULL) {
22730c6d982SEdward Tomasz Napierala 		lss.ss_sp = PTROUT(oss.ss_sp);
22830c6d982SEdward Tomasz Napierala 		lss.ss_size = oss.ss_size;
22930c6d982SEdward Tomasz Napierala 		lss.ss_flags = bsd_to_linux_sigaltstack(oss.ss_flags);
2302722e515SDmitry Chagin 		error = copyout(&lss, uap->uoss, sizeof(lss));
23130c6d982SEdward Tomasz Napierala 	}
23230c6d982SEdward Tomasz Napierala 
23330c6d982SEdward Tomasz Napierala 	return (error);
23430c6d982SEdward Tomasz Napierala }
23530c6d982SEdward Tomasz Napierala 
2367f8f1d7fSDmitry Chagin #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
237c21dee17SSøren Schmidt int
linux_signal(struct thread * td,struct linux_signal_args * args)238b40ce416SJulian Elischer linux_signal(struct thread *td, struct linux_signal_args *args)
239d66a5066SPeter Wemm {
2405002a60fSMarcel Moolenaar 	l_sigaction_t nsa, osa;
241d66a5066SPeter Wemm 	int error;
242d66a5066SPeter Wemm 
24306ebbe77SMarcel Moolenaar 	nsa.lsa_handler = args->handler;
24406ebbe77SMarcel Moolenaar 	nsa.lsa_flags = LINUX_SA_ONESHOT | LINUX_SA_NOMASK;
245956d3333SMarcel Moolenaar 	LINUX_SIGEMPTYSET(nsa.lsa_mask);
246d66a5066SPeter Wemm 
247b40ce416SJulian Elischer 	error = linux_do_sigaction(td, args->sig, &nsa, &osa);
2484af27623STim J. Robbins 	td->td_retval[0] = (int)(intptr_t)osa.lsa_handler;
249d66a5066SPeter Wemm 
250956d3333SMarcel Moolenaar 	return (error);
251d66a5066SPeter Wemm }
2527f8f1d7fSDmitry Chagin #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
253d66a5066SPeter Wemm 
254c21dee17SSøren Schmidt int
linux_rt_sigaction(struct thread * td,struct linux_rt_sigaction_args * args)255b40ce416SJulian Elischer linux_rt_sigaction(struct thread *td, struct linux_rt_sigaction_args *args)
256c21dee17SSøren Schmidt {
2575002a60fSMarcel Moolenaar 	l_sigaction_t nsa, osa;
25806ebbe77SMarcel Moolenaar 	int error;
259c21dee17SSøren Schmidt 
2605002a60fSMarcel Moolenaar 	if (args->sigsetsize != sizeof(l_sigset_t))
261956d3333SMarcel Moolenaar 		return (EINVAL);
26206ebbe77SMarcel Moolenaar 
263956d3333SMarcel Moolenaar 	if (args->act != NULL) {
2642722e515SDmitry Chagin 		error = copyin(args->act, &nsa, sizeof(nsa));
26555731437SDmitry Chagin 		if (error != 0)
266956d3333SMarcel Moolenaar 			return (error);
26706ebbe77SMarcel Moolenaar 	}
26806ebbe77SMarcel Moolenaar 
269b40ce416SJulian Elischer 	error = linux_do_sigaction(td, args->sig,
27006ebbe77SMarcel Moolenaar 				   args->act ? &nsa : NULL,
27106ebbe77SMarcel Moolenaar 				   args->oact ? &osa : NULL);
27206ebbe77SMarcel Moolenaar 
27355731437SDmitry Chagin 	if (args->oact != NULL && error == 0)
2742722e515SDmitry Chagin 		error = copyout(&osa, args->oact, sizeof(osa));
27506ebbe77SMarcel Moolenaar 
276956d3333SMarcel Moolenaar 	return (error);
27706ebbe77SMarcel Moolenaar }
27806ebbe77SMarcel Moolenaar 
27906ebbe77SMarcel Moolenaar static int
linux_do_sigprocmask(struct thread * td,int how,sigset_t * new,l_sigset_t * old)2805e872c27SDmitry Chagin linux_do_sigprocmask(struct thread *td, int how, sigset_t *new,
2815002a60fSMarcel Moolenaar 		     l_sigset_t *old)
28206ebbe77SMarcel Moolenaar {
2835e872c27SDmitry Chagin 	sigset_t omask;
284216af822SJohn Baldwin 	int error;
28506ebbe77SMarcel Moolenaar 
286b40ce416SJulian Elischer 	td->td_retval[0] = 0;
287d66a5066SPeter Wemm 
28819dde5cdSJohn Baldwin 	switch (how) {
28919dde5cdSJohn Baldwin 	case LINUX_SIG_BLOCK:
29019dde5cdSJohn Baldwin 		how = SIG_BLOCK;
29119dde5cdSJohn Baldwin 		break;
29219dde5cdSJohn Baldwin 	case LINUX_SIG_UNBLOCK:
29319dde5cdSJohn Baldwin 		how = SIG_UNBLOCK;
29419dde5cdSJohn Baldwin 		break;
29519dde5cdSJohn Baldwin 	case LINUX_SIG_SETMASK:
29619dde5cdSJohn Baldwin 		how = SIG_SETMASK;
29719dde5cdSJohn Baldwin 		break;
29819dde5cdSJohn Baldwin 	default:
29919dde5cdSJohn Baldwin 		return (EINVAL);
30019dde5cdSJohn Baldwin 	}
3015e872c27SDmitry Chagin 	error = kern_sigprocmask(td, how, new, &omask, 0);
3022f7ed219SJohn Baldwin 	if (error == 0 && old != NULL)
303fe8cdcaeSJohn Baldwin 		bsd_to_linux_sigset(&omask, old);
30406ebbe77SMarcel Moolenaar 
305956d3333SMarcel Moolenaar 	return (error);
30606ebbe77SMarcel Moolenaar }
30706ebbe77SMarcel Moolenaar 
3087f8f1d7fSDmitry Chagin #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
30906ebbe77SMarcel Moolenaar int
linux_sigprocmask(struct thread * td,struct linux_sigprocmask_args * args)310b40ce416SJulian Elischer linux_sigprocmask(struct thread *td, struct linux_sigprocmask_args *args)
31106ebbe77SMarcel Moolenaar {
3125002a60fSMarcel Moolenaar 	l_osigset_t mask;
3135e872c27SDmitry Chagin 	l_sigset_t lset, oset;
3145e872c27SDmitry Chagin 	sigset_t set;
31506ebbe77SMarcel Moolenaar 	int error;
31606ebbe77SMarcel Moolenaar 
31706ebbe77SMarcel Moolenaar 	if (args->mask != NULL) {
3182722e515SDmitry Chagin 		error = copyin(args->mask, &mask, sizeof(mask));
31955731437SDmitry Chagin 		if (error != 0)
320956d3333SMarcel Moolenaar 			return (error);
3215e872c27SDmitry Chagin 		LINUX_SIGEMPTYSET(lset);
3225e872c27SDmitry Chagin 		lset.__mask = mask;
32393107373SDmitry Chagin #ifdef KTRACE
32493107373SDmitry Chagin 		if (KTRPOINT(td, KTR_STRUCT))
32593107373SDmitry Chagin 			linux_ktrsigset(&lset, sizeof(lset));
32693107373SDmitry Chagin #endif
3275e872c27SDmitry Chagin 		linux_to_bsd_sigset(&lset, &set);
32806ebbe77SMarcel Moolenaar 	}
32906ebbe77SMarcel Moolenaar 
330b40ce416SJulian Elischer 	error = linux_do_sigprocmask(td, args->how,
331956d3333SMarcel Moolenaar 				     args->mask ? &set : NULL,
332956d3333SMarcel Moolenaar 				     args->omask ? &oset : NULL);
33306ebbe77SMarcel Moolenaar 
33455731437SDmitry Chagin 	if (args->omask != NULL && error == 0) {
33593107373SDmitry Chagin #ifdef KTRACE
33693107373SDmitry Chagin 		if (KTRPOINT(td, KTR_STRUCT))
33793107373SDmitry Chagin 			linux_ktrsigset(&oset, sizeof(oset));
33893107373SDmitry Chagin #endif
3394ab7403bSDmitry Chagin 		mask = oset.__mask;
3402722e515SDmitry Chagin 		error = copyout(&mask, args->omask, sizeof(mask));
34106ebbe77SMarcel Moolenaar 	}
34206ebbe77SMarcel Moolenaar 
343956d3333SMarcel Moolenaar 	return (error);
34406ebbe77SMarcel Moolenaar }
3457f8f1d7fSDmitry Chagin #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
34606ebbe77SMarcel Moolenaar 
34706ebbe77SMarcel Moolenaar int
linux_rt_sigprocmask(struct thread * td,struct linux_rt_sigprocmask_args * args)348b40ce416SJulian Elischer linux_rt_sigprocmask(struct thread *td, struct linux_rt_sigprocmask_args *args)
34906ebbe77SMarcel Moolenaar {
3505e872c27SDmitry Chagin 	l_sigset_t oset;
3515e872c27SDmitry Chagin 	sigset_t set, *pset;
35206ebbe77SMarcel Moolenaar 	int error;
35306ebbe77SMarcel Moolenaar 
35493107373SDmitry Chagin 	error = linux_copyin_sigset(td, args->mask, args->sigsetsize,
3555e872c27SDmitry Chagin 	    &set, &pset);
3565e872c27SDmitry Chagin 	if (error != 0)
357340f4a8dSEd Maste 		return (EINVAL);
35806ebbe77SMarcel Moolenaar 
3595e872c27SDmitry Chagin 	error = linux_do_sigprocmask(td, args->how, pset,
360956d3333SMarcel Moolenaar 				     args->omask ? &oset : NULL);
36106ebbe77SMarcel Moolenaar 
36293107373SDmitry Chagin 	if (args->omask != NULL && error == 0) {
36393107373SDmitry Chagin #ifdef KTRACE
36493107373SDmitry Chagin 		if (KTRPOINT(td, KTR_STRUCT))
36593107373SDmitry Chagin 			linux_ktrsigset(&oset, sizeof(oset));
36693107373SDmitry Chagin #endif
3672722e515SDmitry Chagin 		error = copyout(&oset, args->omask, sizeof(oset));
36893107373SDmitry Chagin 	}
36906ebbe77SMarcel Moolenaar 
370956d3333SMarcel Moolenaar 	return (error);
371c21dee17SSøren Schmidt }
372c21dee17SSøren Schmidt 
3737f8f1d7fSDmitry Chagin #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
374c21dee17SSøren Schmidt int
linux_sgetmask(struct thread * td,struct linux_sgetmask_args * args)375b40ce416SJulian Elischer linux_sgetmask(struct thread *td, struct linux_sgetmask_args *args)
376c21dee17SSøren Schmidt {
377b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
3785002a60fSMarcel Moolenaar 	l_sigset_t mask;
379956d3333SMarcel Moolenaar 
380216af822SJohn Baldwin 	PROC_LOCK(p);
3814093529dSJeff Roberson 	bsd_to_linux_sigset(&td->td_sigmask, &mask);
382216af822SJohn Baldwin 	PROC_UNLOCK(p);
3834ab7403bSDmitry Chagin 	td->td_retval[0] = mask.__mask;
38493107373SDmitry Chagin #ifdef KTRACE
38593107373SDmitry Chagin 	if (KTRPOINT(td, KTR_STRUCT))
38693107373SDmitry Chagin 		linux_ktrsigset(&mask, sizeof(mask));
38793107373SDmitry Chagin #endif
388956d3333SMarcel Moolenaar 	return (0);
389c21dee17SSøren Schmidt }
390c21dee17SSøren Schmidt 
391c21dee17SSøren Schmidt int
linux_ssetmask(struct thread * td,struct linux_ssetmask_args * args)392b40ce416SJulian Elischer linux_ssetmask(struct thread *td, struct linux_ssetmask_args *args)
393c21dee17SSøren Schmidt {
394b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
3955002a60fSMarcel Moolenaar 	l_sigset_t lset;
396956d3333SMarcel Moolenaar 	sigset_t bset;
397c21dee17SSøren Schmidt 
398216af822SJohn Baldwin 	PROC_LOCK(p);
3994093529dSJeff Roberson 	bsd_to_linux_sigset(&td->td_sigmask, &lset);
4004ab7403bSDmitry Chagin 	td->td_retval[0] = lset.__mask;
401956d3333SMarcel Moolenaar 	LINUX_SIGEMPTYSET(lset);
4024ab7403bSDmitry Chagin 	lset.__mask = args->mask;
403956d3333SMarcel Moolenaar 	linux_to_bsd_sigset(&lset, &bset);
40493107373SDmitry Chagin #ifdef KTRACE
40593107373SDmitry Chagin 	if (KTRPOINT(td, KTR_STRUCT))
40693107373SDmitry Chagin 		linux_ktrsigset(&lset, sizeof(lset));
40793107373SDmitry Chagin #endif
4084093529dSJeff Roberson 	td->td_sigmask = bset;
4094093529dSJeff Roberson 	SIG_CANTMASK(td->td_sigmask);
4104093529dSJeff Roberson 	signotify(td);
411216af822SJohn Baldwin 	PROC_UNLOCK(p);
412956d3333SMarcel Moolenaar 	return (0);
413c21dee17SSøren Schmidt }
414c21dee17SSøren Schmidt 
415c21dee17SSøren Schmidt int
linux_sigpending(struct thread * td,struct linux_sigpending_args * args)416b40ce416SJulian Elischer linux_sigpending(struct thread *td, struct linux_sigpending_args *args)
417c21dee17SSøren Schmidt {
418b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
419956d3333SMarcel Moolenaar 	sigset_t bset;
4205002a60fSMarcel Moolenaar 	l_sigset_t lset;
4215002a60fSMarcel Moolenaar 	l_osigset_t mask;
422c21dee17SSøren Schmidt 
423216af822SJohn Baldwin 	PROC_LOCK(p);
4241d9c5696SJuli Mallett 	bset = p->p_siglist;
4254093529dSJeff Roberson 	SIGSETOR(bset, td->td_siglist);
4264093529dSJeff Roberson 	SIGSETAND(bset, td->td_sigmask);
427216af822SJohn Baldwin 	PROC_UNLOCK(p);
4289d8643ecSJohn Baldwin 	bsd_to_linux_sigset(&bset, &lset);
42993107373SDmitry Chagin #ifdef KTRACE
43093107373SDmitry Chagin 	if (KTRPOINT(td, KTR_STRUCT))
43193107373SDmitry Chagin 		linux_ktrsigset(&lset, sizeof(lset));
43293107373SDmitry Chagin #endif
4334ab7403bSDmitry Chagin 	mask = lset.__mask;
434956d3333SMarcel Moolenaar 	return (copyout(&mask, args->mask, sizeof(mask)));
435c21dee17SSøren Schmidt }
4367f8f1d7fSDmitry Chagin #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
43717138b61SAlexander Leidinger 
43817138b61SAlexander Leidinger /*
43917138b61SAlexander Leidinger  * MPSAFE
44017138b61SAlexander Leidinger  */
44117138b61SAlexander Leidinger int
linux_rt_sigpending(struct thread * td,struct linux_rt_sigpending_args * args)44217138b61SAlexander Leidinger linux_rt_sigpending(struct thread *td, struct linux_rt_sigpending_args *args)
44317138b61SAlexander Leidinger {
44417138b61SAlexander Leidinger 	struct proc *p = td->td_proc;
44517138b61SAlexander Leidinger 	sigset_t bset;
44617138b61SAlexander Leidinger 	l_sigset_t lset;
44717138b61SAlexander Leidinger 
44817138b61SAlexander Leidinger 	if (args->sigsetsize > sizeof(lset))
449340f4a8dSEd Maste 		return (EINVAL);
45017138b61SAlexander Leidinger 		/* NOT REACHED */
45117138b61SAlexander Leidinger 
45217138b61SAlexander Leidinger 	PROC_LOCK(p);
45317138b61SAlexander Leidinger 	bset = p->p_siglist;
45417138b61SAlexander Leidinger 	SIGSETOR(bset, td->td_siglist);
45517138b61SAlexander Leidinger 	SIGSETAND(bset, td->td_sigmask);
45617138b61SAlexander Leidinger 	PROC_UNLOCK(p);
45717138b61SAlexander Leidinger 	bsd_to_linux_sigset(&bset, &lset);
45893107373SDmitry Chagin #ifdef KTRACE
45993107373SDmitry Chagin 	if (KTRPOINT(td, KTR_STRUCT))
46093107373SDmitry Chagin 		linux_ktrsigset(&lset, sizeof(lset));
46193107373SDmitry Chagin #endif
46217138b61SAlexander Leidinger 	return (copyout(&lset, args->set, args->sigsetsize));
46317138b61SAlexander Leidinger }
464c21dee17SSøren Schmidt 
465c9447c75SAlexander Leidinger int
linux_rt_sigtimedwait(struct thread * td,struct linux_rt_sigtimedwait_args * args)466c9447c75SAlexander Leidinger linux_rt_sigtimedwait(struct thread *td,
467c9447c75SAlexander Leidinger 	struct linux_rt_sigtimedwait_args *args)
468c9447c75SAlexander Leidinger {
469c9447c75SAlexander Leidinger 	struct timespec ts, *tsa;
470db4a1f33SDmitry Chagin 	int error;
471c9447c75SAlexander Leidinger 
472c9447c75SAlexander Leidinger 	if (args->timeout) {
473707e567aSDmitry Chagin 		error = linux_get_timespec(&ts, args->timeout);
4740f8dab45SDmitry Chagin 		if (error != 0)
4750f8dab45SDmitry Chagin 			return (error);
476c9447c75SAlexander Leidinger 		tsa = &ts;
4770f8dab45SDmitry Chagin 	} else
4780f8dab45SDmitry Chagin 		tsa = NULL;
4790f8dab45SDmitry Chagin 
480db4a1f33SDmitry Chagin 	return (linux_common_rt_sigtimedwait(td, args->mask, tsa,
481db4a1f33SDmitry Chagin 	    args->ptr, args->sigsetsize));
482db4a1f33SDmitry Chagin }
483db4a1f33SDmitry Chagin 
484db4a1f33SDmitry Chagin static int
linux_common_rt_sigtimedwait(struct thread * td,l_sigset_t * mask,struct timespec * tsa,l_siginfo_t * ptr,l_size_t sigsetsize)485db4a1f33SDmitry Chagin linux_common_rt_sigtimedwait(struct thread *td, l_sigset_t *mask,
486db4a1f33SDmitry Chagin     struct timespec *tsa, l_siginfo_t *ptr, l_size_t sigsetsize)
487db4a1f33SDmitry Chagin {
488db4a1f33SDmitry Chagin 	int error, sig;
489db4a1f33SDmitry Chagin 	sigset_t bset;
490db4a1f33SDmitry Chagin 	l_siginfo_t lsi;
491db4a1f33SDmitry Chagin 	ksiginfo_t ksi;
492db4a1f33SDmitry Chagin 
49393107373SDmitry Chagin 	error = linux_copyin_sigset(td, mask, sigsetsize, &bset, NULL);
4943923e632SDmitry Chagin 	if (error != 0)
495db4a1f33SDmitry Chagin 		return (error);
496db4a1f33SDmitry Chagin 
497db4a1f33SDmitry Chagin 	ksiginfo_init(&ksi);
498f4e80108SDmitry Chagin 	error = kern_sigtimedwait(td, bset, &ksi, tsa);
49955731437SDmitry Chagin 	if (error != 0)
500c9447c75SAlexander Leidinger 		return (error);
501c9447c75SAlexander Leidinger 
502f4e80108SDmitry Chagin 	sig = bsd_to_linux_signal(ksi.ksi_signo);
503f3481dd9SDmitry Chagin 
504db4a1f33SDmitry Chagin 	if (ptr) {
505f4e80108SDmitry Chagin 		memset(&lsi, 0, sizeof(lsi));
506f4e80108SDmitry Chagin 		siginfo_to_lsiginfo(&ksi.ksi_info, &lsi, sig);
507db4a1f33SDmitry Chagin 		error = copyout(&lsi, ptr, sizeof(lsi));
508c9447c75SAlexander Leidinger 	}
509f3481dd9SDmitry Chagin 	if (error == 0)
510f3481dd9SDmitry Chagin 		td->td_retval[0] = sig;
511c9447c75SAlexander Leidinger 
512c9447c75SAlexander Leidinger 	return (error);
513c9447c75SAlexander Leidinger }
514c9447c75SAlexander Leidinger 
515db4a1f33SDmitry Chagin #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
516db4a1f33SDmitry Chagin int
linux_rt_sigtimedwait_time64(struct thread * td,struct linux_rt_sigtimedwait_time64_args * args)517db4a1f33SDmitry Chagin linux_rt_sigtimedwait_time64(struct thread *td,
518db4a1f33SDmitry Chagin 	struct linux_rt_sigtimedwait_time64_args *args)
519db4a1f33SDmitry Chagin {
520db4a1f33SDmitry Chagin 	struct timespec ts, *tsa;
521db4a1f33SDmitry Chagin 	int error;
522db4a1f33SDmitry Chagin 
523db4a1f33SDmitry Chagin 	if (args->timeout) {
524707e567aSDmitry Chagin 		error = linux_get_timespec64(&ts, args->timeout);
525db4a1f33SDmitry Chagin 		if (error != 0)
526db4a1f33SDmitry Chagin 			return (error);
527db4a1f33SDmitry Chagin 		tsa = &ts;
528db4a1f33SDmitry Chagin 	} else
529db4a1f33SDmitry Chagin 		tsa = NULL;
530db4a1f33SDmitry Chagin 
531db4a1f33SDmitry Chagin 	return (linux_common_rt_sigtimedwait(td, args->mask, tsa,
532db4a1f33SDmitry Chagin 	    args->ptr, args->sigsetsize));
533db4a1f33SDmitry Chagin }
534db4a1f33SDmitry Chagin #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
535db4a1f33SDmitry Chagin 
536c21dee17SSøren Schmidt int
linux_kill(struct thread * td,struct linux_kill_args * args)537b40ce416SJulian Elischer linux_kill(struct thread *td, struct linux_kill_args *args)
538c21dee17SSøren Schmidt {
5396201a50dSDmitry Chagin 	int sig;
540c21dee17SSøren Schmidt 
541956d3333SMarcel Moolenaar 	/*
542956d3333SMarcel Moolenaar 	 * Allow signal 0 as a means to check for privileges
543956d3333SMarcel Moolenaar 	 */
54464742216SAlexander Leidinger 	if (!LINUX_SIG_VALID(args->signum) && args->signum != 0)
5459a6a64d3SDmitry Chagin 		return (EINVAL);
546956d3333SMarcel Moolenaar 
5474ab7403bSDmitry Chagin 	if (args->signum > 0)
5486201a50dSDmitry Chagin 		sig = linux_to_bsd_signal(args->signum);
549956d3333SMarcel Moolenaar 	else
5506201a50dSDmitry Chagin 		sig = 0;
551956d3333SMarcel Moolenaar 
5526201a50dSDmitry Chagin 	if (args->pid > PID_MAX)
5536201a50dSDmitry Chagin 		return (linux_psignal(td, args->pid, sig));
5546201a50dSDmitry Chagin 	else
5556201a50dSDmitry Chagin 		return (kern_kill(td, args->pid, sig));
556aa8b2011SKonstantin Belousov }
557aa8b2011SKonstantin Belousov 
5589b44bfc5SAlexander Leidinger int
linux_tgkill(struct thread * td,struct linux_tgkill_args * args)5599b44bfc5SAlexander Leidinger linux_tgkill(struct thread *td, struct linux_tgkill_args *args)
5609b44bfc5SAlexander Leidinger {
56181338031SDmitry Chagin 	int sig;
5629b44bfc5SAlexander Leidinger 
563aa8b2011SKonstantin Belousov 	if (args->pid <= 0 || args->tgid <=0)
564aa8b2011SKonstantin Belousov 		return (EINVAL);
5659b44bfc5SAlexander Leidinger 
56681338031SDmitry Chagin 	/*
56781338031SDmitry Chagin 	 * Allow signal 0 as a means to check for privileges
56881338031SDmitry Chagin 	 */
56981338031SDmitry Chagin 	if (!LINUX_SIG_VALID(args->sig) && args->sig != 0)
57081338031SDmitry Chagin 		return (EINVAL);
57181338031SDmitry Chagin 
5724ab7403bSDmitry Chagin 	if (args->sig > 0)
5734ab7403bSDmitry Chagin 		sig = linux_to_bsd_signal(args->sig);
57481338031SDmitry Chagin 	else
5754ab7403bSDmitry Chagin 		sig = 0;
57681338031SDmitry Chagin 
5776201a50dSDmitry Chagin 	return (linux_tdsignal(td, args->pid, args->tgid, sig));
5789b44bfc5SAlexander Leidinger }
5799b44bfc5SAlexander Leidinger 
58081338031SDmitry Chagin /*
58181338031SDmitry Chagin  * Deprecated since 2.5.75. Replaced by tgkill().
58281338031SDmitry Chagin  */
5839b44bfc5SAlexander Leidinger int
linux_tkill(struct thread * td,struct linux_tkill_args * args)5849b44bfc5SAlexander Leidinger linux_tkill(struct thread *td, struct linux_tkill_args *args)
5859b44bfc5SAlexander Leidinger {
58681338031SDmitry Chagin 	int sig;
58781338031SDmitry Chagin 
588aa8b2011SKonstantin Belousov 	if (args->tid <= 0)
589aa8b2011SKonstantin Belousov 		return (EINVAL);
5909b44bfc5SAlexander Leidinger 
59181338031SDmitry Chagin 	if (!LINUX_SIG_VALID(args->sig))
59281338031SDmitry Chagin 		return (EINVAL);
59381338031SDmitry Chagin 
5944ab7403bSDmitry Chagin 	sig = linux_to_bsd_signal(args->sig);
59581338031SDmitry Chagin 
5966201a50dSDmitry Chagin 	return (linux_tdsignal(td, args->tid, -1, sig));
597aa8b2011SKonstantin Belousov }
598aa8b2011SKonstantin Belousov 
599a6f85b12SDmitry Chagin static int
sigfpe_sicode2lsicode(int si_code)600a6f85b12SDmitry Chagin sigfpe_sicode2lsicode(int si_code)
601a6f85b12SDmitry Chagin {
602a6f85b12SDmitry Chagin 
603a6f85b12SDmitry Chagin 	switch (si_code) {
604a6f85b12SDmitry Chagin 	case FPE_INTOVF:
605a6f85b12SDmitry Chagin 		return (LINUX_FPE_INTOVF);
606a6f85b12SDmitry Chagin 	case FPE_INTDIV:
607a6f85b12SDmitry Chagin 		return (LINUX_FPE_INTDIV);
608a6f85b12SDmitry Chagin 	case FPE_FLTIDO:
609a6f85b12SDmitry Chagin 		return (LINUX_FPE_FLTUNK);
610a6f85b12SDmitry Chagin 	default:
611a6f85b12SDmitry Chagin 		return (si_code);
612a6f85b12SDmitry Chagin 	}
613a6f85b12SDmitry Chagin }
614a6f85b12SDmitry Chagin 
615a6f85b12SDmitry Chagin static int
sigbus_sicode2lsicode(int si_code)616a6f85b12SDmitry Chagin sigbus_sicode2lsicode(int si_code)
617a6f85b12SDmitry Chagin {
618a6f85b12SDmitry Chagin 
619a6f85b12SDmitry Chagin 	switch (si_code) {
620a6f85b12SDmitry Chagin 	case BUS_OOMERR:
621a6f85b12SDmitry Chagin 		return (LINUX_BUS_MCEERR_AR);
622a6f85b12SDmitry Chagin 	default:
623a6f85b12SDmitry Chagin 		return (si_code);
624a6f85b12SDmitry Chagin 	}
625a6f85b12SDmitry Chagin }
626a6f85b12SDmitry Chagin 
627a6f85b12SDmitry Chagin static int
sigsegv_sicode2lsicode(int si_code)628a6f85b12SDmitry Chagin sigsegv_sicode2lsicode(int si_code)
629a6f85b12SDmitry Chagin {
630a6f85b12SDmitry Chagin 
631a6f85b12SDmitry Chagin 	switch (si_code) {
632a6f85b12SDmitry Chagin 	case SEGV_PKUERR:
633a6f85b12SDmitry Chagin 		return (LINUX_SEGV_PKUERR);
634a6f85b12SDmitry Chagin 	default:
635a6f85b12SDmitry Chagin 		return (si_code);
636a6f85b12SDmitry Chagin 	}
637a6f85b12SDmitry Chagin }
638a6f85b12SDmitry Chagin 
639a6f85b12SDmitry Chagin static int
sigtrap_sicode2lsicode(int si_code)640a6f85b12SDmitry Chagin sigtrap_sicode2lsicode(int si_code)
641a6f85b12SDmitry Chagin {
642a6f85b12SDmitry Chagin 
643a6f85b12SDmitry Chagin 	switch (si_code) {
644a6f85b12SDmitry Chagin 	case TRAP_DTRACE:
645a6f85b12SDmitry Chagin 		return (LINUX_TRAP_TRACE);
646a6f85b12SDmitry Chagin 	case TRAP_CAP:
647a6f85b12SDmitry Chagin 		return (LINUX_TRAP_UNK);
648a6f85b12SDmitry Chagin 	default:
649a6f85b12SDmitry Chagin 		return (si_code);
650a6f85b12SDmitry Chagin 	}
651a6f85b12SDmitry Chagin }
652a6f85b12SDmitry Chagin 
653fe4ed1e7SDmitry Chagin static void
sicode_to_lsicode(int sig,int si_code,int * lsi_code)654a6f85b12SDmitry Chagin sicode_to_lsicode(int sig, int si_code, int *lsi_code)
655fe4ed1e7SDmitry Chagin {
656fe4ed1e7SDmitry Chagin 
657fe4ed1e7SDmitry Chagin 	switch (si_code) {
658fe4ed1e7SDmitry Chagin 	case SI_USER:
659fe4ed1e7SDmitry Chagin 		*lsi_code = LINUX_SI_USER;
660fe4ed1e7SDmitry Chagin 		break;
661fe4ed1e7SDmitry Chagin 	case SI_KERNEL:
662fe4ed1e7SDmitry Chagin 		*lsi_code = LINUX_SI_KERNEL;
663fe4ed1e7SDmitry Chagin 		break;
664fe4ed1e7SDmitry Chagin 	case SI_QUEUE:
665fe4ed1e7SDmitry Chagin 		*lsi_code = LINUX_SI_QUEUE;
666fe4ed1e7SDmitry Chagin 		break;
667fe4ed1e7SDmitry Chagin 	case SI_TIMER:
668fe4ed1e7SDmitry Chagin 		*lsi_code = LINUX_SI_TIMER;
669fe4ed1e7SDmitry Chagin 		break;
670fe4ed1e7SDmitry Chagin 	case SI_MESGQ:
671fe4ed1e7SDmitry Chagin 		*lsi_code = LINUX_SI_MESGQ;
672fe4ed1e7SDmitry Chagin 		break;
673fe4ed1e7SDmitry Chagin 	case SI_ASYNCIO:
674fe4ed1e7SDmitry Chagin 		*lsi_code = LINUX_SI_ASYNCIO;
675fe4ed1e7SDmitry Chagin 		break;
676fe4ed1e7SDmitry Chagin 	case SI_LWP:
677fe4ed1e7SDmitry Chagin 		*lsi_code = LINUX_SI_TKILL;
678fe4ed1e7SDmitry Chagin 		break;
679fe4ed1e7SDmitry Chagin 	default:
680a6f85b12SDmitry Chagin 		switch (sig) {
681a6f85b12SDmitry Chagin 		case LINUX_SIGFPE:
682a6f85b12SDmitry Chagin 			*lsi_code = sigfpe_sicode2lsicode(si_code);
683a6f85b12SDmitry Chagin 			break;
684a6f85b12SDmitry Chagin 		case LINUX_SIGBUS:
685a6f85b12SDmitry Chagin 			*lsi_code = sigbus_sicode2lsicode(si_code);
686a6f85b12SDmitry Chagin 			break;
687a6f85b12SDmitry Chagin 		case LINUX_SIGSEGV:
688a6f85b12SDmitry Chagin 			*lsi_code = sigsegv_sicode2lsicode(si_code);
689a6f85b12SDmitry Chagin 			break;
690a6f85b12SDmitry Chagin 		case LINUX_SIGTRAP:
691a6f85b12SDmitry Chagin 			*lsi_code = sigtrap_sicode2lsicode(si_code);
692a6f85b12SDmitry Chagin 			break;
693a6f85b12SDmitry Chagin 		default:
694fe4ed1e7SDmitry Chagin 			*lsi_code = si_code;
695fe4ed1e7SDmitry Chagin 			break;
696fe4ed1e7SDmitry Chagin 		}
697a6f85b12SDmitry Chagin 		break;
698a6f85b12SDmitry Chagin 	}
699fe4ed1e7SDmitry Chagin }
700fe4ed1e7SDmitry Chagin 
701fe4ed1e7SDmitry Chagin void
siginfo_to_lsiginfo(const siginfo_t * si,l_siginfo_t * lsi,l_int sig)702fe4ed1e7SDmitry Chagin siginfo_to_lsiginfo(const siginfo_t *si, l_siginfo_t *lsi, l_int sig)
703fe4ed1e7SDmitry Chagin {
704fe4ed1e7SDmitry Chagin 
705d3d3b76cSGordon Bergling 	/* sig already converted */
706fe4ed1e7SDmitry Chagin 	lsi->lsi_signo = sig;
707a6f85b12SDmitry Chagin 	sicode_to_lsicode(sig, si->si_code, &lsi->lsi_code);
708fe4ed1e7SDmitry Chagin 
709fe4ed1e7SDmitry Chagin 	switch (si->si_code) {
710fe4ed1e7SDmitry Chagin 	case SI_LWP:
711fe4ed1e7SDmitry Chagin 		lsi->lsi_pid = si->si_pid;
712fe4ed1e7SDmitry Chagin 		lsi->lsi_uid = si->si_uid;
713fe4ed1e7SDmitry Chagin 		break;
714fe4ed1e7SDmitry Chagin 
715fe4ed1e7SDmitry Chagin 	case SI_TIMER:
716fe4ed1e7SDmitry Chagin 		lsi->lsi_int = si->si_value.sival_int;
717fe4ed1e7SDmitry Chagin 		lsi->lsi_ptr = PTROUT(si->si_value.sival_ptr);
718fe4ed1e7SDmitry Chagin 		lsi->lsi_tid = si->si_timerid;
719fe4ed1e7SDmitry Chagin 		break;
720fe4ed1e7SDmitry Chagin 
721fe4ed1e7SDmitry Chagin 	case SI_QUEUE:
722fe4ed1e7SDmitry Chagin 		lsi->lsi_pid = si->si_pid;
723fe4ed1e7SDmitry Chagin 		lsi->lsi_uid = si->si_uid;
724fe4ed1e7SDmitry Chagin 		lsi->lsi_ptr = PTROUT(si->si_value.sival_ptr);
725fe4ed1e7SDmitry Chagin 		break;
726fe4ed1e7SDmitry Chagin 
727fe4ed1e7SDmitry Chagin 	case SI_ASYNCIO:
728fe4ed1e7SDmitry Chagin 		lsi->lsi_int = si->si_value.sival_int;
729fe4ed1e7SDmitry Chagin 		lsi->lsi_ptr = PTROUT(si->si_value.sival_ptr);
730fe4ed1e7SDmitry Chagin 		break;
731fe4ed1e7SDmitry Chagin 
732fe4ed1e7SDmitry Chagin 	default:
733aa8b2011SKonstantin Belousov 		switch (sig) {
734aa8b2011SKonstantin Belousov 		case LINUX_SIGPOLL:
735aa8b2011SKonstantin Belousov 			/* XXX si_fd? */
736fe4ed1e7SDmitry Chagin 			lsi->lsi_band = si->si_band;
737aa8b2011SKonstantin Belousov 			break;
738fe4ed1e7SDmitry Chagin 
739aa8b2011SKonstantin Belousov 		case LINUX_SIGCHLD:
740fe4ed1e7SDmitry Chagin 			lsi->lsi_errno = 0;
741fe4ed1e7SDmitry Chagin 			lsi->lsi_pid = si->si_pid;
742fe4ed1e7SDmitry Chagin 			lsi->lsi_uid = si->si_uid;
743fe4ed1e7SDmitry Chagin 
744c8c93b15SEdward Tomasz Napierala 			if (si->si_code == CLD_STOPPED || si->si_code == CLD_KILLED)
7454ab7403bSDmitry Chagin 				lsi->lsi_status = bsd_to_linux_signal(si->si_status);
746fe4ed1e7SDmitry Chagin 			else if (si->si_code == CLD_CONTINUED)
7474ab7403bSDmitry Chagin 				lsi->lsi_status = bsd_to_linux_signal(SIGCONT);
748fe4ed1e7SDmitry Chagin 			else
749fe4ed1e7SDmitry Chagin 				lsi->lsi_status = si->si_status;
750aa8b2011SKonstantin Belousov 			break;
751fe4ed1e7SDmitry Chagin 
752aa8b2011SKonstantin Belousov 		case LINUX_SIGBUS:
753aa8b2011SKonstantin Belousov 		case LINUX_SIGILL:
754aa8b2011SKonstantin Belousov 		case LINUX_SIGFPE:
755aa8b2011SKonstantin Belousov 		case LINUX_SIGSEGV:
756fe4ed1e7SDmitry Chagin 			lsi->lsi_addr = PTROUT(si->si_addr);
757aa8b2011SKonstantin Belousov 			break;
758fe4ed1e7SDmitry Chagin 
759aa8b2011SKonstantin Belousov 		default:
760fe4ed1e7SDmitry Chagin 			lsi->lsi_pid = si->si_pid;
761fe4ed1e7SDmitry Chagin 			lsi->lsi_uid = si->si_uid;
762fe4ed1e7SDmitry Chagin 			if (sig >= LINUX_SIGRTMIN) {
763fe4ed1e7SDmitry Chagin 				lsi->lsi_int = si->si_value.sival_int;
764fe4ed1e7SDmitry Chagin 				lsi->lsi_ptr = PTROUT(si->si_value.sival_ptr);
765fe4ed1e7SDmitry Chagin 			}
766aa8b2011SKonstantin Belousov 			break;
767aa8b2011SKonstantin Belousov 		}
768fe4ed1e7SDmitry Chagin 		break;
76909d6cb0aSDmitry Chagin 	}
7709b44bfc5SAlexander Leidinger }
7717ac9766dSDmitry Chagin 
772794328fbSDmitry Chagin static int
lsiginfo_to_siginfo(struct thread * td,const l_siginfo_t * lsi,siginfo_t * si,int sig)7739c1045ffSDmitry Chagin lsiginfo_to_siginfo(struct thread *td, const l_siginfo_t *lsi,
7749c1045ffSDmitry Chagin     siginfo_t *si, int sig)
7757ac9766dSDmitry Chagin {
7767ac9766dSDmitry Chagin 
7779c1045ffSDmitry Chagin 	switch (lsi->lsi_code) {
7789c1045ffSDmitry Chagin 	case LINUX_SI_TKILL:
779e185d83fSDmitry Chagin 		if (linux_kernver(td) >= LINUX_KERNVER(2,6,39)) {
7809c1045ffSDmitry Chagin 			linux_msg(td, "SI_TKILL forbidden since 2.6.39");
7819c1045ffSDmitry Chagin 			return (EPERM);
7829c1045ffSDmitry Chagin 		}
7839c1045ffSDmitry Chagin 		si->si_code = SI_LWP;
7849c1045ffSDmitry Chagin 	case LINUX_SI_QUEUE:
7859c1045ffSDmitry Chagin 		si->si_code = SI_QUEUE;
7869c1045ffSDmitry Chagin 		break;
7879c1045ffSDmitry Chagin 	case LINUX_SI_TIMER:
7889c1045ffSDmitry Chagin 		si->si_code = SI_TIMER;
7899c1045ffSDmitry Chagin 		break;
7909c1045ffSDmitry Chagin 	case LINUX_SI_MESGQ:
7919c1045ffSDmitry Chagin 		si->si_code = SI_MESGQ;
7929c1045ffSDmitry Chagin 		break;
7939c1045ffSDmitry Chagin 	case LINUX_SI_ASYNCIO:
7949c1045ffSDmitry Chagin 		si->si_code = SI_ASYNCIO;
7959c1045ffSDmitry Chagin 		break;
7969c1045ffSDmitry Chagin 	default:
7979c1045ffSDmitry Chagin 		si->si_code = lsi->lsi_code;
7989c1045ffSDmitry Chagin 		break;
7999c1045ffSDmitry Chagin 	}
8009c1045ffSDmitry Chagin 
8019c1045ffSDmitry Chagin 	si->si_signo = sig;
8029c1045ffSDmitry Chagin 	si->si_pid = td->td_proc->p_pid;
8039c1045ffSDmitry Chagin 	si->si_uid = td->td_ucred->cr_ruid;
8049c1045ffSDmitry Chagin 	si->si_value.sival_ptr = PTRIN(lsi->lsi_value.sival_ptr);
8059c1045ffSDmitry Chagin 	return (0);
8067ac9766dSDmitry Chagin }
8077ac9766dSDmitry Chagin 
8087ac9766dSDmitry Chagin int
linux_rt_sigqueueinfo(struct thread * td,struct linux_rt_sigqueueinfo_args * args)8097ac9766dSDmitry Chagin linux_rt_sigqueueinfo(struct thread *td, struct linux_rt_sigqueueinfo_args *args)
8107ac9766dSDmitry Chagin {
8117ac9766dSDmitry Chagin 	l_siginfo_t linfo;
8127ac9766dSDmitry Chagin 	ksiginfo_t ksi;
8137ac9766dSDmitry Chagin 	int error;
8147ac9766dSDmitry Chagin 	int sig;
8157ac9766dSDmitry Chagin 
8167ac9766dSDmitry Chagin 	if (!LINUX_SIG_VALID(args->sig))
8177ac9766dSDmitry Chagin 		return (EINVAL);
8187ac9766dSDmitry Chagin 
8197ac9766dSDmitry Chagin 	error = copyin(args->info, &linfo, sizeof(linfo));
8207ac9766dSDmitry Chagin 	if (error != 0)
8217ac9766dSDmitry Chagin 		return (error);
8227ac9766dSDmitry Chagin 
8237ac9766dSDmitry Chagin 	if (linfo.lsi_code >= 0)
8249c1045ffSDmitry Chagin 		/* SI_USER, SI_KERNEL */
8257ac9766dSDmitry Chagin 		return (EPERM);
8267ac9766dSDmitry Chagin 
8274ab7403bSDmitry Chagin 	sig = linux_to_bsd_signal(args->sig);
8289c1045ffSDmitry Chagin 	ksiginfo_init(&ksi);
8299c1045ffSDmitry Chagin 	error = lsiginfo_to_siginfo(td, &linfo, &ksi.ksi_info, sig);
8309c1045ffSDmitry Chagin 	if (error != 0)
8319c1045ffSDmitry Chagin 		return (error);
8327ac9766dSDmitry Chagin 
8336201a50dSDmitry Chagin 	return (linux_pksignal(td, args->pid, sig, &ksi));
8347ac9766dSDmitry Chagin }
835486a06bdSDmitry Chagin 
836486a06bdSDmitry Chagin int
linux_rt_tgsigqueueinfo(struct thread * td,struct linux_rt_tgsigqueueinfo_args * args)837486a06bdSDmitry Chagin linux_rt_tgsigqueueinfo(struct thread *td, struct linux_rt_tgsigqueueinfo_args *args)
838486a06bdSDmitry Chagin {
839486a06bdSDmitry Chagin 	l_siginfo_t linfo;
840486a06bdSDmitry Chagin 	ksiginfo_t ksi;
841486a06bdSDmitry Chagin 	int error;
842486a06bdSDmitry Chagin 	int sig;
843486a06bdSDmitry Chagin 
844486a06bdSDmitry Chagin 	if (!LINUX_SIG_VALID(args->sig))
845486a06bdSDmitry Chagin 		return (EINVAL);
846486a06bdSDmitry Chagin 
847486a06bdSDmitry Chagin 	error = copyin(args->uinfo, &linfo, sizeof(linfo));
848486a06bdSDmitry Chagin 	if (error != 0)
849486a06bdSDmitry Chagin 		return (error);
850486a06bdSDmitry Chagin 
851486a06bdSDmitry Chagin 	if (linfo.lsi_code >= 0)
852486a06bdSDmitry Chagin 		return (EPERM);
853486a06bdSDmitry Chagin 
8549c1045ffSDmitry Chagin 	sig = linux_to_bsd_signal(args->sig);
8559c1045ffSDmitry Chagin 	ksiginfo_init(&ksi);
8569c1045ffSDmitry Chagin 	error = lsiginfo_to_siginfo(td, &linfo, &ksi.ksi_info, sig);
8579c1045ffSDmitry Chagin 	if (error != 0)
8589c1045ffSDmitry Chagin 		return (error);
8599c1045ffSDmitry Chagin 
8606201a50dSDmitry Chagin 	return (linux_tdksignal(td, args->tid, args->tgid, sig, &ksi));
861486a06bdSDmitry Chagin }
86272f7ddb5SEdward Tomasz Napierala 
86372f7ddb5SEdward Tomasz Napierala int
linux_rt_sigsuspend(struct thread * td,struct linux_rt_sigsuspend_args * uap)86472f7ddb5SEdward Tomasz Napierala linux_rt_sigsuspend(struct thread *td, struct linux_rt_sigsuspend_args *uap)
86572f7ddb5SEdward Tomasz Napierala {
86672f7ddb5SEdward Tomasz Napierala 	sigset_t sigmask;
86772f7ddb5SEdward Tomasz Napierala 	int error;
86872f7ddb5SEdward Tomasz Napierala 
86993107373SDmitry Chagin 	error = linux_copyin_sigset(td, uap->newset, uap->sigsetsize,
8703923e632SDmitry Chagin 	    &sigmask, NULL);
87172f7ddb5SEdward Tomasz Napierala 	if (error != 0)
87272f7ddb5SEdward Tomasz Napierala 		return (error);
87372f7ddb5SEdward Tomasz Napierala 
87472f7ddb5SEdward Tomasz Napierala 	return (kern_sigsuspend(td, sigmask));
87572f7ddb5SEdward Tomasz Napierala }
8766201a50dSDmitry Chagin 
8776201a50dSDmitry Chagin static int
linux_tdksignal(struct thread * td,lwpid_t tid,int tgid,int sig,ksiginfo_t * ksi)8786201a50dSDmitry Chagin linux_tdksignal(struct thread *td, lwpid_t tid, int tgid, int sig,
8796201a50dSDmitry Chagin     ksiginfo_t *ksi)
8806201a50dSDmitry Chagin {
8816201a50dSDmitry Chagin 	struct thread *tdt;
8826201a50dSDmitry Chagin 	struct proc *p;
8836201a50dSDmitry Chagin 	int error;
8846201a50dSDmitry Chagin 
8856201a50dSDmitry Chagin 	tdt = linux_tdfind(td, tid, tgid);
8866201a50dSDmitry Chagin 	if (tdt == NULL)
8876201a50dSDmitry Chagin 		return (ESRCH);
8886201a50dSDmitry Chagin 
8896201a50dSDmitry Chagin 	p = tdt->td_proc;
8906201a50dSDmitry Chagin 	AUDIT_ARG_SIGNUM(sig);
8916201a50dSDmitry Chagin 	AUDIT_ARG_PID(p->p_pid);
8926201a50dSDmitry Chagin 	AUDIT_ARG_PROCESS(p);
8936201a50dSDmitry Chagin 
8946201a50dSDmitry Chagin 	error = p_cansignal(td, p, sig);
8956201a50dSDmitry Chagin 	if (error != 0 || sig == 0)
8966201a50dSDmitry Chagin 		goto out;
8976201a50dSDmitry Chagin 
8986201a50dSDmitry Chagin 	tdksignal(tdt, sig, ksi);
8996201a50dSDmitry Chagin 
9006201a50dSDmitry Chagin out:
9016201a50dSDmitry Chagin 	PROC_UNLOCK(p);
9026201a50dSDmitry Chagin 	return (error);
9036201a50dSDmitry Chagin }
9046201a50dSDmitry Chagin 
9056201a50dSDmitry Chagin static int
linux_tdsignal(struct thread * td,lwpid_t tid,int tgid,int sig)9066201a50dSDmitry Chagin linux_tdsignal(struct thread *td, lwpid_t tid, int tgid, int sig)
9076201a50dSDmitry Chagin {
9086201a50dSDmitry Chagin 	ksiginfo_t ksi;
9096201a50dSDmitry Chagin 
9106201a50dSDmitry Chagin 	ksiginfo_init(&ksi);
9116201a50dSDmitry Chagin 	ksi.ksi_signo = sig;
9126201a50dSDmitry Chagin 	ksi.ksi_code = SI_LWP;
9136201a50dSDmitry Chagin 	ksi.ksi_pid = td->td_proc->p_pid;
9146201a50dSDmitry Chagin 	ksi.ksi_uid = td->td_proc->p_ucred->cr_ruid;
9156201a50dSDmitry Chagin 	return (linux_tdksignal(td, tid, tgid, sig, &ksi));
9166201a50dSDmitry Chagin }
9176201a50dSDmitry Chagin 
9186201a50dSDmitry Chagin static int
linux_pksignal(struct thread * td,int pid,int sig,ksiginfo_t * ksi)9196201a50dSDmitry Chagin linux_pksignal(struct thread *td, int pid, int sig, ksiginfo_t *ksi)
9206201a50dSDmitry Chagin {
9216201a50dSDmitry Chagin 	struct thread *tdt;
9226201a50dSDmitry Chagin 	struct proc *p;
9236201a50dSDmitry Chagin 	int error;
9246201a50dSDmitry Chagin 
9256201a50dSDmitry Chagin 	tdt = linux_tdfind(td, pid, -1);
9266201a50dSDmitry Chagin 	if (tdt == NULL)
9276201a50dSDmitry Chagin 		return (ESRCH);
9286201a50dSDmitry Chagin 
9296201a50dSDmitry Chagin 	p = tdt->td_proc;
9306201a50dSDmitry Chagin 	AUDIT_ARG_SIGNUM(sig);
9316201a50dSDmitry Chagin 	AUDIT_ARG_PID(p->p_pid);
9326201a50dSDmitry Chagin 	AUDIT_ARG_PROCESS(p);
9336201a50dSDmitry Chagin 
9346201a50dSDmitry Chagin 	error = p_cansignal(td, p, sig);
9356201a50dSDmitry Chagin 	if (error != 0 || sig == 0)
9366201a50dSDmitry Chagin 		goto out;
9376201a50dSDmitry Chagin 
9386201a50dSDmitry Chagin 	pksignal(p, sig, ksi);
9396201a50dSDmitry Chagin 
9406201a50dSDmitry Chagin out:
9416201a50dSDmitry Chagin 	PROC_UNLOCK(p);
9426201a50dSDmitry Chagin 	return (error);
9436201a50dSDmitry Chagin }
9446201a50dSDmitry Chagin 
9456201a50dSDmitry Chagin static int
linux_psignal(struct thread * td,int pid,int sig)9466201a50dSDmitry Chagin linux_psignal(struct thread *td, int pid, int sig)
9476201a50dSDmitry Chagin {
9486201a50dSDmitry Chagin 	ksiginfo_t ksi;
9496201a50dSDmitry Chagin 
9506201a50dSDmitry Chagin 	ksiginfo_init(&ksi);
9516201a50dSDmitry Chagin 	ksi.ksi_signo = sig;
9526201a50dSDmitry Chagin 	ksi.ksi_code = SI_LWP;
9536201a50dSDmitry Chagin 	ksi.ksi_pid = td->td_proc->p_pid;
9546201a50dSDmitry Chagin 	ksi.ksi_uid = td->td_proc->p_ucred->cr_ruid;
9556201a50dSDmitry Chagin 	return (linux_pksignal(td, pid, sig, &ksi));
9566201a50dSDmitry Chagin }
9573923e632SDmitry Chagin 
9583923e632SDmitry Chagin int
linux_copyin_sigset(struct thread * td,l_sigset_t * lset,l_size_t sigsetsize,sigset_t * set,sigset_t ** pset)95993107373SDmitry Chagin linux_copyin_sigset(struct thread *td, l_sigset_t *lset,
96093107373SDmitry Chagin     l_size_t sigsetsize, sigset_t *set, sigset_t **pset)
9613923e632SDmitry Chagin {
9623923e632SDmitry Chagin 	l_sigset_t lmask;
9633923e632SDmitry Chagin 	int error;
9643923e632SDmitry Chagin 
9653923e632SDmitry Chagin 	if (sigsetsize != sizeof(l_sigset_t))
9663923e632SDmitry Chagin 		return (EINVAL);
9673923e632SDmitry Chagin 	if (lset != NULL) {
9682722e515SDmitry Chagin 		error = copyin(lset, &lmask, sizeof(lmask));
9693923e632SDmitry Chagin 		if (error != 0)
9703923e632SDmitry Chagin 			return (error);
9713923e632SDmitry Chagin 		linux_to_bsd_sigset(&lmask, set);
9723923e632SDmitry Chagin 		if (pset != NULL)
9733923e632SDmitry Chagin 			*pset = set;
97493107373SDmitry Chagin #ifdef KTRACE
97593107373SDmitry Chagin 		if (KTRPOINT(td, KTR_STRUCT))
97693107373SDmitry Chagin 			linux_ktrsigset(&lmask, sizeof(lmask));
97793107373SDmitry Chagin #endif
9783923e632SDmitry Chagin 	} else if (pset != NULL)
9793923e632SDmitry Chagin 		*pset = NULL;
9803923e632SDmitry Chagin 	return (0);
9813923e632SDmitry Chagin }
982