1 /* $NetBSD: linux_signal.c,v 1.25 1999/12/04 22:26:52 tron Exp $ */ 2 /*- 3 * Copyright (c) 1995, 1998 The NetBSD Foundation, Inc. 4 * All rights reserved. 5 * 6 * This code is derived from software contributed to The NetBSD Foundation 7 * by Frank van der Linden and Eric Haszlakiewicz. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by the NetBSD 20 * Foundation, Inc. and its contributors. 21 * 4. Neither the name of The NetBSD Foundation nor the names of its 22 * contributors may be used to endorse or promote products derived 23 * from this software without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 26 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 * POSSIBILITY OF SUCH DAMAGE. 36 */ 37 /* 38 * heavily from: svr4_signal.c,v 1.7 1995/01/09 01:04:21 christos Exp 39 */ 40 41 /* 42 * Functions in multiarch: 43 * linux_sys_signal : linux_sig_notalpha.c 44 * linux_sys_siggetmask : linux_sig_notalpha.c 45 * linux_sys_sigsetmask : linux_sig_notalpha.c 46 * linux_sys_pause : linux_sig_notalpha.c 47 * linux_sys_sigaction : linux_sigaction.c 48 * 49 */ 50 51 /* 52 * Unimplemented: 53 * linux_sys_rt_sigtimedwait : sigsuspend w/timeout. 54 */ 55 56 #define COMPAT_LINUX 1 57 58 #include <sys/param.h> 59 #include <sys/systm.h> 60 #include <sys/namei.h> 61 #include <sys/proc.h> 62 #include <sys/filedesc.h> 63 #include <sys/ioctl.h> 64 #include <sys/mount.h> 65 #include <sys/kernel.h> 66 #include <sys/signal.h> 67 #include <sys/signalvar.h> 68 #include <sys/malloc.h> 69 70 #include <sys/syscallargs.h> 71 72 #include <compat/linux/common/linux_types.h> 73 #include <compat/linux/common/linux_signal.h> 74 #include <compat/linux/common/linux_siginfo.h> 75 #include <compat/linux/common/linux_util.h> 76 77 #include <compat/linux/linux_syscallargs.h> 78 79 /* Locally used defines (in bsd<->linux conversion functions): */ 80 #define linux_sigemptyset(s) memset((s), 0, sizeof(*(s))) 81 #define linux_sigismember(s, n) ((s)->sig[((n) - 1) / LINUX__NSIG_BPW] \ 82 & (1 << ((n) - 1) % LINUX__NSIG_BPW)) 83 #define linux_sigaddset(s, n) ((s)->sig[((n) - 1) / LINUX__NSIG_BPW] \ 84 |= (1 << ((n) - 1) % LINUX__NSIG_BPW)) 85 86 /* Note: linux_to_native_sig[] is in <arch>/linux_sigarray.c */ 87 int native_to_linux_sig[NSIG] = { 88 0, 89 LINUX_SIGHUP, 90 LINUX_SIGINT, 91 LINUX_SIGQUIT, 92 LINUX_SIGILL, 93 LINUX_SIGTRAP, 94 LINUX_SIGABRT, 95 0, /* SIGEMT */ 96 LINUX_SIGFPE, 97 LINUX_SIGKILL, 98 LINUX_SIGBUS, 99 LINUX_SIGSEGV, 100 0, /* SIGSYS */ 101 LINUX_SIGPIPE, 102 LINUX_SIGALRM, 103 LINUX_SIGTERM, 104 LINUX_SIGURG, 105 LINUX_SIGSTOP, 106 LINUX_SIGTSTP, 107 LINUX_SIGCONT, 108 LINUX_SIGCHLD, 109 LINUX_SIGTTIN, 110 LINUX_SIGTTOU, 111 LINUX_SIGIO, 112 LINUX_SIGXCPU, 113 LINUX_SIGXFSZ, 114 LINUX_SIGVTALRM, 115 LINUX_SIGPROF, 116 LINUX_SIGWINCH, 117 0, /* SIGINFO */ 118 LINUX_SIGUSR1, 119 LINUX_SIGUSR2, 120 LINUX_SIGPWR, 121 }; 122 123 /* 124 * Convert between Linux and BSD signal sets. 125 */ 126 #if LINUX__NSIG_WORDS > 1 127 void 128 linux_old_extra_to_native_sigset(lss, extra, bss) 129 const linux_old_sigset_t *lss; 130 const unsigned long *extra; 131 sigset_t *bss; 132 { 133 linux_sigset_t lsnew; 134 135 /* convert old sigset to new sigset */ 136 linux_sigemptyset(&lsnew); 137 lsnew.sig[0] = *lss; 138 if (extra) 139 bcopy(extra, &lsnew.sig[1], 140 sizeof(linux_sigset_t) - sizeof(linux_old_sigset_t)); 141 142 linux_to_native_sigset(&lsnew, bss); 143 } 144 145 void 146 native_to_linux_old_extra_sigset(bss, lss, extra) 147 const sigset_t *bss; 148 linux_old_sigset_t *lss; 149 unsigned long *extra; 150 { 151 linux_sigset_t lsnew; 152 153 native_to_linux_sigset(bss, &lsnew); 154 155 /* convert new sigset to old sigset */ 156 *lss = lsnew.sig[0]; 157 if (extra) 158 bcopy(&lsnew.sig[1], extra, 159 sizeof(linux_sigset_t) - sizeof(linux_old_sigset_t)); 160 } 161 #endif 162 163 void 164 linux_to_native_sigset(lss, bss) 165 const linux_sigset_t *lss; 166 sigset_t *bss; 167 { 168 int i, newsig; 169 170 sigemptyset(bss); 171 for (i = 1; i < LINUX__NSIG; i++) { 172 if (linux_sigismember(lss, i)) { 173 newsig = linux_to_native_sig[i]; 174 if (newsig) 175 sigaddset(bss, newsig); 176 } 177 } 178 } 179 180 void 181 native_to_linux_sigset(bss, lss) 182 const sigset_t *bss; 183 linux_sigset_t *lss; 184 { 185 int i, newsig; 186 187 linux_sigemptyset(lss); 188 for (i = 1; i < NSIG; i++) { 189 if (sigismember(bss, i)) { 190 newsig = native_to_linux_sig[i]; 191 if (newsig) 192 linux_sigaddset(lss, newsig); 193 } 194 } 195 } 196 197 /* 198 * Convert between Linux and BSD sigaction structures. Linux sometimes 199 * has one extra field (sa_restorer) which we don't support. 200 */ 201 void 202 linux_old_to_native_sigaction(lsa, bsa) 203 struct linux_old_sigaction *lsa; 204 struct sigaction *bsa; 205 { 206 207 bsa->sa_handler = lsa->sa_handler; 208 linux_old_to_native_sigset(&lsa->sa_mask, &bsa->sa_mask); 209 bsa->sa_flags = 0; 210 if ((lsa->sa_flags & LINUX_SA_NOCLDSTOP) != 0) 211 bsa->sa_flags |= SA_NOCLDSTOP; 212 if ((lsa->sa_flags & LINUX_SA_ONSTACK) != 0) 213 bsa->sa_flags |= SA_ONSTACK; 214 if ((lsa->sa_flags & LINUX_SA_RESTART) != 0) 215 bsa->sa_flags |= SA_RESTART; 216 if ((lsa->sa_flags & LINUX_SA_ONESHOT) != 0) 217 bsa->sa_flags |= SA_RESETHAND; 218 if ((lsa->sa_flags & LINUX_SA_NOMASK) != 0) 219 bsa->sa_flags |= SA_NODEFER; 220 if ((lsa->sa_flags & LINUX_SA_SIGINFO) != 0) 221 bsa->sa_flags |= SA_SIGINFO; 222 #ifdef DEBUG_LINUX 223 if ((lsa->sa_flags & ~LINUX_SA_ALLBITS) != 0) 224 /*XXX*/ printf("linux_old_to_native_sigaction: extra bits ignored\n"); 225 if (lsa->sa_restorer != 0) 226 /*XXX*/ printf("linux_old_to_native_sigaction: sa_restorer ignored\n"); 227 #endif 228 } 229 230 void 231 native_to_linux_old_sigaction(bsa, lsa) 232 struct sigaction *bsa; 233 struct linux_old_sigaction *lsa; 234 { 235 236 /* Clear sa_flags and sa_restorer (if it exists) */ 237 bzero(lsa, sizeof(struct linux_old_sigaction)); 238 239 /* ...and fill in the mask and flags */ 240 native_to_linux_old_sigset(&bsa->sa_mask, &lsa->sa_mask); 241 if ((bsa->sa_flags & SA_NOCLDSTOP) != 0) 242 lsa->sa_flags |= LINUX_SA_NOCLDSTOP; 243 if ((bsa->sa_flags & SA_ONSTACK) != 0) 244 lsa->sa_flags |= LINUX_SA_ONSTACK; 245 if ((bsa->sa_flags & SA_RESTART) != 0) 246 lsa->sa_flags |= LINUX_SA_RESTART; 247 if ((bsa->sa_flags & SA_NODEFER) != 0) 248 lsa->sa_flags |= LINUX_SA_NOMASK; 249 if ((bsa->sa_flags & SA_RESETHAND) != 0) 250 lsa->sa_flags |= LINUX_SA_ONESHOT; 251 if ((bsa->sa_flags & SA_SIGINFO) != 0) 252 lsa->sa_flags |= LINUX_SA_SIGINFO; 253 lsa->sa_handler = bsa->sa_handler; 254 } 255 256 /* ...and the new sigaction conversion funcs. */ 257 void 258 linux_to_native_sigaction(lsa, bsa) 259 struct linux_sigaction *lsa; 260 struct sigaction *bsa; 261 { 262 263 bsa->sa_handler = lsa->sa_handler; 264 linux_to_native_sigset(&lsa->sa_mask, &bsa->sa_mask); 265 bsa->sa_flags = 0; 266 if ((lsa->sa_flags & LINUX_SA_NOCLDSTOP) != 0) 267 bsa->sa_flags |= SA_NOCLDSTOP; 268 if ((lsa->sa_flags & LINUX_SA_ONSTACK) != 0) 269 bsa->sa_flags |= SA_ONSTACK; 270 if ((lsa->sa_flags & LINUX_SA_RESTART) != 0) 271 bsa->sa_flags |= SA_RESTART; 272 if ((lsa->sa_flags & LINUX_SA_ONESHOT) != 0) 273 bsa->sa_flags |= SA_RESETHAND; 274 if ((lsa->sa_flags & LINUX_SA_NOMASK) != 0) 275 bsa->sa_flags |= SA_NODEFER; 276 if ((lsa->sa_flags & LINUX_SA_SIGINFO) != 0) 277 bsa->sa_flags |= SA_SIGINFO; 278 #ifdef DEBUG_LINUX 279 if ((lsa->sa_flags & ~LINUX_SA_ALLBITS) != 0) 280 /*XXX*/ printf("linux_to_native_sigaction: extra bits ignored\n"); 281 if (lsa->sa_restorer != 0) 282 /*XXX*/ printf("linux_to_native_sigaction: sa_restorer ignored\n"); 283 #endif 284 } 285 286 void 287 native_to_linux_sigaction(bsa, lsa) 288 struct sigaction *bsa; 289 struct linux_sigaction *lsa; 290 { 291 292 /* Clear sa_flags and sa_restorer (if it exists) */ 293 bzero(lsa, sizeof(struct linux_sigaction)); 294 295 /* ...and fill in the mask and flags */ 296 native_to_linux_sigset(&bsa->sa_mask, &lsa->sa_mask); 297 if ((bsa->sa_flags & SA_NOCLDSTOP) != 0) 298 lsa->sa_flags |= LINUX_SA_NOCLDSTOP; 299 if ((bsa->sa_flags & SA_ONSTACK) != 0) 300 lsa->sa_flags |= LINUX_SA_ONSTACK; 301 if ((bsa->sa_flags & SA_RESTART) != 0) 302 lsa->sa_flags |= LINUX_SA_RESTART; 303 if ((bsa->sa_flags & SA_NODEFER) != 0) 304 lsa->sa_flags |= LINUX_SA_NOMASK; 305 if ((bsa->sa_flags & SA_RESETHAND) != 0) 306 lsa->sa_flags |= LINUX_SA_ONESHOT; 307 if ((bsa->sa_flags & SA_SIGINFO) != 0) 308 lsa->sa_flags |= LINUX_SA_SIGINFO; 309 lsa->sa_handler = bsa->sa_handler; 310 } 311 312 /* ----------------------------------------------------------------------- */ 313 314 /* 315 * The Linux sigaction() system call. Do the usual conversions, 316 * and just call sigaction(). Some flags and values are silently 317 * ignored (see above). 318 */ 319 int 320 linux_sys_rt_sigaction(p, v, retval) 321 register struct proc *p; 322 void *v; 323 register_t *retval; 324 { 325 struct linux_sys_rt_sigaction_args /* { 326 syscallarg(int) signum; 327 syscallarg(const struct linux_sigaction *) nsa; 328 syscallarg(struct linux_sigaction *) osa; 329 syscallarg(size_t) sigsetsize; 330 } */ *uap = v; 331 struct linux_sigaction nlsa, olsa; 332 struct sigaction nbsa, obsa; 333 int error, sig; 334 335 if (SCARG(uap, sigsetsize) != sizeof(linux_sigset_t)) 336 return (EINVAL); 337 338 if (SCARG(uap, nsa)) { 339 error = copyin(SCARG(uap, nsa), &nlsa, sizeof(nlsa)); 340 if (error) 341 return (error); 342 linux_to_native_sigaction(&nlsa, &nbsa); 343 } 344 sig = SCARG(uap, signum); 345 if (sig < 0 || sig >= LINUX__NSIG) 346 return (EINVAL); 347 error = sigaction1(p, linux_to_native_sig[sig], 348 SCARG(uap, nsa) ? &nbsa : 0, SCARG(uap, osa) ? &obsa : 0); 349 if (error) 350 return (error); 351 if (SCARG(uap, osa)) { 352 native_to_linux_sigaction(&obsa, &olsa); 353 error = copyout(&olsa, SCARG(uap, osa), sizeof(olsa)); 354 if (error) 355 return (error); 356 } 357 return (0); 358 } 359 360 int 361 linux_sigprocmask1(p, how, set, oset) 362 register struct proc *p; 363 int how; 364 const linux_old_sigset_t *set; 365 linux_old_sigset_t *oset; 366 { 367 linux_old_sigset_t nlss, olss; 368 sigset_t nbss, obss; 369 int error; 370 371 switch (how) { 372 case LINUX_SIG_BLOCK: 373 how = SIG_BLOCK; 374 break; 375 case LINUX_SIG_UNBLOCK: 376 how = SIG_UNBLOCK; 377 break; 378 case LINUX_SIG_SETMASK: 379 how = SIG_SETMASK; 380 break; 381 default: 382 return (EINVAL); 383 } 384 385 if (set) { 386 error = copyin(set, &nlss, sizeof(nlss)); 387 if (error) 388 return (error); 389 linux_old_to_native_sigset(&nlss, &nbss); 390 } 391 error = sigprocmask1(p, how, 392 set ? &nbss : 0, oset ? &obss : 0); 393 if (error) 394 return (error); 395 if (oset) { 396 native_to_linux_old_sigset(&obss, &olss); 397 error = copyout(&olss, oset, sizeof(olss)); 398 if (error) 399 return (error); 400 } 401 return (error); 402 } 403 404 int 405 linux_sys_rt_sigprocmask(p, v, retval) 406 register struct proc *p; 407 void *v; 408 register_t *retval; 409 { 410 struct linux_sys_rt_sigprocmask_args /* { 411 syscallarg(int) how; 412 syscallarg(const linux_sigset_t *) set; 413 syscallarg(linux_sigset_t *) oset; 414 syscallarg(size_t) sigsetsize; 415 } */ *uap = v; 416 417 linux_sigset_t nlss, olss, *oset; 418 const linux_sigset_t *set; 419 sigset_t nbss, obss; 420 int error, how; 421 422 if (SCARG(uap, sigsetsize) != sizeof(linux_sigset_t)) 423 return (EINVAL); 424 425 switch (SCARG(uap, how)) { 426 case LINUX_SIG_BLOCK: 427 how = SIG_BLOCK; 428 break; 429 case LINUX_SIG_UNBLOCK: 430 how = SIG_UNBLOCK; 431 break; 432 case LINUX_SIG_SETMASK: 433 how = SIG_SETMASK; 434 break; 435 default: 436 return (EINVAL); 437 } 438 439 set = SCARG(uap, set); 440 oset = SCARG(uap, oset); 441 442 if (set) { 443 error = copyin(set, &nlss, sizeof(nlss)); 444 if (error) 445 return (error); 446 linux_to_native_sigset(&nlss, &nbss); 447 } 448 error = sigprocmask1(p, how, 449 set ? &nbss : 0, oset ? &obss : 0); 450 if (error) 451 return (error); 452 if (oset) { 453 native_to_linux_sigset(&obss, &olss); 454 error = copyout(&olss, oset, sizeof(olss)); 455 if (error) 456 return (error); 457 } 458 return (error); 459 } 460 461 int 462 linux_sys_rt_sigpending(p, v, retval) 463 register struct proc *p; 464 void *v; 465 register_t *retval; 466 { 467 struct linux_sys_rt_sigpending_args /* { 468 syscallarg(linux_sigset_t *) set; 469 syscallarg(size_t) sigsetsize; 470 } */ *uap = v; 471 sigset_t bss; 472 linux_sigset_t lss; 473 474 if (SCARG(uap, sigsetsize) != sizeof(linux_sigset_t)) 475 return (EINVAL); 476 477 sigpending1(p, &bss); 478 native_to_linux_sigset(&bss, &lss); 479 return copyout(&lss, SCARG(uap, set), sizeof(lss)); 480 } 481 482 int 483 linux_sys_sigpending(p, v, retval) 484 register struct proc *p; 485 void *v; 486 register_t *retval; 487 { 488 struct linux_sys_sigpending_args /* { 489 syscallarg(linux_old_sigset_t *) mask; 490 } */ *uap = v; 491 sigset_t bss; 492 linux_old_sigset_t lss; 493 494 sigpending1(p, &bss); 495 native_to_linux_old_sigset(&bss, &lss); 496 return copyout(&lss, SCARG(uap, set), sizeof(lss)); 497 } 498 499 int 500 linux_sys_sigsuspend(p, v, retval) 501 register struct proc *p; 502 void *v; 503 register_t *retval; 504 { 505 struct linux_sys_sigsuspend_args /* { 506 syscallarg(caddr_t) restart; 507 syscallarg(int) oldmask; 508 syscallarg(int) mask; 509 } */ *uap = v; 510 linux_old_sigset_t lss; 511 sigset_t bss; 512 513 lss = SCARG(uap, mask); 514 linux_old_to_native_sigset(&lss, &bss); 515 return (sigsuspend1(p, &bss)); 516 } 517 int 518 linux_sys_rt_sigsuspend(p, v, retval) 519 register struct proc *p; 520 void *v; 521 register_t *retval; 522 { 523 struct linux_sys_rt_sigsuspend_args /* { 524 syscallarg(linux_sigset_t *) unewset; 525 syscallarg(size_t) sigsetsize; 526 } */ *uap = v; 527 linux_sigset_t lss; 528 sigset_t bss; 529 int error; 530 531 if (SCARG(uap, sigsetsize) != sizeof(linux_sigset_t)) 532 return (EINVAL); 533 534 error = copyin(SCARG(uap, unewset), &lss, sizeof(linux_sigset_t)); 535 if (error) 536 return (error); 537 538 linux_to_native_sigset(&lss, &bss); 539 540 return (sigsuspend1(p, &bss)); 541 } 542 543 /* 544 * Once more: only a signal conversion is needed. 545 * Note: also used as sys_rt_queueinfo. The info field is ignored. 546 */ 547 int 548 linux_sys_rt_queueinfo(p, v, retval) 549 register struct proc *p; 550 void *v; 551 register_t *retval; 552 { 553 /* XXX XAX This isn't this really int, int, siginfo_t *, is it? */ 554 #if 0 555 struct linux_sys_rt_queueinfo_args /* { 556 syscallarg(int) pid; 557 syscallarg(int) signum; 558 syscallarg(siginfo_t *) uinfo; 559 } */ *uap = v; 560 #endif 561 562 /* XXX To really implement this we need to */ 563 /* XXX keep a list of queued signals somewhere. */ 564 return (linux_sys_kill(p, v, retval)); 565 } 566 567 int 568 linux_sys_kill(p, v, retval) 569 register struct proc *p; 570 void *v; 571 register_t *retval; 572 { 573 struct linux_sys_kill_args /* { 574 syscallarg(int) pid; 575 syscallarg(int) signum; 576 } */ *uap = v; 577 struct sys_kill_args ka; 578 int sig; 579 580 SCARG(&ka, pid) = SCARG(uap, pid); 581 sig = SCARG(uap, signum); 582 if (sig < 0 || sig >= LINUX__NSIG) 583 return (EINVAL); 584 SCARG(&ka, signum) = linux_to_native_sig[sig]; 585 return sys_kill(p, &ka, retval); 586 } 587