1 /* $NetBSD: linux32_signal.c,v 1.13 2009/06/08 13:34:23 njoly 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 34 #include <sys/cdefs.h> 35 __KERNEL_RCSID(0, "$NetBSD: linux32_signal.c,v 1.13 2009/06/08 13:34:23 njoly Exp $"); 36 37 #include <sys/param.h> 38 #include <sys/ucred.h> 39 #include <sys/signalvar.h> 40 #include <sys/lwp.h> 41 #include <sys/time.h> 42 #include <sys/proc.h> 43 44 #include <compat/netbsd32/netbsd32.h> 45 46 #include <compat/linux32/common/linux32_types.h> 47 #include <compat/linux32/common/linux32_signal.h> 48 #include <compat/linux32/linux32_syscallargs.h> 49 50 #define linux32_sigemptyset(s) memset((s), 0, sizeof(*(s))) 51 #define linux32_sigismember(s, n) ((s)->sig[((n) - 1) / LINUX32__NSIG_BPW] \ 52 & (1 << ((n) - 1) % LINUX32__NSIG_BPW)) 53 #define linux32_sigaddset(s, n) ((s)->sig[((n) - 1) / LINUX32__NSIG_BPW] \ 54 |= (1 << ((n) - 1) % LINUX32__NSIG_BPW)) 55 56 extern const int native_to_linux32_signo[]; 57 extern const int linux32_to_native_signo[]; 58 59 #ifdef DEBUG_LINUX 60 #define DPRINTF(a) uprintf a 61 #else 62 #define DPRINTF(a) 63 #endif 64 65 void 66 linux32_to_native_sigset(sigset_t *bss, const linux32_sigset_t *lss) 67 { 68 int i, newsig; 69 70 sigemptyset(bss); 71 for (i = 1; i < LINUX32__NSIG; i++) { 72 if (linux32_sigismember(lss, i)) { 73 newsig = linux32_to_native_signo[i]; 74 if (newsig) 75 sigaddset(bss, newsig); 76 } 77 } 78 } 79 80 void 81 native_to_linux32_sigset(linux32_sigset_t *lss, const sigset_t *bss) 82 { 83 int i, newsig; 84 85 linux32_sigemptyset(lss); 86 for (i = 1; i < NSIG; i++) { 87 if (sigismember(bss, i)) { 88 newsig = native_to_linux32_signo[i]; 89 if (newsig) 90 linux32_sigaddset(lss, newsig); 91 } 92 } 93 } 94 95 unsigned int 96 native_to_linux32_sigflags(const int bsf) 97 { 98 unsigned int lsf = 0; 99 if ((bsf & SA_NOCLDSTOP) != 0) 100 lsf |= LINUX32_SA_NOCLDSTOP; 101 if ((bsf & SA_NOCLDWAIT) != 0) 102 lsf |= LINUX32_SA_NOCLDWAIT; 103 if ((bsf & SA_ONSTACK) != 0) 104 lsf |= LINUX32_SA_ONSTACK; 105 if ((bsf & SA_RESTART) != 0) 106 lsf |= LINUX32_SA_RESTART; 107 if ((bsf & SA_NODEFER) != 0) 108 lsf |= LINUX32_SA_NOMASK; 109 if ((bsf & SA_RESETHAND) != 0) 110 lsf |= LINUX32_SA_ONESHOT; 111 if ((bsf & SA_SIGINFO) != 0) 112 lsf |= LINUX32_SA_SIGINFO; 113 return lsf; 114 } 115 116 int 117 linux32_to_native_sigflags(const unsigned long lsf) 118 { 119 int bsf = 0; 120 if ((lsf & LINUX32_SA_NOCLDSTOP) != 0) 121 bsf |= SA_NOCLDSTOP; 122 if ((lsf & LINUX32_SA_NOCLDWAIT) != 0) 123 bsf |= SA_NOCLDWAIT; 124 if ((lsf & LINUX32_SA_ONSTACK) != 0) 125 bsf |= SA_ONSTACK; 126 if ((lsf & LINUX32_SA_RESTART) != 0) 127 bsf |= SA_RESTART; 128 if ((lsf & LINUX32_SA_ONESHOT) != 0) 129 bsf |= SA_RESETHAND; 130 if ((lsf & LINUX32_SA_NOMASK) != 0) 131 bsf |= SA_NODEFER; 132 if ((lsf & LINUX32_SA_SIGINFO) != 0) 133 bsf |= SA_SIGINFO; 134 if ((lsf & ~LINUX32_SA_ALLBITS) != 0) { 135 #ifdef DEBUG_LINUX 136 printf("linux32_old_to_native_sigflags: " 137 "%lx extra bits ignored\n", lsf); 138 #endif 139 } 140 return bsf; 141 } 142 143 void 144 linux32_to_native_sigaction(struct sigaction *bsa, const struct linux32_sigaction *lsa) 145 { 146 bsa->sa_handler = NETBSD32PTR64(lsa->linux_sa_handler); 147 linux32_to_native_sigset(&bsa->sa_mask, &lsa->linux_sa_mask); 148 bsa->sa_flags = linux32_to_native_sigflags(lsa->linux_sa_flags); 149 } 150 151 void 152 native_to_linux32_sigaction(struct linux32_sigaction *lsa, const struct sigaction *bsa) 153 { 154 NETBSD32PTR32(lsa->linux_sa_handler, bsa->sa_handler); 155 native_to_linux32_sigset(&lsa->linux_sa_mask, &bsa->sa_mask); 156 lsa->linux_sa_flags = native_to_linux32_sigflags(bsa->sa_flags); 157 NETBSD32PTR32(lsa->linux_sa_restorer, NULL); 158 } 159 160 void 161 native_to_linux32_sigaltstack(struct linux32_sigaltstack *lss, const struct sigaltstack *bss) 162 { 163 NETBSD32PTR32(lss->ss_sp, bss->ss_sp); 164 lss->ss_size = bss->ss_size; 165 if (bss->ss_flags & SS_ONSTACK) 166 lss->ss_flags = LINUX32_SS_ONSTACK; 167 else if (bss->ss_flags & SS_DISABLE) 168 lss->ss_flags = LINUX32_SS_DISABLE; 169 else 170 lss->ss_flags = 0; 171 } 172 173 174 void 175 native_to_linux32_old_sigset(linux32_old_sigset_t *lss, const sigset_t *bss) 176 { 177 linux32_sigset_t lsnew; 178 179 native_to_linux32_sigset(&lsnew, bss); 180 181 /* convert new sigset to old sigset */ 182 *lss = lsnew.sig[0]; 183 } 184 185 void 186 linux32_old_to_native_sigset(sigset_t *bss, const linux32_old_sigset_t *lss) 187 { 188 linux32_sigset_t ls; 189 190 memset(&ls, 0, sizeof(ls)); 191 ls.sig[0] = *lss; 192 193 linux32_to_native_sigset(bss, &ls); 194 } 195 196 int 197 linux32_sys_rt_sigaction(struct lwp *l, const struct linux32_sys_rt_sigaction_args *uap, register_t *retval) 198 { 199 /* { 200 syscallarg(int) signum; 201 syscallarg(const linux32_sigactionp_t) nsa; 202 syscallarg(linux32_sigactionp_t) osa; 203 syscallarg(netbsd32_size_t) sigsetsize; 204 } */ 205 struct linux32_sigaction nls32; 206 struct linux32_sigaction ols32; 207 struct sigaction ns; 208 struct sigaction os; 209 int error; 210 int sig; 211 int vers = 0; 212 void *tramp = NULL; 213 214 if (SCARG(uap, sigsetsize) != sizeof(linux32_sigset_t)) { 215 DPRINTF(("rt_sigaction: Inconsistent sigsetsize %u %zu\n", 216 SCARG(uap, sigsetsize), sizeof(linux32_sigset_t))); 217 return EINVAL; 218 } 219 220 if (SCARG_P32(uap, nsa) != NULL) { 221 if ((error = copyin(SCARG_P32(uap, nsa), 222 &nls32, sizeof(nls32))) != 0) { 223 DPRINTF(("rt_sigaction: Copyin %d\n", error)); 224 return error; 225 } 226 linux32_to_native_sigaction(&ns, &nls32); 227 } 228 229 sig = SCARG(uap, signum); 230 if (sig < 0 || sig >= LINUX32__NSIG) { 231 DPRINTF(("rt_sigaction: Bad signal number %d %d\n", 232 sig, LINUX32__NSIG)); 233 return EINVAL; 234 } 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, 242 linux32_to_native_signo[sig], 243 SCARG_P32(uap, nsa) ? &ns : NULL, 244 SCARG_P32(uap, osa) ? &os : NULL, 245 tramp, vers)) != 0) { 246 DPRINTF(("rt_sigaction: sigaction %d\n", error)); 247 return error; 248 } 249 } 250 251 if (SCARG_P32(uap, osa) != NULL) { 252 native_to_linux32_sigaction(&ols32, &os); 253 254 if ((error = copyout(&ols32, SCARG_P32(uap, osa), 255 sizeof(ols32))) != 0) { 256 DPRINTF(("rt_sigaction: Copyout %d\n", error)); 257 return error; 258 } 259 } 260 261 return 0; 262 } 263 264 int 265 linux32_sys_rt_sigprocmask(struct lwp *l, const struct linux32_sys_rt_sigprocmask_args *uap, register_t *retval) 266 { 267 /* { 268 syscallarg(int) how; 269 syscallarg(const linux32_sigsetp_t) set; 270 syscallarg(linux32_sigsetp_t) oset; 271 syscallarg(netbsd32_size_t) sigsetsize; 272 } */ 273 struct proc *p = l->l_proc; 274 linux32_sigset_t nls32, ols32; 275 sigset_t ns, os; 276 int error; 277 int how; 278 279 if (SCARG(uap, sigsetsize) != sizeof(linux32_sigset_t)) 280 return EINVAL; 281 282 switch (SCARG(uap, how)) { 283 case LINUX32_SIG_BLOCK: 284 how = SIG_BLOCK; 285 break; 286 case LINUX32_SIG_UNBLOCK: 287 how = SIG_UNBLOCK; 288 break; 289 case LINUX32_SIG_SETMASK: 290 how = SIG_SETMASK; 291 break; 292 default: 293 return EINVAL; 294 break; 295 } 296 297 if (SCARG_P32(uap, set) != NULL) { 298 if ((error = copyin(SCARG_P32(uap, set), 299 &nls32, sizeof(nls32))) != 0) 300 return error; 301 linux32_to_native_sigset(&ns, &nls32); 302 } 303 304 mutex_enter(p->p_lock); 305 error = sigprocmask1(l, how, 306 SCARG_P32(uap, set) ? &ns : NULL, 307 SCARG_P32(uap, oset) ? &os : NULL); 308 mutex_exit(p->p_lock); 309 310 if (error != 0) 311 return error; 312 313 if (SCARG_P32(uap, oset) != NULL) { 314 native_to_linux32_sigset(&ols32, &os); 315 if ((error = copyout(&ols32, 316 SCARG_P32(uap, oset), sizeof(ols32))) != 0) 317 return error; 318 } 319 320 return 0; 321 } 322 323 int 324 linux32_sys_kill(struct lwp *l, const struct linux32_sys_kill_args *uap, register_t *retval) 325 { 326 /* { 327 syscallarg(int) pid; 328 syscallarg(int) signum; 329 } */ 330 331 struct sys_kill_args ka; 332 int sig; 333 334 SCARG(&ka, pid) = SCARG(uap, pid); 335 sig = SCARG(uap, signum); 336 if (sig < 0 || sig >= LINUX32__NSIG) 337 return (EINVAL); 338 SCARG(&ka, signum) = linux32_to_native_signo[sig]; 339 return sys_kill(l, &ka, retval); 340 } 341 342 int 343 linux32_sys_rt_sigsuspend(struct lwp *l, const struct linux32_sys_rt_sigsuspend_args *uap, register_t *retval) 344 { 345 /* { 346 syscallarg(linux32_sigsetp_t) unewset; 347 syscallarg(netbsd32_size_t) sigsetsize; 348 } */ 349 linux32_sigset_t lss; 350 sigset_t bss; 351 int error; 352 353 if (SCARG(uap, sigsetsize) != sizeof(linux32_sigset_t)) 354 return EINVAL; 355 356 if ((error = copyin(SCARG_P32(uap, unewset), 357 &lss, sizeof(linux32_sigset_t))) != 0) 358 return error; 359 360 linux32_to_native_sigset(&bss, &lss); 361 362 return sigsuspend1(l, &bss); 363 } 364 365 int 366 linux32_sys_signal(struct lwp *l, const struct linux32_sys_signal_args *uap, register_t *retval) 367 { 368 /* { 369 syscallarg(int) signum; 370 syscallarg(linux32_handler_t) handler; 371 } */ 372 struct sigaction nbsa, obsa; 373 int error, sig; 374 375 *retval = -1; 376 377 sig = SCARG(uap, signum); 378 if (sig < 0 || sig >= LINUX32__NSIG) 379 return EINVAL; 380 381 nbsa.sa_handler = SCARG_P32(uap, handler); 382 sigemptyset(&nbsa.sa_mask); 383 nbsa.sa_flags = SA_RESETHAND | SA_NODEFER; 384 385 if ((error = sigaction1(l, linux32_to_native_signo[sig], 386 &nbsa, &obsa, NULL, 0)) != 0) 387 return error; 388 389 *retval = (int)(long)obsa.sa_handler; 390 return 0; 391 } 392 393 int 394 linux32_sys_rt_sigpending(struct lwp *l, const struct linux32_sys_rt_sigpending_args *uap, register_t *retval) 395 { 396 /* { 397 syscallarg(linux32_sigsetp_t) set; 398 syscallarg(netbsd32_size_t) sigsetsize; 399 } */ 400 sigset_t bss; 401 linux32_sigset_t lss; 402 403 if (SCARG(uap, sigsetsize) != sizeof(linux32_sigset_t)) 404 return EINVAL; 405 406 sigpending1(l, &bss); 407 native_to_linux32_sigset(&lss, &bss); 408 return copyout(&lss, SCARG_P32(uap, set), sizeof(lss)); 409 } 410 411 int 412 linux32_sys_siggetmask(struct lwp *l, const void *v, register_t *retval) 413 { 414 struct proc *p = l->l_proc; 415 sigset_t bss; 416 linux32_old_sigset_t lss; 417 int error; 418 419 mutex_enter(p->p_lock); 420 error = sigprocmask1(l, SIG_SETMASK, 0, &bss); 421 mutex_exit(p->p_lock); 422 if (error) 423 return error; 424 native_to_linux32_old_sigset(&lss, &bss); 425 *retval = lss; 426 return 0; 427 } 428 429 int 430 linux32_sys_sigsetmask(struct lwp *l, const struct linux32_sys_sigsetmask_args *uap, register_t *retval) 431 { 432 /* { 433 syscallarg(linux32_old_sigset_t) mask; 434 } */ 435 sigset_t nbss, obss; 436 linux32_old_sigset_t nlss, olss; 437 struct proc *p = l->l_proc; 438 int error; 439 440 nlss = SCARG(uap, mask); 441 linux32_old_to_native_sigset(&nbss, &nlss); 442 mutex_enter(p->p_lock); 443 error = sigprocmask1(l, SIG_SETMASK, &nbss, &obss); 444 mutex_exit(p->p_lock); 445 if (error) 446 return error; 447 native_to_linux32_old_sigset(&olss, &obss); 448 *retval = olss; 449 return 0; 450 } 451 452 int 453 linux32_sys_rt_queueinfo(struct lwp *l, const struct linux32_sys_rt_queueinfo_args *uap, register_t *retval) 454 { 455 /* 456 syscallarg(int) pid; 457 syscallarg(int) sig; 458 syscallarg(linux32_siginfop_t) uinfo; 459 */ 460 int error; 461 linux32_siginfo_t info; 462 463 error = copyin(SCARG_P32(uap, uinfo), &info, sizeof(info)); 464 if (error) 465 return error; 466 if (info.lsi_code >= 0) 467 return EPERM; 468 469 /* XXX To really implement this we need to */ 470 /* XXX keep a list of queued signals somewhere. */ 471 return linux32_sys_kill(l, (const void *)uap, retval); 472 } 473