1/*	$NetBSD: linux_signal.c,v 1.74 2011/11/18 15:45:47 christos Exp $	*/
2
3/*-
4 * Copyright (c) 1995, 1998 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Frank van der Linden and Eric Haszlakiewicz.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31/*
32 * heavily from: svr4_signal.c,v 1.7 1995/01/09 01:04:21 christos Exp
33 */
34
35/*
36 *   Functions in multiarch:
37 *	linux_sys_signal	: linux_sig_notalpha.c
38 *	linux_sys_siggetmask	: linux_sig_notalpha.c
39 *	linux_sys_sigsetmask	: linux_sig_notalpha.c
40 *	linux_sys_pause		: linux_sig_notalpha.c
41 *	linux_sys_sigaction	: linux_sigaction.c
42 *
43 */
44
45/*
46 *   Unimplemented:
47 *	linux_sys_rt_sigtimedwait	: sigsuspend w/timeout.
48 */
49
50#include <sys/cdefs.h>
51__KERNEL_RCSID(0, "$NetBSD: linux_signal.c,v 1.74 2011/11/18 15:45:47 christos Exp $");
52
53#define COMPAT_LINUX 1
54
55#include <sys/param.h>
56#include <sys/systm.h>
57#include <sys/namei.h>
58#include <sys/proc.h>
59#include <sys/filedesc.h>
60#include <sys/ioctl.h>
61#include <sys/mount.h>
62#include <sys/kernel.h>
63#include <sys/signal.h>
64#include <sys/signalvar.h>
65#include <sys/malloc.h>
66#include <sys/wait.h>
67
68#include <sys/syscallargs.h>
69
70#include <compat/linux/common/linux_types.h>
71#include <compat/linux/common/linux_signal.h>
72#include <compat/linux/common/linux_emuldata.h>
73#include <compat/linux/common/linux_siginfo.h>
74#include <compat/linux/common/linux_sigevent.h>
75#include <compat/linux/common/linux_util.h>
76#include <compat/linux/common/linux_ipc.h>
77#include <compat/linux/common/linux_sem.h>
78#include <compat/linux/common/linux_errno.h>
79#include <compat/linux/common/linux_sched.h>
80
81#include <compat/linux/linux_syscallargs.h>
82
83/* Locally used defines (in bsd<->linux conversion functions): */
84#define	linux_sigemptyset(s)	memset((s), 0, sizeof(*(s)))
85#define	linux_sigismember(s, n)	((s)->sig[((n) - 1) / LINUX__NSIG_BPW]	\
86					& (1L << ((n) - 1) % LINUX__NSIG_BPW))
87#define	linux_sigaddset(s, n)	((s)->sig[((n) - 1) / LINUX__NSIG_BPW]	\
88					|= (1L << ((n) - 1) % LINUX__NSIG_BPW))
89
90#ifdef DEBUG_LINUX
91#define DPRINTF(a)	uprintf a
92#else
93#define DPRINTF(a)
94#endif
95
96extern const int native_to_linux_signo[];
97extern const int linux_to_native_signo[];
98
99/*
100 * Convert between Linux and BSD signal sets.
101 */
102#if LINUX__NSIG_WORDS > 1
103void
104linux_old_extra_to_native_sigset(sigset_t *bss, const linux_old_sigset_t *lss, const unsigned long *extra)
105{
106	linux_sigset_t lsnew;
107
108	/* convert old sigset to new sigset */
109	linux_sigemptyset(&lsnew);
110	lsnew.sig[0] = *lss;
111	if (extra)
112		memcpy(&lsnew.sig[1], extra,
113		    sizeof(linux_sigset_t) - sizeof(linux_old_sigset_t));
114
115	linux_to_native_sigset(bss, &lsnew);
116}
117
118void
119native_to_linux_old_extra_sigset(linux_old_sigset_t *lss, unsigned long *extra, const sigset_t *bss)
120{
121	linux_sigset_t lsnew;
122
123	native_to_linux_sigset(&lsnew, bss);
124
125	/* convert new sigset to old sigset */
126	*lss = lsnew.sig[0];
127	if (extra)
128		memcpy(extra, &lsnew.sig[1],
129		    sizeof(linux_sigset_t) - sizeof(linux_old_sigset_t));
130}
131#endif /* LINUX__NSIG_WORDS > 1 */
132
133void
134linux_to_native_sigset(sigset_t *bss, const linux_sigset_t *lss)
135{
136	int i, newsig;
137
138	sigemptyset(bss);
139	for (i = 1; i < LINUX__NSIG; i++) {
140		if (linux_sigismember(lss, i)) {
141			newsig = linux_to_native_signo[i];
142			if (newsig)
143				sigaddset(bss, newsig);
144		}
145	}
146}
147
148void
149native_to_linux_sigset(linux_sigset_t *lss, const sigset_t *bss)
150{
151	int i, newsig;
152
153	linux_sigemptyset(lss);
154	for (i = 1; i < NSIG; i++) {
155		if (sigismember(bss, i)) {
156			newsig = native_to_linux_signo[i];
157			if (newsig)
158				linux_sigaddset(lss, newsig);
159		}
160	}
161}
162
163void
164native_to_linux_siginfo(linux_siginfo_t *lsi, const struct _ksiginfo *ksi)
165{
166	memset(lsi, 0, sizeof(*lsi));
167
168	lsi->lsi_signo = native_to_linux_signo[ksi->_signo];
169	lsi->lsi_errno = native_to_linux_errno[ksi->_errno];
170	lsi->lsi_code = native_to_linux_si_code(ksi->_code);
171
172	switch (ksi->_code) {
173	case SI_NOINFO:
174		break;
175
176	case SI_USER:
177		lsi->lsi_pid = ksi->_reason._rt._pid;
178		lsi->lsi_uid = ksi->_reason._rt._uid;
179		if (lsi->lsi_signo == LINUX_SIGALRM ||
180		    lsi->lsi_signo >= LINUX_SIGRTMIN)
181			lsi->lsi_value.sival_ptr =
182			    ksi->_reason._rt._value.sival_ptr;
183		break;
184
185	case SI_TIMER:
186	case SI_QUEUE:
187		lsi->lsi_uid = ksi->_reason._rt._uid;
188		lsi->lsi_uid = ksi->_reason._rt._uid;
189		lsi->lsi_value.sival_ptr = ksi->_reason._rt._value.sival_ptr;
190		break;
191
192	case SI_ASYNCIO:
193	case SI_MESGQ:
194		lsi->lsi_value.sival_ptr = ksi->_reason._rt._value.sival_ptr;
195		break;
196
197	default:
198		switch (ksi->_signo) {
199		case SIGCHLD:
200			lsi->lsi_uid = ksi->_reason._child._uid;
201			lsi->lsi_pid = ksi->_reason._child._pid;
202			lsi->lsi_status = native_to_linux_si_status(
203			    ksi->_code, ksi->_reason._child._status);
204			lsi->lsi_utime = ksi->_reason._child._utime;
205			lsi->lsi_stime = ksi->_reason._child._stime;
206			break;
207
208		case SIGILL:
209		case SIGFPE:
210		case SIGSEGV:
211		case SIGBUS:
212		case SIGTRAP:
213			lsi->lsi_addr = ksi->_reason._fault._addr;
214			break;
215
216		case SIGIO:
217			lsi->lsi_fd = ksi->_reason._poll._fd;
218			lsi->lsi_band = ksi->_reason._poll._band;
219			break;
220		default:
221			break;
222		}
223	}
224}
225
226unsigned int
227native_to_linux_sigflags(const int bsf)
228{
229	unsigned int lsf = 0;
230	if ((bsf & SA_NOCLDSTOP) != 0)
231		lsf |= LINUX_SA_NOCLDSTOP;
232	if ((bsf & SA_NOCLDWAIT) != 0)
233		lsf |= LINUX_SA_NOCLDWAIT;
234	if ((bsf & SA_ONSTACK) != 0)
235		lsf |= LINUX_SA_ONSTACK;
236	if ((bsf & SA_RESTART) != 0)
237		lsf |= LINUX_SA_RESTART;
238	if ((bsf & SA_NODEFER) != 0)
239		lsf |= LINUX_SA_NOMASK;
240	if ((bsf & SA_RESETHAND) != 0)
241		lsf |= LINUX_SA_ONESHOT;
242	if ((bsf & SA_SIGINFO) != 0)
243		lsf |= LINUX_SA_SIGINFO;
244	return lsf;
245}
246
247int
248linux_to_native_sigflags(const unsigned long lsf)
249{
250	int bsf = 0;
251	if ((lsf & LINUX_SA_NOCLDSTOP) != 0)
252		bsf |= SA_NOCLDSTOP;
253	if ((lsf & LINUX_SA_NOCLDWAIT) != 0)
254		bsf |= SA_NOCLDWAIT;
255	if ((lsf & LINUX_SA_ONSTACK) != 0)
256		bsf |= SA_ONSTACK;
257	if ((lsf & LINUX_SA_RESTART) != 0)
258		bsf |= SA_RESTART;
259	if ((lsf & LINUX_SA_ONESHOT) != 0)
260		bsf |= SA_RESETHAND;
261	if ((lsf & LINUX_SA_NOMASK) != 0)
262		bsf |= SA_NODEFER;
263	if ((lsf & LINUX_SA_SIGINFO) != 0)
264		bsf |= SA_SIGINFO;
265	if ((lsf & ~LINUX_SA_ALLBITS) != 0) {
266		DPRINTF(("linux_old_to_native_sigflags: "
267		    "%lx extra bits ignored\n", lsf));
268	}
269	return bsf;
270}
271
272/*
273 * Convert between Linux and BSD sigaction structures.
274 */
275void
276linux_old_to_native_sigaction(struct sigaction *bsa, const struct linux_old_sigaction *lsa)
277{
278	bsa->sa_handler = lsa->linux_sa_handler;
279	linux_old_to_native_sigset(&bsa->sa_mask, &lsa->linux_sa_mask);
280	bsa->sa_flags = linux_to_native_sigflags(lsa->linux_sa_flags);
281}
282
283void
284native_to_linux_old_sigaction(struct linux_old_sigaction *lsa, const struct sigaction *bsa)
285{
286	lsa->linux_sa_handler = bsa->sa_handler;
287	native_to_linux_old_sigset(&lsa->linux_sa_mask, &bsa->sa_mask);
288	lsa->linux_sa_flags = native_to_linux_sigflags(bsa->sa_flags);
289#ifndef __alpha__
290	lsa->linux_sa_restorer = NULL;
291#endif
292}
293
294/* ...and the new sigaction conversion funcs. */
295void
296linux_to_native_sigaction(struct sigaction *bsa, const struct linux_sigaction *lsa)
297{
298	bsa->sa_handler = lsa->linux_sa_handler;
299	linux_to_native_sigset(&bsa->sa_mask, &lsa->linux_sa_mask);
300	bsa->sa_flags = linux_to_native_sigflags(lsa->linux_sa_flags);
301}
302
303void
304native_to_linux_sigaction(struct linux_sigaction *lsa, const struct sigaction *bsa)
305{
306	lsa->linux_sa_handler = bsa->sa_handler;
307	native_to_linux_sigset(&lsa->linux_sa_mask, &bsa->sa_mask);
308	lsa->linux_sa_flags = native_to_linux_sigflags(bsa->sa_flags);
309#ifndef __alpha__
310	lsa->linux_sa_restorer = NULL;
311#endif
312}
313
314/* ----------------------------------------------------------------------- */
315
316/*
317 * The Linux sigaction() system call. Do the usual conversions,
318 * and just call sigaction(). Some flags and values are silently
319 * ignored (see above).
320 */
321int
322linux_sys_rt_sigaction(struct lwp *l, const struct linux_sys_rt_sigaction_args *uap, register_t *retval)
323{
324	/* {
325		syscallarg(int) signum;
326		syscallarg(const struct linux_sigaction *) nsa;
327		syscallarg(struct linux_sigaction *) osa;
328		syscallarg(size_t) sigsetsize;
329	} */
330	struct linux_sigaction nlsa, olsa;
331	struct sigaction nbsa, obsa;
332	int error, sig;
333	void *tramp = NULL;
334	int vers = 0;
335#if defined __amd64__
336	struct sigacts *ps = l->l_proc->p_sigacts;
337#endif
338
339	if (SCARG(uap, sigsetsize) != sizeof(linux_sigset_t))
340		return (EINVAL);
341
342	if (SCARG(uap, nsa)) {
343		error = copyin(SCARG(uap, nsa), &nlsa, sizeof(nlsa));
344		if (error)
345			return (error);
346		linux_to_native_sigaction(&nbsa, &nlsa);
347	}
348
349	sig = SCARG(uap, signum);
350	if (sig < 0 || sig >= LINUX__NSIG)
351		return (EINVAL);
352	if (sig > 0 && !linux_to_native_signo[sig]) {
353		/* Pretend that we did something useful for unknown signals. */
354		obsa.sa_handler = SIG_IGN;
355		sigemptyset(&obsa.sa_mask);
356		obsa.sa_flags = 0;
357	} else {
358#if defined __amd64__
359		if (nlsa.linux_sa_flags & LINUX_SA_RESTORER) {
360			if ((tramp = nlsa.linux_sa_restorer) != NULL)
361				vers = 2; /* XXX arch dependent */
362		}
363#endif
364
365		error = sigaction1(l, linux_to_native_signo[sig],
366		    SCARG(uap, nsa) ? &nbsa : NULL,
367		    SCARG(uap, osa) ? &obsa : NULL,
368		    tramp, vers);
369		if (error)
370			return (error);
371	}
372	if (SCARG(uap, osa)) {
373		native_to_linux_sigaction(&olsa, &obsa);
374
375#if defined __amd64__
376		if (ps->sa_sigdesc[sig].sd_vers != 0) {
377			olsa.linux_sa_restorer = ps->sa_sigdesc[sig].sd_tramp;
378			olsa.linux_sa_flags |= LINUX_SA_RESTORER;
379		}
380#endif
381
382		error = copyout(&olsa, SCARG(uap, osa), sizeof(olsa));
383		if (error)
384			return (error);
385	}
386	return (0);
387}
388
389int
390linux_sigprocmask1(struct lwp *l, int how, const linux_old_sigset_t *set, linux_old_sigset_t *oset)
391{
392	struct proc *p = l->l_proc;
393	linux_old_sigset_t nlss, olss;
394	sigset_t nbss, obss;
395	int error;
396
397	switch (how) {
398	case LINUX_SIG_BLOCK:
399		how = SIG_BLOCK;
400		break;
401	case LINUX_SIG_UNBLOCK:
402		how = SIG_UNBLOCK;
403		break;
404	case LINUX_SIG_SETMASK:
405		how = SIG_SETMASK;
406		break;
407	default:
408		return (EINVAL);
409	}
410
411	if (set) {
412		error = copyin(set, &nlss, sizeof(nlss));
413		if (error)
414			return (error);
415		linux_old_to_native_sigset(&nbss, &nlss);
416	}
417	mutex_enter(p->p_lock);
418	error = sigprocmask1(l, how,
419	    set ? &nbss : NULL, oset ? &obss : NULL);
420	mutex_exit(p->p_lock);
421	if (error)
422		return (error);
423	if (oset) {
424		native_to_linux_old_sigset(&olss, &obss);
425		error = copyout(&olss, oset, sizeof(olss));
426		if (error)
427			return (error);
428	}
429	return (error);
430}
431
432int
433linux_sys_rt_sigprocmask(struct lwp *l, const struct linux_sys_rt_sigprocmask_args *uap, register_t *retval)
434{
435	/* {
436		syscallarg(int) how;
437		syscallarg(const linux_sigset_t *) set;
438		syscallarg(linux_sigset_t *) oset;
439		syscallarg(size_t) sigsetsize;
440	} */
441	linux_sigset_t nlss, olss, *oset;
442	const linux_sigset_t *set;
443	struct proc *p = l->l_proc;
444	sigset_t nbss, obss;
445	int error, how;
446
447	if (SCARG(uap, sigsetsize) != sizeof(linux_sigset_t))
448		return (EINVAL);
449
450	switch (SCARG(uap, how)) {
451	case LINUX_SIG_BLOCK:
452		how = SIG_BLOCK;
453		break;
454	case LINUX_SIG_UNBLOCK:
455		how = SIG_UNBLOCK;
456		break;
457	case LINUX_SIG_SETMASK:
458		how = SIG_SETMASK;
459		break;
460	default:
461		return (EINVAL);
462	}
463
464	set = SCARG(uap, set);
465	oset = SCARG(uap, oset);
466
467	if (set) {
468		error = copyin(set, &nlss, sizeof(nlss));
469		if (error)
470			return (error);
471		linux_to_native_sigset(&nbss, &nlss);
472	}
473	mutex_enter(p->p_lock);
474	error = sigprocmask1(l, how,
475	    set ? &nbss : NULL, oset ? &obss : NULL);
476	mutex_exit(p->p_lock);
477	if (!error && oset) {
478		native_to_linux_sigset(&olss, &obss);
479		error = copyout(&olss, oset, sizeof(olss));
480	}
481	return (error);
482}
483
484int
485linux_sys_rt_sigpending(struct lwp *l, const struct linux_sys_rt_sigpending_args *uap, register_t *retval)
486{
487	/* {
488		syscallarg(linux_sigset_t *) set;
489		syscallarg(size_t) sigsetsize;
490	} */
491	sigset_t bss;
492	linux_sigset_t lss;
493
494	if (SCARG(uap, sigsetsize) != sizeof(linux_sigset_t))
495		return (EINVAL);
496
497	sigpending1(l, &bss);
498	native_to_linux_sigset(&lss, &bss);
499	return copyout(&lss, SCARG(uap, set), sizeof(lss));
500}
501
502#ifndef __amd64__
503int
504linux_sys_sigpending(struct lwp *l, const struct linux_sys_sigpending_args *uap, register_t *retval)
505{
506	/* {
507		syscallarg(linux_old_sigset_t *) mask;
508	} */
509	sigset_t bss;
510	linux_old_sigset_t lss;
511
512	sigpending1(l, &bss);
513	native_to_linux_old_sigset(&lss, &bss);
514	return copyout(&lss, SCARG(uap, set), sizeof(lss));
515}
516
517int
518linux_sys_sigsuspend(struct lwp *l, const struct linux_sys_sigsuspend_args *uap, register_t *retval)
519{
520	/* {
521		syscallarg(void *) restart;
522		syscallarg(int) oldmask;
523		syscallarg(int) mask;
524	} */
525	linux_old_sigset_t lss;
526	sigset_t bss;
527
528	lss = SCARG(uap, mask);
529	linux_old_to_native_sigset(&bss, &lss);
530	return (sigsuspend1(l, &bss));
531}
532#endif /* __amd64__ */
533
534int
535linux_sys_rt_sigsuspend(struct lwp *l, const struct linux_sys_rt_sigsuspend_args *uap, register_t *retval)
536{
537	/* {
538		syscallarg(linux_sigset_t *) unewset;
539		syscallarg(size_t) sigsetsize;
540	} */
541	linux_sigset_t lss;
542	sigset_t bss;
543	int error;
544
545	if (SCARG(uap, sigsetsize) != sizeof(linux_sigset_t))
546		return (EINVAL);
547
548	error = copyin(SCARG(uap, unewset), &lss, sizeof(linux_sigset_t));
549	if (error)
550		return (error);
551
552	linux_to_native_sigset(&bss, &lss);
553
554	return (sigsuspend1(l, &bss));
555}
556
557static int
558fetchss(const void *u, void *s, size_t len)
559{
560	int error;
561	linux_sigset_t lss;
562
563	if ((error = copyin(u, &lss, sizeof(lss))) != 0)
564		return error;
565
566	linux_to_native_sigset(s, &lss);
567	return 0;
568}
569
570static int
571fetchts(const void *u, void *s, size_t len)
572{
573	int error;
574	struct linux_timespec lts;
575
576	if ((error = copyin(u, &lts, sizeof(lts))) != 0)
577		return error;
578
579	linux_to_native_timespec(s, &lts);
580	return 0;
581}
582
583static int
584fakestorets(const void *u, void *s, size_t len)
585{
586	/* Do nothing, sigtimedwait does not alter timeout like ours */
587	return 0;
588}
589
590static int
591storeinfo(const void *s, void *u, size_t len)
592{
593	struct linux_siginfo lsi;
594
595	native_to_linux_siginfo(&lsi, &((const siginfo_t *)s)->_info);
596	return copyout(&lsi, u, sizeof(lsi));
597}
598
599int
600linux_sys_rt_sigtimedwait(struct lwp *l,
601    const struct linux_sys_rt_sigtimedwait_args *uap, register_t *retval)
602{
603	/* {
604		syscallarg(const linux_sigset_t *) set;
605		syscallarg(linux_siginfo_t *) info);
606		syscallarg(const struct linux_timespec *) timeout;
607	} */
608
609	return sigtimedwait1(l, (const struct sys_____sigtimedwait50_args *)uap,
610	    retval, fetchss, storeinfo, fetchts, fakestorets);
611}
612
613/*
614 * Once more: only a signal conversion is needed.
615 * Note: also used as sys_rt_queueinfo.  The info field is ignored.
616 */
617int
618linux_sys_rt_queueinfo(struct lwp *l, const struct linux_sys_rt_queueinfo_args *uap, register_t *retval)
619{
620	/*
621		syscallarg(int) pid;
622		syscallarg(int) signum;
623		syscallarg(linix_siginfo_t *) uinfo;
624	*/
625	int error;
626	linux_siginfo_t info;
627
628	error = copyin(SCARG(uap, uinfo), &info, sizeof(info));
629	if (error)
630		return error;
631	if (info.lsi_code >= 0)
632		return EPERM;
633
634	/* XXX To really implement this we need to	*/
635	/* XXX keep a list of queued signals somewhere.	*/
636	return (linux_sys_kill(l, (const void *)uap, retval));
637}
638
639int
640linux_sys_kill(struct lwp *l, const struct linux_sys_kill_args *uap, register_t *retval)
641{
642	/* {
643		syscallarg(int) pid;
644		syscallarg(int) signum;
645	} */
646
647	struct sys_kill_args ka;
648	int sig;
649
650	SCARG(&ka, pid) = SCARG(uap, pid);
651	sig = SCARG(uap, signum);
652	if (sig < 0 || sig >= LINUX__NSIG)
653		return (EINVAL);
654	SCARG(&ka, signum) = linux_to_native_signo[sig];
655	return sys_kill(l, &ka, retval);
656}
657
658#ifdef LINUX_SS_ONSTACK
659static void linux_to_native_sigaltstack(struct sigaltstack *,
660    const struct linux_sigaltstack *);
661
662static void
663linux_to_native_sigaltstack(struct sigaltstack *bss, const struct linux_sigaltstack *lss)
664{
665	bss->ss_sp = lss->ss_sp;
666	bss->ss_size = lss->ss_size;
667	if (lss->ss_flags & LINUX_SS_ONSTACK)
668	    bss->ss_flags = SS_ONSTACK;
669	else if (lss->ss_flags & LINUX_SS_DISABLE)
670	    bss->ss_flags = SS_DISABLE;
671	else
672	    bss->ss_flags = 0;
673}
674
675void
676native_to_linux_sigaltstack(struct linux_sigaltstack *lss, const struct sigaltstack *bss)
677{
678	lss->ss_sp = bss->ss_sp;
679	lss->ss_size = bss->ss_size;
680	if (bss->ss_flags & SS_ONSTACK)
681	    lss->ss_flags = LINUX_SS_ONSTACK;
682	else if (bss->ss_flags & SS_DISABLE)
683	    lss->ss_flags = LINUX_SS_DISABLE;
684	else
685	    lss->ss_flags = 0;
686}
687
688int
689linux_sys_sigaltstack(struct lwp *l, const struct linux_sys_sigaltstack_args *uap, register_t *retval)
690{
691	/* {
692		syscallarg(const struct linux_sigaltstack *) ss;
693		syscallarg(struct linux_sigaltstack *) oss;
694	} */
695	struct linux_sigaltstack ss;
696	struct sigaltstack nss;
697	struct proc *p = l->l_proc;
698	int error = 0;
699
700	if (SCARG(uap, oss)) {
701		native_to_linux_sigaltstack(&ss, &l->l_sigstk);
702		if ((error = copyout(&ss, SCARG(uap, oss), sizeof(ss))) != 0)
703			return error;
704	}
705
706	if (SCARG(uap, ss) != NULL) {
707		if ((error = copyin(SCARG(uap, ss), &ss, sizeof(ss))) != 0)
708			return error;
709		linux_to_native_sigaltstack(&nss, &ss);
710
711		mutex_enter(p->p_lock);
712
713		if (nss.ss_flags & ~SS_ALLBITS)
714			error = EINVAL;
715		else if (nss.ss_flags & SS_DISABLE) {
716			if (l->l_sigstk.ss_flags & SS_ONSTACK)
717				error = EINVAL;
718		} else if (nss.ss_size < LINUX_MINSIGSTKSZ)
719			error = ENOMEM;
720
721		if (error == 0)
722			l->l_sigstk = nss;
723
724		mutex_exit(p->p_lock);
725	}
726
727	return error;
728}
729#endif /* LINUX_SS_ONSTACK */
730
731static int
732linux_do_tkill(struct lwp *l, int tgid, int tid, int signum)
733{
734	struct proc *p;
735	struct lwp *t;
736	ksiginfo_t ksi;
737	int error;
738
739	if (signum < 0 || signum >= LINUX__NSIG)
740		return EINVAL;
741	signum = linux_to_native_signo[signum];
742
743	if (tgid == -1) {
744		tgid = tid;
745	}
746
747	KSI_INIT(&ksi);
748	ksi.ksi_signo = signum;
749	ksi.ksi_code = SI_LWP;
750	ksi.ksi_pid = l->l_proc->p_pid;
751	ksi.ksi_uid = kauth_cred_geteuid(l->l_cred);
752	ksi.ksi_lid = tid;
753
754	mutex_enter(proc_lock);
755	p = proc_find(tgid);
756	if (p == NULL) {
757		mutex_exit(proc_lock);
758		return ESRCH;
759	}
760	mutex_enter(p->p_lock);
761	error = kauth_authorize_process(l->l_cred,
762	    KAUTH_PROCESS_SIGNAL, p, KAUTH_ARG(signum), NULL, NULL);
763	if ((t = lwp_find(p, ksi.ksi_lid)) == NULL)
764		error = ESRCH;
765	else if (signum != 0)
766		kpsignal2(p, &ksi);
767	mutex_exit(p->p_lock);
768	mutex_exit(proc_lock);
769
770	return error;
771}
772
773int
774linux_sys_tkill(struct lwp *l, const struct linux_sys_tkill_args *uap, register_t *retval)
775{
776	/* {
777		syscallarg(int) tid;
778		syscallarg(int) sig;
779	} */
780
781	if (SCARG(uap, tid) <= 0)
782		return EINVAL;
783
784	return linux_do_tkill(l, -1, SCARG(uap, tid), SCARG(uap, sig));
785}
786
787int
788linux_sys_tgkill(struct lwp *l, const struct linux_sys_tgkill_args *uap, register_t *retval)
789{
790	/* {
791		syscallarg(int) tgid;
792		syscallarg(int) tid;
793		syscallarg(int) sig;
794	} */
795
796	if (SCARG(uap, tid) <= 0 || SCARG(uap, tgid) < -1)
797		return EINVAL;
798
799	return linux_do_tkill(l, SCARG(uap, tgid), SCARG(uap, tid), SCARG(uap, sig));
800}
801
802int
803native_to_linux_si_code(int code)
804{
805	int si_codes[] = {
806	    LINUX_SI_USER, LINUX_SI_QUEUE, LINUX_SI_TIMER, LINUX_SI_ASYNCIO,
807	    LINUX_SI_MESGQ, LINUX_SI_TKILL /* SI_LWP */
808	};
809
810	if (code <= 0 && -code < __arraycount(si_codes))
811		return si_codes[-code];
812
813	return code;
814}
815
816int
817native_to_linux_si_status(int code, int status)
818{
819	int sts;
820
821	switch (code) {
822	case CLD_CONTINUED:
823		sts = LINUX_SIGCONT;
824		break;
825	case CLD_EXITED:
826		sts = WEXITSTATUS(status);
827		break;
828	case CLD_STOPPED:
829	case CLD_TRAPPED:
830	case CLD_DUMPED:
831	case CLD_KILLED:
832	default:
833		sts = native_to_linux_signo[WTERMSIG(status)];
834		break;
835	}
836
837	return sts;
838}
839