xref: /netbsd-src/sys/compat/linux/common/linux_signal.c (revision 2a399c6883d870daece976daec6ffa7bb7f934ce)
1 /*	$NetBSD: linux_signal.c,v 1.10 1996/04/04 23:51:36 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 1995 Frank van der Linden
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *      This product includes software developed for the NetBSD Project
18  *      by Frank van der Linden
19  * 4. The name of the author may not be used to endorse or promote products
20  *    derived from this software without specific prior written permission
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  *
33  * heavily from: svr4_signal.c,v 1.7 1995/01/09 01:04:21 christos Exp
34  */
35 
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/namei.h>
39 #include <sys/proc.h>
40 #include <sys/filedesc.h>
41 #include <sys/ioctl.h>
42 #include <sys/mount.h>
43 #include <sys/kernel.h>
44 #include <sys/signal.h>
45 #include <sys/signalvar.h>
46 #include <sys/malloc.h>
47 
48 #include <sys/syscallargs.h>
49 
50 #include <compat/linux/linux_types.h>
51 #include <compat/linux/linux_signal.h>
52 #include <compat/linux/linux_syscallargs.h>
53 #include <compat/linux/linux_util.h>
54 
55 #define	sigemptyset(s)		bzero((s), sizeof(*(s)))
56 #define	sigismember(s, n)	(*(s) & sigmask(n))
57 #define	sigaddset(s, n)		(*(s) |= sigmask(n))
58 
59 #define	linux_sigmask(n)	(1 << ((n) - 1))
60 #define	linux_sigemptyset(s)	bzero((s), sizeof(*(s)))
61 #define	linux_sigismember(s, n)	(*(s) & linux_sigmask(n))
62 #define	linux_sigaddset(s, n)	(*(s) |= linux_sigmask(n))
63 
64 int bsd_to_linux_sig[] = {
65 	0,
66 	LINUX_SIGHUP,
67 	LINUX_SIGINT,
68 	LINUX_SIGQUIT,
69 	LINUX_SIGILL,
70 	LINUX_SIGTRAP,
71 	LINUX_SIGABRT,
72 	0,
73 	LINUX_SIGFPE,
74 	LINUX_SIGKILL,
75 	LINUX_SIGBUS,
76 	LINUX_SIGSEGV,
77 	0,
78 	LINUX_SIGPIPE,
79 	LINUX_SIGALRM,
80 	LINUX_SIGTERM,
81 	LINUX_SIGURG,
82 	LINUX_SIGSTOP,
83 	LINUX_SIGTSTP,
84 	LINUX_SIGCONT,
85 	LINUX_SIGCHLD,
86 	LINUX_SIGTTIN,
87 	LINUX_SIGTTOU,
88 	LINUX_SIGIO,
89 	LINUX_SIGXCPU,
90 	LINUX_SIGXFSZ,
91 	LINUX_SIGVTALRM,
92 	LINUX_SIGPROF,
93 	LINUX_SIGWINCH,
94 	0,
95 	LINUX_SIGUSR1,
96 	LINUX_SIGUSR2,
97 };
98 
99 int linux_to_bsd_sig[] = {
100 	0,
101 	SIGHUP,
102 	SIGINT,
103 	SIGQUIT,
104 	SIGILL,
105 	SIGTRAP,
106 	SIGABRT,
107 	SIGBUS,
108 	SIGFPE,
109 	SIGKILL,
110 	SIGUSR1,
111 	SIGSEGV,
112 	SIGUSR2,
113 	SIGPIPE,
114 	SIGALRM,
115 	SIGTERM,
116 	0,
117 	SIGCHLD,
118 	SIGCONT,
119 	SIGSTOP,
120 	SIGTSTP,
121 	SIGTTIN,
122 	SIGTTOU,
123 	SIGURG,
124 	SIGXCPU,
125 	SIGXFSZ,
126 	SIGVTALRM,
127 	SIGPROF,
128 	SIGWINCH,
129 	SIGIO,
130 	0,
131 	0,
132 };
133 
134 
135 /* linux_signal.c */
136 void linux_to_bsd_sigset __P((const linux_sigset_t *, sigset_t *));
137 void bsd_to_linux_sigset __P((const sigset_t *, linux_sigset_t *));
138 void linux_to_bsd_sigaction __P((struct linux_sigaction *, struct sigaction *));
139 void bsd_to_linux_sigaction __P((struct sigaction *, struct linux_sigaction *));
140 
141 /*
142  * Ok, we know that Linux and BSD signals both are just an unsigned int.
143  * Don't bother to use the sigismember() stuff for now.
144  */
145 void
146 linux_to_bsd_sigset(lss, bss)
147 	const linux_sigset_t *lss;
148 	sigset_t *bss;
149 {
150 	int i, newsig;
151 
152 	sigemptyset(bss);
153 	for (i = 1; i < LINUX_NSIG; i++) {
154 		if (linux_sigismember(lss, i)) {
155 			newsig = linux_to_bsd_sig[i];
156 			if (newsig)
157 				sigaddset(bss, newsig);
158 		}
159 	}
160 }
161 
162 void
163 bsd_to_linux_sigset(bss, lss)
164 	const sigset_t *bss;
165 	linux_sigset_t *lss;
166 {
167 	int i, newsig;
168 
169 	linux_sigemptyset(lss);
170 	for (i = 1; i < NSIG; i++) {
171 		if (sigismember(bss, i)) {
172 			newsig = bsd_to_linux_sig[i];
173 			if (newsig)
174 				linux_sigaddset(lss, newsig);
175 		}
176 	}
177 }
178 
179 /*
180  * Convert between Linux and BSD sigaction structures. Linux has
181  * one extra field (sa_restorer) which we don't support.
182  */
183 void
184 linux_to_bsd_sigaction(lsa, bsa)
185 	struct linux_sigaction *lsa;
186 	struct sigaction *bsa;
187 {
188 
189 	bsa->sa_handler = lsa->sa_handler;
190 	linux_to_bsd_sigset(&lsa->sa_mask, &bsa->sa_mask);
191 	bsa->sa_flags = 0;
192 	if ((lsa->sa_flags & LINUX_SA_ONSTACK) != 0)
193 		bsa->sa_flags |= SA_ONSTACK;
194 	if ((lsa->sa_flags & LINUX_SA_RESTART) != 0)
195 		bsa->sa_flags |= SA_RESTART;
196 	if ((lsa->sa_flags & LINUX_SA_ONESHOT) != 0)
197 		bsa->sa_flags |= SA_RESETHAND;
198 	if ((lsa->sa_flags & LINUX_SA_NOCLDSTOP) != 0)
199 		bsa->sa_flags |= SA_NOCLDSTOP;
200 	if ((lsa->sa_flags & LINUX_SA_NOMASK) != 0)
201 		bsa->sa_flags |= SA_NODEFER;
202 }
203 
204 void
205 bsd_to_linux_sigaction(bsa, lsa)
206 	struct sigaction *bsa;
207 	struct linux_sigaction *lsa;
208 {
209 
210 	lsa->sa_handler = bsa->sa_handler;
211 	bsd_to_linux_sigset(&bsa->sa_mask, &lsa->sa_mask);
212 	lsa->sa_flags = 0;
213 	if ((bsa->sa_flags & SA_NOCLDSTOP) != 0)
214 		lsa->sa_flags |= LINUX_SA_NOCLDSTOP;
215 	if ((bsa->sa_flags & SA_ONSTACK) != 0)
216 		lsa->sa_flags |= LINUX_SA_ONSTACK;
217 	if ((bsa->sa_flags & SA_RESTART) != 0)
218 		lsa->sa_flags |= LINUX_SA_RESTART;
219 	if ((bsa->sa_flags & SA_NODEFER) != 0)
220 		lsa->sa_flags |= LINUX_SA_NOMASK;
221 	if ((bsa->sa_flags & SA_RESETHAND) != 0)
222 		lsa->sa_flags |= LINUX_SA_ONESHOT;
223 	lsa->sa_restorer = NULL;
224 }
225 
226 
227 /*
228  * The Linux sigaction() system call. Do the usual conversions,
229  * and just call sigaction(). Some flags and values are silently
230  * ignored (see above).
231  */
232 int
233 linux_sys_sigaction(p, v, retval)
234 	register struct proc *p;
235 	void *v;
236 	register_t *retval;
237 {
238 	struct linux_sys_sigaction_args /* {
239 		syscallarg(int) signum;
240 		syscallarg(struct linux_sigaction *) nsa;
241 		syscallarg(struct linux_sigaction *) osa;
242 	} */ *uap = v;
243 	struct linux_sigaction *nlsa, *olsa, tmplsa;
244 	struct sigaction *nbsa, *obsa, tmpbsa;
245 	struct sys_sigaction_args sa;
246 	caddr_t sg;
247 	int error;
248 
249 	sg = stackgap_init(p->p_emul);
250 	nlsa = SCARG(uap, nsa);
251 	olsa = SCARG(uap, osa);
252 
253 	if (olsa != NULL)
254 		obsa = stackgap_alloc(&sg, sizeof(struct sigaction));
255 	else
256 		obsa = NULL;
257 
258 	if (nlsa != NULL) {
259 		nbsa = stackgap_alloc(&sg, sizeof(struct sigaction));
260 		if ((error = copyin(nlsa, &tmplsa, sizeof(tmplsa))) != 0)
261 			return error;
262 		linux_to_bsd_sigaction(&tmplsa, &tmpbsa);
263 		if ((error = copyout(&tmpbsa, nbsa, sizeof(tmpbsa))) != 0)
264 			return error;
265 	} else
266 		nbsa = NULL;
267 
268 	SCARG(&sa, signum) = linux_to_bsd_sig[SCARG(uap, signum)];
269 	SCARG(&sa, nsa) = nbsa;
270 	SCARG(&sa, osa) = obsa;
271 
272 	if ((error = sys_sigaction(p, &sa, retval)) != 0)
273 		return error;
274 
275 	if (olsa != NULL) {
276 		if ((error = copyin(obsa, &tmpbsa, sizeof(tmpbsa))) != 0)
277 			return error;
278 		bsd_to_linux_sigaction(&tmpbsa, &tmplsa);
279 		if ((error = copyout(&tmplsa, olsa, sizeof(tmplsa))) != 0)
280 			return error;
281 	}
282 
283 	return 0;
284 }
285 
286 /*
287  * The Linux signal() system call. I think that the signal() in the C
288  * library actually calls sigaction, so I doubt this one is ever used.
289  * But hey, it can't hurt having it here. The same restrictions as for
290  * sigaction() apply.
291  */
292 int
293 linux_sys_signal(p, v, retval)
294 	register struct proc *p;
295 	void *v;
296 	register_t *retval;
297 {
298 	struct linux_sys_signal_args /* {
299 		syscallarg(int) sig;
300 		syscallarg(linux_handler_t) handler;
301 	} */ *uap = v;
302 	caddr_t sg;
303 	struct sys_sigaction_args sa_args;
304 	struct sigaction *osa, *nsa, tmpsa;
305 	int error;
306 
307 	sg = stackgap_init(p->p_emul);
308 	nsa = stackgap_alloc(&sg, sizeof *nsa);
309 	osa = stackgap_alloc(&sg, sizeof *osa);
310 
311 	tmpsa.sa_handler = SCARG(uap, handler);
312 	tmpsa.sa_mask = (sigset_t) 0;
313 	tmpsa.sa_flags = SA_RESETHAND | SA_NODEFER;
314 	if ((error = copyout(&tmpsa, nsa, sizeof tmpsa)))
315 		return error;
316 
317 	SCARG(&sa_args, signum) = linux_to_bsd_sig[SCARG(uap, sig)];
318 	SCARG(&sa_args, osa) = osa;
319 	SCARG(&sa_args, nsa) = nsa;
320 	if ((error = sys_sigaction(p, &sa_args, retval)))
321 		return error;
322 
323 	if ((error = copyin(osa, &tmpsa, sizeof *osa)))
324 		return error;
325 	retval[0] = (register_t) tmpsa.sa_handler;
326 
327 	return 0;
328 }
329 
330 /*
331  * This is just a copy of the svr4 compat one. I feel so creative now.
332  */
333 int
334 linux_sys_sigprocmask(p, v, retval)
335 	register struct proc *p;
336 	void *v;
337 	register_t *retval;
338 {
339 	struct linux_sys_sigprocmask_args /* {
340 		syscallarg(int) how;
341 		syscallarg(linux_sigset_t *) set;
342 		syscallarg(linux_sigset_t *) oset;
343 	} */ *uap = v;
344 	linux_sigset_t ss;
345 	sigset_t bs;
346 	int error = 0;
347 
348 	*retval = 0;
349 
350 	if (SCARG(uap, oset) != NULL) {
351 		/* Fix the return value first if needed */
352 		bsd_to_linux_sigset(&p->p_sigmask, &ss);
353 		if ((error = copyout(&ss, SCARG(uap, oset), sizeof(ss))) != 0)
354 			return error;
355 	}
356 
357 	if (SCARG(uap, set) == NULL)
358 		/* Just examine */
359 		return 0;
360 
361 	if ((error = copyin(SCARG(uap, set), &ss, sizeof(ss))) != 0)
362 		return error;
363 
364 	linux_to_bsd_sigset(&ss, &bs);
365 
366 	(void) splhigh();
367 
368 	switch (SCARG(uap, how)) {
369 	case LINUX_SIG_BLOCK:
370 		p->p_sigmask |= bs & ~sigcantmask;
371 		break;
372 
373 	case LINUX_SIG_UNBLOCK:
374 		p->p_sigmask &= ~bs;
375 		break;
376 
377 	case LINUX_SIG_SETMASK:
378 		p->p_sigmask = bs & ~sigcantmask;
379 		break;
380 
381 	default:
382 		error = EINVAL;
383 		break;
384 	}
385 
386 	(void) spl0();
387 
388 	return error;
389 }
390 
391 /*
392  * The functions below really make no distinction between an int
393  * and [linux_]sigset_t. This is ok for now, but it might break
394  * sometime. Then again, sigset_t is trusted to be an int everywhere
395  * else in the kernel too.
396  */
397 /* ARGSUSED */
398 int
399 linux_sys_siggetmask(p, v, retval)
400 	register struct proc *p;
401 	void *v;
402 	register_t *retval;
403 {
404 
405 	bsd_to_linux_sigset(&p->p_sigmask, (linux_sigset_t *)retval);
406 	return 0;
407 }
408 
409 /*
410  * The following three functions fiddle with a process' signal mask.
411  * Convert the signal masks because of the different signal
412  * values for Linux. The need for this is the reason why
413  * they are here, and have not been mapped directly.
414  */
415 int
416 linux_sys_sigsetmask(p, v, retval)
417 	register struct proc *p;
418 	void *v;
419 	register_t *retval;
420 {
421 	struct linux_sys_sigsetmask_args /* {
422 		syscallarg(linux_sigset_t) mask;
423 	} */ *uap = v;
424 	linux_sigset_t mask;
425 	sigset_t bsdsig;
426 
427 	bsd_to_linux_sigset(&p->p_sigmask, (linux_sigset_t *)retval);
428 
429 	mask = SCARG(uap, mask);
430 	bsd_to_linux_sigset(&bsdsig, &mask);
431 
432 	splhigh();
433 	p->p_sigmask = bsdsig & ~sigcantmask;
434 	spl0();
435 
436 	return 0;
437 }
438 
439 int
440 linux_sys_sigpending(p, v, retval)
441 	register struct proc *p;
442 	void *v;
443 	register_t *retval;
444 {
445 	struct linux_sys_sigpending_args /* {
446 		syscallarg(linux_sigset_t *) mask;
447 	} */ *uap = v;
448 	sigset_t bs;
449 	linux_sigset_t ls;
450 
451 	bs = p->p_siglist & p->p_sigmask;
452 	bsd_to_linux_sigset(&bs, &ls);
453 
454 	return copyout(&ls, SCARG(uap, mask), sizeof(ls));
455 }
456 
457 int
458 linux_sys_sigsuspend(p, v, retval)
459 	register struct proc *p;
460 	void *v;
461 	register_t *retval;
462 {
463 	struct linux_sys_sigsuspend_args /* {
464 		syscallarg(caddr_t) restart;
465 		syscallarg(int) oldmask;
466 		syscallarg(int) mask;
467 	} */ *uap = v;
468 	struct sys_sigsuspend_args sa;
469 	linux_sigset_t mask = SCARG(uap, mask);
470 
471 	linux_to_bsd_sigset(&mask, &SCARG(&sa, mask));
472 	return sys_sigsuspend(p, &sa, retval);
473 }
474 
475 /*
476  * The deprecated pause(2), which is really just an instance
477  * of sigsuspend(2).
478  */
479 int
480 linux_sys_pause(p, v, retval)
481 	register struct proc *p;
482 	void *v;
483 	register_t *retval;
484 {
485 	struct sys_sigsuspend_args bsa;
486 
487 	SCARG(&bsa, mask) = p->p_sigmask;
488 	return sys_sigsuspend(p, &bsa, retval);
489 }
490 
491 /*
492  * Once more: only a signal conversion is needed.
493  */
494 int
495 linux_sys_kill(p, v, retval)
496 	register struct proc *p;
497 	void *v;
498 	register_t *retval;
499 {
500 	struct linux_sys_kill_args /* {
501 		syscallarg(int) pid;
502 		syscallarg(int) signum;
503 	} */ *uap = v;
504 	struct sys_kill_args ka;
505 
506 	SCARG(&ka, pid) = SCARG(uap, pid);
507 	SCARG(&ka, signum) = linux_to_bsd_sig[SCARG(uap, signum)];
508 	return sys_kill(p, &ka, retval);
509 }
510