Skip to content

Commit d72500f

Browse files
npigginmpe
authored andcommitted
powerpc/64s/syscall: Fix ptrace syscall info with scv syscalls
The scv implementation missed updating syscall return value and error value get/set functions to deal with the changed register ABI. This broke ptrace PTRACE_GET_SYSCALL_INFO as well as some kernel auditing and tracing functions. Fix. tools/testing/selftests/ptrace/get_syscall_info now passes when scv is used. Fixes: 7fa95f9 ("powerpc/64s: system call support for scv/rfscv instructions") Cc: [email protected] # v5.9+ Reported-by: "Dmitry V. Levin" <[email protected]> Signed-off-by: Nicholas Piggin <[email protected]> Reviewed-by: Dmitry V. Levin <[email protected]> Signed-off-by: Michael Ellerman <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 5665bc3 commit d72500f

File tree

2 files changed

+52
-35
lines changed

2 files changed

+52
-35
lines changed

arch/powerpc/include/asm/ptrace.h

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#ifndef _ASM_POWERPC_PTRACE_H
2020
#define _ASM_POWERPC_PTRACE_H
2121

22+
#include <linux/err.h>
2223
#include <uapi/asm/ptrace.h>
2324
#include <asm/asm-const.h>
2425

@@ -152,25 +153,6 @@ extern unsigned long profile_pc(struct pt_regs *regs);
152153
long do_syscall_trace_enter(struct pt_regs *regs);
153154
void do_syscall_trace_leave(struct pt_regs *regs);
154155

155-
#define kernel_stack_pointer(regs) ((regs)->gpr[1])
156-
static inline int is_syscall_success(struct pt_regs *regs)
157-
{
158-
return !(regs->ccr & 0x10000000);
159-
}
160-
161-
static inline long regs_return_value(struct pt_regs *regs)
162-
{
163-
if (is_syscall_success(regs))
164-
return regs->gpr[3];
165-
else
166-
return -regs->gpr[3];
167-
}
168-
169-
static inline void regs_set_return_value(struct pt_regs *regs, unsigned long rc)
170-
{
171-
regs->gpr[3] = rc;
172-
}
173-
174156
#ifdef __powerpc64__
175157
#define user_mode(regs) ((((regs)->msr) >> MSR_PR_LG) & 0x1)
176158
#else
@@ -235,6 +217,31 @@ static __always_inline void set_trap_norestart(struct pt_regs *regs)
235217
regs->trap |= 0x1;
236218
}
237219

220+
#define kernel_stack_pointer(regs) ((regs)->gpr[1])
221+
static inline int is_syscall_success(struct pt_regs *regs)
222+
{
223+
if (trap_is_scv(regs))
224+
return !IS_ERR_VALUE((unsigned long)regs->gpr[3]);
225+
else
226+
return !(regs->ccr & 0x10000000);
227+
}
228+
229+
static inline long regs_return_value(struct pt_regs *regs)
230+
{
231+
if (trap_is_scv(regs))
232+
return regs->gpr[3];
233+
234+
if (is_syscall_success(regs))
235+
return regs->gpr[3];
236+
else
237+
return -regs->gpr[3];
238+
}
239+
240+
static inline void regs_set_return_value(struct pt_regs *regs, unsigned long rc)
241+
{
242+
regs->gpr[3] = rc;
243+
}
244+
238245
#define arch_has_single_step() (1)
239246
#define arch_has_block_step() (true)
240247
#define ARCH_HAS_USER_SINGLE_STEP_REPORT

arch/powerpc/include/asm/syscall.h

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,17 @@ static inline void syscall_rollback(struct task_struct *task,
4141
static inline long syscall_get_error(struct task_struct *task,
4242
struct pt_regs *regs)
4343
{
44-
/*
45-
* If the system call failed,
46-
* regs->gpr[3] contains a positive ERRORCODE.
47-
*/
48-
return (regs->ccr & 0x10000000UL) ? -regs->gpr[3] : 0;
44+
if (trap_is_scv(regs)) {
45+
unsigned long error = regs->gpr[3];
46+
47+
return IS_ERR_VALUE(error) ? error : 0;
48+
} else {
49+
/*
50+
* If the system call failed,
51+
* regs->gpr[3] contains a positive ERRORCODE.
52+
*/
53+
return (regs->ccr & 0x10000000UL) ? -regs->gpr[3] : 0;
54+
}
4955
}
5056

5157
static inline long syscall_get_return_value(struct task_struct *task,
@@ -58,18 +64,22 @@ static inline void syscall_set_return_value(struct task_struct *task,
5864
struct pt_regs *regs,
5965
int error, long val)
6066
{
61-
/*
62-
* In the general case it's not obvious that we must deal with CCR
63-
* here, as the syscall exit path will also do that for us. However
64-
* there are some places, eg. the signal code, which check ccr to
65-
* decide if the value in r3 is actually an error.
66-
*/
67-
if (error) {
68-
regs->ccr |= 0x10000000L;
69-
regs->gpr[3] = error;
67+
if (trap_is_scv(regs)) {
68+
regs->gpr[3] = (long) error ?: val;
7069
} else {
71-
regs->ccr &= ~0x10000000L;
72-
regs->gpr[3] = val;
70+
/*
71+
* In the general case it's not obvious that we must deal with
72+
* CCR here, as the syscall exit path will also do that for us.
73+
* However there are some places, eg. the signal code, which
74+
* check ccr to decide if the value in r3 is actually an error.
75+
*/
76+
if (error) {
77+
regs->ccr |= 0x10000000L;
78+
regs->gpr[3] = error;
79+
} else {
80+
regs->ccr &= ~0x10000000L;
81+
regs->gpr[3] = val;
82+
}
7383
}
7484
}
7585

0 commit comments

Comments
 (0)