diff options
Diffstat (limited to 'arch/sparc/kernel/signal.c')
-rw-r--r-- | arch/sparc/kernel/signal.c | 84 |
1 files changed, 45 insertions, 39 deletions
diff --git a/arch/sparc/kernel/signal.c b/arch/sparc/kernel/signal.c index 3c312290c3c2..3fd1df9f9ba7 100644 --- a/arch/sparc/kernel/signal.c +++ b/arch/sparc/kernel/signal.c | |||
@@ -145,6 +145,9 @@ asmlinkage void do_sigreturn(struct pt_regs *regs) | |||
145 | regs->psr = (up_psr & ~(PSR_ICC | PSR_EF)) | 145 | regs->psr = (up_psr & ~(PSR_ICC | PSR_EF)) |
146 | | (regs->psr & (PSR_ICC | PSR_EF)); | 146 | | (regs->psr & (PSR_ICC | PSR_EF)); |
147 | 147 | ||
148 | /* Prevent syscall restart. */ | ||
149 | pt_regs_clear_syscall(regs); | ||
150 | |||
148 | err |= __get_user(fpu_save, &sf->fpu_save); | 151 | err |= __get_user(fpu_save, &sf->fpu_save); |
149 | 152 | ||
150 | if (fpu_save) | 153 | if (fpu_save) |
@@ -199,6 +202,9 @@ asmlinkage void do_rt_sigreturn(struct pt_regs *regs) | |||
199 | 202 | ||
200 | regs->psr = (regs->psr & ~PSR_ICC) | (psr & PSR_ICC); | 203 | regs->psr = (regs->psr & ~PSR_ICC) | (psr & PSR_ICC); |
201 | 204 | ||
205 | /* Prevent syscall restart. */ | ||
206 | pt_regs_clear_syscall(regs); | ||
207 | |||
202 | err |= __get_user(fpu_save, &sf->fpu_save); | 208 | err |= __get_user(fpu_save, &sf->fpu_save); |
203 | 209 | ||
204 | if (fpu_save) | 210 | if (fpu_save) |
@@ -245,15 +251,29 @@ static inline int invalid_frame_pointer(void __user *fp, int fplen) | |||
245 | 251 | ||
246 | static inline void __user *get_sigframe(struct sigaction *sa, struct pt_regs *regs, unsigned long framesize) | 252 | static inline void __user *get_sigframe(struct sigaction *sa, struct pt_regs *regs, unsigned long framesize) |
247 | { | 253 | { |
248 | unsigned long sp; | 254 | unsigned long sp = regs->u_regs[UREG_FP]; |
249 | 255 | ||
250 | sp = regs->u_regs[UREG_FP]; | 256 | /* |
257 | * If we are on the alternate signal stack and would overflow it, don't. | ||
258 | * Return an always-bogus address instead so we will die with SIGSEGV. | ||
259 | */ | ||
260 | if (on_sig_stack(sp) && !likely(on_sig_stack(sp - framesize))) | ||
261 | return (void __user *) -1L; | ||
251 | 262 | ||
252 | /* This is the X/Open sanctioned signal stack switching. */ | 263 | /* This is the X/Open sanctioned signal stack switching. */ |
253 | if (sa->sa_flags & SA_ONSTACK) { | 264 | if (sa->sa_flags & SA_ONSTACK) { |
254 | if (!on_sig_stack(sp) && !((current->sas_ss_sp + current->sas_ss_size) & 7)) | 265 | if (sas_ss_flags(sp) == 0) |
255 | sp = current->sas_ss_sp + current->sas_ss_size; | 266 | sp = current->sas_ss_sp + current->sas_ss_size; |
256 | } | 267 | } |
268 | |||
269 | /* Always align the stack frame. This handles two cases. First, | ||
270 | * sigaltstack need not be mindful of platform specific stack | ||
271 | * alignment. Second, if we took this signal because the stack | ||
272 | * is not aligned properly, we'd like to take the signal cleanly | ||
273 | * and report that. | ||
274 | */ | ||
275 | sp &= ~7UL; | ||
276 | |||
257 | return (void __user *)(sp - framesize); | 277 | return (void __user *)(sp - framesize); |
258 | } | 278 | } |
259 | 279 | ||
@@ -493,26 +513,36 @@ static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs, | |||
493 | * want to handle. Thus you cannot kill init even with a SIGKILL even by | 513 | * want to handle. Thus you cannot kill init even with a SIGKILL even by |
494 | * mistake. | 514 | * mistake. |
495 | */ | 515 | */ |
496 | asmlinkage void do_signal(struct pt_regs * regs, unsigned long orig_i0, int restart_syscall) | 516 | asmlinkage void do_signal(struct pt_regs * regs, unsigned long orig_i0) |
497 | { | 517 | { |
498 | siginfo_t info; | ||
499 | struct sparc_deliver_cookie cookie; | ||
500 | struct k_sigaction ka; | 518 | struct k_sigaction ka; |
501 | int signr; | 519 | int restart_syscall; |
502 | sigset_t *oldset; | 520 | sigset_t *oldset; |
521 | siginfo_t info; | ||
522 | int signr; | ||
503 | 523 | ||
504 | cookie.restart_syscall = restart_syscall; | 524 | if (pt_regs_is_syscall(regs) && (regs->psr & PSR_C)) |
505 | cookie.orig_i0 = orig_i0; | 525 | restart_syscall = 1; |
526 | else | ||
527 | restart_syscall = 0; | ||
506 | 528 | ||
507 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | 529 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) |
508 | oldset = ¤t->saved_sigmask; | 530 | oldset = ¤t->saved_sigmask; |
509 | else | 531 | else |
510 | oldset = ¤t->blocked; | 532 | oldset = ¤t->blocked; |
511 | 533 | ||
512 | signr = get_signal_to_deliver(&info, &ka, regs, &cookie); | 534 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); |
535 | |||
536 | /* If the debugger messes with the program counter, it clears | ||
537 | * the software "in syscall" bit, directing us to not perform | ||
538 | * a syscall restart. | ||
539 | */ | ||
540 | if (restart_syscall && !pt_regs_is_syscall(regs)) | ||
541 | restart_syscall = 0; | ||
542 | |||
513 | if (signr > 0) { | 543 | if (signr > 0) { |
514 | if (cookie.restart_syscall) | 544 | if (restart_syscall) |
515 | syscall_restart(cookie.orig_i0, regs, &ka.sa); | 545 | syscall_restart(orig_i0, regs, &ka.sa); |
516 | handle_signal(signr, &ka, &info, oldset, regs); | 546 | handle_signal(signr, &ka, &info, oldset, regs); |
517 | 547 | ||
518 | /* a signal was successfully delivered; the saved | 548 | /* a signal was successfully delivered; the saved |
@@ -524,16 +554,16 @@ asmlinkage void do_signal(struct pt_regs * regs, unsigned long orig_i0, int rest | |||
524 | clear_thread_flag(TIF_RESTORE_SIGMASK); | 554 | clear_thread_flag(TIF_RESTORE_SIGMASK); |
525 | return; | 555 | return; |
526 | } | 556 | } |
527 | if (cookie.restart_syscall && | 557 | if (restart_syscall && |
528 | (regs->u_regs[UREG_I0] == ERESTARTNOHAND || | 558 | (regs->u_regs[UREG_I0] == ERESTARTNOHAND || |
529 | regs->u_regs[UREG_I0] == ERESTARTSYS || | 559 | regs->u_regs[UREG_I0] == ERESTARTSYS || |
530 | regs->u_regs[UREG_I0] == ERESTARTNOINTR)) { | 560 | regs->u_regs[UREG_I0] == ERESTARTNOINTR)) { |
531 | /* replay the system call when we are done */ | 561 | /* replay the system call when we are done */ |
532 | regs->u_regs[UREG_I0] = cookie.orig_i0; | 562 | regs->u_regs[UREG_I0] = orig_i0; |
533 | regs->pc -= 4; | 563 | regs->pc -= 4; |
534 | regs->npc -= 4; | 564 | regs->npc -= 4; |
535 | } | 565 | } |
536 | if (cookie.restart_syscall && | 566 | if (restart_syscall && |
537 | regs->u_regs[UREG_I0] == ERESTART_RESTARTBLOCK) { | 567 | regs->u_regs[UREG_I0] == ERESTART_RESTARTBLOCK) { |
538 | regs->u_regs[UREG_G1] = __NR_restart_syscall; | 568 | regs->u_regs[UREG_G1] = __NR_restart_syscall; |
539 | regs->pc -= 4; | 569 | regs->pc -= 4; |
@@ -585,27 +615,3 @@ do_sys_sigstack(struct sigstack __user *ssptr, struct sigstack __user *ossptr, | |||
585 | out: | 615 | out: |
586 | return ret; | 616 | return ret; |
587 | } | 617 | } |
588 | |||
589 | void ptrace_signal_deliver(struct pt_regs *regs, void *cookie) | ||
590 | { | ||
591 | struct sparc_deliver_cookie *cp = cookie; | ||
592 | |||
593 | if (cp->restart_syscall && | ||
594 | (regs->u_regs[UREG_I0] == ERESTARTNOHAND || | ||
595 | regs->u_regs[UREG_I0] == ERESTARTSYS || | ||
596 | regs->u_regs[UREG_I0] == ERESTARTNOINTR)) { | ||
597 | /* replay the system call when we are done */ | ||
598 | regs->u_regs[UREG_I0] = cp->orig_i0; | ||
599 | regs->pc -= 4; | ||
600 | regs->npc -= 4; | ||
601 | cp->restart_syscall = 0; | ||
602 | } | ||
603 | |||
604 | if (cp->restart_syscall && | ||
605 | regs->u_regs[UREG_I0] == ERESTART_RESTARTBLOCK) { | ||
606 | regs->u_regs[UREG_G1] = __NR_restart_syscall; | ||
607 | regs->pc -= 4; | ||
608 | regs->npc -= 4; | ||
609 | cp->restart_syscall = 0; | ||
610 | } | ||
611 | } | ||