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 | |
| 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>
| -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 | ||
