xref: /freebsd/sys/compat/linux/linux_signal.c (revision cb166ce422ac2bc81f42c2a2e2cd68625c11478d)
1 /*-
2  * Copyright (c) 1994-1995 S�ren Schmidt
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer
10  *    in this position and unchanged.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. The name of the author may not be used to endorse or promote products
15  *    derived from this software withough specific prior written permission
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * $FreeBSD$
29  */
30 
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/sysproto.h>
34 #include <sys/proc.h>
35 #include <sys/signalvar.h>
36 
37 #include <i386/linux/linux.h>
38 #include <i386/linux/linux_proto.h>
39 #include <i386/linux/linux_util.h>
40 
41 static void
42 linux_to_bsd_sigset(linux_sigset_t *lss, sigset_t *bss)
43 {
44 	int b, l;
45 
46 	SIGEMPTYSET(*bss);
47 	bss->__bits[0] = lss->__bits[0] & ~((1U << LINUX_SIGTBLSZ) - 1);
48 	bss->__bits[1] = lss->__bits[1];
49 	for (l = 1; l <= LINUX_SIGTBLSZ; l++) {
50 		if (LINUX_SIGISMEMBER(*lss, l)) {
51 			b = linux_to_bsd_signal[_SIG_IDX(l)];
52 			if (b)
53 				SIGADDSET(*bss, b);
54 		}
55 	}
56 }
57 
58 static void
59 bsd_to_linux_sigset(sigset_t *bss, linux_sigset_t *lss)
60 {
61 	int b, l;
62 
63 	LINUX_SIGEMPTYSET(*lss);
64 	lss->__bits[0] = bss->__bits[0] & ~((1U << LINUX_SIGTBLSZ) - 1);
65 	lss->__bits[1] = bss->__bits[1];
66 	for (b = 1; b <= LINUX_SIGTBLSZ; b++) {
67 		if (SIGISMEMBER(*bss, b)) {
68 			l = bsd_to_linux_signal[_SIG_IDX(b)];
69 			if (l)
70 				LINUX_SIGADDSET(*lss, l);
71 		}
72 	}
73 }
74 
75 static void
76 linux_to_bsd_sigaction(linux_sigaction_t *lsa, struct sigaction *bsa)
77 {
78 
79 	linux_to_bsd_sigset(&lsa->lsa_mask, &bsa->sa_mask);
80 	bsa->sa_handler = lsa->lsa_handler;
81 	bsa->sa_flags = 0;
82 	if (lsa->lsa_flags & LINUX_SA_NOCLDSTOP)
83 		bsa->sa_flags |= SA_NOCLDSTOP;
84 	if (lsa->lsa_flags & LINUX_SA_NOCLDWAIT)
85 		bsa->sa_flags |= SA_NOCLDWAIT;
86 	if (lsa->lsa_flags & LINUX_SA_SIGINFO)
87 		bsa->sa_flags |= SA_SIGINFO;
88 	if (lsa->lsa_flags & LINUX_SA_ONSTACK)
89 		bsa->sa_flags |= SA_ONSTACK;
90 	if (lsa->lsa_flags & LINUX_SA_RESTART)
91 		bsa->sa_flags |= SA_RESTART;
92 	if (lsa->lsa_flags & LINUX_SA_ONESHOT)
93 		bsa->sa_flags |= SA_RESETHAND;
94 	if (lsa->lsa_flags & LINUX_SA_NOMASK)
95 		bsa->sa_flags |= SA_NODEFER;
96 }
97 
98 static void
99 bsd_to_linux_sigaction(struct sigaction *bsa, linux_sigaction_t *lsa)
100 {
101 
102 	bsd_to_linux_sigset(&bsa->sa_mask, &lsa->lsa_mask);
103 	lsa->lsa_handler = bsa->sa_handler;
104 	lsa->lsa_restorer = NULL;	/* unsupported */
105 	lsa->lsa_flags = 0;
106 	if (bsa->sa_flags & SA_NOCLDSTOP)
107 		lsa->lsa_flags |= LINUX_SA_NOCLDSTOP;
108 	if (bsa->sa_flags & SA_NOCLDWAIT)
109 		lsa->lsa_flags |= LINUX_SA_NOCLDWAIT;
110 	if (bsa->sa_flags & SA_SIGINFO)
111 		lsa->lsa_flags |= LINUX_SA_SIGINFO;
112 	if (bsa->sa_flags & SA_ONSTACK)
113 		lsa->lsa_flags |= LINUX_SA_ONSTACK;
114 	if (bsa->sa_flags & SA_RESTART)
115 		lsa->lsa_flags |= LINUX_SA_RESTART;
116 	if (bsa->sa_flags & SA_RESETHAND)
117 		lsa->lsa_flags |= LINUX_SA_ONESHOT;
118 	if (bsa->sa_flags & SA_NODEFER)
119 		lsa->lsa_flags |= LINUX_SA_NOMASK;
120 }
121 
122 static int
123 linux_do_sigaction(struct proc *p, int linux_sig, linux_sigaction_t *linux_nsa,
124 		   linux_sigaction_t *linux_osa)
125 {
126 	struct sigaction *nsa, *osa;
127 	struct sigaction_args sa_args;
128 	int error;
129 	caddr_t sg = stackgap_init();
130 
131 	if (linux_sig <= 0 || linux_sig > LINUX_NSIG)
132 		return (EINVAL);
133 
134 	if (linux_osa != NULL)
135 		osa = stackgap_alloc(&sg, sizeof(struct sigaction));
136 	else
137 		osa = NULL;
138 
139 	if (linux_nsa != NULL) {
140 		nsa = stackgap_alloc(&sg, sizeof(struct sigaction));
141 		linux_to_bsd_sigaction(linux_nsa, nsa);
142 	}
143 	else
144 		nsa = NULL;
145 
146 	if (linux_sig <= LINUX_SIGTBLSZ)
147 		sa_args.sig = linux_to_bsd_signal[_SIG_IDX(linux_sig)];
148 	else
149 		sa_args.sig = linux_sig;
150 
151 	sa_args.act = nsa;
152 	sa_args.oact = osa;
153 	error = sigaction(p, &sa_args);
154 	if (error)
155 		return (error);
156 
157 	if (linux_osa != NULL)
158 		bsd_to_linux_sigaction(osa, linux_osa);
159 
160 	return (0);
161 }
162 
163 int
164 linux_sigaction(struct proc *p, struct linux_sigaction_args *args)
165 {
166 	linux_osigaction_t osa;
167 	linux_sigaction_t act, oact;
168 	int error;
169 
170 #ifdef DEBUG
171 	printf("Linux-emul(%ld): sigaction(%d, %p, %p)\n", (long)p->p_pid,
172 	       args->sig, (void *)args->nsa, (void *)args->osa);
173 #endif
174 
175 	if (args->nsa != NULL) {
176 		error = copyin(args->nsa, &osa, sizeof(linux_osigaction_t));
177 		if (error)
178 			return (error);
179 		act.lsa_handler = osa.lsa_handler;
180 		act.lsa_flags = osa.lsa_flags;
181 		act.lsa_restorer = osa.lsa_restorer;
182 		LINUX_SIGEMPTYSET(act.lsa_mask);
183 		act.lsa_mask.__bits[0] = osa.lsa_mask;
184 	}
185 
186 	error = linux_do_sigaction(p, args->sig,
187 				   args->nsa ? &act : NULL,
188 				   args->osa ? &oact : NULL);
189 
190 	if (args->osa != NULL && !error) {
191 		osa.lsa_handler = oact.lsa_handler;
192 		osa.lsa_flags = oact.lsa_flags;
193 		osa.lsa_restorer = oact.lsa_restorer;
194 		osa.lsa_mask = oact.lsa_mask.__bits[0];
195 		error = copyout(&osa, args->osa, sizeof(linux_osigaction_t));
196 	}
197 
198 	return (error);
199 }
200 
201 int
202 linux_signal(struct proc *p, struct linux_signal_args *args)
203 {
204 	linux_sigaction_t nsa, osa;
205 	int error;
206 
207 #ifdef DEBUG
208 	printf("Linux-emul(%ld): signal(%d, %p)\n",
209 	       (long)p->p_pid, args->sig, (void *)args->handler);
210 #endif
211 
212 	nsa.lsa_handler = args->handler;
213 	nsa.lsa_flags = LINUX_SA_ONESHOT | LINUX_SA_NOMASK;
214 	LINUX_SIGEMPTYSET(nsa.lsa_mask);
215 
216 	error = linux_do_sigaction(p, args->sig, &nsa, &osa);
217 	p->p_retval[0] = (int)osa.lsa_handler;
218 
219 	return (error);
220 }
221 
222 int
223 linux_rt_sigaction(struct proc *p, struct linux_rt_sigaction_args *args)
224 {
225 	linux_sigaction_t nsa, osa;
226 	int error;
227 
228 #ifdef DEBUG
229 	printf("Linux-emul(%ld): rt_sigaction(%d, %p, %p, %d)\n",
230 	       (long)p->p_pid, args->sig, (void *)args->act,
231 	       (void *)args->oact, args->sigsetsize);
232 #endif
233 
234 	if (args->sigsetsize != sizeof(linux_sigset_t))
235 		return (EINVAL);
236 
237 	if (args->act != NULL) {
238 		error = copyin(args->act, &nsa, sizeof(linux_sigaction_t));
239 		if (error)
240 			return (error);
241 	}
242 
243 	error = linux_do_sigaction(p, args->sig,
244 				   args->act ? &nsa : NULL,
245 				   args->oact ? &osa : NULL);
246 
247 	if (args->oact != NULL && !error) {
248 		error = copyout(&osa, args->oact, sizeof(linux_sigaction_t));
249 	}
250 
251 	return (error);
252 }
253 
254 static int
255 linux_do_sigprocmask(struct proc *p, int how, linux_sigset_t *new,
256 		     linux_sigset_t *old)
257 {
258 	int error, s;
259 	sigset_t mask;
260 
261 	error = 0;
262 	p->p_retval[0] = 0;
263 
264 	if (old != NULL)
265 		bsd_to_linux_sigset(&p->p_sigmask, old);
266 
267 	if (new != NULL) {
268 		linux_to_bsd_sigset(new, &mask);
269 
270 		s = splhigh();
271 
272 		switch (how) {
273 		case LINUX_SIG_BLOCK:
274 			SIGSETOR(p->p_sigmask, mask);
275 			SIG_CANTMASK(p->p_sigmask);
276 			break;
277 		case LINUX_SIG_UNBLOCK:
278 			SIGSETNAND(p->p_sigmask, mask);
279 			break;
280 		case LINUX_SIG_SETMASK:
281 			p->p_sigmask = mask;
282 			SIG_CANTMASK(p->p_sigmask);
283 			break;
284 		default:
285 			error = EINVAL;
286 			break;
287 		}
288 
289 		splx(s);
290 	}
291 
292 	return (error);
293 }
294 
295 int
296 linux_sigprocmask(struct proc *p, struct linux_sigprocmask_args *args)
297 {
298 	linux_osigset_t mask;
299 	linux_sigset_t set, oset;
300 	int error;
301 
302 #ifdef DEBUG
303 	printf("Linux-emul(%d): sigprocmask(%d, *, *)\n", p->p_pid, args->how);
304 #endif
305 
306 	if (args->mask != NULL) {
307 		error = copyin(args->mask, &mask, sizeof(linux_osigset_t));
308 		if (error)
309 			return (error);
310 		LINUX_SIGEMPTYSET(set);
311 		set.__bits[0] = mask;
312 	}
313 
314 	error = linux_do_sigprocmask(p, args->how,
315 				     args->mask ? &set : NULL,
316 				     args->omask ? &oset : NULL);
317 
318 	if (args->omask != NULL && !error) {
319 		mask = oset.__bits[0];
320 		error = copyout(&mask, args->omask, sizeof(linux_osigset_t));
321 	}
322 
323 	return (error);
324 }
325 
326 int
327 linux_rt_sigprocmask(struct proc *p, struct linux_rt_sigprocmask_args *args)
328 {
329 	linux_sigset_t set, oset;
330 	int error;
331 
332 #ifdef DEBUG
333 	printf("Linux-emul(%ld): rt_sigprocmask(%d, %p, %p, %d)\n",
334 	       (long)p->p_pid, args->how, (void *)args->mask,
335 	       (void *)args->omask, args->sigsetsize);
336 #endif
337 
338 	if (args->sigsetsize != sizeof(linux_sigset_t))
339 		return EINVAL;
340 
341 	if (args->mask != NULL) {
342 		error = copyin(args->mask, &set, sizeof(linux_sigset_t));
343 		if (error)
344 			return (error);
345 	}
346 
347 	error = linux_do_sigprocmask(p, args->how,
348 				     args->mask ? &set : NULL,
349 				     args->omask ? &oset : NULL);
350 
351 	if (args->omask != NULL && !error) {
352 		error = copyout(&oset, args->omask, sizeof(linux_sigset_t));
353 	}
354 
355 	return (error);
356 }
357 
358 int
359 linux_siggetmask(struct proc *p, struct linux_siggetmask_args *args)
360 {
361 	linux_sigset_t mask;
362 
363 #ifdef DEBUG
364 	printf("Linux-emul(%d): siggetmask()\n", p->p_pid);
365 #endif
366 
367 	bsd_to_linux_sigset(&p->p_sigmask, &mask);
368 	p->p_retval[0] = mask.__bits[0];
369 	return (0);
370 }
371 
372 int
373 linux_sigsetmask(struct proc *p, struct linux_sigsetmask_args *args)
374 {
375 	linux_sigset_t lset;
376 	sigset_t bset;
377 	int s;
378 
379 #ifdef DEBUG
380 	printf("Linux-emul(%ld): sigsetmask(%08lx)\n",
381 	       (long)p->p_pid, (unsigned long)args->mask);
382 #endif
383 
384 	bsd_to_linux_sigset(&p->p_sigmask, &lset);
385 	p->p_retval[0] = lset.__bits[0];
386 	LINUX_SIGEMPTYSET(lset);
387 	lset.__bits[0] = args->mask;
388 	linux_to_bsd_sigset(&lset, &bset);
389 	s = splhigh();
390 	p->p_sigmask = bset;
391 	SIG_CANTMASK(p->p_sigmask);
392 	splx(s);
393 	return (0);
394 }
395 
396 int
397 linux_sigpending(struct proc *p, struct linux_sigpending_args *args)
398 {
399 	sigset_t bset;
400 	linux_sigset_t lset;
401 	linux_osigset_t mask;
402 
403 #ifdef DEBUG
404 	printf("Linux-emul(%d): sigpending(*)\n", p->p_pid);
405 #endif
406 
407 	bset = p->p_siglist;
408 	SIGSETAND(bset, p->p_sigmask);
409 	bsd_to_linux_sigset(&bset, &lset);
410 	mask = lset.__bits[0];
411 	return (copyout(&mask, args->mask, sizeof(mask)));
412 }
413 
414 /*
415  * Linux has two extra args, restart and oldmask.  We dont use these,
416  * but it seems that "restart" is actually a context pointer that
417  * enables the signal to happen with a different register set.
418  */
419 int
420 linux_sigsuspend(struct proc *p, struct linux_sigsuspend_args *args)
421 {
422 	struct sigsuspend_args bsd;
423 	sigset_t *sigmask;
424 	linux_sigset_t mask;
425 	caddr_t sg = stackgap_init();
426 
427 #ifdef DEBUG
428 	printf("Linux-emul(%ld): sigsuspend(%08lx)\n",
429 	       (long)p->p_pid, (unsigned long)args->mask);
430 #endif
431 
432 	sigmask = stackgap_alloc(&sg, sizeof(sigset_t));
433 	LINUX_SIGEMPTYSET(mask);
434 	mask.__bits[0] = args->mask;
435 	linux_to_bsd_sigset(&mask, sigmask);
436 	bsd.sigmask = sigmask;
437 	return (sigsuspend(p, &bsd));
438 }
439 
440 int
441 linux_rt_sigsuspend(p, uap)
442 	struct proc *p;
443 	struct linux_rt_sigsuspend_args *uap;
444 {
445 	linux_sigset_t lmask;
446 	sigset_t *bmask;
447 	struct sigsuspend_args bsd;
448 	caddr_t sg = stackgap_init();
449 	int error;
450 
451 #ifdef DEBUG
452 	printf("Linux-emul(%ld): rt_sigsuspend(%p, %d)\n", (long)p->p_pid,
453 	       (void *)uap->newset, uap->sigsetsize);
454 #endif
455 
456 	if (uap->sigsetsize != sizeof(linux_sigset_t))
457 		return (EINVAL);
458 
459 	error = copyin(uap->newset, &lmask, sizeof(linux_sigset_t));
460 	if (error)
461 		return (error);
462 
463 	bmask = stackgap_alloc(&sg, sizeof(sigset_t));
464 	linux_to_bsd_sigset(&lmask, bmask);
465 	bsd.sigmask = bmask;
466 	return (sigsuspend(p, &bsd));
467 }
468 
469 int
470 linux_pause(struct proc *p, struct linux_pause_args *args)
471 {
472 	struct sigsuspend_args bsd;
473 	sigset_t *sigmask;
474 	caddr_t sg = stackgap_init();
475 
476 #ifdef DEBUG
477 	printf("Linux-emul(%d): pause()\n", p->p_pid);
478 #endif
479 
480 	sigmask = stackgap_alloc(&sg, sizeof(sigset_t));
481 	*sigmask = p->p_sigmask;
482 	bsd.sigmask = sigmask;
483 	return sigsuspend(p, &bsd);
484 }
485 
486 int
487 linux_kill(struct proc *p, struct linux_kill_args *args)
488 {
489 	struct kill_args /* {
490 	    int pid;
491 	    int signum;
492 	} */ tmp;
493 
494 #ifdef DEBUG
495 	printf("Linux-emul(%d): kill(%d, %d)\n",
496 	       p->p_pid, args->pid, args->signum);
497 #endif
498 
499 	/*
500 	 * Allow signal 0 as a means to check for privileges
501 	 */
502 	if (args->signum < 0 || args->signum > LINUX_NSIG)
503 		return EINVAL;
504 
505 	if (args->signum > 0 && args->signum <= LINUX_SIGTBLSZ)
506 		tmp.signum = linux_to_bsd_signal[_SIG_IDX(args->signum)];
507 	else
508 		tmp.signum = args->signum;
509 
510 	tmp.pid = args->pid;
511 	return (kill(p, &tmp));
512 }
513 
514 int
515 linux_sigaltstack(p, uap)
516 	struct proc *p;
517 	struct linux_sigaltstack_args *uap;
518 {
519 	struct sigaltstack_args bsd;
520 	stack_t *ss, *oss;
521 	linux_stack_t lss;
522 	int error;
523 	caddr_t sg = stackgap_init();
524 
525 #ifdef DEBUG
526 	printf("Linux-emul(%ld): sigaltstack(%p, %p)\n",
527 	    (long)p->p_pid, uap->uss, uap->uoss);
528 #endif
529 
530 	error = copyin(uap->uss, &lss, sizeof(linux_stack_t));
531 	if (error)
532 		return (error);
533 
534 	ss = stackgap_alloc(&sg, sizeof(stack_t));
535 	ss->ss_sp = lss.ss_sp;
536 	ss->ss_size = lss.ss_size;
537 	ss->ss_flags = lss.ss_flags;
538 
539 	oss = (uap->uoss != NULL)
540 	    ? stackgap_alloc(&sg, sizeof(stack_t))
541 	    : NULL;
542 
543 	bsd.ss = ss;
544 	bsd.oss = oss;
545 	error = sigaltstack(p, &bsd);
546 
547 	if (!error && oss != NULL) {
548 		lss.ss_sp = oss->ss_sp;
549 		lss.ss_size = oss->ss_size;
550 		lss.ss_flags = oss->ss_flags;
551 		error = copyout(&lss, uap->uoss, sizeof(linux_stack_t));
552 	}
553 
554 	return (error);
555 }
556