xref: /netbsd-src/sys/compat/linux32/common/linux32_signal.c (revision 12f8dfa1698827761c5118c283a9eaf94928eea5)
1 /*	$NetBSD: linux32_signal.c,v 1.1 2006/02/09 19:18:57 manu Exp $ */
2 
3 /*-
4  * Copyright (c) 2006 Emmanuel Dreyfus, all rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
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. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *	This product includes software developed by Emmanuel Dreyfus
17  * 4. The name of the author may not be used to endorse or promote
18  *    products derived from this software without specific prior written
19  *    permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE THE AUTHOR AND CONTRIBUTORS ``AS IS''
22  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
23  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
25  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  */
33 #include <sys/param.h>
34 #include <sys/ucred.h>
35 #include <sys/signalvar.h>
36 #include <sys/lwp.h>
37 #include <sys/time.h>
38 
39 #include <compat/netbsd32/netbsd32.h>
40 
41 #include <compat/linux32/common/linux32_types.h>
42 #include <compat/linux32/common/linux32_signal.h>
43 #include <compat/linux32/linux32_syscallargs.h>
44 
45 #define linux32_sigemptyset(s)    memset((s), 0, sizeof(*(s)))
46 #define linux32_sigismember(s, n) ((s)->sig[((n) - 1) / LINUX32__NSIG_BPW]  \
47 				    & (1 << ((n) - 1) % LINUX32__NSIG_BPW))
48 #define linux32_sigaddset(s, n)   ((s)->sig[((n) - 1) / LINUX32__NSIG_BPW]  \
49 				    |= (1 << ((n) - 1) % LINUX32__NSIG_BPW))
50 
51 extern const int native_to_linux32_signo[];
52 extern const int linux32_to_native_signo[];
53 
54 void
55 linux32_to_native_sigset(bss, lss)
56 	sigset_t *bss;
57 	const linux32_sigset_t *lss;
58 {
59 	int i, newsig;
60 
61 	sigemptyset(bss);
62 	for (i = 1; i < LINUX32__NSIG; i++) {
63 		if (linux32_sigismember(lss, i)) {
64 			newsig = linux32_to_native_signo[i];
65 			if (newsig)
66 				sigaddset(bss, newsig);
67 		}
68 	}
69 }
70 
71 void
72 native_to_linux32_sigset(lss, bss)
73 	linux32_sigset_t *lss;
74 	const sigset_t *bss;
75 {
76 	int i, newsig;
77 
78 	linux32_sigemptyset(lss);
79 	for (i = 1; i < NSIG; i++) {
80 		if (sigismember(bss, i)) {
81 			newsig = native_to_linux32_signo[i];
82 			if (newsig)
83 				linux32_sigaddset(lss, newsig);
84 		}
85 	}
86 }
87 
88 unsigned int
89 native_to_linux32_sigflags(bsf)
90 	const int bsf;
91 {
92 	unsigned int lsf = 0;
93 	if ((bsf & SA_NOCLDSTOP) != 0)
94 		lsf |= LINUX32_SA_NOCLDSTOP;
95 	if ((bsf & SA_NOCLDWAIT) != 0)
96 		lsf |= LINUX32_SA_NOCLDWAIT;
97 	if ((bsf & SA_ONSTACK) != 0)
98 		lsf |= LINUX32_SA_ONSTACK;
99 	if ((bsf & SA_RESTART) != 0)
100 		lsf |= LINUX32_SA_RESTART;
101 	if ((bsf & SA_NODEFER) != 0)
102 		lsf |= LINUX32_SA_NOMASK;
103 	if ((bsf & SA_RESETHAND) != 0)
104 		lsf |= LINUX32_SA_ONESHOT;
105 	if ((bsf & SA_SIGINFO) != 0)
106 		lsf |= LINUX32_SA_SIGINFO;
107 	return lsf;
108 }
109 
110 int
111 linux32_to_native_sigflags(lsf)
112 	const unsigned long lsf;
113 {
114 	int bsf = 0;
115 	if ((lsf & LINUX32_SA_NOCLDSTOP) != 0)
116 		bsf |= SA_NOCLDSTOP;
117 	if ((lsf & LINUX32_SA_NOCLDWAIT) != 0)
118 		bsf |= SA_NOCLDWAIT;
119 	if ((lsf & LINUX32_SA_ONSTACK) != 0)
120 		bsf |= SA_ONSTACK;
121 	if ((lsf & LINUX32_SA_RESTART) != 0)
122 		bsf |= SA_RESTART;
123 	if ((lsf & LINUX32_SA_ONESHOT) != 0)
124 		bsf |= SA_RESETHAND;
125 	if ((lsf & LINUX32_SA_NOMASK) != 0)
126 		bsf |= SA_NODEFER;
127 	if ((lsf & LINUX32_SA_SIGINFO) != 0)
128 		bsf |= SA_SIGINFO;
129 	if ((lsf & ~LINUX32_SA_ALLBITS) != 0) {
130 #ifdef DEBUG_LINUX
131 		printf("linux32_old_to_native_sigflags: "
132 		    "%lx extra bits ignored\n", lsf);
133 #endif
134 	}
135 	return bsf;
136 }
137 
138 void
139 linux32_to_native_sigaction(bsa, lsa)
140 	struct sigaction *bsa;
141 	const struct linux32_sigaction *lsa;
142 {
143 	bsa->sa_handler = NETBSD32PTR64(lsa->linux_sa_handler);
144 	linux32_to_native_sigset(&bsa->sa_mask, &lsa->linux_sa_mask);
145 	bsa->sa_flags = linux32_to_native_sigflags(lsa->linux_sa_flags);
146 }
147 
148 void
149 native_to_linux32_sigaction(lsa, bsa)
150 	struct linux32_sigaction *lsa;
151 	const struct sigaction *bsa;
152 {
153 	lsa->linux_sa_handler = (linux32_handler_t)(long)bsa->sa_handler;
154 	native_to_linux32_sigset(&lsa->linux_sa_mask, &bsa->sa_mask);
155 	lsa->linux_sa_flags = native_to_linux32_sigflags(bsa->sa_flags);
156 	lsa->linux_sa_restorer = (linux32_restorer_t)NULL;
157 }
158 
159 void
160 native_to_linux32_sigaltstack(lss, bss)
161 	struct linux32_sigaltstack *lss;
162 	const struct sigaltstack *bss;
163 {
164 	lss->ss_sp = (netbsd32_voidp)(long)bss->ss_sp;
165 	lss->ss_size = bss->ss_size;
166 	if (bss->ss_flags & SS_ONSTACK)
167 	    lss->ss_flags = LINUX32_SS_ONSTACK;
168 	else if (bss->ss_flags & SS_DISABLE)
169 	    lss->ss_flags = LINUX32_SS_DISABLE;
170 	else
171 	    lss->ss_flags = 0;
172 }
173 
174 
175 void
176 native_to_linux32_old_sigset(lss, bss)
177 	linux32_old_sigset_t *lss;
178 	const sigset_t *bss;
179 {
180 	linux32_sigset_t lsnew;
181 
182 	native_to_linux32_sigset(&lsnew, bss);
183 
184 	/* convert new sigset to old sigset */
185 	*lss = lsnew.sig[0];
186 }
187 
188 void
189 linux32_old_to_native_sigset(bss, lss)
190 	sigset_t *bss;
191 	const linux32_old_sigset_t *lss;
192 {
193 	linux32_sigset_t ls;
194 
195 	bzero(&ls, sizeof(ls));
196 	ls.sig[0] = *lss;
197 
198 	linux32_to_native_sigset(bss, &ls);
199 }
200 
201 int
202 linux32_sys_rt_sigaction(l, v, retval)
203 	struct lwp *l;
204 	void *v;
205 	register_t *retval;
206 {
207 	struct linux32_sys_rt_sigaction_args /* {
208 		syscallarg(int) signum;
209 		syscallarg(const linux32_sigactionp_t) nsa;
210 		syscallarg(linux32_sigactionp_t) osa;
211 		syscallarg(netbsd32_size_t) sigsetsize;
212 	} */ *uap = v;
213 	struct linux32_sigaction nls32;
214 	struct linux32_sigaction ols32;
215 	struct sigaction ns;
216 	struct sigaction os;
217 	int error;
218 	int sig;
219 	int vers = 0;
220 	void *tramp = NULL;
221 
222 	if (SCARG(uap, sigsetsize) != sizeof(linux32_sigset_t))
223 		return EINVAL;
224 
225 	if (NETBSD32PTR64(SCARG(uap, nsa)) != NULL) {
226 		if ((error = copyin(NETBSD32PTR64(SCARG(uap, nsa)),
227 		    &nls32, sizeof(nls32))) != 0)
228 			return error;
229 		linux32_to_native_sigaction(&ns, &nls32);
230 	}
231 
232 	sig = SCARG(uap, signum);
233 	if (sig < 0 || sig >= LINUX32__NSIG)
234 		return EINVAL;
235 	if (sig > 0 && !linux32_to_native_signo[sig]) {
236 		/* unknown signal... */
237 		os.sa_handler = SIG_IGN;
238 		sigemptyset(&os.sa_mask);
239 		os.sa_flags = 0;
240 	} else {
241 		if ((error = sigaction1(l->l_proc,
242 		    linux32_to_native_signo[sig],
243 		    NETBSD32PTR64(SCARG(uap, nsa)) ? &ns : NULL,
244 		    NETBSD32PTR64(SCARG(uap, osa)) ? &os : NULL,
245 		    tramp, vers)) != 0)
246 			return error;
247 	}
248 
249 	if (NETBSD32PTR64(SCARG(uap, osa)) != NULL) {
250 		native_to_linux32_sigaction(&ols32, &os);
251 
252 		if ((error = copyout(&ols32, NETBSD32PTR64(SCARG(uap, osa)),
253 		    sizeof(ols32))) != 0)
254 			return error;
255 	}
256 
257 	return 0;
258 }
259 
260 int
261 linux32_sys_rt_sigprocmask(l, v, retval)
262 	struct lwp *l;
263 	void *v;
264 	register_t *retval;
265 {
266 	struct linux32_sys_rt_sigprocmask_args /* {
267 		syscallarg(int) how;
268 		syscallarg(const linux32_sigsetp_t) set;
269 		syscallarg(linux32_sigsetp_t) oset;
270 		syscallarg(netbsd32_size_t) sigsetsize;
271 	} */ *uap = v;
272 	struct proc *p = l->l_proc;
273 	linux32_sigset_t nls32, ols32;
274 	sigset_t ns, os;
275 	int error;
276 	int how;
277 
278 	if (SCARG(uap, sigsetsize) != sizeof(linux32_sigset_t))
279 		return EINVAL;
280 
281 	switch (SCARG(uap, how)) {
282 	case LINUX32_SIG_BLOCK:
283 		how = SIG_BLOCK;
284 		break;
285 	case LINUX32_SIG_UNBLOCK:
286 		how = SIG_UNBLOCK;
287 		break;
288 	case LINUX32_SIG_SETMASK:
289 		how = SIG_SETMASK;
290 		break;
291 	default:
292 		return EINVAL;
293 		break;
294 	}
295 
296 	if (NETBSD32PTR64(SCARG(uap, set)) != NULL) {
297 		if ((error = copyin(NETBSD32PTR64(SCARG(uap, set)),
298 		    &nls32, sizeof(nls32))) != 0)
299 			return error;
300 		linux32_to_native_sigset(&ns, &nls32);
301 	}
302 
303 	if ((error = sigprocmask1(p, how,
304 	    NETBSD32PTR64(SCARG(uap, set)) ? &ns : NULL,
305 	    NETBSD32PTR64(SCARG(uap, oset)) ? &os : NULL)) != 0)
306 		return error;
307 
308 	if (NETBSD32PTR64(SCARG(uap, oset)) != NULL) {
309 		native_to_linux32_sigset(&ols32, &os);
310 		if ((error = copyout(&ols32,
311 		    NETBSD32PTR64(SCARG(uap, oset)), sizeof(ols32))) != 0)
312 			return error;
313 	}
314 
315 	return 0;
316 }
317 
318 int
319 linux32_sys_kill(l, v, retval)
320 	struct lwp *l;
321 	void *v;
322 	register_t *retval;
323 {
324 	struct linux32_sys_kill_args /* {
325 		syscallarg(int) pid;
326 		syscallarg(int) signum;
327 	} */ *uap = v;
328 
329 	struct sys_kill_args ka;
330 	int sig;
331 
332 	SCARG(&ka, pid) = SCARG(uap, pid);
333 	sig = SCARG(uap, signum);
334 	if (sig < 0 || sig >= LINUX32__NSIG)
335 		return (EINVAL);
336 	SCARG(&ka, signum) = linux32_to_native_signo[sig];
337 	return sys_kill(l, &ka, retval);
338 }
339 
340 int
341 linux32_sys_rt_sigsuspend(l, v, retval)
342 	struct lwp *l;
343 	void *v;
344 	register_t *retval;
345 {
346 	struct linux32_sys_rt_sigsuspend_args /* {
347 		syscallarg(linux32_sigsetp_t) unewset;
348                 syscallarg(netbsd32_size_t) sigsetsize;
349 	} */ *uap = v;
350 	linux32_sigset_t lss;
351 	sigset_t bss;
352 	int error;
353 
354 	if (SCARG(uap, sigsetsize) != sizeof(linux32_sigset_t))
355 		return EINVAL;
356 
357 	if ((error = copyin(NETBSD32PTR64(SCARG(uap, unewset)),
358 	    &lss, sizeof(linux32_sigset_t))) != 0)
359 		return error;
360 
361 	linux32_to_native_sigset(&bss, &lss);
362 
363 	return sigsuspend1(l->l_proc, &bss);
364 }
365 
366 int
367 linux32_sys_signal(l, v, retval)
368 	struct lwp *l;
369 	void *v;
370 	register_t *retval;
371 {
372 	struct linux32_sys_signal_args /* {
373 		syscallarg(int) signum;
374 		syscallarg(linux32_handler_t) handler;
375 	} */ *uap = v;
376         struct proc *p = l->l_proc;
377         struct sigaction nbsa, obsa;
378         int error, sig;
379 
380         *retval = -1;
381 
382         sig = SCARG(uap, signum);
383         if (sig < 0 || sig >= LINUX32__NSIG)
384                 return EINVAL;
385 
386         nbsa.sa_handler = NETBSD32PTR64(SCARG(uap, handler));
387         sigemptyset(&nbsa.sa_mask);
388         nbsa.sa_flags = SA_RESETHAND | SA_NODEFER;
389 
390         if ((error = sigaction1(p, linux32_to_native_signo[sig],
391             &nbsa, &obsa, NULL, 0)) != 0)
392 		return error;
393 
394         *retval = (int)(long)obsa.sa_handler;
395         return 0;
396 }
397