From a1a6f8a14cb09657b26dd31f73cc310af8d548fc Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Fri, 29 Nov 2019 14:54:06 -0800 Subject: [PATCH] xtensa: fix system_call interaction with ptrace [ 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 Signed-off-by: Sasha Levin --- 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 59671603c9c6..1f07876ea2ed 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 b964f0b2d886..145742d70a9f 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)