From ea7f517e3d27ba1dc44b757f4db005b049643b63 Mon Sep 17 00:00:00 2001 From: "Shiratori, Takehiro" Date: Tue, 5 Mar 2019 12:22:18 +0900 Subject: [PATCH] arm64: ptrace: Fix overwriting 1st argument with return value Since arm64 shares the return value with the area of the first argument, rewriting the return value before the system call execution completes destroys the first argument. Change-Id: I959944879254d8dd3a29489a65d8f274d45338e6 Fujitsu: POSTK_DEBUG_ARCH_DEP_110 --- arch/arm64/kernel/syscall.c | 8 ++++++++ arch/x86_64/kernel/syscall.c | 9 +++++++++ kernel/include/syscall.h | 4 ++++ kernel/syscall.c | 22 ++++++++++++++-------- 4 files changed, 35 insertions(+), 8 deletions(-) diff --git a/arch/arm64/kernel/syscall.c b/arch/arm64/kernel/syscall.c index 9d7f5afa..54d54e5e 100644 --- a/arch/arm64/kernel/syscall.c +++ b/arch/arm64/kernel/syscall.c @@ -2735,4 +2735,12 @@ void calculate_time_from_tsc(struct timespec *ts) ++ts->tv_sec; } } + +extern void ptrace_syscall_event(struct thread *thread); +long arch_ptrace_syscall_event(struct thread *thread, + ihk_mc_user_context_t *ctx, long setret) +{ + ptrace_syscall_event(thread); + return setret; +} /*** End of File ***/ diff --git a/arch/x86_64/kernel/syscall.c b/arch/x86_64/kernel/syscall.c index e8a4b964..bd5664f9 100644 --- a/arch/x86_64/kernel/syscall.c +++ b/arch/x86_64/kernel/syscall.c @@ -2858,4 +2858,13 @@ void calculate_time_from_tsc(struct timespec *ts) ++ts->tv_sec; } } + +extern void ptrace_syscall_event(struct thread *thread); +long arch_ptrace_syscall_event(struct thread *thread, + ihk_mc_user_context_t *ctx, long setret) +{ + ihk_mc_syscall_ret(ctx) = setret; + ptrace_syscall_event(thread); + return ihk_mc_syscall_ret(ctx); +} /*** End of File ***/ diff --git a/kernel/include/syscall.h b/kernel/include/syscall.h index 3a5ccfd5..bc8369d9 100644 --- a/kernel/include/syscall.h +++ b/kernel/include/syscall.h @@ -586,6 +586,10 @@ typedef struct uti_attr { uint64_t flags; /* Representing location and behavior hints by bitmap */ } uti_attr_t; +struct thread; +long arch_ptrace_syscall_event(struct thread *thread, + ihk_mc_user_context_t *ctx, long setret); + struct uti_ctx { union { char ctx[4096]; diff --git a/kernel/syscall.c b/kernel/syscall.c index ca851c6b..1e4c6937 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -2273,7 +2273,7 @@ static int ptrace_report_exec(struct thread *thread) return 0; } -static void ptrace_syscall_event(struct thread *thread) +void ptrace_syscall_event(struct thread *thread) { int ptrace = thread->ptrace; @@ -2551,8 +2551,7 @@ SYSCALL_DECLARE(execve) } if (thread->ptrace) { - ihk_mc_syscall_ret(ctx) = 0; - ptrace_syscall_event(thread); + arch_ptrace_syscall_event(thread, ctx, 0); } /* Unmap all memory areas of the process, userspace will be gone */ @@ -9619,6 +9618,9 @@ long syscall(int num, ihk_mc_user_context_t *ctx) if(cpu_local_var(current)->proc->status == PS_EXITED && (num != __NR_exit && num != __NR_exit_group)){ + /* x86_64: Setting -EINVAL to rax is done in the + * following return. + */ save_syscall_return_value(num, -EINVAL); check_signal(-EINVAL, NULL, -1); set_cputime(CPUTIME_MODE_K2U); @@ -9628,8 +9630,8 @@ long syscall(int num, ihk_mc_user_context_t *ctx) cpu_enable_interrupt(); if (cpu_local_var(current)->ptrace) { - ihk_mc_syscall_ret(ctx) = -ENOSYS; - ptrace_syscall_event(cpu_local_var(current)); + arch_ptrace_syscall_event(cpu_local_var(current), + ctx, -ENOSYS); num = ihk_mc_syscall_number(ctx); } @@ -9675,11 +9677,15 @@ long syscall(int num, ihk_mc_user_context_t *ctx) } if (cpu_local_var(current)->ptrace) { - ihk_mc_syscall_ret(ctx) = l; - ptrace_syscall_event(cpu_local_var(current)); - l = ihk_mc_syscall_ret(ctx); + /* arm64: The return value modified by the tracer is + * stored to x0 in the following check_signal(). + */ + l = arch_ptrace_syscall_event(cpu_local_var(current), ctx, l); } + /* x86_64: Setting l to rax is done in the + * following return. + */ save_syscall_return_value(num, l); #ifdef PROFILE_ENABLE