aboutsummaryrefslogtreecommitdiffstats
path: root/arch/alpha
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2010-09-18 08:41:16 -0400
committerMatt Turner <mattst88@gmail.com>2010-09-18 23:08:28 -0400
commit53293638618f1a8b0b182dfedaab08b28930f992 (patch)
tree76c925826dbf71832db6212538b7a2f417008dd5 /arch/alpha
parent392fb6e35400edbee183baba24b34a0fa2053813 (diff)
alpha: fix a 14 years old bug in sigreturn tracing
The way sigreturn() is implemented on alpha breaks PTRACE_SYSCALL, all way back to 1.3.95 when alpha has grown PTRACE_SYSCALL support. What happens is direct return to ret_from_syscall, in order to bypass mangling of a3 (error indicator) and prevent other mutilations of registers (e.g. by syscall restart). That's fine, but... the entire TIF_SYSCALL_TRACE codepath is kept separate on alpha and post-syscall stopping/notifying the tracer is after the syscall. And the normal path we are forcibly switching to doesn't have it. So we end up with *one* stop in traced sigreturn() vs. two in other syscalls. And yes, strace is visibly broken by that; try to strace the following #include <signal.h> #include <stdio.h> void f(int sig) {} main() { signal(SIGHUP, f); raise(SIGHUP); write(1, "eeeek\n", 6); } and watch the show. The close(1) = 405 in the end of strace output is coming from return value of write() (6 == __NR_close on alpha) and syscall number of exit_group() (__NR_exit_group == 405 there). The fix is fairly simple - the only thing we end up missing is the call of syscall_trace() and we can tell whether we'd been called from the SYSCALL_TRACE path by checking ra value. Since we are setting the switch_stack up (that's what sys_sigreturn() does), we have the right environment for calling syscall_trace() - just before we call undo_switch_stack() and return. Since undo_switch_stack() will overwrite s0 anyway, we can use it to store the result of "has it been called from SYSCALL_TRACE path?" check. The same thing applies in rt_sigreturn(). Tested-by: Michael Cree <mcree@orcon.net.nz> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Matt Turner <mattst88@gmail.com>
Diffstat (limited to 'arch/alpha')
-rw-r--r--arch/alpha/kernel/entry.S13
1 files changed, 11 insertions, 2 deletions
diff --git a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S
index bceb325fd4c5..a3e9cd85cfee 100644
--- a/arch/alpha/kernel/entry.S
+++ b/arch/alpha/kernel/entry.S
@@ -430,6 +430,7 @@ strace:
430 beq $1, 1f 430 beq $1, 1f
431 ldq $27, 0($2) 431 ldq $27, 0($2)
4321: jsr $26, ($27), sys_gettimeofday 4321: jsr $26, ($27), sys_gettimeofday
433ret_from_straced:
433 ldgp $gp, 0($26) 434 ldgp $gp, 0($26)
434 435
435 /* check return.. */ 436 /* check return.. */
@@ -757,11 +758,15 @@ sys_vfork:
757 .ent sys_sigreturn 758 .ent sys_sigreturn
758sys_sigreturn: 759sys_sigreturn:
759 .prologue 0 760 .prologue 0
761 lda $9, ret_from_straced
762 cmpult $26, $9, $9
760 mov $sp, $17 763 mov $sp, $17
761 lda $18, -SWITCH_STACK_SIZE($sp) 764 lda $18, -SWITCH_STACK_SIZE($sp)
762 lda $sp, -SWITCH_STACK_SIZE($sp) 765 lda $sp, -SWITCH_STACK_SIZE($sp)
763 jsr $26, do_sigreturn 766 jsr $26, do_sigreturn
764 br $1, undo_switch_stack 767 bne $9, 1f
768 jsr $26, syscall_trace
7691: br $1, undo_switch_stack
765 br ret_from_sys_call 770 br ret_from_sys_call
766.end sys_sigreturn 771.end sys_sigreturn
767 772
@@ -770,11 +775,15 @@ sys_sigreturn:
770 .ent sys_rt_sigreturn 775 .ent sys_rt_sigreturn
771sys_rt_sigreturn: 776sys_rt_sigreturn:
772 .prologue 0 777 .prologue 0
778 lda $9, ret_from_straced
779 cmpult $26, $9, $9
773 mov $sp, $17 780 mov $sp, $17
774 lda $18, -SWITCH_STACK_SIZE($sp) 781 lda $18, -SWITCH_STACK_SIZE($sp)
775 lda $sp, -SWITCH_STACK_SIZE($sp) 782 lda $sp, -SWITCH_STACK_SIZE($sp)
776 jsr $26, do_rt_sigreturn 783 jsr $26, do_rt_sigreturn
777 br $1, undo_switch_stack 784 bne $9, 1f
785 jsr $26, syscall_trace
7861: br $1, undo_switch_stack
778 br ret_from_sys_call 787 br ret_from_sys_call
779.end sys_rt_sigreturn 788.end sys_rt_sigreturn
780 789