diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-02-23 21:50:11 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-02-23 21:50:11 -0500 |
commit | 9e2d59ad580d590134285f361a0e80f0e98c0207 (patch) | |
tree | f3232be75781484193413f32ec82c21f6d8eb76e /arch/alpha | |
parent | 5ce1a70e2f00f0bce0cab57f798ca354b9496169 (diff) | |
parent | 235b80226b986dabcbba844968f7807866bd0bfe (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/signal
Pull signal handling cleanups from Al Viro:
"This is the first pile; another one will come a bit later and will
contain SYSCALL_DEFINE-related patches.
- a bunch of signal-related syscalls (both native and compat)
unified.
- a bunch of compat syscalls switched to COMPAT_SYSCALL_DEFINE
(fixing several potential problems with missing argument
validation, while we are at it)
- a lot of now-pointless wrappers killed
- a couple of architectures (cris and hexagon) forgot to save
altstack settings into sigframe, even though they used the
(uninitialized) values in sigreturn; fixed.
- microblaze fixes for delivery of multiple signals arriving at once
- saner set of helpers for signal delivery introduced, several
architectures switched to using those."
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/signal: (143 commits)
x86: convert to ksignal
sparc: convert to ksignal
arm: switch to struct ksignal * passing
alpha: pass k_sigaction and siginfo_t using ksignal pointer
burying unused conditionals
make do_sigaltstack() static
arm64: switch to generic old sigaction() (compat-only)
arm64: switch to generic compat rt_sigaction()
arm64: switch compat to generic old sigsuspend
arm64: switch to generic compat rt_sigqueueinfo()
arm64: switch to generic compat rt_sigpending()
arm64: switch to generic compat rt_sigprocmask()
arm64: switch to generic sigaltstack
sparc: switch to generic old sigsuspend
sparc: COMPAT_SYSCALL_DEFINE does all sign-extension as well as SYSCALL_DEFINE
sparc: kill sign-extending wrappers for native syscalls
kill sparc32_open()
sparc: switch to use of generic old sigaction
sparc: switch sys_compat_rt_sigaction() to COMPAT_SYSCALL_DEFINE
mips: switch to generic sys_fork() and sys_clone()
...
Diffstat (limited to 'arch/alpha')
-rw-r--r-- | arch/alpha/Kconfig | 3 | ||||
-rw-r--r-- | arch/alpha/include/asm/signal.h | 11 | ||||
-rw-r--r-- | arch/alpha/include/asm/unistd.h | 1 | ||||
-rw-r--r-- | arch/alpha/kernel/process.c | 1 | ||||
-rw-r--r-- | arch/alpha/kernel/signal.c | 121 |
5 files changed, 48 insertions, 89 deletions
diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig index dabc93649495..1ecbf7a1b677 100644 --- a/arch/alpha/Kconfig +++ b/arch/alpha/Kconfig | |||
@@ -21,7 +21,8 @@ config ALPHA | |||
21 | select GENERIC_STRNLEN_USER | 21 | select GENERIC_STRNLEN_USER |
22 | select HAVE_MOD_ARCH_SPECIFIC | 22 | select HAVE_MOD_ARCH_SPECIFIC |
23 | select MODULES_USE_ELF_RELA | 23 | select MODULES_USE_ELF_RELA |
24 | select GENERIC_SIGALTSTACK | 24 | select ODD_RT_SIGACTION |
25 | select OLD_SIGSUSPEND | ||
25 | help | 26 | help |
26 | The Alpha is a 64-bit general-purpose processor designed and | 27 | The Alpha is a 64-bit general-purpose processor designed and |
27 | marketed by the Digital Equipment Corporation of blessed memory, | 28 | marketed by the Digital Equipment Corporation of blessed memory, |
diff --git a/arch/alpha/include/asm/signal.h b/arch/alpha/include/asm/signal.h index 8a1ac28cd562..963f0494dca7 100644 --- a/arch/alpha/include/asm/signal.h +++ b/arch/alpha/include/asm/signal.h | |||
@@ -22,15 +22,6 @@ struct osf_sigaction { | |||
22 | int sa_flags; | 22 | int sa_flags; |
23 | }; | 23 | }; |
24 | 24 | ||
25 | struct sigaction { | 25 | #define __ARCH_HAS_KA_RESTORER |
26 | __sighandler_t sa_handler; | ||
27 | unsigned long sa_flags; | ||
28 | sigset_t sa_mask; /* mask last for extensibility */ | ||
29 | }; | ||
30 | |||
31 | struct k_sigaction { | ||
32 | struct sigaction sa; | ||
33 | __sigrestore_t ka_restorer; | ||
34 | }; | ||
35 | #include <asm/sigcontext.h> | 26 | #include <asm/sigcontext.h> |
36 | #endif | 27 | #endif |
diff --git a/arch/alpha/include/asm/unistd.h b/arch/alpha/include/asm/unistd.h index b3396ee039b7..6d6fe7ab5473 100644 --- a/arch/alpha/include/asm/unistd.h +++ b/arch/alpha/include/asm/unistd.h | |||
@@ -14,7 +14,6 @@ | |||
14 | #define __ARCH_WANT_SYS_OLD_GETRLIMIT | 14 | #define __ARCH_WANT_SYS_OLD_GETRLIMIT |
15 | #define __ARCH_WANT_SYS_OLDUMOUNT | 15 | #define __ARCH_WANT_SYS_OLDUMOUNT |
16 | #define __ARCH_WANT_SYS_SIGPENDING | 16 | #define __ARCH_WANT_SYS_SIGPENDING |
17 | #define __ARCH_WANT_SYS_RT_SIGSUSPEND | ||
18 | #define __ARCH_WANT_SYS_FORK | 17 | #define __ARCH_WANT_SYS_FORK |
19 | #define __ARCH_WANT_SYS_VFORK | 18 | #define __ARCH_WANT_SYS_VFORK |
20 | #define __ARCH_WANT_SYS_CLONE | 19 | #define __ARCH_WANT_SYS_CLONE |
diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c index b5d0d0923699..63d27fb9b023 100644 --- a/arch/alpha/kernel/process.c +++ b/arch/alpha/kernel/process.c | |||
@@ -250,7 +250,6 @@ copy_thread(unsigned long clone_flags, unsigned long usp, | |||
250 | struct pt_regs *childregs = task_pt_regs(p); | 250 | struct pt_regs *childregs = task_pt_regs(p); |
251 | struct pt_regs *regs = current_pt_regs(); | 251 | struct pt_regs *regs = current_pt_regs(); |
252 | struct switch_stack *childstack, *stack; | 252 | struct switch_stack *childstack, *stack; |
253 | unsigned long settls; | ||
254 | 253 | ||
255 | childstack = ((struct switch_stack *) childregs) - 1; | 254 | childstack = ((struct switch_stack *) childregs) - 1; |
256 | childti->pcb.ksp = (unsigned long) childstack; | 255 | childti->pcb.ksp = (unsigned long) childstack; |
diff --git a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c index 02d02c047f17..6cec2881acbf 100644 --- a/arch/alpha/kernel/signal.c +++ b/arch/alpha/kernel/signal.c | |||
@@ -113,16 +113,6 @@ SYSCALL_DEFINE5(rt_sigaction, int, sig, const struct sigaction __user *, act, | |||
113 | } | 113 | } |
114 | 114 | ||
115 | /* | 115 | /* |
116 | * Atomically swap in the new signal mask, and wait for a signal. | ||
117 | */ | ||
118 | SYSCALL_DEFINE1(sigsuspend, old_sigset_t, mask) | ||
119 | { | ||
120 | sigset_t blocked; | ||
121 | siginitset(&blocked, mask); | ||
122 | return sigsuspend(&blocked); | ||
123 | } | ||
124 | |||
125 | /* | ||
126 | * Do a signal return; undo the signal stack. | 116 | * Do a signal return; undo the signal stack. |
127 | */ | 117 | */ |
128 | 118 | ||
@@ -282,12 +272,9 @@ give_sigsegv: | |||
282 | */ | 272 | */ |
283 | 273 | ||
284 | static inline void __user * | 274 | static inline void __user * |
285 | get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size) | 275 | get_sigframe(struct ksignal *ksig, unsigned long sp, size_t frame_size) |
286 | { | 276 | { |
287 | if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! sas_ss_flags(sp)) | 277 | return (void __user *)((sigsp(sp, ksig) - frame_size) & -32ul); |
288 | sp = current->sas_ss_sp + current->sas_ss_size; | ||
289 | |||
290 | return (void __user *)((sp - frame_size) & -32ul); | ||
291 | } | 278 | } |
292 | 279 | ||
293 | static long | 280 | static long |
@@ -348,14 +335,13 @@ setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, | |||
348 | } | 335 | } |
349 | 336 | ||
350 | static int | 337 | static int |
351 | setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, | 338 | setup_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs) |
352 | struct pt_regs *regs) | ||
353 | { | 339 | { |
354 | unsigned long oldsp, r26, err = 0; | 340 | unsigned long oldsp, r26, err = 0; |
355 | struct sigframe __user *frame; | 341 | struct sigframe __user *frame; |
356 | 342 | ||
357 | oldsp = rdusp(); | 343 | oldsp = rdusp(); |
358 | frame = get_sigframe(ka, oldsp, sizeof(*frame)); | 344 | frame = get_sigframe(ksig, oldsp, sizeof(*frame)); |
359 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | 345 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
360 | return -EFAULT; | 346 | return -EFAULT; |
361 | 347 | ||
@@ -365,9 +351,8 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, | |||
365 | 351 | ||
366 | /* Set up to return from userspace. If provided, use a stub | 352 | /* Set up to return from userspace. If provided, use a stub |
367 | already in userspace. */ | 353 | already in userspace. */ |
368 | if (ka->ka_restorer) { | 354 | r26 = (unsigned long) ksig->ka.ka_restorer; |
369 | r26 = (unsigned long) ka->ka_restorer; | 355 | if (!r26) { |
370 | } else { | ||
371 | err |= __put_user(INSN_MOV_R30_R16, frame->retcode+0); | 356 | err |= __put_user(INSN_MOV_R30_R16, frame->retcode+0); |
372 | err |= __put_user(INSN_LDI_R0+__NR_sigreturn, frame->retcode+1); | 357 | err |= __put_user(INSN_LDI_R0+__NR_sigreturn, frame->retcode+1); |
373 | err |= __put_user(INSN_CALLSYS, frame->retcode+2); | 358 | err |= __put_user(INSN_CALLSYS, frame->retcode+2); |
@@ -381,8 +366,8 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, | |||
381 | 366 | ||
382 | /* "Return" to the handler */ | 367 | /* "Return" to the handler */ |
383 | regs->r26 = r26; | 368 | regs->r26 = r26; |
384 | regs->r27 = regs->pc = (unsigned long) ka->sa.sa_handler; | 369 | regs->r27 = regs->pc = (unsigned long) ksig->ka.sa.sa_handler; |
385 | regs->r16 = sig; /* a0: signal number */ | 370 | regs->r16 = ksig->sig; /* a0: signal number */ |
386 | regs->r17 = 0; /* a1: exception code */ | 371 | regs->r17 = 0; /* a1: exception code */ |
387 | regs->r18 = (unsigned long) &frame->sc; /* a2: sigcontext pointer */ | 372 | regs->r18 = (unsigned long) &frame->sc; /* a2: sigcontext pointer */ |
388 | wrusp((unsigned long) frame); | 373 | wrusp((unsigned long) frame); |
@@ -395,18 +380,17 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, | |||
395 | } | 380 | } |
396 | 381 | ||
397 | static int | 382 | static int |
398 | setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | 383 | setup_rt_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs) |
399 | sigset_t *set, struct pt_regs *regs) | ||
400 | { | 384 | { |
401 | unsigned long oldsp, r26, err = 0; | 385 | unsigned long oldsp, r26, err = 0; |
402 | struct rt_sigframe __user *frame; | 386 | struct rt_sigframe __user *frame; |
403 | 387 | ||
404 | oldsp = rdusp(); | 388 | oldsp = rdusp(); |
405 | frame = get_sigframe(ka, oldsp, sizeof(*frame)); | 389 | frame = get_sigframe(ksig, oldsp, sizeof(*frame)); |
406 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | 390 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
407 | return -EFAULT; | 391 | return -EFAULT; |
408 | 392 | ||
409 | err |= copy_siginfo_to_user(&frame->info, info); | 393 | err |= copy_siginfo_to_user(&frame->info, &ksig->info); |
410 | 394 | ||
411 | /* Create the ucontext. */ | 395 | /* Create the ucontext. */ |
412 | err |= __put_user(0, &frame->uc.uc_flags); | 396 | err |= __put_user(0, &frame->uc.uc_flags); |
@@ -421,9 +405,8 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
421 | 405 | ||
422 | /* Set up to return from userspace. If provided, use a stub | 406 | /* Set up to return from userspace. If provided, use a stub |
423 | already in userspace. */ | 407 | already in userspace. */ |
424 | if (ka->ka_restorer) { | 408 | r26 = (unsigned long) ksig->ka.ka_restorer; |
425 | r26 = (unsigned long) ka->ka_restorer; | 409 | if (!r26) { |
426 | } else { | ||
427 | err |= __put_user(INSN_MOV_R30_R16, frame->retcode+0); | 410 | err |= __put_user(INSN_MOV_R30_R16, frame->retcode+0); |
428 | err |= __put_user(INSN_LDI_R0+__NR_rt_sigreturn, | 411 | err |= __put_user(INSN_LDI_R0+__NR_rt_sigreturn, |
429 | frame->retcode+1); | 412 | frame->retcode+1); |
@@ -437,8 +420,8 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
437 | 420 | ||
438 | /* "Return" to the handler */ | 421 | /* "Return" to the handler */ |
439 | regs->r26 = r26; | 422 | regs->r26 = r26; |
440 | regs->r27 = regs->pc = (unsigned long) ka->sa.sa_handler; | 423 | regs->r27 = regs->pc = (unsigned long) ksig->ka.sa.sa_handler; |
441 | regs->r16 = sig; /* a0: signal number */ | 424 | regs->r16 = ksig->sig; /* a0: signal number */ |
442 | regs->r17 = (unsigned long) &frame->info; /* a1: siginfo pointer */ | 425 | regs->r17 = (unsigned long) &frame->info; /* a1: siginfo pointer */ |
443 | regs->r18 = (unsigned long) &frame->uc; /* a2: ucontext pointer */ | 426 | regs->r18 = (unsigned long) &frame->uc; /* a2: ucontext pointer */ |
444 | wrusp((unsigned long) frame); | 427 | wrusp((unsigned long) frame); |
@@ -456,22 +439,17 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
456 | * OK, we're invoking a handler. | 439 | * OK, we're invoking a handler. |
457 | */ | 440 | */ |
458 | static inline void | 441 | static inline void |
459 | handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info, | 442 | handle_signal(struct ksignal *ksig, struct pt_regs *regs) |
460 | struct pt_regs * regs) | ||
461 | { | 443 | { |
462 | sigset_t *oldset = sigmask_to_save(); | 444 | sigset_t *oldset = sigmask_to_save(); |
463 | int ret; | 445 | int ret; |
464 | 446 | ||
465 | if (ka->sa.sa_flags & SA_SIGINFO) | 447 | if (ksig->ka.sa.sa_flags & SA_SIGINFO) |
466 | ret = setup_rt_frame(sig, ka, info, oldset, regs); | 448 | ret = setup_rt_frame(ksig, oldset, regs); |
467 | else | 449 | else |
468 | ret = setup_frame(sig, ka, oldset, regs); | 450 | ret = setup_frame(ksig, oldset, regs); |
469 | 451 | ||
470 | if (ret) { | 452 | signal_setup_done(ret, ksig, 0); |
471 | force_sigsegv(sig, current); | ||
472 | return; | ||
473 | } | ||
474 | signal_delivered(sig, info, ka, regs, 0); | ||
475 | } | 453 | } |
476 | 454 | ||
477 | static inline void | 455 | static inline void |
@@ -514,47 +492,38 @@ syscall_restart(unsigned long r0, unsigned long r19, | |||
514 | static void | 492 | static void |
515 | do_signal(struct pt_regs *regs, unsigned long r0, unsigned long r19) | 493 | do_signal(struct pt_regs *regs, unsigned long r0, unsigned long r19) |
516 | { | 494 | { |
517 | siginfo_t info; | ||
518 | int signr; | ||
519 | unsigned long single_stepping = ptrace_cancel_bpt(current); | 495 | unsigned long single_stepping = ptrace_cancel_bpt(current); |
520 | struct k_sigaction ka; | 496 | struct ksignal ksig; |
521 | 497 | ||
522 | /* This lets the debugger run, ... */ | 498 | /* This lets the debugger run, ... */ |
523 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | 499 | if (get_signal(&ksig)) { |
524 | 500 | /* ... so re-check the single stepping. */ | |
525 | /* ... so re-check the single stepping. */ | 501 | single_stepping |= ptrace_cancel_bpt(current); |
526 | single_stepping |= ptrace_cancel_bpt(current); | ||
527 | |||
528 | if (signr > 0) { | ||
529 | /* Whee! Actually deliver the signal. */ | 502 | /* Whee! Actually deliver the signal. */ |
530 | if (r0) | 503 | if (r0) |
531 | syscall_restart(r0, r19, regs, &ka); | 504 | syscall_restart(r0, r19, regs, &ksig.ka); |
532 | handle_signal(signr, &ka, &info, regs); | 505 | handle_signal(&ksig, regs); |
533 | if (single_stepping) | 506 | } else { |
534 | ptrace_set_bpt(current); /* re-set bpt */ | 507 | single_stepping |= ptrace_cancel_bpt(current); |
535 | return; | 508 | if (r0) { |
536 | } | 509 | switch (regs->r0) { |
537 | 510 | case ERESTARTNOHAND: | |
538 | if (r0) { | 511 | case ERESTARTSYS: |
539 | switch (regs->r0) { | 512 | case ERESTARTNOINTR: |
540 | case ERESTARTNOHAND: | 513 | /* Reset v0 and a3 and replay syscall. */ |
541 | case ERESTARTSYS: | 514 | regs->r0 = r0; |
542 | case ERESTARTNOINTR: | 515 | regs->r19 = r19; |
543 | /* Reset v0 and a3 and replay syscall. */ | 516 | regs->pc -= 4; |
544 | regs->r0 = r0; | 517 | break; |
545 | regs->r19 = r19; | 518 | case ERESTART_RESTARTBLOCK: |
546 | regs->pc -= 4; | 519 | /* Set v0 to the restart_syscall and replay */ |
547 | break; | 520 | regs->r0 = __NR_restart_syscall; |
548 | case ERESTART_RESTARTBLOCK: | 521 | regs->pc -= 4; |
549 | /* Force v0 to the restart syscall and reply. */ | 522 | break; |
550 | regs->r0 = __NR_restart_syscall; | 523 | } |
551 | regs->pc -= 4; | ||
552 | break; | ||
553 | } | 524 | } |
525 | restore_saved_sigmask(); | ||
554 | } | 526 | } |
555 | |||
556 | /* If there's no signal to deliver, we just restore the saved mask. */ | ||
557 | restore_saved_sigmask(); | ||
558 | if (single_stepping) | 527 | if (single_stepping) |
559 | ptrace_set_bpt(current); /* re-set breakpoint */ | 528 | ptrace_set_bpt(current); /* re-set breakpoint */ |
560 | } | 529 | } |