linux/arch/ia64/include/asm/syscall.h
Sergei Trofimovich 61bf318eac ia64: fix ptrace(PTRACE_SYSCALL_INFO_EXIT) sign
In https://bugs.gentoo.org/769614 Dmitry noticed that
`ptrace(PTRACE_GET_SYSCALL_INFO)` does not return error sign properly.

The bug is in mismatch between get/set errors:

static inline long syscall_get_error(struct task_struct *task,
                                     struct pt_regs *regs)
{
        return regs->r10 == -1 ? regs->r8:0;
}

static inline long syscall_get_return_value(struct task_struct *task,
                                            struct pt_regs *regs)
{
        return regs->r8;
}

static inline void syscall_set_return_value(struct task_struct *task,
                                            struct pt_regs *regs,
                                            int error, long val)
{
        if (error) {
                /* error < 0, but ia64 uses > 0 return value */
                regs->r8 = -error;
                regs->r10 = -1;
        } else {
                regs->r8 = val;
                regs->r10 = 0;
        }
}

Tested on v5.10 on rx3600 machine (ia64 9040 CPU).

Link: https://lkml.kernel.org/r/20210221002554.333076-2-slyfox@gentoo.org
Link: https://bugs.gentoo.org/769614
Signed-off-by: Sergei Trofimovich <slyfox@gentoo.org>
Reported-by: Dmitry V. Levin <ldv@altlinux.org>
Reviewed-by: Dmitry V. Levin <ldv@altlinux.org>
Cc: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>
Cc: Oleg Nesterov <oleg@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2021-03-13 11:27:31 -08:00

79 lines
1.8 KiB
C

/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Access to user system call parameters and results
*
* Copyright (C) 2008 Intel Corp. Shaohua Li <shaohua.li@intel.com>
*
* See asm-generic/syscall.h for descriptions of what we must do here.
*/
#ifndef _ASM_SYSCALL_H
#define _ASM_SYSCALL_H 1
#include <uapi/linux/audit.h>
#include <linux/sched.h>
#include <linux/err.h>
static inline long syscall_get_nr(struct task_struct *task,
struct pt_regs *regs)
{
if ((long)regs->cr_ifs < 0) /* Not a syscall */
return -1;
return regs->r15;
}
static inline void syscall_rollback(struct task_struct *task,
struct pt_regs *regs)
{
/* do nothing */
}
static inline long syscall_get_error(struct task_struct *task,
struct pt_regs *regs)
{
return regs->r10 == -1 ? -regs->r8:0;
}
static inline long syscall_get_return_value(struct task_struct *task,
struct pt_regs *regs)
{
return regs->r8;
}
static inline void syscall_set_return_value(struct task_struct *task,
struct pt_regs *regs,
int error, long val)
{
if (error) {
/* error < 0, but ia64 uses > 0 return value */
regs->r8 = -error;
regs->r10 = -1;
} else {
regs->r8 = val;
regs->r10 = 0;
}
}
extern void ia64_syscall_get_set_arguments(struct task_struct *task,
struct pt_regs *regs, unsigned long *args, int rw);
static inline void syscall_get_arguments(struct task_struct *task,
struct pt_regs *regs,
unsigned long *args)
{
ia64_syscall_get_set_arguments(task, regs, args, 0);
}
static inline void syscall_set_arguments(struct task_struct *task,
struct pt_regs *regs,
unsigned long *args)
{
ia64_syscall_get_set_arguments(task, regs, args, 1);
}
static inline int syscall_get_arch(struct task_struct *task)
{
return AUDIT_ARCH_IA64;
}
#endif /* _ASM_SYSCALL_H */