xtensa: fix system_call interaction with ptrace
authorMax Filippov <jcmvbkbc@gmail.com>
Fri, 29 Nov 2019 22:54:06 +0000 (14:54 -0800)
committerMax Filippov <jcmvbkbc@gmail.com>
Fri, 29 Nov 2019 23:47:54 +0000 (15:47 -0800)
Don't overwrite return value if system call was cancelled at entry by
ptrace. Return status code from do_syscall_trace_enter so that
pt_regs::syscall doesn't need to be changed to skip syscall.

Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
arch/xtensa/kernel/entry.S
arch/xtensa/kernel/ptrace.c

index 59af494d99407ef17bc354e43d498ae74af9d91c..138469e265609cb7a17a7145679c74a2742338d5 100644 (file)
@@ -1892,6 +1892,7 @@ ENTRY(system_call)
 
        mov     a6, a2
        call4   do_syscall_trace_enter
+       beqz    a6, .Lsyscall_exit
        l32i    a7, a2, PT_SYSCALL
 
 1:
@@ -1904,8 +1905,6 @@ ENTRY(system_call)
 
        addx4   a4, a7, a4
        l32i    a4, a4, 0
-       movi    a5, sys_ni_syscall;
-       beq     a4, a5, 1f
 
        /* Load args: arg0 - arg5 are passed via regs. */
 
@@ -1925,6 +1924,7 @@ ENTRY(system_call)
 
        s32i    a6, a2, PT_AREG2
        bnez    a3, 1f
+.Lsyscall_exit:
        abi_ret(4)
 
 1:
index b964f0b2d8864ea091ecca93ab0cf14754aaac80..145742d70a9f21d4d02cb2884b3b79367dca5723 100644 (file)
@@ -542,14 +542,28 @@ long arch_ptrace(struct task_struct *child, long request,
        return ret;
 }
 
-void do_syscall_trace_enter(struct pt_regs *regs)
+void do_syscall_trace_leave(struct pt_regs *regs);
+int do_syscall_trace_enter(struct pt_regs *regs)
 {
+       if (regs->syscall == NO_SYSCALL)
+               regs->areg[2] = -ENOSYS;
+
        if (test_thread_flag(TIF_SYSCALL_TRACE) &&
-           tracehook_report_syscall_entry(regs))
+           tracehook_report_syscall_entry(regs)) {
+               regs->areg[2] = -ENOSYS;
                regs->syscall = NO_SYSCALL;
+               return 0;
+       }
+
+       if (regs->syscall == NO_SYSCALL) {
+               do_syscall_trace_leave(regs);
+               return 0;
+       }
 
        if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
                trace_sys_enter(regs, syscall_get_nr(current, regs));
+
+       return 1;
 }
 
 void do_syscall_trace_leave(struct pt_regs *regs)