diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2010-09-18 08:41:16 -0400 |
---|---|---|
committer | Matt Turner <mattst88@gmail.com> | 2010-09-18 23:08:28 -0400 |
commit | 53293638618f1a8b0b182dfedaab08b28930f992 (patch) | |
tree | 76c925826dbf71832db6212538b7a2f417008dd5 /arch/alpha/kernel | |
parent | 392fb6e35400edbee183baba24b34a0fa2053813 (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/kernel')
-rw-r--r-- | arch/alpha/kernel/entry.S | 13 |
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) |
432 | 1: jsr $26, ($27), sys_gettimeofday | 432 | 1: jsr $26, ($27), sys_gettimeofday |
433 | ret_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 |
758 | sys_sigreturn: | 759 | sys_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 | ||
769 | 1: 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 |
771 | sys_rt_sigreturn: | 776 | sys_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 | ||
786 | 1: 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 | ||