mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
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:
@@ -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
|
||||
====================
|
||||
|
||||
|
||||
@@ -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
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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, ®no);
|
||||
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))
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)))
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,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))) {
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user