aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc64/kernel/signal.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2008-05-11 05:07:19 -0400
committerDavid S. Miller <davem@davemloft.net>2008-05-11 05:07:19 -0400
commit28e6103665301ce60634e8a77f0b657c6cc099de (patch)
tree1ba78c7db8d139529b8f0db5f0de60a6fbf701cb /arch/sparc64/kernel/signal.c
parent986bef854fab44012df678a5b51817d5274d3ca1 (diff)
sparc: Fix debugger syscall restart interactions.
So, forever, we've had this ptrace_signal_deliver implementation which tries to handle all of the nasties that can occur when the debugger looks at a process about to take a signal. It's meant to address all of these issues inside of the kernel so that the debugger need not be mindful of such things. Problem is, this doesn't work. The idea was that we should do the syscall restart business first, so that the debugger captures that state. Otherwise, if the debugger for example saves the child's state, makes the child execute something else, then restores the saved state, we won't handle the syscall restart properly because we lose the "we're in a syscall" state. The code here worked for most cases, but if the debugger actually passes the signal through to the child unaltered, it's possible that we would do a syscall restart when we shouldn't have. In particular this breaks the case of debugging a process under a gdb which is being debugged by yet another gdb. gdb uses sigsuspend to wait for SIGCHLD of the inferior, but if gdb itself is being debugged by a top-level gdb we get a ptrace_stop(). The top-level gdb does a PTRACE_CONT with SIGCHLD to let the inferior gdb see the signal. But ptrace_signal_deliver() assumed the debugger would cancel out the signal and therefore did a syscall restart, because the return error was ERESTARTNOHAND. Fix this by simply making ptrace_signal_deliver() a nop, and providing a way for the debugger to control system call restarting properly: 1) Report a "in syscall" software bit in regs->{tstate,psr}. It is set early on in trap entry to a system call and is fully visible to the debugger via ptrace() and regsets. 2) Test this bit right before doing a syscall restart. We have to do a final recheck right after get_signal_to_deliver() in case the debugger cleared the bit during ptrace_stop(). 3) Clear the bit in trap return so we don't accidently try to set that bit in the real register. As a result we also get a ptrace_{is,clear}_syscall() for sparc32 just like sparc64 has. M68K has this same exact bug, and is now the only other user of the ptrace_signal_deliver hook. It needs to be fixed in the same exact way as sparc. Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc64/kernel/signal.c')
-rw-r--r--arch/sparc64/kernel/signal.c60
1 files changed, 22 insertions, 38 deletions
diff --git a/arch/sparc64/kernel/signal.c b/arch/sparc64/kernel/signal.c
index 07c0443ea3f5..2378482c2aab 100644
--- a/arch/sparc64/kernel/signal.c
+++ b/arch/sparc64/kernel/signal.c
@@ -333,7 +333,7 @@ void do_rt_sigreturn(struct pt_regs *regs)
333 regs->tnpc = tnpc; 333 regs->tnpc = tnpc;
334 334
335 /* Prevent syscall restart. */ 335 /* Prevent syscall restart. */
336 pt_regs_clear_trap_type(regs); 336 pt_regs_clear_syscall(regs);
337 337
338 sigdelsetmask(&set, ~_BLOCKABLE); 338 sigdelsetmask(&set, ~_BLOCKABLE);
339 spin_lock_irq(&current->sighand->siglock); 339 spin_lock_irq(&current->sighand->siglock);
@@ -499,7 +499,7 @@ static inline void handle_signal(unsigned long signr, struct k_sigaction *ka,
499} 499}
500 500
501static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs, 501static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs,
502 struct sigaction *sa) 502 struct sigaction *sa)
503{ 503{
504 switch (regs->u_regs[UREG_I0]) { 504 switch (regs->u_regs[UREG_I0]) {
505 case ERESTART_RESTARTBLOCK: 505 case ERESTART_RESTARTBLOCK:
@@ -525,19 +525,17 @@ static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs,
525 */ 525 */
526static void do_signal(struct pt_regs *regs, unsigned long orig_i0) 526static void do_signal(struct pt_regs *regs, unsigned long orig_i0)
527{ 527{
528 struct signal_deliver_cookie cookie;
529 struct k_sigaction ka; 528 struct k_sigaction ka;
529 int restart_syscall;
530 sigset_t *oldset; 530 sigset_t *oldset;
531 siginfo_t info; 531 siginfo_t info;
532 int signr; 532 int signr;
533 533
534 if (pt_regs_is_syscall(regs) && 534 if (pt_regs_is_syscall(regs) &&
535 (regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY))) { 535 (regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY))) {
536 pt_regs_clear_trap_type(regs); 536 restart_syscall = 1;
537 cookie.restart_syscall = 1;
538 } else 537 } else
539 cookie.restart_syscall = 0; 538 restart_syscall = 0;
540 cookie.orig_i0 = orig_i0;
541 539
542 if (test_thread_flag(TIF_RESTORE_SIGMASK)) 540 if (test_thread_flag(TIF_RESTORE_SIGMASK))
543 oldset = &current->saved_sigmask; 541 oldset = &current->saved_sigmask;
@@ -547,16 +545,25 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0)
547#ifdef CONFIG_COMPAT 545#ifdef CONFIG_COMPAT
548 if (test_thread_flag(TIF_32BIT)) { 546 if (test_thread_flag(TIF_32BIT)) {
549 extern void do_signal32(sigset_t *, struct pt_regs *, 547 extern void do_signal32(sigset_t *, struct pt_regs *,
550 struct signal_deliver_cookie *); 548 int restart_syscall,
551 do_signal32(oldset, regs, &cookie); 549 unsigned long orig_i0);
550 do_signal32(oldset, regs, restart_syscall, orig_i0);
552 return; 551 return;
553 } 552 }
554#endif 553#endif
555 554
556 signr = get_signal_to_deliver(&info, &ka, regs, &cookie); 555 signr = get_signal_to_deliver(&info, &ka, regs, NULL);
556
557 /* If the debugger messes with the program counter, it clears
558 * the software "in syscall" bit, directing us to not perform
559 * a syscall restart.
560 */
561 if (restart_syscall && !pt_regs_is_syscall(regs))
562 restart_syscall = 0;
563
557 if (signr > 0) { 564 if (signr > 0) {
558 if (cookie.restart_syscall) 565 if (restart_syscall)
559 syscall_restart(cookie.orig_i0, regs, &ka.sa); 566 syscall_restart(orig_i0, regs, &ka.sa);
560 handle_signal(signr, &ka, &info, oldset, regs); 567 handle_signal(signr, &ka, &info, oldset, regs);
561 568
562 /* a signal was successfully delivered; the saved 569 /* a signal was successfully delivered; the saved
@@ -568,16 +575,16 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0)
568 clear_thread_flag(TIF_RESTORE_SIGMASK); 575 clear_thread_flag(TIF_RESTORE_SIGMASK);
569 return; 576 return;
570 } 577 }
571 if (cookie.restart_syscall && 578 if (restart_syscall &&
572 (regs->u_regs[UREG_I0] == ERESTARTNOHAND || 579 (regs->u_regs[UREG_I0] == ERESTARTNOHAND ||
573 regs->u_regs[UREG_I0] == ERESTARTSYS || 580 regs->u_regs[UREG_I0] == ERESTARTSYS ||
574 regs->u_regs[UREG_I0] == ERESTARTNOINTR)) { 581 regs->u_regs[UREG_I0] == ERESTARTNOINTR)) {
575 /* replay the system call when we are done */ 582 /* replay the system call when we are done */
576 regs->u_regs[UREG_I0] = cookie.orig_i0; 583 regs->u_regs[UREG_I0] = orig_i0;
577 regs->tpc -= 4; 584 regs->tpc -= 4;
578 regs->tnpc -= 4; 585 regs->tnpc -= 4;
579 } 586 }
580 if (cookie.restart_syscall && 587 if (restart_syscall &&
581 regs->u_regs[UREG_I0] == ERESTART_RESTARTBLOCK) { 588 regs->u_regs[UREG_I0] == ERESTART_RESTARTBLOCK) {
582 regs->u_regs[UREG_G1] = __NR_restart_syscall; 589 regs->u_regs[UREG_G1] = __NR_restart_syscall;
583 regs->tpc -= 4; 590 regs->tpc -= 4;
@@ -598,26 +605,3 @@ void do_notify_resume(struct pt_regs *regs, unsigned long orig_i0, unsigned long
598 if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)) 605 if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
599 do_signal(regs, orig_i0); 606 do_signal(regs, orig_i0);
600} 607}
601
602void ptrace_signal_deliver(struct pt_regs *regs, void *cookie)
603{
604 struct signal_deliver_cookie *cp = cookie;
605
606 if (cp->restart_syscall &&
607 (regs->u_regs[UREG_I0] == ERESTARTNOHAND ||
608 regs->u_regs[UREG_I0] == ERESTARTSYS ||
609 regs->u_regs[UREG_I0] == ERESTARTNOINTR)) {
610 /* replay the system call when we are done */
611 regs->u_regs[UREG_I0] = cp->orig_i0;
612 regs->tpc -= 4;
613 regs->tnpc -= 4;
614 cp->restart_syscall = 0;
615 }
616 if (cp->restart_syscall &&
617 regs->u_regs[UREG_I0] == ERESTART_RESTARTBLOCK) {
618 regs->u_regs[UREG_G1] = __NR_restart_syscall;
619 regs->tpc -= 4;
620 regs->tnpc -= 4;
621 cp->restart_syscall = 0;
622 }
623}