mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs.git
synced 2026-10-30 13:52:50 +01:00
Pull generic entry code updates from Thomas Gleixner: - Make syscall user dispatching configurable Not all architectures can makes use of syscall user dispatching. Allow them to disable the feature completely. - Consolidate stack randomization for the generic entry code and the architectures using it. Stack randomization on syscall entry was sprinkled throughout the architecture specific low level entry code and in some cases at the wrong points, e.g. before establishing state, which violates the non-instrumentable constraints of that code. Clean this up by integrating stack randomization into the generic entry code helpers so that it is invoked at the earliest possible point right after establishing state and converting all generic entry code using architecture over. - Clean up the syscall number handling in the generic entry code. It works correctly for architectures which have a separate return value storage in pt_regs, but fails to distinguish the case where user space handed in -1 as syscall number from the case where the entry code rejects it by returning -1 to the callers. Aside of that the return value functionality of those interfaces is not really intuitive. Fix this by separating the decision to reject a syscall (user dispatch, ptrace, seccomp ...) from the potential modification of the syscall number through these mechanisms. This solves most of the problems for architectures which do not have a separate return value storage in pt_regs except for the case where a tracepoint has a BPF script or a probe attached which overwrite both the syscall number and the return value. But that's a problem which cannot be solved in the generic code, that only can be addressed by separating the storage model in the affected architectures. * tag 'core-entry-2026-08-17' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (23 commits) entry, treewide: Make syscall_enter_from_user_mode[_work]() indicate syscall execution entry: Make return type of syscall_trace_enter() bool entry: Rework trace_syscall_enter() entry: Rework syscall_audit_enter() syscall_user_dispatch: Introduce ARCH_SUPPORTS_SYSCALL_USER_DISPATCH entry: Fix seccomp bypass after ptrace with TSYNC x86/entry: Simplify the syscall number logic x86/entry: Get rid of the sys_ni_syscall() indirection x86/entry: Make syscall functions static ptrace, treewide: Rename ptrace_report_syscall_entry() to ptrace_report_syscall_permit_entry() seccomp, treewide: Rename and convert __secure_computing() to return boolean entry: Use syscall number instead of rereading it entry: Remove syscall_enter_from_user_mode() x86/syscall: Use [syscall_]enter_from_user_mode_randomize_stack() s390/syscall: Use enter_from_user_mode_randomize_stack() riscv/syscall: Use syscall_enter_from_user_mode_randomize_stack() powerpc/syscall: Use syscall_enter_from_user_mode_randomize_stack() loongarch/syscall: Use syscall_enter_from_user_mode_randomize_stack() entry: Provide [syscall_]enter_from_user_mode_randomize_stack() randomize_kstack: Provide add_random_kstack_offset_irqsoff() ...
149 lines
3.8 KiB
C
149 lines
3.8 KiB
C
/* SPDX-License-Identifier: GPL-2.0-only */
|
|
/*
|
|
* Access to user system call parameters and results
|
|
*
|
|
* Copyright (C) 2008 Red Hat, Inc. All rights reserved.
|
|
*
|
|
* 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/thread_info.h>
|
|
|
|
#ifdef CONFIG_ARCH_HAS_SYSCALL_WRAPPER
|
|
typedef long (*syscall_fn)(const struct pt_regs *);
|
|
#else
|
|
typedef long (*syscall_fn)(unsigned long, unsigned long, unsigned long,
|
|
unsigned long, unsigned long, unsigned long);
|
|
#endif
|
|
|
|
/* ftrace syscalls requires exporting the sys_call_table */
|
|
extern const syscall_fn sys_call_table[];
|
|
extern const syscall_fn compat_sys_call_table[];
|
|
|
|
static inline int syscall_get_nr(struct task_struct *task, struct pt_regs *regs)
|
|
{
|
|
/*
|
|
* Note that we are returning an int here. That means 0xffffffff, ie.
|
|
* 32-bit negative 1, will be interpreted as -1 on a 64-bit kernel.
|
|
* This is important for seccomp so that compat tasks can set r0 = -1
|
|
* to reject the syscall.
|
|
*/
|
|
if (trap_is_syscall(regs))
|
|
return regs->gpr[0];
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
static inline void syscall_set_nr(struct task_struct *task, struct pt_regs *regs, int nr)
|
|
{
|
|
/*
|
|
* Unlike syscall_get_nr(), syscall_set_nr() can be called only when
|
|
* the target task is stopped for tracing on entering syscall, so
|
|
* there is no need to have the same check syscall_get_nr() has.
|
|
*/
|
|
regs->gpr[0] = nr;
|
|
}
|
|
|
|
static inline void syscall_rollback(struct task_struct *task,
|
|
struct pt_regs *regs)
|
|
{
|
|
regs->gpr[3] = regs->orig_gpr3;
|
|
}
|
|
|
|
static inline long syscall_get_error(struct task_struct *task,
|
|
struct pt_regs *regs)
|
|
{
|
|
if (trap_is_scv(regs)) {
|
|
unsigned long error = regs->gpr[3];
|
|
|
|
return IS_ERR_VALUE(error) ? error : 0;
|
|
} else {
|
|
/*
|
|
* If the system call failed,
|
|
* regs->gpr[3] contains a positive ERRORCODE.
|
|
*/
|
|
return (regs->ccr & 0x10000000UL) ? -regs->gpr[3] : 0;
|
|
}
|
|
}
|
|
|
|
static inline long syscall_get_return_value(struct task_struct *task,
|
|
struct pt_regs *regs)
|
|
{
|
|
return regs->gpr[3];
|
|
}
|
|
|
|
static inline void syscall_set_return_value(struct task_struct *task,
|
|
struct pt_regs *regs,
|
|
int error, long val)
|
|
{
|
|
if (trap_is_scv(regs)) {
|
|
regs->gpr[3] = (long) error ?: val;
|
|
} else {
|
|
/*
|
|
* In the general case it's not obvious that we must deal with
|
|
* CCR here, as the syscall exit path will also do that for us.
|
|
* However there are some places, eg. the signal code, which
|
|
* check ccr to decide if the value in r3 is actually an error.
|
|
*/
|
|
if (error) {
|
|
regs->ccr |= 0x10000000L;
|
|
regs->gpr[3] = error;
|
|
} else {
|
|
regs->ccr &= ~0x10000000L;
|
|
regs->gpr[3] = val;
|
|
}
|
|
}
|
|
/*
|
|
* Mark that a return value has been explicitly set by seccomp or
|
|
* ptrace so that system_call_exception() can skip the syscall
|
|
* unconditionally, even when the user requested syscall(-1).
|
|
*/
|
|
set_thread_flag(TIF_SYSCALL_RET);
|
|
}
|
|
|
|
static inline void syscall_get_arguments(struct task_struct *task,
|
|
struct pt_regs *regs,
|
|
unsigned long *args)
|
|
{
|
|
unsigned long val, mask = -1UL;
|
|
unsigned int n = 6;
|
|
|
|
if (is_tsk_32bit_task(task))
|
|
mask = 0xffffffff;
|
|
|
|
while (n--) {
|
|
if (n == 0)
|
|
val = regs->orig_gpr3;
|
|
else
|
|
val = regs->gpr[3 + n];
|
|
|
|
args[n] = val & mask;
|
|
}
|
|
}
|
|
|
|
static inline void syscall_set_arguments(struct task_struct *task,
|
|
struct pt_regs *regs,
|
|
const unsigned long *args)
|
|
{
|
|
memcpy(®s->gpr[3], args, 6 * sizeof(args[0]));
|
|
|
|
/* Also copy the first argument into orig_gpr3 */
|
|
regs->orig_gpr3 = args[0];
|
|
}
|
|
|
|
static inline int syscall_get_arch(struct task_struct *task)
|
|
{
|
|
if (is_tsk_32bit_task(task))
|
|
return AUDIT_ARCH_PPC;
|
|
else if (IS_ENABLED(CONFIG_CPU_LITTLE_ENDIAN))
|
|
return AUDIT_ARCH_PPC64LE;
|
|
else
|
|
return AUDIT_ARCH_PPC64;
|
|
}
|
|
#endif /* _ASM_SYSCALL_H */
|