Merge branch into tip/master: 'core/entry'

# New commits in core/entry:
    05c033db7e ("entry, treewide: Make syscall_enter_from_user_mode[_work]() indicate syscall execution")
    71ff30013f ("entry: Make return type of syscall_trace_enter() bool")
    dfc98c7a46 ("entry: Rework trace_syscall_enter()")
    6f25517010 ("entry: Rework syscall_audit_enter()")
    8383e05af7 ("syscall_user_dispatch: Introduce ARCH_SUPPORTS_SYSCALL_USER_DISPATCH")
    4a3591287f ("entry: Fix seccomp bypass after ptrace with TSYNC")
    fb419d53f2 ("x86/entry: Simplify the syscall number logic")
    1b1f3b3e1b ("x86/entry: Get rid of the sys_ni_syscall() indirection")
    2b341c74db ("x86/entry: Make syscall functions static")
    622f04e974 ("ptrace, treewide: Rename ptrace_report_syscall_entry() to ptrace_report_syscall_permit_entry()")
    7ba2ba7471 ("seccomp, treewide: Rename and convert __secure_computing() to return boolean")
    8af25d0a2e ("entry: Use syscall number instead of rereading it")
    bad2a27ba8 ("entry: Remove syscall_enter_from_user_mode()")
    9d311796e2 ("x86/syscall: Use [syscall_]enter_from_user_mode_randomize_stack()")
    05a194d8bd ("s390/syscall: Use enter_from_user_mode_randomize_stack()")
    d023abfbc4 ("riscv/syscall: Use syscall_enter_from_user_mode_randomize_stack()")
    3b2b9c0198 ("powerpc/syscall: Use syscall_enter_from_user_mode_randomize_stack()")
    7892c5a22a ("loongarch/syscall: Use syscall_enter_from_user_mode_randomize_stack()")
    855c103f86 ("entry: Provide [syscall_]enter_from_user_mode_randomize_stack()")
    0b9a305753 ("randomize_kstack: Provide add_random_kstack_offset_irqsoff()")
    89d163dd9d ("powerpc: Move stack randomization after syscall_enter_from_user_mode()")
    5b6e32ba7b ("syscall_user_dispatch: Add kernel.syscall_user_dispatch sysctl")
    ee935e8dc7 ("syscall_user_dispatch: Make it configurable in Kconfig")

Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
Ingo Molnar
2026-07-31 11:53:11 +02:00
48 changed files with 408 additions and 323 deletions
@@ -1402,6 +1402,23 @@ Note that if you change this from 0 to 1, already created segments
without users and with a dead originative process will be destroyed.
syscall_user_dispatch
=====================
Controls whether userspace may arm Syscall User Dispatch via
``prctl(PR_SET_SYSCALL_USER_DISPATCH, ...)`` or the
``PTRACE_SET_SYSCALL_USER_DISPATCH_CONFIG`` ptrace request:
== ===================================================================
0 Arming syscall user dispatch is denied with ``-EPERM``. Tasks that
already armed it keep it, and disabling it is always permitted.
1 (default) Arming syscall user dispatch is permitted.
== ===================================================================
Only present when the kernel is built with ``CONFIG_SYSCALL_USER_DISPATCH``
and ``CONFIG_PROC_SYSCTL``.
sysctl_writes_strict
====================
+46 -18
View File
@@ -58,32 +58,59 @@ state transitions must run with interrupts disabled.
Syscalls
--------
Syscall-entry code starts in assembly code and calls out into low-level C code
after establishing low-level architecture-specific state and stack frames. This
low-level C code must not be instrumented. A typical syscall handling function
invoked from low-level assembly code looks like this:
Syscall-entry code starts in assembly code and calls out into low-level C
code after establishing low-level architecture-specific state and stack
frames. This low-level C code must not be instrumented. The recommended
syscall handling function invoked from low-level assembly code looks like
this:
.. code-block:: c
noinstr void syscall(struct pt_regs *regs, int nr)
noinstr void syscall(struct pt_regs *regs, long nr)
{
arch_syscall_enter(regs);
nr = syscall_enter_from_user_mode(regs, nr);
instrumentation_begin();
if (!invoke_syscall(regs, nr) && nr != -1)
result_reg(regs) = __sys_ni_syscall(regs);
instrumentation_end();
result_reg(regs) = -ENOSYS;
if (syscall_enter_from_user_mode_randomize_stack(regs, &nr)) {
instrumentation_begin();
if (valid(nr)
result_reg(regs) = invoke_syscall(regs, nr);
instrumentation_end();
}
syscall_exit_to_user_mode(regs);
}
syscall_enter_from_user_mode() first invokes enter_from_user_mode() which
establishes state in the following order:
This is the most resilent variant as it has always a guaranteed valid
return code. The alternative variant is:
.. code-block:: c
noinstr void syscall(struct pt_regs *regs, long nr)
{
arch_syscall_enter(regs);
if (syscall_enter_from_user_mode_randomize_stack(regs, &nr)) {
instrumentation_begin();
if (valid(nr)
result_reg(regs) = invoke_syscall(regs, nr);
else
result_reg(regs) = -ENOSYS;
instrumentation_end();
}
syscall_exit_to_user_mode(regs);
}
That works for most situations except when a probe/BPF attached to the
syscall tracepoint sets an invalid syscall number e.g. -1 and also modifies
the result register. So this variant will obviously overwrite the modified
result with -ENOSYS.
syscall_enter_from_user_mode_randomize_stack() first invokes
enter_from_user_mode_randomize_stack() which establishes state in the
following order:
* Lockdep
* RCU / Context tracking
* Tracing
* Apply stack randomization
and then invokes the various entry work functions like ptrace, seccomp, audit,
syscall tracing, etc. After all that is done, the instrumentable invoke_syscall
@@ -99,10 +126,11 @@ transition in the reverse order:
* RCU / Context tracking
* Lockdep
syscall_enter_from_user_mode() and syscall_exit_to_user_mode() are also
available as fine grained subfunctions in cases where the architecture code
has to do extra work between the various steps. In such cases it has to
ensure that enter_from_user_mode() is called first on entry and
syscall_enter_from_user_mode_randomize_stack() and
syscall_exit_to_user_mode() are also available as fine grained subfunctions
in cases where the architecture code has to do extra work between the
various steps. In such cases it has to ensure that
enter_from_user_mode_randomize_stack() is called first on entry and
exit_to_user_mode() is called last on exit.
Do not nest syscalls. Nested syscalls will cause RCU and/or context tracking
+15 -1
View File
@@ -114,6 +114,20 @@ config GENERIC_ENTRY
select GENERIC_IRQ_ENTRY
select GENERIC_SYSCALL
config ARCH_SUPPORTS_SYSCALL_USER_DISPATCH
bool
config SYSCALL_USER_DISPATCH
bool "Syscall User Dispatch"
depends on ARCH_SUPPORTS_SYSCALL_USER_DISPATCH
depends on GENERIC_ENTRY
default y
help
Syscall User Dispatch lets a thread have its own system calls
intercepted and redirected to a userspace signal handler based
on a prctl() configured instruction pointer range.
If unsure, say Y.
config KPROBES
bool "Kprobes"
depends on HAVE_KPROBES
@@ -637,7 +651,7 @@ config HAVE_ARCH_SECCOMP_FILTER
- syscall_set_return_value()
- SIGSYS siginfo_t support
- secure_computing is called from a ptrace_event()-safe context
- secure_computing return value is checked and a return value of -1
- secure_computing return value is checked and if false it
results in the system call being skipped immediately.
- seccomp syscall wired up
- if !HAVE_SPARSE_SYSCALL_NR, have SECCOMP_ARCH_NATIVE,
+2 -2
View File
@@ -375,7 +375,7 @@ asmlinkage unsigned long syscall_trace_enter(void)
struct pt_regs *regs = current_pt_regs();
if (test_thread_flag(TIF_SYSCALL_TRACE) &&
ptrace_report_syscall_entry(regs)) {
!ptrace_report_syscall_permit_entry(regs)) {
syscall_set_nr(current, regs, -1);
if (regs->r19 == 0 && regs->r0 == (unsigned long)-1)
syscall_set_return_value(current, regs, -ENOSYS, 0);
@@ -387,7 +387,7 @@ asmlinkage unsigned long syscall_trace_enter(void)
* If this fails, seccomp may already have set up the return value
* (e.g. SECCOMP_RET_ERRNO / TRACE).
*/
if (secure_computing() == -1) {
if (!seccomp_permit_syscall()) {
if (regs->r19 == 0 && regs->r0 == (unsigned long)-1)
syscall_set_return_value(current, regs, -ENOSYS, 0);
syscall_set_nr(current, regs, -1);
+1 -1
View File
@@ -342,7 +342,7 @@ long arch_ptrace(struct task_struct *child, long request,
asmlinkage int syscall_trace_enter(struct pt_regs *regs)
{
if (test_thread_flag(TIF_SYSCALL_TRACE))
if (ptrace_report_syscall_entry(regs))
if (!ptrace_report_syscall_permit_entry(regs))
return ULONG_MAX;
#ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS
+2 -2
View File
@@ -840,7 +840,7 @@ static void report_syscall(struct pt_regs *regs, enum ptrace_syscall_dir dir)
if (dir == PTRACE_SYSCALL_EXIT)
ptrace_report_syscall_exit(regs, 0);
else if (ptrace_report_syscall_entry(regs))
else if (!ptrace_report_syscall_permit_entry(regs))
current_thread_info()->abi_syscall = -1;
regs->ARM_ip = ip;
@@ -855,7 +855,7 @@ asmlinkage int syscall_trace_enter(struct pt_regs *regs)
/* Do seccomp after ptrace; syscall may have changed. */
#ifdef CONFIG_HAVE_ARCH_SECCOMP_FILTER
if (secure_computing() == -1)
if (!seccomp_permit_syscall())
return -1;
#else
/* XXX: remove this once OABI gets fixed */
+2 -2
View File
@@ -2379,7 +2379,7 @@ static int report_syscall_entry(struct pt_regs *regs)
int regno, ret;
saved_reg = ptrace_save_reg(regs, PTRACE_SYSCALL_ENTER, &regno);
ret = ptrace_report_syscall_entry(regs);
ret = !ptrace_report_syscall_permit_entry(regs);
if (ret)
forget_syscall(regs);
regs->regs[regno] = saved_reg;
@@ -2420,7 +2420,7 @@ int syscall_trace_enter(struct pt_regs *regs)
}
/* Do the secure computing after ptrace; failures should be fast. */
if (secure_computing() == -1)
if (!seccomp_permit_syscall())
return NO_SYSCALL;
if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
+2 -2
View File
@@ -320,10 +320,10 @@ long arch_ptrace(struct task_struct *child, long request,
asmlinkage int syscall_trace_enter(struct pt_regs *regs)
{
if (test_thread_flag(TIF_SYSCALL_TRACE))
if (ptrace_report_syscall_entry(regs))
if (!ptrace_report_syscall_permit_entry(regs))
return -1;
if (secure_computing() == -1)
if (!seccomp_permit_syscall())
return -1;
if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
+1 -1
View File
@@ -345,7 +345,7 @@ void do_trap0(struct pt_regs *regs)
/* allow strace to catch syscall args */
if (unlikely(test_thread_flag(TIF_SYSCALL_TRACE) &&
ptrace_report_syscall_entry(regs)))
!ptrace_report_syscall_permit_entry(regs)))
return; /* return -ENOSYS somewhere? */
/* Interrupts should be re-enabled for syscall processing */
-6
View File
@@ -84,10 +84,4 @@ static inline int syscall_get_arch(struct task_struct *task)
return AUDIT_ARCH_LOONGARCH64;
#endif
}
static inline bool arch_syscall_is_vdso_sigreturn(struct pt_regs *regs)
{
return false;
}
#endif /* __ASM_LOONGARCH_SYSCALL_H */
+7 -10
View File
@@ -11,7 +11,6 @@
#include <linux/linkage.h>
#include <linux/nospec.h>
#include <linux/objtool.h>
#include <linux/randomize_kstack.h>
#include <linux/syscalls.h>
#include <linux/unistd.h>
@@ -58,8 +57,8 @@ typedef long (*sys_call_fn)(unsigned long, unsigned long,
void noinstr __no_stack_protector do_syscall(struct pt_regs *regs)
{
unsigned long nr;
sys_call_fn syscall_fn;
unsigned long nr;
nr = regs->regs[11];
/* Set for syscall restarting */
@@ -70,14 +69,12 @@ void noinstr __no_stack_protector do_syscall(struct pt_regs *regs)
regs->orig_a0 = regs->regs[4];
regs->regs[4] = -ENOSYS;
nr = syscall_enter_from_user_mode(regs, nr);
add_random_kstack_offset();
if (nr < NR_syscalls) {
syscall_fn = sys_call_table[array_index_nospec(nr, NR_syscalls)];
regs->regs[4] = syscall_fn(regs->orig_a0, regs->regs[5], regs->regs[6],
regs->regs[7], regs->regs[8], regs->regs[9]);
if (likely(syscall_enter_from_user_mode_randomize_stack(regs, &nr))) {
if (nr < NR_syscalls) {
syscall_fn = sys_call_table[array_index_nospec(nr, NR_syscalls)];
regs->regs[4] = syscall_fn(regs->orig_a0, regs->regs[5], regs->regs[6],
regs->regs[7], regs->regs[8], regs->regs[9]);
}
}
syscall_exit_to_user_mode(regs);
+2 -2
View File
@@ -279,9 +279,9 @@ asmlinkage int syscall_trace_enter(void)
int ret = 0;
if (test_thread_flag(TIF_SYSCALL_TRACE))
ret = ptrace_report_syscall_entry(task_pt_regs(current));
ret = !ptrace_report_syscall_permit_entry(task_pt_regs(current));
if (secure_computing() == -1)
if (!seccomp_permit_syscall())
return -1;
return ret;
+1 -1
View File
@@ -139,7 +139,7 @@ asmlinkage unsigned long do_syscall_trace_enter(struct pt_regs *regs)
secure_computing_strict(regs->r12);
if (test_thread_flag(TIF_SYSCALL_TRACE) &&
ptrace_report_syscall_entry(regs))
!ptrace_report_syscall_permit_entry(regs))
/*
* Tracing decided this syscall should not happen.
* We'll return a bogus call number to get an ENOSYS
+2 -2
View File
@@ -1324,11 +1324,11 @@ asmlinkage long syscall_trace_enter(struct pt_regs *regs)
user_exit();
if (test_thread_flag(TIF_SYSCALL_TRACE)) {
if (ptrace_report_syscall_entry(regs))
if (!ptrace_report_syscall_permit_entry(regs))
return -1;
}
if (secure_computing())
if (!seccomp_permit_syscall())
return -1;
if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
+1 -1
View File
@@ -133,7 +133,7 @@ asmlinkage int do_syscall_trace_enter(void)
int ret = 0;
if (test_thread_flag(TIF_SYSCALL_TRACE))
ret = ptrace_report_syscall_entry(task_pt_regs(current));
ret = !ptrace_report_syscall_permit_entry(task_pt_regs(current));
return ret;
}
+1 -1
View File
@@ -293,7 +293,7 @@ asmlinkage long do_syscall_trace_enter(struct pt_regs *regs)
long ret = 0;
if (test_thread_flag(TIF_SYSCALL_TRACE) &&
ptrace_report_syscall_entry(regs))
!ptrace_report_syscall_permit_entry(regs))
/*
* Tracing decided this syscall should not happen.
* We'll return a bogus call number to get an ENOSYS
+5 -7
View File
@@ -326,7 +326,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
long do_syscall_trace_enter(struct pt_regs *regs)
{
if (test_thread_flag(TIF_SYSCALL_TRACE)) {
int rc = ptrace_report_syscall_entry(regs);
bool permit = ptrace_report_syscall_permit_entry(regs);
/*
* As tracesys_next does not set %r28 to -ENOSYS
@@ -334,12 +334,10 @@ long do_syscall_trace_enter(struct pt_regs *regs)
*/
regs->gr[28] = -ENOSYS;
if (rc) {
if (!permit) {
/*
* A nonzero return code from
* ptrace_report_syscall_entry() tells us
* to prevent the syscall execution. Skip
* the syscall call and the syscall restart handling.
* Skip the syscall call and the syscall restart
* handling.
*
* Note that the tracer may also just change
* regs->gr[20] to an invalid syscall number,
@@ -351,7 +349,7 @@ long do_syscall_trace_enter(struct pt_regs *regs)
}
/* Do the secure computing check after ptrace. */
if (secure_computing() == -1)
if (!seccomp_permit_syscall())
return -1;
#ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS
-5
View File
@@ -139,9 +139,4 @@ static inline int syscall_get_arch(struct task_struct *task)
else
return AUDIT_ARCH_PPC64;
}
static inline bool arch_syscall_is_vdso_sigreturn(struct pt_regs *regs)
{
return false;
}
#endif /* _ASM_SYSCALL_H */
+2 -3
View File
@@ -2,7 +2,6 @@
#include <linux/compat.h>
#include <linux/context_tracking.h>
#include <linux/randomize_kstack.h>
#include <linux/entry-common.h>
#include <asm/interrupt.h>
@@ -19,8 +18,8 @@ notrace long system_call_exception(struct pt_regs *regs, unsigned long r0)
long ret;
syscall_fn f;
add_random_kstack_offset();
r0 = syscall_enter_from_user_mode(regs, r0);
if (unlikely(!syscall_enter_from_user_mode_randomize_stack(regs, &r0)))
return syscall_get_error(current, regs);
if (unlikely(r0 >= NR_syscalls)) {
if (unlikely(trap_is_unsupported_scv(regs))) {
-5
View File
@@ -112,11 +112,6 @@ static inline void syscall_handler(struct pt_regs *regs, ulong syscall)
regs->a0 = fn(regs);
}
static inline bool arch_syscall_is_vdso_sigreturn(struct pt_regs *regs)
{
return false;
}
asmlinkage long sys_riscv_flush_icache(uintptr_t, uintptr_t, uintptr_t);
asmlinkage long sys_riscv_hwprobe(struct riscv_hwprobe *, size_t, size_t,

Some files were not shown because too many files have changed in this diff Show More