Home | History | Annotate | Line # | Download | only in common
linux_signal.c revision 1.54.14.2
      1 /*	$NetBSD: linux_signal.c,v 1.54.14.2 2007/12/09 19:37:05 jmcneill 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  * 3. All advertising materials mentioning features or use of this software
     19  *    must display the following acknowledgement:
     20  *	This product includes software developed by the NetBSD
     21  *	Foundation, Inc. and its contributors.
     22  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23  *    contributors may be used to endorse or promote products derived
     24  *    from this software without specific prior written permission.
     25  *
     26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36  * POSSIBILITY OF SUCH DAMAGE.
     37  */
     38 /*
     39  * heavily from: svr4_signal.c,v 1.7 1995/01/09 01:04:21 christos Exp
     40  */
     41 
     42 /*
     43  *   Functions in multiarch:
     44  *	linux_sys_signal	: linux_sig_notalpha.c
     45  *	linux_sys_siggetmask	: linux_sig_notalpha.c
     46  *	linux_sys_sigsetmask	: linux_sig_notalpha.c
     47  *	linux_sys_pause		: linux_sig_notalpha.c
     48  *	linux_sys_sigaction	: linux_sigaction.c
     49  *
     50  */
     51 
     52 /*
     53  *   Unimplemented:
     54  *	linux_sys_rt_sigtimedwait	: sigsuspend w/timeout.
     55  */
     56 
     57 #include <sys/cdefs.h>
     58 __KERNEL_RCSID(0, "$NetBSD: linux_signal.c,v 1.54.14.2 2007/12/09 19:37:05 jmcneill Exp $");
     59 
     60 #define COMPAT_LINUX 1
     61 
     62 #include <sys/param.h>
     63 #include <sys/systm.h>
     64 #include <sys/namei.h>
     65 #include <sys/proc.h>
     66 #include <sys/filedesc.h>
     67 #include <sys/ioctl.h>
     68 #include <sys/mount.h>
     69 #include <sys/kernel.h>
     70 #include <sys/signal.h>
     71 #include <sys/signalvar.h>
     72 #include <sys/malloc.h>
     73 
     74 #include <sys/syscallargs.h>
     75 
     76 #include <compat/linux/common/linux_types.h>
     77 #include <compat/linux/common/linux_signal.h>
     78 #include <compat/linux/common/linux_exec.h> /* For emul_linux */
     79 #include <compat/linux/common/linux_machdep.h> /* For LINUX_NPTL */
     80 #include <compat/linux/common/linux_emuldata.h> /* for linux_emuldata */
     81 #include <compat/linux/common/linux_siginfo.h>
     82 #include <compat/linux/common/linux_sigevent.h>
     83 #include <compat/linux/common/linux_util.h>
     84 #include <compat/linux/common/linux_ipc.h>
     85 #include <compat/linux/common/linux_sem.h>
     86 
     87 #include <compat/linux/linux_syscallargs.h>
     88 
     89 /* Locally used defines (in bsd<->linux conversion functions): */
     90 #define	linux_sigemptyset(s)	memset((s), 0, sizeof(*(s)))
     91 #define	linux_sigismember(s, n)	((s)->sig[((n) - 1) / LINUX__NSIG_BPW]	\
     92 					& (1 << ((n) - 1) % LINUX__NSIG_BPW))
     93 #define	linux_sigaddset(s, n)	((s)->sig[((n) - 1) / LINUX__NSIG_BPW]	\
     94 					|= (1 << ((n) - 1) % LINUX__NSIG_BPW))
     95 
     96 #ifdef DEBUG_LINUX
     97 #define DPRINTF(a)	uprintf a
     98 #else
     99 #define DPRINTF(a)
    100 #endif
    101 
    102 extern const int native_to_linux_signo[];
    103 extern const int linux_to_native_signo[];
    104 
    105 /*
    106  * Convert between Linux and BSD signal sets.
    107  */
    108 #if LINUX__NSIG_WORDS > 1
    109 void
    110 linux_old_extra_to_native_sigset(sigset_t *bss, const linux_old_sigset_t *lss, const unsigned long *extra)
    111 {
    112 	linux_sigset_t lsnew;
    113 
    114 	/* convert old sigset to new sigset */
    115 	linux_sigemptyset(&lsnew);
    116 	lsnew.sig[0] = *lss;
    117 	if (extra)
    118 		memcpy(&lsnew.sig[1], extra,
    119 		    sizeof(linux_sigset_t) - sizeof(linux_old_sigset_t));
    120 
    121 	linux_to_native_sigset(bss, &lsnew);
    122 }
    123 
    124 void
    125 native_to_linux_old_extra_sigset(linux_old_sigset_t *lss, unsigned long *extra, const sigset_t *bss)
    126 {
    127 	linux_sigset_t lsnew;
    128 
    129 	native_to_linux_sigset(&lsnew, bss);
    130 
    131 	/* convert new sigset to old sigset */
    132 	*lss = lsnew.sig[0];
    133 	if (extra)
    134 		memcpy(extra, &lsnew.sig[1],
    135 		    sizeof(linux_sigset_t) - sizeof(linux_old_sigset_t));
    136 }
    137 #endif /* LINUX__NSIG_WORDS > 1 */
    138 
    139 void
    140 linux_to_native_sigset(sigset_t *bss, const linux_sigset_t *lss)
    141 {
    142 	int i, newsig;
    143 
    144 	sigemptyset(bss);
    145 	for (i = 1; i < LINUX__NSIG; i++) {
    146 		if (linux_sigismember(lss, i)) {
    147 			newsig = linux_to_native_signo[i];
    148 			if (newsig)
    149 				sigaddset(bss, newsig);
    150 		}
    151 	}
    152 }
    153 
    154 void
    155 native_to_linux_sigset(linux_sigset_t *lss, const sigset_t *bss)
    156 {
    157 	int i, newsig;
    158 
    159 	linux_sigemptyset(lss);
    160 	for (i = 1; i < NSIG; i++) {
    161 		if (sigismember(bss, i)) {
    162 			newsig = native_to_linux_signo[i];
    163 			if (newsig)
    164 				linux_sigaddset(lss, newsig);
    165 		}
    166 	}
    167 }
    168 
    169 unsigned int
    170 native_to_linux_sigflags(const int bsf)
    171 {
    172 	unsigned int lsf = 0;
    173 	if ((bsf & SA_NOCLDSTOP) != 0)
    174 		lsf |= LINUX_SA_NOCLDSTOP;
    175 	if ((bsf & SA_NOCLDWAIT) != 0)
    176 		lsf |= LINUX_SA_NOCLDWAIT;
    177 	if ((bsf & SA_ONSTACK) != 0)
    178 		lsf |= LINUX_SA_ONSTACK;
    179 	if ((bsf & SA_RESTART) != 0)
    180 		lsf |= LINUX_SA_RESTART;
    181 	if ((bsf & SA_NODEFER) != 0)
    182 		lsf |= LINUX_SA_NOMASK;
    183 	if ((bsf & SA_RESETHAND) != 0)
    184 		lsf |= LINUX_SA_ONESHOT;
    185 	if ((bsf & SA_SIGINFO) != 0)
    186 		lsf |= LINUX_SA_SIGINFO;
    187 	return lsf;
    188 }
    189 
    190 int
    191 linux_to_native_sigflags(const unsigned long lsf)
    192 {
    193 	int bsf = 0;
    194 	if ((lsf & LINUX_SA_NOCLDSTOP) != 0)
    195 		bsf |= SA_NOCLDSTOP;
    196 	if ((lsf & LINUX_SA_NOCLDWAIT) != 0)
    197 		bsf |= SA_NOCLDWAIT;
    198 	if ((lsf & LINUX_SA_ONSTACK) != 0)
    199 		bsf |= SA_ONSTACK;
    200 	if ((lsf & LINUX_SA_RESTART) != 0)
    201 		bsf |= SA_RESTART;
    202 	if ((lsf & LINUX_SA_ONESHOT) != 0)
    203 		bsf |= SA_RESETHAND;
    204 	if ((lsf & LINUX_SA_NOMASK) != 0)
    205 		bsf |= SA_NODEFER;
    206 	if ((lsf & LINUX_SA_SIGINFO) != 0)
    207 		bsf |= SA_SIGINFO;
    208 	if ((lsf & ~LINUX_SA_ALLBITS) != 0) {
    209 		DPRINTF(("linux_old_to_native_sigflags: "
    210 		    "%lx extra bits ignored\n", lsf));
    211 	}
    212 	return bsf;
    213 }
    214 
    215 /*
    216  * Convert between Linux and BSD sigaction structures.
    217  */
    218 void
    219 linux_old_to_native_sigaction(struct sigaction *bsa, const struct linux_old_sigaction *lsa)
    220 {
    221 	bsa->sa_handler = lsa->linux_sa_handler;
    222 	linux_old_to_native_sigset(&bsa->sa_mask, &lsa->linux_sa_mask);
    223 	bsa->sa_flags = linux_to_native_sigflags(lsa->linux_sa_flags);
    224 }
    225 
    226 void
    227 native_to_linux_old_sigaction(struct linux_old_sigaction *lsa, const struct sigaction *bsa)
    228 {
    229 	lsa->linux_sa_handler = bsa->sa_handler;
    230 	native_to_linux_old_sigset(&lsa->linux_sa_mask, &bsa->sa_mask);
    231 	lsa->linux_sa_flags = native_to_linux_sigflags(bsa->sa_flags);
    232 #ifndef __alpha__
    233 	lsa->linux_sa_restorer = NULL;
    234 #endif
    235 }
    236 
    237 /* ...and the new sigaction conversion funcs. */
    238 void
    239 linux_to_native_sigaction(struct sigaction *bsa, const struct linux_sigaction *lsa)
    240 {
    241 	bsa->sa_handler = lsa->linux_sa_handler;
    242 	linux_to_native_sigset(&bsa->sa_mask, &lsa->linux_sa_mask);
    243 	bsa->sa_flags = linux_to_native_sigflags(lsa->linux_sa_flags);
    244 }
    245 
    246 void
    247 native_to_linux_sigaction(struct linux_sigaction *lsa, const struct sigaction *bsa)
    248 {
    249 	lsa->linux_sa_handler = bsa->sa_handler;
    250 	native_to_linux_sigset(&lsa->linux_sa_mask, &bsa->sa_mask);
    251 	lsa->linux_sa_flags = native_to_linux_sigflags(bsa->sa_flags);
    252 #ifndef __alpha__
    253 	lsa->linux_sa_restorer = NULL;
    254 #endif
    255 }
    256 
    257 /* ----------------------------------------------------------------------- */
    258 
    259 /*
    260  * The Linux sigaction() system call. Do the usual conversions,
    261  * and just call sigaction(). Some flags and values are silently
    262  * ignored (see above).
    263  */
    264 int
    265 linux_sys_rt_sigaction(struct lwp *l, void *v, register_t *retval)
    266 {
    267 	struct linux_sys_rt_sigaction_args /* {
    268 		syscallarg(int) signum;
    269 		syscallarg(const struct linux_sigaction *) nsa;
    270 		syscallarg(struct linux_sigaction *) osa;
    271 		syscallarg(size_t) sigsetsize;
    272 	} */ *uap = v;
    273 	struct linux_sigaction nlsa, olsa;
    274 	struct sigaction nbsa, obsa;
    275 	int error, sig;
    276 	void *tramp = NULL;
    277 	int vers = 0;
    278 #if defined __amd64__
    279 	struct sigacts *ps = l->l_proc->p_sigacts;
    280 #endif
    281 
    282 	if (SCARG(uap, sigsetsize) != sizeof(linux_sigset_t))
    283 		return (EINVAL);
    284 
    285 	if (SCARG(uap, nsa)) {
    286 		error = copyin(SCARG(uap, nsa), &nlsa, sizeof(nlsa));
    287 		if (error)
    288 			return (error);
    289 		linux_to_native_sigaction(&nbsa, &nlsa);
    290 	}
    291 
    292 	sig = SCARG(uap, signum);
    293 	if (sig < 0 || sig >= LINUX__NSIG)
    294 		return (EINVAL);
    295 	if (sig > 0 && !linux_to_native_signo[sig]) {
    296 		/* Pretend that we did something useful for unknown signals. */
    297 		obsa.sa_handler = SIG_IGN;
    298 		sigemptyset(&obsa.sa_mask);
    299 		obsa.sa_flags = 0;
    300 	} else {
    301 #if defined __amd64__
    302 		if (nlsa.linux_sa_flags & LINUX_SA_RESTORER) {
    303 			if ((tramp = nlsa.linux_sa_restorer) != NULL)
    304 				vers = 2; /* XXX arch dependant */
    305 		}
    306 #endif
    307 
    308 		error = sigaction1(l, linux_to_native_signo[sig],
    309 		    SCARG(uap, nsa) ? &nbsa : NULL,
    310 		    SCARG(uap, osa) ? &obsa : NULL,
    311 		    tramp, vers);
    312 		if (error)
    313 			return (error);
    314 	}
    315 	if (SCARG(uap, osa)) {
    316 		native_to_linux_sigaction(&olsa, &obsa);
    317 
    318 #if defined __amd64__
    319 		if (ps->sa_sigdesc[sig].sd_vers != 0) {
    320 			olsa.linux_sa_restorer = ps->sa_sigdesc[sig].sd_tramp;
    321 			olsa.linux_sa_flags |= LINUX_SA_RESTORER;
    322 		}
    323 #endif
    324 
    325 		error = copyout(&olsa, SCARG(uap, osa), sizeof(olsa));
    326 		if (error)
    327 			return (error);
    328 	}
    329 	return (0);
    330 }
    331 
    332 int
    333 linux_sigprocmask1(struct lwp *l, int how, const linux_old_sigset_t *set, linux_old_sigset_t *oset)
    334 {
    335 	struct proc *p = l->l_proc;
    336 	linux_old_sigset_t nlss, olss;
    337 	sigset_t nbss, obss;
    338 	int error;
    339 
    340 	switch (how) {
    341 	case LINUX_SIG_BLOCK:
    342 		how = SIG_BLOCK;
    343 		break;
    344 	case LINUX_SIG_UNBLOCK:
    345 		how = SIG_UNBLOCK;
    346 		break;
    347 	case LINUX_SIG_SETMASK:
    348 		how = SIG_SETMASK;
    349 		break;
    350 	default:
    351 		return (EINVAL);
    352 	}
    353 
    354 	if (set) {
    355 		error = copyin(set, &nlss, sizeof(nlss));
    356 		if (error)
    357 			return (error);
    358 		linux_old_to_native_sigset(&nbss, &nlss);
    359 	}
    360 	mutex_enter(&p->p_smutex);
    361 	error = sigprocmask1(l, how,
    362 	    set ? &nbss : NULL, oset ? &obss : NULL);
    363 	mutex_exit(&p->p_smutex);
    364 	if (error)
    365 		return (error);
    366 	if (oset) {
    367 		native_to_linux_old_sigset(&olss, &obss);
    368 		error = copyout(&olss, oset, sizeof(olss));
    369 		if (error)
    370 			return (error);
    371 	}
    372 	return (error);
    373 }
    374 
    375 int
    376 linux_sys_rt_sigprocmask(struct lwp *l, void *v, register_t *retval)
    377 {
    378 	struct linux_sys_rt_sigprocmask_args /* {
    379 		syscallarg(int) how;
    380 		syscallarg(const linux_sigset_t *) set;
    381 		syscallarg(linux_sigset_t *) oset;
    382 		syscallarg(size_t) sigsetsize;
    383 	} */ *uap = v;
    384 	linux_sigset_t nlss, olss, *oset;
    385 	const linux_sigset_t *set;
    386 	struct proc *p = l->l_proc;
    387 	sigset_t nbss, obss;
    388 	int error, how;
    389 
    390 	if (SCARG(uap, sigsetsize) != sizeof(linux_sigset_t))
    391 		return (EINVAL);
    392 
    393 	switch (SCARG(uap, how)) {
    394 	case LINUX_SIG_BLOCK:
    395 		how = SIG_BLOCK;
    396 		break;
    397 	case LINUX_SIG_UNBLOCK:
    398 		how = SIG_UNBLOCK;
    399 		break;
    400 	case LINUX_SIG_SETMASK:
    401 		how = SIG_SETMASK;
    402 		break;
    403 	default:
    404 		return (EINVAL);
    405 	}
    406 
    407 	set = SCARG(uap, set);
    408 	oset = SCARG(uap, oset);
    409 
    410 	if (set) {
    411 		error = copyin(set, &nlss, sizeof(nlss));
    412 		if (error)
    413 			return (error);
    414 		linux_to_native_sigset(&nbss, &nlss);
    415 	}
    416 	mutex_enter(&p->p_smutex);
    417 	error = sigprocmask1(l, how,
    418 	    set ? &nbss : NULL, oset ? &obss : NULL);
    419 	mutex_exit(&p->p_smutex);
    420 	if (!error && oset) {
    421 		native_to_linux_sigset(&olss, &obss);
    422 		error = copyout(&olss, oset, sizeof(olss));
    423 	}
    424 	return (error);
    425 }
    426 
    427 int
    428 linux_sys_rt_sigpending(struct lwp *l, void *v, register_t *retval)
    429 {
    430 	struct linux_sys_rt_sigpending_args /* {
    431 		syscallarg(linux_sigset_t *) set;
    432 		syscallarg(size_t) sigsetsize;
    433 	} */ *uap = v;
    434 	sigset_t bss;
    435 	linux_sigset_t lss;
    436 
    437 	if (SCARG(uap, sigsetsize) != sizeof(linux_sigset_t))
    438 		return (EINVAL);
    439 
    440 	sigpending1(l, &bss);
    441 	native_to_linux_sigset(&lss, &bss);
    442 	return copyout(&lss, SCARG(uap, set), sizeof(lss));
    443 }
    444 
    445 #ifndef __amd64__
    446 int
    447 linux_sys_sigpending(struct lwp *l, void *v, register_t *retval)
    448 {
    449 	struct linux_sys_sigpending_args /* {
    450 		syscallarg(linux_old_sigset_t *) mask;
    451 	} */ *uap = v;
    452 	sigset_t bss;
    453 	linux_old_sigset_t lss;
    454 
    455 	sigpending1(l, &bss);
    456 	native_to_linux_old_sigset(&lss, &bss);
    457 	return copyout(&lss, SCARG(uap, set), sizeof(lss));
    458 }
    459 
    460 int
    461 linux_sys_sigsuspend(struct lwp *l, void *v, register_t *retval)
    462 {
    463 	struct linux_sys_sigsuspend_args /* {
    464 		syscallarg(void *) restart;
    465 		syscallarg(int) oldmask;
    466 		syscallarg(int) mask;
    467 	} */ *uap = v;
    468 	linux_old_sigset_t lss;
    469 	sigset_t bss;
    470 
    471 	lss = SCARG(uap, mask);
    472 	linux_old_to_native_sigset(&bss, &lss);
    473 	return (sigsuspend1(l, &bss));
    474 }
    475 #endif /* __amd64__ */
    476 
    477 int
    478 linux_sys_rt_sigsuspend(struct lwp *l, void *v, register_t *retval)
    479 {
    480 	struct linux_sys_rt_sigsuspend_args /* {
    481 		syscallarg(linux_sigset_t *) unewset;
    482 		syscallarg(size_t) sigsetsize;
    483 	} */ *uap = v;
    484 	linux_sigset_t lss;
    485 	sigset_t bss;
    486 	int error;
    487 
    488 	if (SCARG(uap, sigsetsize) != sizeof(linux_sigset_t))
    489 		return (EINVAL);
    490 
    491 	error = copyin(SCARG(uap, unewset), &lss, sizeof(linux_sigset_t));
    492 	if (error)
    493 		return (error);
    494 
    495 	linux_to_native_sigset(&bss, &lss);
    496 
    497 	return (sigsuspend1(l, &bss));
    498 }
    499 
    500 /*
    501  * Once more: only a signal conversion is needed.
    502  * Note: also used as sys_rt_queueinfo.  The info field is ignored.
    503  */
    504 int
    505 linux_sys_rt_queueinfo(struct lwp *l, void *v, register_t *retval)
    506 {
    507 	/* XXX XAX This isn't this really int, int, siginfo_t *, is it? */
    508 #if 0
    509 	struct linux_sys_rt_queueinfo_args /* {
    510 		syscallarg(int) pid;
    511 		syscallarg(int) signum;
    512 		syscallarg(siginfo_t *) uinfo;
    513 	} */ *uap = v;
    514 #endif
    515 
    516 	/* XXX To really implement this we need to	*/
    517 	/* XXX keep a list of queued signals somewhere.	*/
    518 	return (linux_sys_kill(l, v, retval));
    519 }
    520 
    521 int
    522 linux_sys_kill(struct lwp *l, void *v, register_t *retval)
    523 {
    524 	struct linux_sys_kill_args /* {
    525 		syscallarg(int) pid;
    526 		syscallarg(int) signum;
    527 	} */ *uap = v;
    528 
    529 	struct sys_kill_args ka;
    530 	int sig;
    531 
    532 	SCARG(&ka, pid) = SCARG(uap, pid);
    533 	sig = SCARG(uap, signum);
    534 	if (sig < 0 || sig >= LINUX__NSIG)
    535 		return (EINVAL);
    536 	SCARG(&ka, signum) = linux_to_native_signo[sig];
    537 	return sys_kill(l, &ka, retval);
    538 }
    539 
    540 #ifdef LINUX_SS_ONSTACK
    541 static void linux_to_native_sigaltstack(struct sigaltstack *,
    542     const struct linux_sigaltstack *);
    543 
    544 static void
    545 linux_to_native_sigaltstack(struct sigaltstack *bss, const struct linux_sigaltstack *lss)
    546 {
    547 	bss->ss_sp = lss->ss_sp;
    548 	bss->ss_size = lss->ss_size;
    549 	if (lss->ss_flags & LINUX_SS_ONSTACK)
    550 	    bss->ss_flags = SS_ONSTACK;
    551 	else if (lss->ss_flags & LINUX_SS_DISABLE)
    552 	    bss->ss_flags = SS_DISABLE;
    553 	else
    554 	    bss->ss_flags = 0;
    555 }
    556 
    557 void
    558 native_to_linux_sigaltstack(struct linux_sigaltstack *lss, const struct sigaltstack *bss)
    559 {
    560 	lss->ss_sp = bss->ss_sp;
    561 	lss->ss_size = bss->ss_size;
    562 	if (bss->ss_flags & SS_ONSTACK)
    563 	    lss->ss_flags = LINUX_SS_ONSTACK;
    564 	else if (bss->ss_flags & SS_DISABLE)
    565 	    lss->ss_flags = LINUX_SS_DISABLE;
    566 	else
    567 	    lss->ss_flags = 0;
    568 }
    569 
    570 int
    571 linux_sys_sigaltstack(struct lwp *l, void *v, register_t *retval)
    572 {
    573 	struct linux_sys_sigaltstack_args /* {
    574 		syscallarg(const struct linux_sigaltstack *) ss;
    575 		syscallarg(struct linux_sigaltstack *) oss;
    576 	} */ *uap = v;
    577 	struct linux_sigaltstack ss;
    578 	struct sigaltstack nss;
    579 	struct proc *p = l->l_proc;
    580 	int error = 0;
    581 
    582 	if (SCARG(uap, oss)) {
    583 		native_to_linux_sigaltstack(&ss, &l->l_sigstk);
    584 		if ((error = copyout(&ss, SCARG(uap, oss), sizeof(ss))) != 0)
    585 			return error;
    586 	}
    587 
    588 	if (SCARG(uap, ss) != NULL) {
    589 		if ((error = copyin(SCARG(uap, ss), &ss, sizeof(ss))) != 0)
    590 			return error;
    591 		linux_to_native_sigaltstack(&nss, &ss);
    592 
    593 		mutex_enter(&p->p_smutex);
    594 
    595 		if (nss.ss_flags & ~SS_ALLBITS)
    596 			error = EINVAL;
    597 		else if (nss.ss_flags & SS_DISABLE) {
    598 			if (l->l_sigstk.ss_flags & SS_ONSTACK)
    599 				error = EINVAL;
    600 		} else if (nss.ss_size < LINUX_MINSIGSTKSZ)
    601 			error = ENOMEM;
    602 
    603 		if (error == 0)
    604 			l->l_sigstk = nss;
    605 
    606 		mutex_exit(&p->p_smutex);
    607 	}
    608 
    609 	return error;
    610 }
    611 #endif /* LINUX_SS_ONSTACK */
    612 
    613 #ifdef LINUX_NPTL
    614 int
    615 linux_sys_tkill(struct lwp *l, void *v, register_t *retval)
    616 {
    617 	struct linux_sys_tkill_args /* {
    618 		syscallarg(int) tid;
    619 		syscallarg(int) sig;
    620 	} */ *uap = v;
    621 	struct linux_sys_kill_args cup;
    622 
    623 	/* We use the PID as the TID ... */
    624 	SCARG(&cup, pid) = SCARG(uap, tid);
    625 	SCARG(&cup, signum) = SCARG(uap, sig);
    626 
    627 	return linux_sys_kill(l, &cup, retval);
    628 }
    629 
    630 int
    631 linux_sys_tgkill(struct lwp *l, void *v, register_t *retval)
    632 {
    633 	struct linux_sys_tgkill_args /* {
    634 		syscallarg(int) tgid;
    635 		syscallarg(int) tid;
    636 		syscallarg(int) sig;
    637 	} */ *uap = v;
    638 	struct linux_sys_kill_args cup;
    639 	struct linux_emuldata *led;
    640 	struct proc *p;
    641 
    642 	SCARG(&cup, pid) = SCARG(uap, tid);
    643 	SCARG(&cup, signum) = SCARG(uap, sig);
    644 
    645 	if (SCARG(uap, tgid) == -1)
    646 		return linux_sys_kill(l, &cup, retval);
    647 
    648 	/* We use the PID as the TID, but make sure the group ID is right */
    649 	if ((p = pfind(SCARG(uap, tid))) == NULL)
    650 		return ESRCH;
    651 
    652 	if (p->p_emul != &emul_linux)
    653 		return ESRCH;
    654 
    655 	led = p->p_emuldata;
    656 
    657 	if (led->s->group_pid != SCARG(uap, tgid))
    658 		return ESRCH;
    659 
    660 	return linux_sys_kill(l, &cup, retval);
    661 }
    662 #endif /* LINUX_NPTL */
    663