From: Max Filippov <jcmvb...@gmail.com>

[ Upstream commit 02ce94c229251555ac726ecfebe3458ef5905fa9 ]

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 <jcmvb...@gmail.com>
Signed-off-by: Sasha Levin <sas...@kernel.org>
---
 arch/xtensa/kernel/entry.S  |  4 ++--
 arch/xtensa/kernel/ptrace.c | 18 ++++++++++++++++--
 2 files changed, 18 insertions(+), 4 deletions(-)

diff --git a/arch/xtensa/kernel/entry.S b/arch/xtensa/kernel/entry.S
index 59671603c9c62..1f07876ea2ed7 100644
--- a/arch/xtensa/kernel/entry.S
+++ b/arch/xtensa/kernel/entry.S
@@ -1897,6 +1897,7 @@ ENTRY(system_call)
 
        mov     a6, a2
        call4   do_syscall_trace_enter
+       beqz    a6, .Lsyscall_exit
        l32i    a7, a2, PT_SYSCALL
 
 1:
@@ -1911,8 +1912,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. */
 
@@ -1932,6 +1931,7 @@ ENTRY(system_call)
 
        s32i    a6, a2, PT_AREG2
        bnez    a3, 1f
+.Lsyscall_exit:
        abi_ret(4)
 
 1:
diff --git a/arch/xtensa/kernel/ptrace.c b/arch/xtensa/kernel/ptrace.c
index b964f0b2d8864..145742d70a9f2 100644
--- a/arch/xtensa/kernel/ptrace.c
+++ b/arch/xtensa/kernel/ptrace.c
@@ -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)
-- 
2.25.1



Reply via email to