• A
    alpha: fix a 14 years old bug in sigreturn tracing · 53293638
    Al Viro 提交于
    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: NMichael Cree <mcree@orcon.net.nz>
    Signed-off-by: NAl Viro <viro@zeniv.linux.org.uk>
    Signed-off-by: NMatt Turner <mattst88@gmail.com>
    53293638
entry.S 18.4 KB