Skip to contentSkip to conversation

entry: Consolidate and rework syscall entry handling

PATCH Applied Thomas Gleixner 19 participants 145 messages Jul 7 – Nov 3 Page 1 of 2

Subsystems (30)
lore
Share & tools
lore

Thomas Gleixner

author maintainer
#0 lore raw

cover entry: Consolidate and rework syscall entry handling

Sorry for the long CC list, but this is a treewide change.

Michal recently posted a RFC patch to separate the potential syscall number modifications in syscall_enter_user_mode_work() from the information whether the syscall should be processed and the return value modified:

https://lore.kernel.org/lkml/[email protected]

The existing logic is:

arch_syscall()

	regs->result = -ENOSYS;

	syscallnr = syscall_enter_from_user_mode(regs, syscall);

	if (syscallnr != -1L)
		regs->result = invoke_syscall(regs, syscall;

syscall_enter_from_user_mode() invokes ptrace, seccomp and tracing/BPF/Probes. All of them can modify the syscall number.

ptrace and seccomp explicitly set the syscall number to -1L to indicate that the syscall invocation needs to be skipped and the result has not to be modified as it might have been modified by ptrace or seccomp. The tracer/BPF/Probes mechanism can modify the syscall number as well and relies implicitly on the -1L logic.

This can obviously not be differentiated from a syscall invocation where userspace provided -1 as syscall number.

The general agreement of the discussion was that the current mechanism, while functionally correct is non-intuitive and something like Michals proposal would make that code clearer and easier to handle on the architecture side:

arch_syscall()

	regs->result = -ENOSYS;

	if (syscall_enter_from_user_mode(regs, &syscall)) 
		regs->result = invoke_syscall(regs, syscall;

That discussion made me look deeper into the related code and as usual there were a lot of other things to discover.

1) Stack randomization

add_random_kstack_offset() can only be invoked after enter_from_user_mode() established proper state as it calls into instrumentable code.

PowerPC got that wrong and the other architectures either invoke it after enter_from_user_mode() or after syscall_enter_from_user_mode().

The latter is suboptimal as the randomization takes place after all the user mode entry work. Aside of that add_random_kstack_offset() uses get/put_cpu_var(), which makes it usable in preemptible code, but when invoked in the interrupt disabled region that's pointless overhead.

2) As discussed in the above thread just changing the function signature of syscall_enter_from_user_mode[_work]() so they take a pointer argument for the syscall and then return 0 on success is not really intuitive either. Aside of that this breaks the implicit assumption of the tracer when setting the syscall number to -1.

3) The x86 entry code has some historically accumulated oddities

The following series addresses this by:

1) Providing new [syscall_]enter_from_user_mode() variants, which include stack randomization and utilize a new add_random_kstack_offset_irqsoff() variant, which avoids the get/put_cpu_var() overhead and converting all usage sites over

2) Picking up Jinjie's seccomp patch from:

https://lore.kernel.org/lkml/[email protected]

and addressing the feedback (renaming the seccomp functions)

3) Making the ptrace and tracer related functions return a boolean value to indicate syscall permission

4) Addressing the x86 oddities

5) Converting the tree over to the new scheme

With that all architectures using the generic syscall entry code follow the same scheme, apply stack randomization at the correct and earliest possible place and skip syscall processing depending on the boolean return value of syscall_enter_from_user_mode[_work]().

There should be no functional changes, at least there are none intended.

The resulting text size for the syscall entry code on x8664 is slightly smaller than before these changes.

Testing syscall heavy workloads and micro benchmarks shows a small performance gain for the general rework, but the last patch, which changes the logic to be more understandable has no measurable impact in either direction.

The series applies on Linus tree and is also available from git:

git://git.kernel.org/pub/scm/linux/kernel/git/tglx/devel.git entry-rework-v1

Thanks,

tglx

---
 Documentation/core-api/entry.rst      |   33 +++++---
 arch/alpha/kernel/ptrace.c            |    4 -
 arch/arc/kernel/ptrace.c              |    2 
 arch/arm/kernel/ptrace.c              |    4 -
 arch/arm64/kernel/ptrace.c            |    4 -
 arch/csky/kernel/ptrace.c             |    4 -
 arch/hexagon/kernel/traps.c           |    2 
 arch/loongarch/kernel/syscall.c       |   17 +---
 arch/m68k/kernel/ptrace.c             |    4 -
 arch/microblaze/kernel/ptrace.c       |    2 
 arch/mips/kernel/ptrace.c             |    4 -
 arch/nios2/kernel/ptrace.c            |    2 
 arch/openrisc/kernel/ptrace.c         |    2 
 arch/parisc/kernel/ptrace.c           |   12 +--
 arch/powerpc/kernel/syscall.c         |    5 -
 arch/riscv/kernel/traps.c             |   14 +--
 arch/s390/kernel/syscall.c            |   11 +-
 arch/sh/kernel/ptrace_32.c            |    4 -
 arch/sparc/kernel/ptrace_32.c         |    2 
 arch/sparc/kernel/ptrace_64.c         |    2 
 arch/um/kernel/ptrace.c               |    2 
 arch/um/kernel/skas/syscall.c         |    2 
 arch/x86/entry/syscall_32.c           |   70 +++++++------------
 arch/x86/entry/syscall_64.c           |   61 ++++++----------
 arch/x86/entry/vsyscall/vsyscall_64.c |   14 +--
 arch/x86/include/asm/entry-common.h   |    1 
 arch/x86/include/asm/syscall.h        |   10 --
 arch/xtensa/kernel/ptrace.c           |    5 -
 include/asm-generic/syscall.h         |    4 -
 include/linux/entry-common.h          |  125 ++++++++++++++++++++--------------
 include/linux/irq-entry-common.h      |    6 -
 include/linux/ptrace.h                |   13 +--
 include/linux/randomize_kstack.h      |   19 +++++
 include/linux/seccomp.h               |   12 +--
 kernel/entry/syscall-common.c         |    7 +
 kernel/seccomp.c                      |   35 ++++-----
 36 files changed, 264 insertions(+), 256 deletions(-)
author maintainer
#1 lore raw

PATCH 1/18 powerpc: Move stack randomization after syscall_enter_from_user_mode()

add_random_kstack_offset() is invoked before syscall_enter_from_user_mode() establishes state. That's wrong because add_random_kstack_offset() calls into instrumentable code.

Move it after syscall_enter_from_user_mode() to ensure that state is correctly established.

Cc Michael Ellerman <[email protected]>
Cc Shrikanth Hegde <[email protected]>
---
 arch/powerpc/kernel/syscall.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
arch/powerpc/kernel/syscall.c +1 -1
@@ -19,8 +19,8 @@ notrace long system_call_exception(struc
 	long ret;
 	syscall_fn f;
 
-	add_random_kstack_offset();
 	r0 = syscall_enter_from_user_mode(regs, r0);
+	add_random_kstack_offset();
 
 	if (unlikely(r0 >= NR_syscalls)) {
 		if (unlikely(trap_is_unsupported_scv(regs))) {
reviewer Reviewed-by on v1 1/18
#2 lore raw

Re: [patch 01/18] powerpc: Move stack randomization after syscall_enter_from_user_mode()

Quoted 3 lines · Thomas Gleixner

add_random_kstack_offset() is invoked before syscall_enter_from_user_mode() establishes state. That's wrong because add_random_kstack_offset() calls into instrumentable code.

Thanks for fixing that.

Quoted 16 lines

Move it after syscall_enter_from_user_mode() to ensure that state is correctly established.

Cc Michael Ellerman <[email protected]>
Cc Shrikanth Hegde <[email protected]>
---
  arch/powerpc/kernel/syscall.c |    2 +-
  1 file changed, 1 insertion(+), 1 deletion(-)

arch/powerpc/kernel/syscall.c notrace long system_call_exception(struc · line 26

Quoted 9 lines
arch/powerpc/kernel/syscall.c +1 -1
@@ -19,8 +19,8 @@ notrace long system_call_exception(struc
  	long ret;
  	syscall_fn f;
 
-	add_random_kstack_offset();
  	r0 = syscall_enter_from_user_mode(regs, r0);
+	add_random_kstack_offset();
 
  	if (unlikely(r0 >= NR_syscalls)) {
  		if (unlikely(trap_is_unsupported_scv(regs))) {
Reviewed-by on v1 1/18
#3 lore raw

Re: [patch 01/18] powerpc: Move stack randomization after syscall_enter_from_user_mode()

In reply to Thomas Gleixner
Quoted 24 lines · Thomas Gleixner

add_random_kstack_offset() is invoked before syscall_enter_from_user_mode() establishes state. That's wrong because add_random_kstack_offset() calls into instrumentable code.

Move it after syscall_enter_from_user_mode() to ensure that state is correctly established.

Cc Michael Ellerman <[email protected]>
Cc Shrikanth Hegde <[email protected]>

---
 arch/powerpc/kernel/syscall.c |    2 +-

 1 file changed, 1 insertion(+), 1 deletion(-)
arch/powerpc/kernel/syscall.c +0 -0
@@ -19,8 +19,8 @@ notrace long system_call_exception(struc
  	long ret;
  	syscall_fn f;

arch/powerpc/kernel/syscall.c +0 -1
-	add_random_kstack_offset();

  r0 = syscall_enter_from_user_mode(regs, r0);

arch/powerpc/kernel/syscall.c +1 -0
+	add_random_kstack_offset();
Quoted 3 lines


  if (unlikely(r0 >= NR_syscalls)) {
  if (unlikely(trap_is_unsupported_scv(regs))) {

Reviewed-by on v1 1/18
#4 lore raw

Re: [patch 01/18] powerpc: Move stack randomization after syscall_enter_from_user_mode()

In reply to Thomas Gleixner
Quoted 18 lines · Thomas Gleixner

add_random_kstack_offset() is invoked before syscall_enter_from_user_mode() establishes state. That's wrong because add_random_kstack_offset() calls into instrumentable code.

Move it after syscall_enter_from_user_mode() to ensure that state is correctly established.

Cc Michael Ellerman <[email protected]>
Cc Shrikanth Hegde <[email protected]>
---
 arch/powerpc/kernel/syscall.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

arch/powerpc/kernel/syscall.c notrace long system_call_exception(struc · line 23

Quoted 6 lines
arch/powerpc/kernel/syscall.c +1 -1
@@ -19,8 +19,8 @@ notrace long system_call_exception(struc
 	long ret;
 	syscall_fn f;
 
-	add_random_kstack_offset();
 	r0 = syscall_enter_from_user_mode(regs, r0);
+	add_random_kstack_offset();
Quoted 4 lines
arch/powerpc/kernel/syscall.c +0 -0
 	if (unlikely(r0 >= NR_syscalls)) {
 		if (unlikely(trap_is_unsupported_scv(regs))) {
 
Reviewed-by on v1 1/18
#5 lore raw

Re: [patch 01/18] powerpc: Move stack randomization after syscall_enter_from_user_mode()

In reply to Thomas Gleixner
Quoted 19 lines · Thomas Gleixner

add_random_kstack_offset() is invoked before syscall_enter_from_user_mode() establishes state. That's wrong because add_random_kstack_offset() calls into instrumentable code.

Move it after syscall_enter_from_user_mode() to ensure that state is correctly established.

Cc Michael Ellerman <[email protected]>
Cc Shrikanth Hegde <[email protected]>
---
  arch/powerpc/kernel/syscall.c |    2 +-
  1 file changed, 1 insertion(+), 1 deletion(-)

arch/powerpc/kernel/syscall.c notrace long system_call_exception(struc · line 26

Quoted 9 lines
arch/powerpc/kernel/syscall.c +1 -1
@@ -19,8 +19,8 @@ notrace long system_call_exception(struc
  	long ret;
  	syscall_fn f;
 
-	add_random_kstack_offset();
  	r0 = syscall_enter_from_user_mode(regs, r0);
+	add_random_kstack_offset();
 
  	if (unlikely(r0 >= NR_syscalls)) {
  		if (unlikely(trap_is_unsupported_scv(regs))) {
Reviewed-by on v1 1/18
#6 lore raw

Re: [patch 01/18] powerpc: Move stack randomization after syscall_enter_from_user_mode()

In reply to Thomas Gleixner
Quoted 11 lines · Thomas Gleixner

add_random_kstack_offset() is invoked before syscall_enter_from_user_mode() establishes state. That's wrong because add_random_kstack_offset() calls into instrumentable code.

Move it after syscall_enter_from_user_mode() to ensure that state is correctly established.

Cc Michael Ellerman <[email protected]>
Cc Shrikanth Hegde <[email protected]>

Thanks for fixing this.

[...]

#7 lore raw

[tip: core/entry] powerpc: Move stack randomization after syscall_enter_from_user_mode()

In reply to Thomas Gleixner
The following commit has been merged into the core/entry branch of tip:

The following commit has been merged into the core/entry branch of tip:

Commit-ID:     89d163dd9dacb028773244dba0a2c86f3a6b74b7
Gitweb:        https://git.kernel.org/tip/89d163dd9dacb028773244dba0a2c86f3a6b74b7
Author:        Thomas Gleixner <[email protected]>
AuthorDate:    Tue, 07 Jul 2026 21:05:58 +02:00
Committer:     Thomas Gleixner <[email protected]>
CommitterDate: Sun, 12 Jul 2026 12:38:00 +02:00

powerpc: Move stack randomization after syscall_enter_from_user_mode()

add_random_kstack_offset() is invoked before syscall_enter_from_user_mode() establishes state. That's wrong because add_random_kstack_offset() calls into instrumentable code.

Move it after syscall_enter_from_user_mode() to ensure that state is correctly established.

---
 arch/powerpc/kernel/syscall.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
arch/powerpc/kernel/syscall.c +1 -1
index a9da2af..ee07b2e 100644
@@ -19,8 +19,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);
+	add_random_kstack_offset();
 
 	if (unlikely(r0 >= NR_syscalls)) {
 		if (unlikely(trap_is_unsupported_scv(regs))) {
author maintainer
#8 lore raw

PATCH 2/18 randomize_kstack: Provide add_random_kstack_offset_irqsoff()

In reply to Thomas Gleixner

add_random_kstack_offset() uses get/put_cpu_var() which is pointless overhead when it is invoked from low level entry code with interrupts disabled.

Provide a irqsoff() variant, which avoids that.

---
 include/linux/randomize_kstack.h |   19 +++++++++++++++++++
 1 file changed, 19 insertions(+)
include/linux/randomize_kstack.h +19 -0
@@ -77,8 +77,27 @@ static __always_inline u32 get_kstack_of
 	}								\
 } while (0)
 
+/**
+ * add_random_kstack_offset_irqsoff - Increase stack utilization by a random offset.
+ *
+ * This should be used in the syscall entry path after user registers have been
+ * stored to the stack. Interrupts must be still disabled.
+ */
+#define add_random_kstack_offset_irqsoff()					\
+do {										\
+	lockdep_assert_irqs_disabled();						\
+	if (static_branch_maybe(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT,		\
+				&randomize_kstack_offset)) {			\
+		u32 offset = prandom_u32_state(raw_cpu_ptr(&kstack_rnd_state));	\
+		u8 *ptr = __kstack_alloca(KSTACK_OFFSET_MAX(offset));		\
+		/* Keep allocation even after "ptr" loses scope. */		\
+		asm volatile("" :: "r"(ptr) : "memory");			\
+	}									\
+} while (0)
+
 #else /* CONFIG_RANDOMIZE_KSTACK_OFFSET */
 #define add_random_kstack_offset()		do { } while (0)
+#define add_random_kstack_offset_irqsoff()	do { } while (0)
 #endif /* CONFIG_RANDOMIZE_KSTACK_OFFSET */
 
 #endif
Reviewed-by on v1 2/18
#9 lore raw

Re: [patch 02/18] randomize_kstack: Provide add_random_kstack_offset_irqsoff()

Quoted 36 lines · Thomas Gleixner

add_random_kstack_offset() uses get/put_cpu_var() which is pointless overhead when it is invoked from low level entry code with interrupts disabled.

Provide a irqsoff() variant, which avoids that.

---
 include/linux/randomize_kstack.h |   19 +++++++++++++++++++

 1 file changed, 19 insertions(+)
include/linux/randomize_kstack.h +0 -0
@@ -77,8 +77,27 @@ static __always_inline u32 get_kstack_of
  	}								\
  } while (0)

include/linux/randomize_kstack.h +18 -0
+/**
+ * add_random_kstack_offset_irqsoff - Increase stack utilization by a random offset.
+ *
+ * This should be used in the syscall entry path after user registers have been
+ * stored to the stack. Interrupts must be still disabled.
+ */
+#define add_random_kstack_offset_irqsoff()					\
+do {										\
+	lockdep_assert_irqs_disabled();						\
+	if (static_branch_maybe(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT,		\
+				&randomize_kstack_offset)) {			\
+		u32 offset = prandom_u32_state(raw_cpu_ptr(&kstack_rnd_state));	\
+		u8 *ptr = __kstack_alloca(KSTACK_OFFSET_MAX(offset));		\
+		/* Keep allocation even after "ptr" loses scope. */		\
+		asm volatile("" :: "r"(ptr) : "memory");			\
+	}									\
+} while (0)
+
Quoted 6 lines

 #else /* CONFIG_RANDOMIZE_KSTACK_OFFSET */
 #define add_random_kstack_offset() do { } while (0)
+#define add_random_kstack_offset_irqsoff() do { } while (0)
 #endif /* CONFIG_RANDOMIZE_KSTACK_OFFSET */

 #endif

#10 lore raw

Re: [patch 02/18] randomize_kstack: Provide add_random_kstack_offset_irqsoff()

In reply to Thomas Gleixner
Quoted 25 lines · Thomas Gleixner

add_random_kstack_offset() uses get/put_cpu_var() which is pointless overhead when it is invoked from low level entry code with interrupts disabled.

Provide a irqsoff() variant, which avoids that.

---
 include/linux/randomize_kstack.h |   19 +++++++++++++++++++
 1 file changed, 19 insertions(+)
include/linux/randomize_kstack.h +7 -0
@@ -77,8 +77,27 @@ static __always_inline u32 get_kstack_of
 	}								\
 } while (0)
 
+/**
+ * add_random_kstack_offset_irqsoff - Increase stack utilization by a random offset.
+ *
+ * This should be used in the syscall entry path after user registers have been
+ * stored to the stack. Interrupts must be still disabled.
+ */
+#define add_random_kstack_offset_irqsoff()					\

include/linux/randomize_kstack.h static __always_inline u32 get_kstack_of · line 96

Quoted 10 lines
include/linux/randomize_kstack.h +10 -0
+do {										\
+	lockdep_assert_irqs_disabled();						\
+	if (static_branch_maybe(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT,		\
+				&randomize_kstack_offset)) {			\
+		u32 offset = prandom_u32_state(raw_cpu_ptr(&kstack_rnd_state));	\
+		u8 *ptr = __kstack_alloca(KSTACK_OFFSET_MAX(offset));		\
+		/* Keep allocation even after "ptr" loses scope. */		\
+		asm volatile("" :: "r"(ptr) : "memory");			\
+	}									\
+} while (0)

Or can we avoid these repetitions and reuse the same code?

Quoted 8 lines
include/linux/randomize_kstack.h +2 -0
+
 #else /* CONFIG_RANDOMIZE_KSTACK_OFFSET */
 #define add_random_kstack_offset()		do { } while (0)
+#define add_random_kstack_offset_irqsoff()	do { } while (0)
 #endif /* CONFIG_RANDOMIZE_KSTACK_OFFSET */
 
 #endif
maintainer Reviewed-by on v1 2/18
#11 lore raw

Re: [patch 02/18] randomize_kstack: Provide add_random_kstack_offset_irqsoff()

In reply to Thomas Gleixner
Quoted 7 lines · Thomas Gleixner

add_random_kstack_offset() uses get/put_cpu_var() which is pointless overhead when it is invoked from low level entry code with interrupts disabled.

Provide a irqsoff() variant, which avoids that.

Seems good. I don't think macro'izing the interior is worth it since both cases are very short, with only the lockdep and raw bits changed.

-Kees

Signature · 1 line
Kees Cook
Reviewed-by on v1 2/18
#12 lore raw

Re: [patch 02/18] randomize_kstack: Provide add_random_kstack_offset_irqsoff()

In reply to Thomas Gleixner
Quoted 33 lines · Thomas Gleixner

add_random_kstack_offset() uses get/put_cpu_var() which is pointless overhead when it is invoked from low level entry code with interrupts disabled.

Provide a irqsoff() variant, which avoids that.

---
 include/linux/randomize_kstack.h |   19 +++++++++++++++++++
 1 file changed, 19 insertions(+)
include/linux/randomize_kstack.h +14 -0
@@ -77,8 +77,27 @@ static __always_inline u32 get_kstack_of
 	}								\
 } while (0)
 
+/**
+ * add_random_kstack_offset_irqsoff - Increase stack utilization by a random offset.
+ *
+ * This should be used in the syscall entry path after user registers have been
+ * stored to the stack. Interrupts must be still disabled.
+ */
+#define add_random_kstack_offset_irqsoff()					\
+do {										\
+	lockdep_assert_irqs_disabled();						\
+	if (static_branch_maybe(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT,		\
+				&randomize_kstack_offset)) {			\
+		u32 offset = prandom_u32_state(raw_cpu_ptr(&kstack_rnd_state));	\
+		u8 *ptr = __kstack_alloca(KSTACK_OFFSET_MAX(offset));		\
+		/* Keep allocation even after "ptr" loses scope. */		\

include/linux/randomize_kstack.h static __always_inline u32 get_kstack_of · line 103

Quoted 10 lines
include/linux/randomize_kstack.h +5 -0
+		asm volatile("" :: "r"(ptr) : "memory");			\
+	}									\
+} while (0)
+
 #else /* CONFIG_RANDOMIZE_KSTACK_OFFSET */
 #define add_random_kstack_offset()		do { } while (0)
+#define add_random_kstack_offset_irqsoff()	do { } while (0)
 #endif /* CONFIG_RANDOMIZE_KSTACK_OFFSET */
 
 #endif

LGTM.

Quoted 5 lines

_______________________________________________
linux-snps-arc mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-snps-arc

#13 lore raw

[tip: core/entry] randomize_kstack: Provide add_random_kstack_offset_irqsoff()

In reply to Thomas Gleixner
The following commit has been merged into the core/entry branch of tip:

The following commit has been merged into the core/entry branch of tip:

Commit-ID:     0b9a3057530cc1c3f87ce2ab9d1278164e81990f
Gitweb:        https://git.kernel.org/tip/0b9a3057530cc1c3f87ce2ab9d1278164e81990f
Author:        Thomas Gleixner <[email protected]>
AuthorDate:    Tue, 07 Jul 2026 21:06:02 +02:00
Committer:     Thomas Gleixner <[email protected]>
CommitterDate: Sun, 12 Jul 2026 12:38:00 +02:00

randomize_kstack: Provide add_random_kstack_offset_irqsoff()

add_random_kstack_offset() uses get/put_cpu_var() which is pointless overhead when it is invoked from low level entry code with interrupts disabled.

Provide a irqsoff() variant, which avoids that.

---
 include/linux/randomize_kstack.h | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)
include/linux/randomize_kstack.h +19 -0
index 024fc20..d8b939f 100644
@@ -77,8 +77,27 @@ static __always_inline u32 get_kstack_offset(void)
 	}								\
 } while (0)
 
+/**
+ * add_random_kstack_offset_irqsoff - Increase stack utilization by a random offset.
+ *
+ * This should be used in the syscall entry path after user registers have been
+ * stored to the stack. Interrupts must be still disabled.
+ */
+#define add_random_kstack_offset_irqsoff()					\
+do {										\
+	lockdep_assert_irqs_disabled();						\
+	if (static_branch_maybe(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT,		\
+				&randomize_kstack_offset)) {			\
+		u32 offset = prandom_u32_state(raw_cpu_ptr(&kstack_rnd_state));	\
+		u8 *ptr = __kstack_alloca(KSTACK_OFFSET_MAX(offset));		\
+		/* Keep allocation even after "ptr" loses scope. */		\
+		asm volatile("" :: "r"(ptr) : "memory");			\
+	}									\
+} while (0)
+
 #else /* CONFIG_RANDOMIZE_KSTACK_OFFSET */
 #define add_random_kstack_offset()		do { } while (0)
+#define add_random_kstack_offset_irqsoff()	do { } while (0)
 #endif /* CONFIG_RANDOMIZE_KSTACK_OFFSET */
 
 #endif
author maintainer
#14 lore raw

PATCH 3/18 entry: Provide [syscall_]enter_from_user_mode_randomize_stack()

In reply to Thomas Gleixner

Randomizing the syscall stack can only happen after state is established via enter_from_user_mode() or syscall_enter_from_user_mode(). The earlier it happens the better.

Provide two new macros to consolidate that:

- enter_from_user_mode_randomize_stack()

	enter_from_user_mode();
	add_random_kstack_offset_irqsoff();

- syscall_enter_from_user_mode_randomize_stack()

	enter_from_user_mode_randomize_stack();
	syscall_enter_from_user_mode_work();

to reduce boiler plate code.

Those are macros and not inline functions as the latter would limit the stack randomization scope to the inline function itself.

---
 include/linux/entry-common.h |   56 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 56 insertions(+)
include/linux/entry-common.h +56 -0
@@ -6,6 +6,7 @@
 #include <linux/irq-entry-common.h>
 #include <linux/livepatch.h>
 #include <linux/ptrace.h>
+#include <linux/randomize_kstack.h>
 #include <linux/resume_user_mode.h>
 #include <linux/seccomp.h>
 #include <linux/sched.h>
@@ -150,6 +151,61 @@ static __always_inline long syscall_ente
 }
 
 /**
+ * enter_from_user_mode_randomize_stack - Establish state and add stack randomization
+ *					  before invoking syscall_enter_from_user_mode_work()
+ * @regs:	Pointer to currents pt_regs
+ *
+ * Invoked from architecture specific syscall entry code with interrupts
+ * disabled. The calling code has to be non-instrumentable. When the function
+ * returns all state is correct, interrupts are still disabled and the
+ * subsequent functions can be instrumented.
+ *
+ * Implemented as a macro so that the stack randomization is effective
+ * throughout the function in which it is invoked. An inline would only make it
+ * effective in the scope of the inline function.
+ */
+#define enter_from_user_mode_randomize_stack(regs)			\
+do {									\
+	enter_from_user_mode(regs);					\
+	instrumentation_begin();					\
+	add_random_kstack_offset_irqsoff();				\
+	instrumentation_end();						\
+} while (0)
+
+/**
+ * syscall_enter_from_user_mode_randomize_stack - Establish state and check and handle work
+ *						  before invoking a syscall
+ * @regs:	Pointer to currents pt_regs
+ * @syscall:	The syscall number
+ *
+ * Invoked from architecture specific syscall entry code with interrupts
+ * disabled. The calling code has to be non-instrumentable. When the
+ * function returns all state is correct, interrupts are enabled and the
+ * subsequent functions can be instrumented.
+ *
+ * This is the combination of enter_from_user_mode_randomize_stack() and
+ * syscall_enter_from_user_mode_work() to be used when there is no
+ * architecture specific work to be done between the two.
+ *
+ * Returns: The original or a modified syscall number. See
+ * syscall_enter_from_user_mode_work() for further explanation.
+ *
+ * Implemented as a macro to make stack randomization effective in the calling
+ * scope.
+ */
+#define syscall_enter_from_user_mode_randomize_stack(regs, syscall)	\
+({									\
+	enter_from_user_mode_randomize_stack(regs);			\
+									\
+	instrumentation_begin();					\
+	local_irq_enable();						\
+	long _ret = syscall_enter_from_user_mode_work(regs, syscall);	\
+	instrumentation_end();						\
+									\
+	_ret;								\
+})
+
+/**
  * syscall_enter_from_user_mode - Establish state and check and handle work
  *				  before invoking a syscall
  * @regs:	Pointer to currents pt_regs
Reviewed-by on v1 3/18
#15 lore raw

Re: [patch 03/18] entry: Provide [syscall_]enter_from_user_mode_randomize_stack()

Quoted 36 lines · Thomas Gleixner

Randomizing the syscall stack can only happen after state is established via enter_from_user_mode() or syscall_enter_from_user_mode(). The earlier it happens the better.

Provide two new macros to consolidate that:

  - enter_from_user_mode_randomize_stack()

	enter_from_user_mode();
	add_random_kstack_offset_irqsoff();

  - syscall_enter_from_user_mode_randomize_stack()

	enter_from_user_mode_randomize_stack();
	syscall_enter_from_user_mode_work();


to reduce boiler plate code.

Those are macros and not inline functions as the latter would limit the stack randomization scope to the inline function itself.

---
 include/linux/entry-common.h |   56 +++++++++++++++++++++++++++++++++++++++++++

 1 file changed, 56 insertions(+)
include/linux/entry-common.h +1 -0
@@ -6,6 +6,7 @@
  #include <linux/irq-entry-common.h>
  #include <linux/livepatch.h>
  #include <linux/ptrace.h>
+#include <linux/randomize_kstack.h>
  #include <linux/resume_user_mode.h>
  #include <linux/seccomp.h>
  #include <linux/sched.h>
@@ -150,6 +151,61 @@ static __always_inline long syscall_ente
  }
Quoted 5 lines


 /**
+ * enter_from_user_mode_randomize_stack - Establish state and add stack randomization
+ *   before invoking syscall_enter_from_user_mode_work()
+ * @regs: Pointer to currents pt_regs

                           ^^^^^^^^

Nit: current

Quoted 12 lines

+ *
+ * Invoked from architecture specific syscall entry code with interrupts
+ * disabled. The calling code has to be non-instrumentable. When the function
+ * returns all state is correct, interrupts are still disabled and the
+ * subsequent functions can be instrumented.
+ *
+ * Implemented as a macro so that the stack randomization is effective
+ * throughout the function in which it is invoked. An inline would only make it
+ * effective in the scope of the inline function.
+ */

include/linux/entry-common.h +2 -0
+#define enter_from_user_mode_randomize_stack(regs)			\
+do {									\

include/linux/entry-common.h static __always_inline long syscall_ente · line 178

Quoted 10 lines
include/linux/entry-common.h +10 -0
+	enter_from_user_mode(regs);					\
+	instrumentation_begin();					\
+	add_random_kstack_offset_irqsoff();				\
+	instrumentation_end();						\
+} while (0)
+
+/**
+ * syscall_enter_from_user_mode_randomize_stack - Establish state and check and handle work
+ *						  before invoking a syscall
+ * @regs:	Pointer to currents pt_regs
                           ^^^^^^^^

Same here.

Quoted 30 lines

+ * @syscall: The syscall number
+ *
+ * Invoked from architecture specific syscall entry code with interrupts
+ * disabled. The calling code has to be non-instrumentable. When the
+ * function returns all state is correct, interrupts are enabled and the
+ * subsequent functions can be instrumented.
+ *
+ * This is the combination of enter_from_user_mode_randomize_stack() and
+ * syscall_enter_from_user_mode_work() to be used when there is no
+ * architecture specific work to be done between the two.
+ *
+ * Returns: The original or a modified syscall number. See
+ * syscall_enter_from_user_mode_work() for further explanation.
+ *
+ * Implemented as a macro to make stack randomization effective in the calling
+ * scope.
+ */

include/linux/entry-common.h +13 -0
+#define syscall_enter_from_user_mode_randomize_stack(regs, syscall)	\
+({									\
+	enter_from_user_mode_randomize_stack(regs);			\
+									\
+	instrumentation_begin();					\
+	local_irq_enable();						\
+	long _ret = syscall_enter_from_user_mode_work(regs, syscall);	\
+	instrumentation_end();						\
+									\
+	_ret;								\
+})
+
+/**
Quoted 3 lines

  * syscall_enter_from_user_mode - Establish state and check and handle work
  *   before invoking a syscall
  * @regs: Pointer to currents pt_regs

With the above nits,

Reviewed-by on v1 3/18
#16 lore raw

Re: [patch 03/18] entry: Provide [syscall_]enter_from_user_mode_randomize_stack()

In reply to Thomas Gleixner
Quoted 81 lines · Thomas Gleixner

Randomizing the syscall stack can only happen after state is established via enter_from_user_mode() or syscall_enter_from_user_mode(). The earlier it happens the better.

Provide two new macros to consolidate that:

- enter_from_user_mode_randomize_stack()

	enter_from_user_mode();
	add_random_kstack_offset_irqsoff();

- syscall_enter_from_user_mode_randomize_stack()

	enter_from_user_mode_randomize_stack();
	syscall_enter_from_user_mode_work();

to reduce boiler plate code.

Those are macros and not inline functions as the latter would limit the stack randomization scope to the inline function itself.

---
 include/linux/entry-common.h |   56 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 56 insertions(+)
include/linux/entry-common.h +44 -0
@@ -6,6 +6,7 @@
 #include <linux/irq-entry-common.h>
 #include <linux/livepatch.h>
 #include <linux/ptrace.h>
+#include <linux/randomize_kstack.h>
 #include <linux/resume_user_mode.h>
 #include <linux/seccomp.h>
 #include <linux/sched.h>
@@ -150,6 +151,61 @@ static __always_inline long syscall_ente
 }
 
 /**
+ * enter_from_user_mode_randomize_stack - Establish state and add stack randomization
+ *					  before invoking syscall_enter_from_user_mode_work()
+ * @regs:	Pointer to currents pt_regs
+ *
+ * Invoked from architecture specific syscall entry code with interrupts
+ * disabled. The calling code has to be non-instrumentable. When the function
+ * returns all state is correct, interrupts are still disabled and the
+ * subsequent functions can be instrumented.
+ *
+ * Implemented as a macro so that the stack randomization is effective
+ * throughout the function in which it is invoked. An inline would only make it
+ * effective in the scope of the inline function.
+ */
+#define enter_from_user_mode_randomize_stack(regs)			\
+do {									\
+	enter_from_user_mode(regs);					\
+	instrumentation_begin();					\
+	add_random_kstack_offset_irqsoff();				\
+	instrumentation_end();						\
+} while (0)
+
+/**
+ * syscall_enter_from_user_mode_randomize_stack - Establish state and check and handle work
+ *						  before invoking a syscall
+ * @regs:	Pointer to currents pt_regs
+ * @syscall:	The syscall number
+ *
+ * Invoked from architecture specific syscall entry code with interrupts
+ * disabled. The calling code has to be non-instrumentable. When the
+ * function returns all state is correct, interrupts are enabled and the
+ * subsequent functions can be instrumented.
+ *
+ * This is the combination of enter_from_user_mode_randomize_stack() and
+ * syscall_enter_from_user_mode_work() to be used when there is no
+ * architecture specific work to be done between the two.
+ *
+ * Returns: The original or a modified syscall number. See
+ * syscall_enter_from_user_mode_work() for further explanation.
+ *
+ * Implemented as a macro to make stack randomization effective in the calling
+ * scope.
+ */
+#define syscall_enter_from_user_mode_randomize_stack(regs, syscall)	\

include/linux/entry-common.h static __always_inline long syscall_ente · line 206

Quoted 10 lines
include/linux/entry-common.h +10 -0
+({									\
+	enter_from_user_mode_randomize_stack(regs);			\
+									\
+	instrumentation_begin();					\
+	local_irq_enable();						\
+	long _ret = syscall_enter_from_user_mode_work(regs, syscall);	\
+	instrumentation_end();						\
+									\
+	_ret;								\
+})
Quoted 6 lines
include/linux/entry-common.h +2 -0
+
+/**
  * syscall_enter_from_user_mode - Establish state and check and handle work
  *				  before invoking a syscall
  * @regs:	Pointer to currents pt_regs
#17 lore raw

Re: [patch 03/18] entry: Provide [syscall_]enter_from_user_mode_randomize_stack()

In reply to Thomas Gleixner
Quoted 48 lines · Thomas Gleixner

Randomizing the syscall stack can only happen after state is established via enter_from_user_mode() or syscall_enter_from_user_mode(). The earlier it happens the better.

Provide two new macros to consolidate that:

- enter_from_user_mode_randomize_stack()

	enter_from_user_mode();
	add_random_kstack_offset_irqsoff();

- syscall_enter_from_user_mode_randomize_stack()

	enter_from_user_mode_randomize_stack();
	syscall_enter_from_user_mode_work();

to reduce boiler plate code.

Those are macros and not inline functions as the latter would limit the stack randomization scope to the inline function itself.

---
 include/linux/entry-common.h |   56 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 56 insertions(+)
include/linux/entry-common.h +11 -0
@@ -6,6 +6,7 @@
 #include <linux/irq-entry-common.h>
 #include <linux/livepatch.h>
 #include <linux/ptrace.h>
+#include <linux/randomize_kstack.h>
 #include <linux/resume_user_mode.h>
 #include <linux/seccomp.h>
 #include <linux/sched.h>
@@ -150,6 +151,61 @@ static __always_inline long syscall_ente
 }
 
 /**
+ * enter_from_user_mode_randomize_stack - Establish state and add stack randomization
+ *					  before invoking syscall_enter_from_user_mode_work()
+ * @regs:	Pointer to currents pt_regs
+ *
+ * Invoked from architecture specific syscall entry code with interrupts
+ * disabled. The calling code has to be non-instrumentable. When the function
+ * returns all state is correct, interrupts are still disabled and the
+ * subsequent functions can be instrumented.
+ *
+ * Implemented as a macro so that the stack randomization is effective

include/linux/entry-common.h static __always_inline long syscall_ente · line 173

Quoted 10 lines
include/linux/entry-common.h +10 -0
+ * throughout the function in which it is invoked. An inline would only make it
+ * effective in the scope of the inline function.
+ */
+#define enter_from_user_mode_randomize_stack(regs)			\
+do {									\
+	enter_from_user_mode(regs);					\
+	instrumentation_begin();					\
+	add_random_kstack_offset_irqsoff();				\
+	instrumentation_end();						\
+} while (0)

Perhaps this new function can also be reused when the ARM64 is switched to the generic entry as the irq also disabled now.

arch/arm64/kernel/entry-common.c +0 -0
@@ -64,7 +64,7 @@ static void noinstr arm64_exit_to_kernel_mode(struct

pt_regs *regs,

static __always_inline void arm64_syscall_enter_from_user_mode(struct
pt_regs *regs)
{
- enter_from_user_mode(regs);

+       enter_from_user_mode_randomize_stack(regs);
        mte_disable_tco_entry(current);
        sme_enter_from_user_mode();

}

arch/arm64/kernel/syscall.c +0 -1
index e0a98fac3b85..42ac02573b66 100644
@@ -6,7 +6,6 @@
 #include <linux/errno.h>
 #include <linux/nospec.h>
 #include <linux/ptrace.h>
-#include <linux/randomize_kstack.h>
 #include <linux/syscalls.h>
 
 #include <asm/debug-monitors.h>
@@ -42,8 +41,6 @@ static void invoke_syscall(struct pt_regs *regs,

unsigned int scno,

 {
        long ret;

- add_random_kstack_offset();
-

        if (likely(scno < sc_nr)) {
                syscall_fn_t syscall_fn;
                syscall_fn = syscall_table[array_index_nospec(scno, sc_nr)];
Quoted 39 lines
include/linux/entry-common.h +35 -0
+
+/**
+ * syscall_enter_from_user_mode_randomize_stack - Establish state and check and handle work
+ *						  before invoking a syscall
+ * @regs:	Pointer to currents pt_regs
+ * @syscall:	The syscall number
+ *
+ * Invoked from architecture specific syscall entry code with interrupts
+ * disabled. The calling code has to be non-instrumentable. When the
+ * function returns all state is correct, interrupts are enabled and the
+ * subsequent functions can be instrumented.
+ *
+ * This is the combination of enter_from_user_mode_randomize_stack() and
+ * syscall_enter_from_user_mode_work() to be used when there is no
+ * architecture specific work to be done between the two.
+ *
+ * Returns: The original or a modified syscall number. See
+ * syscall_enter_from_user_mode_work() for further explanation.
+ *
+ * Implemented as a macro to make stack randomization effective in the calling
+ * scope.
+ */
+#define syscall_enter_from_user_mode_randomize_stack(regs, syscall)	\
+({									\
+	enter_from_user_mode_randomize_stack(regs);			\
+									\
+	instrumentation_begin();					\
+	local_irq_enable();						\
+	long _ret = syscall_enter_from_user_mode_work(regs, syscall);	\
+	instrumentation_end();						\
+									\
+	_ret;								\
+})
+
+/**
  * syscall_enter_from_user_mode - Establish state and check and handle work
  *				  before invoking a syscall
  * @regs:	Pointer to currents pt_regs
Reviewed-by on v1 3/18
#18 lore raw

Re: [patch 03/18] entry: Provide [syscall_]enter_from_user_mode_randomize_stack()

In reply to Thomas Gleixner
Quoted 16 lines · Thomas Gleixner

Randomizing the syscall stack can only happen after state is established via enter_from_user_mode() or syscall_enter_from_user_mode(). The earlier it happens the better.

Provide two new macros to consolidate that:

   - enter_from_user_mode_randomize_stack()
	enter_from_user_mode();
	add_random_kstack_offset_irqsoff();

   - syscall_enter_from_user_mode_randomize_stack()
	enter_from_user_mode_randomize_stack();
	syscall_enter_from_user_mode_work();

to reduce boiler plate code.

Quoted 7 lines

Those are macros and not inline functions as the latter would limit the stack randomization scope to the inline function itself.

---
  include/linux/entry-common.h |   56 +++++++++++++++++++++++++++++++++++++++++++
  1 file changed, 56 insertions(+)
Reviewed-by on v1 3/18
#19 lore raw

Re: [patch 03/18] entry: Provide [syscall_]enter_from_user_mode_randomize_stack()

In reply to Thomas Gleixner
Quoted 87 lines · Thomas Gleixner

Randomizing the syscall stack can only happen after state is established via enter_from_user_mode() or syscall_enter_from_user_mode(). The earlier it happens the better.

Provide two new macros to consolidate that:

- enter_from_user_mode_randomize_stack()

	enter_from_user_mode();
	add_random_kstack_offset_irqsoff();

- syscall_enter_from_user_mode_randomize_stack()

	enter_from_user_mode_randomize_stack();
	syscall_enter_from_user_mode_work();

to reduce boiler plate code.

Those are macros and not inline functions as the latter would limit the stack randomization scope to the inline function itself.

---
 include/linux/entry-common.h |   56 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 56 insertions(+)
include/linux/entry-common.h +49 -0
@@ -6,6 +6,7 @@
 #include <linux/irq-entry-common.h>
 #include <linux/livepatch.h>
 #include <linux/ptrace.h>
+#include <linux/randomize_kstack.h>
 #include <linux/resume_user_mode.h>
 #include <linux/seccomp.h>
 #include <linux/sched.h>
@@ -150,6 +151,61 @@ static __always_inline long syscall_ente
 }
 
 /**
+ * enter_from_user_mode_randomize_stack - Establish state and add stack randomization
+ *					  before invoking syscall_enter_from_user_mode_work()
+ * @regs:	Pointer to currents pt_regs
+ *
+ * Invoked from architecture specific syscall entry code with interrupts
+ * disabled. The calling code has to be non-instrumentable. When the function
+ * returns all state is correct, interrupts are still disabled and the
+ * subsequent functions can be instrumented.
+ *
+ * Implemented as a macro so that the stack randomization is effective
+ * throughout the function in which it is invoked. An inline would only make it
+ * effective in the scope of the inline function.
+ */
+#define enter_from_user_mode_randomize_stack(regs)			\
+do {									\
+	enter_from_user_mode(regs);					\
+	instrumentation_begin();					\
+	add_random_kstack_offset_irqsoff();				\
+	instrumentation_end();						\
+} while (0)
+
+/**
+ * syscall_enter_from_user_mode_randomize_stack - Establish state and check and handle work
+ *						  before invoking a syscall
+ * @regs:	Pointer to currents pt_regs
+ * @syscall:	The syscall number
+ *
+ * Invoked from architecture specific syscall entry code with interrupts
+ * disabled. The calling code has to be non-instrumentable. When the
+ * function returns all state is correct, interrupts are enabled and the
+ * subsequent functions can be instrumented.
+ *
+ * This is the combination of enter_from_user_mode_randomize_stack() and
+ * syscall_enter_from_user_mode_work() to be used when there is no
+ * architecture specific work to be done between the two.
+ *
+ * Returns: The original or a modified syscall number. See
+ * syscall_enter_from_user_mode_work() for further explanation.
+ *
+ * Implemented as a macro to make stack randomization effective in the calling
+ * scope.
+ */
+#define syscall_enter_from_user_mode_randomize_stack(regs, syscall)	\
+({									\
+	enter_from_user_mode_randomize_stack(regs);			\
+									\
+	instrumentation_begin();					\
+	local_irq_enable();						\

include/linux/entry-common.h static __always_inline long syscall_ente · line 211

Quoted 10 lines
include/linux/entry-common.h +7 -0
+	long _ret = syscall_enter_from_user_mode_work(regs, syscall);	\
+	instrumentation_end();						\
+									\
+	_ret;								\
+})
+
+/**
  * syscall_enter_from_user_mode - Establish state and check and handle work
  *				  before invoking a syscall
  * @regs:	Pointer to currents pt_regs
Quoted 5 lines

_______________________________________________
linux-snps-arc mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-snps-arc

#20 lore raw

[tip: core/entry] entry: Provide [syscall_]enter_from_user_mode_randomize_stack()

In reply to Thomas Gleixner
The following commit has been merged into the core/entry branch of tip:

The following commit has been merged into the core/entry branch of tip:

Commit-ID:     855c103f86275a55eba115cabb86eb84f8236933
Gitweb:        https://git.kernel.org/tip/855c103f86275a55eba115cabb86eb84f8236933
Author:        Thomas Gleixner <[email protected]>
AuthorDate:    Tue, 07 Jul 2026 21:06:07 +02:00
Committer:     Thomas Gleixner <[email protected]>
CommitterDate: Sun, 12 Jul 2026 12:38:01 +02:00

entry: Provide [syscall_]enter_from_user_mode_randomize_stack()

Randomizing the syscall stack can only happen after state is established via enter_from_user_mode() or syscall_enter_from_user_mode(). The earlier it happens the better.

Provide two new macros to consolidate that:

- enter_from_user_mode_randomize_stack()

	enter_from_user_mode();
	add_random_kstack_offset_irqsoff();

- syscall_enter_from_user_mode_randomize_stack()

	enter_from_user_mode_randomize_stack();
	syscall_enter_from_user_mode_work();

to reduce boiler plate code.

Those are macros and not inline functions as the latter would limit the stack randomization scope to the inline function itself.

---
 include/linux/entry-common.h | 56 +++++++++++++++++++++++++++++++++++-
 1 file changed, 56 insertions(+)
include/linux/entry-common.h +56 -0
index 9336516..166b1ed 100644
@@ -6,6 +6,7 @@
 #include <linux/irq-entry-common.h>
 #include <linux/livepatch.h>
 #include <linux/ptrace.h>
+#include <linux/randomize_kstack.h>
 #include <linux/resume_user_mode.h>
 #include <linux/seccomp.h>
 #include <linux/sched.h>
@@ -150,6 +151,61 @@ static __always_inline long syscall_enter_from_user_mode_work(struct pt_regs *re
 }
 
 /**
+ * enter_from_user_mode_randomize_stack - Establish state and add stack randomization
+ *					  before invoking syscall_enter_from_user_mode_work()
+ * @regs:	Pointer to currents pt_regs
+ *
+ * Invoked from architecture specific syscall entry code with interrupts
+ * disabled. The calling code has to be non-instrumentable. When the function
+ * returns all state is correct, interrupts are still disabled and the
+ * subsequent functions can be instrumented.
+ *
+ * Implemented as a macro so that the stack randomization is effective
+ * throughout the function in which it is invoked. An inline would only make it
+ * effective in the scope of the inline function.
+ */
+#define enter_from_user_mode_randomize_stack(regs)			\
+do {									\
+	enter_from_user_mode(regs);					\
+	instrumentation_begin();					\
+	add_random_kstack_offset_irqsoff();				\
+	instrumentation_end();						\
+} while (0)
+
+/**
+ * syscall_enter_from_user_mode_randomize_stack - Establish state and check and handle work
+ *						  before invoking a syscall
+ * @regs:	Pointer to currents pt_regs
+ * @syscall:	The syscall number
+ *
+ * Invoked from architecture specific syscall entry code with interrupts
+ * disabled. The calling code has to be non-instrumentable. When the
+ * function returns all state is correct, interrupts are enabled and the
+ * subsequent functions can be instrumented.
+ *
+ * This is the combination of enter_from_user_mode_randomize_stack() and
+ * syscall_enter_from_user_mode_work() to be used when there is no
+ * architecture specific work to be done between the two.
+ *
+ * Returns: The original or a modified syscall number. See
+ * syscall_enter_from_user_mode_work() for further explanation.
+ *
+ * Implemented as a macro to make stack randomization effective in the calling
+ * scope.
+ */
+#define syscall_enter_from_user_mode_randomize_stack(regs, syscall)	\
+({									\
+	enter_from_user_mode_randomize_stack(regs);			\
+									\
+	instrumentation_begin();					\
+	local_irq_enable();						\
+	long _ret = syscall_enter_from_user_mode_work(regs, syscall);	\
+	instrumentation_end();						\
+									\
+	_ret;								\
+})
+
+/**
  * syscall_enter_from_user_mode - Establish state and check and handle work
  *				  before invoking a syscall
  * @regs:	Pointer to currents pt_regs
#21 lore raw

Re: [patch 03/18] entry: Provide [syscall_]enter_from_user_mode_randomize_stack()

In reply to Thomas Gleixner
Quoted 10 lines · Thomas Gleixner

Randomizing the syscall stack can only happen after state is established via enter_from_user_mode() or syscall_enter_from_user_mode(). The earlier it happens the better.

Provide two new macros to consolidate that:

- enter_from_user_mode_randomize_stack()

	enter_from_user_mode();
	add_random_kstack_offset_irqsoff();
Quoted 9 lines

- syscall_enter_from_user_mode_randomize_stack()

	enter_from_user_mode_randomize_stack();
	syscall_enter_from_user_mode_work();

to reduce boiler plate code.

Those are macros and not inline functions as the latter would limit the stack randomization scope to the inline function itself.

Not directly related to this patchset, but still:

Can anyone *please* find out what the actual security requirements are for the syscall randomization offset?

The original checkin, 39218ff4c625 ("stack: Optionally randomize kernel stack offset each syscall") indicates that it is fundamental that the stack offset is applied *after* pt_regs pushing, but that isn't documented anywhere in the kernel sources as far as I can tell.

However, I have also come to understand that there are further, undocumented constraints; at least at one point I was told that "the offset should not be stored in memory while running in the kernel", which seems more than a bit odd.

This matters, because it creates a data dependency on exit. The original checkin does call out that RDTSC timing is inappropriate if the user could control it, but using a hardware CSPRNG like RDRAND (or its equivalent for other architectures) would be feasible if it isn't in the critical path. If an RDRAND - store sequence can be executed on entry, *after* the stack adjustment, then the high latency of RDRAND can hopefully be very effectively hidden by an OO CPU.

Incidentally, in case you are wondering "why doesn't each core get a dedicated CSPRNG and hardware randomness generator, to avoid high latency", the answer is pretty simple: a hardware random number source, regardless of the specifics of the design, almost by definition violates the hardware design rules of any digital design; after all, the design rules are designed to *eliminate* noise (making the circuit behave as closely as physically possible to a realization of the abstract digital circuit), whereas the very goal of a HWRNG source is to *extract and amplify* quantum thermal noise. This means that considerable chip area is consumed by a "keep-out zone", a designated "no man's land" keeping the digital logic away from the noise source. This keep-out zone is typically much, much larger than the noise source itself.

-hpa

author maintainer
#22 lore raw

Re: [patch 03/18] entry: Provide [syscall_]enter_from_user_mode_randomize_stack()

Quoted 11 lines · H. Peter Anvin

Can anyone *please* find out what the actual security requirements are for the syscall randomization offset?

The original checkin, 39218ff4c625 ("stack: Optionally randomize kernel stack offset each syscall") indicates that it is fundamental that the stack offset is applied *after* pt_regs pushing, but that isn't documented anywhere in the kernel sources as far as I can tell.

However, I have also come to understand that there are further, undocumented constraints; at least at one point I was told that "the offset should not be stored in memory while running in the kernel", which seems more than a bit odd.

This thread has the initial discussions about it with more explanations:

https://lore.kernel.org/kernel-hardening/2236FBA76BA1254E88B949DDB74E612BA4BC57C1@IRSMSX102.ger.corp.intel.com/

Thanks,

tglx

author maintainer
#23 lore raw

PATCH 4/18 loongarch/syscall: Use syscall_enter_from_user_mode_randomize_stack()

In reply to Thomas Gleixner

syscall_enter_from_user_mode_randomize_stack() replaces syscall_enter_from_user_mode() and the subsequent invocation of add_random_kstack_offset().

The advantage is that it applies the stack randomization right after enter_from_user_mode() and thereby avoids the overhead of get/put_cpu_var() as that code is invoked with interrupts disabled.

No functional change.

---
 arch/loongarch/kernel/syscall.c |    5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)
arch/loongarch/kernel/syscall.c +1 -4
@@ -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>
 
@@ -70,9 +69,7 @@ void noinstr __no_stack_protector do_sys
 	regs->orig_a0 = regs->regs[4];
 	regs->regs[4] = -ENOSYS;
 
-	nr = syscall_enter_from_user_mode(regs, nr);
-
-	add_random_kstack_offset();
+	nr = syscall_enter_from_user_mode_randomize_stack(regs, nr);
 
 	if (nr < NR_syscalls) {
 		syscall_fn = sys_call_table[array_index_nospec(nr, NR_syscalls)];
Reviewed-by on v1 4/18
#24 lore raw

Re: [patch 04/18] loongarch/syscall: Use syscall_enter_from_user_mode_randomize_stack()

Quoted 35 lines · Thomas Gleixner

syscall_enter_from_user_mode_randomize_stack() replaces syscall_enter_from_user_mode() and the subsequent invocation of add_random_kstack_offset().

The advantage is that it applies the stack randomization right after enter_from_user_mode() and thereby avoids the overhead of get/put_cpu_var() as that code is invoked with interrupts disabled.

No functional change.

---
 arch/loongarch/kernel/syscall.c |    5 +----

 1 file changed, 1 insertion(+), 4 deletions(-)
arch/loongarch/kernel/syscall.c +0 -1
@@ -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>

arch/loongarch/kernel/syscall.c +0 -0
@@ -70,9 +69,7 @@ void noinstr __no_stack_protector do_sys
  	regs->orig_a0 = regs->regs[4];
  	regs->regs[4] = -ENOSYS;

arch/loongarch/kernel/syscall.c +1 -3
-	nr = syscall_enter_from_user_mode(regs, nr);
-
-	add_random_kstack_offset();
+	nr = syscall_enter_from_user_mode_randomize_stack(regs, nr);
Quoted 3 lines


  if (nr < NR_syscalls) {
  syscall_fn = sys_call_table[array_index_nospec(nr, NR_syscalls)];

Reviewed-by on v1 4/18
#25 lore raw

Re: [patch 04/18] loongarch/syscall: Use syscall_enter_from_user_mode_randomize_stack()

In reply to Thomas Gleixner
Quoted 28 lines · Thomas Gleixner

syscall_enter_from_user_mode_randomize_stack() replaces syscall_enter_from_user_mode() and the subsequent invocation of add_random_kstack_offset().

The advantage is that it applies the stack randomization right after enter_from_user_mode() and thereby avoids the overhead of get/put_cpu_var() as that code is invoked with interrupts disabled.

No functional change.

---
 arch/loongarch/kernel/syscall.c |    5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)
arch/loongarch/kernel/syscall.c +0 -1
@@ -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>
 

arch/loongarch/kernel/syscall.c void noinstr __no_stack_protector do_sys · line 72

Quoted 7 lines
arch/loongarch/kernel/syscall.c +1 -3
@@ -70,9 +69,7 @@ void noinstr __no_stack_protector do_sys
 	regs->orig_a0 = regs->regs[4];
 	regs->regs[4] = -ENOSYS;
 
-	nr = syscall_enter_from_user_mode(regs, nr);
-
-	add_random_kstack_offset();
+	nr = syscall_enter_from_user_mode_randomize_stack(regs, nr);
Quoted 4 lines
arch/loongarch/kernel/syscall.c +0 -0
 	if (nr < NR_syscalls) {
 		syscall_fn = sys_call_table[array_index_nospec(nr, NR_syscalls)];
 
Reviewed-by on v1 4/18
#26 lore raw

Re: [patch 04/18] loongarch/syscall: Use syscall_enter_from_user_mode_randomize_stack()

In reply to Thomas Gleixner
Quoted 8 lines · Thomas Gleixner

syscall_enter_from_user_mode_randomize_stack() replaces syscall_enter_from_user_mode() and the subsequent invocation of add_random_kstack_offset().

The advantage is that it applies the stack randomization right after enter_from_user_mode() and thereby avoids the overhead of get/put_cpu_var() as that code is invoked with interrupts disabled.

Quoted 8 lines

No functional change.

---
  arch/loongarch/kernel/syscall.c |    5 +----
  1 file changed, 1 insertion(+), 4 deletions(-)
Reviewed-by on v1 4/18
#27 lore raw

Re: [patch 04/18] loongarch/syscall: Use syscall_enter_from_user_mode_randomize_stack()

In reply to Thomas Gleixner
Quoted 30 lines · Thomas Gleixner

syscall_enter_from_user_mode_randomize_stack() replaces syscall_enter_from_user_mode() and the subsequent invocation of add_random_kstack_offset().

The advantage is that it applies the stack randomization right after enter_from_user_mode() and thereby avoids the overhead of get/put_cpu_var() as that code is invoked with interrupts disabled.

No functional change.

---
 arch/loongarch/kernel/syscall.c |    5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)
arch/loongarch/kernel/syscall.c +0 -1
@@ -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>
 

arch/loongarch/kernel/syscall.c void noinstr __no_stack_protector do_sys · line 75

Quoted 10 lines
arch/loongarch/kernel/syscall.c +1 -3
@@ -70,9 +69,7 @@ void noinstr __no_stack_protector do_sys
 	regs->orig_a0 = regs->regs[4];
 	regs->regs[4] = -ENOSYS;
 
-	nr = syscall_enter_from_user_mode(regs, nr);
-
-	add_random_kstack_offset();
+	nr = syscall_enter_from_user_mode_randomize_stack(regs, nr);
 
 	if (nr < NR_syscalls) {
 		syscall_fn = sys_call_table[array_index_nospec(nr, NR_syscalls)];
Quoted 4 lines

_______________________________________________
linux-snps-arc mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-snps-arc

#28 lore raw

[tip: core/entry] loongarch/syscall: Use syscall_enter_from_user_mode_randomize_stack()

In reply to Thomas Gleixner
The following commit has been merged into the core/entry branch of tip:

The following commit has been merged into the core/entry branch of tip:

Commit-ID:     7892c5a22a4e11d1ed3590c04ff73f047c0ce453
Gitweb:        https://git.kernel.org/tip/7892c5a22a4e11d1ed3590c04ff73f047c0ce453
Author:        Thomas Gleixner <[email protected]>
AuthorDate:    Tue, 07 Jul 2026 21:06:11 +02:00
Committer:     Thomas Gleixner <[email protected]>
CommitterDate: Sun, 12 Jul 2026 12:38:01 +02:00

loongarch/syscall: Use syscall_enter_from_user_mode_randomize_stack()

syscall_enter_from_user_mode_randomize_stack() replaces syscall_enter_from_user_mode() and the subsequent invocation of add_random_kstack_offset().

The advantage is that it applies the stack randomization right after enter_from_user_mode() and thereby avoids the overhead of get/put_cpu_var() as that code is invoked with interrupts disabled.

No functional change.

---
 arch/loongarch/kernel/syscall.c | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)
arch/loongarch/kernel/syscall.c +1 -4
index 94c1c3b..142a9c2 100644
@@ -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>
 
@@ -70,9 +69,7 @@ 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();
+	nr = syscall_enter_from_user_mode_randomize_stack(regs, nr);
 
 	if (nr < NR_syscalls) {
 		syscall_fn = sys_call_table[array_index_nospec(nr, NR_syscalls)];
author maintainer
#29 lore raw

PATCH 5/18 powerpc/syscall: Use syscall_enter_from_user_mode_randomize_stack()

In reply to Thomas Gleixner

syscall_enter_from_user_mode_randomize_stack() replaces syscall_enter_from_user_mode() and the subsequent invocation of add_random_kstack_offset().

The advantage is that it applies the stack randomization right after enter_from_user_mode() and thereby avoids the overhead of get/put_cpu_var() as that code is invoked with interrupts disabled.

No functional change.

Cc Michael Ellerman <[email protected]>
Cc Shrikanth Hegde <[email protected]>
---
 arch/powerpc/kernel/syscall.c |    4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)
arch/powerpc/kernel/syscall.c +1 -3
@@ -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,7 @@ notrace long system_call_exception(struc
 	long ret;
 	syscall_fn f;
 
-	r0 = syscall_enter_from_user_mode(regs, r0);
-	add_random_kstack_offset();
+	r0 = syscall_enter_from_user_mode_randomize_stack(regs, r0);
 
 	if (unlikely(r0 >= NR_syscalls)) {
 		if (unlikely(trap_is_unsupported_scv(regs))) {
Reviewed-by on v1 5/18
#30 lore raw

Re: [patch 05/18] powerpc/syscall: Use syscall_enter_from_user_mode_randomize_stack()

Quoted 35 lines · Thomas Gleixner

syscall_enter_from_user_mode_randomize_stack() replaces syscall_enter_from_user_mode() and the subsequent invocation of add_random_kstack_offset().

The advantage is that it applies the stack randomization right after enter_from_user_mode() and thereby avoids the overhead of get/put_cpu_var() as that code is invoked with interrupts disabled.

No functional change.

Cc Michael Ellerman <[email protected]>
Cc Shrikanth Hegde <[email protected]>

---
 arch/powerpc/kernel/syscall.c |    4 +---

 1 file changed, 1 insertion(+), 3 deletions(-)
arch/powerpc/kernel/syscall.c +0 -0
@@ -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>

arch/powerpc/kernel/syscall.c +0 -0
@@ -19,8 +18,7 @@ notrace long system_call_exception(struc
  	long ret;
  	syscall_fn f;

arch/powerpc/kernel/syscall.c +1 -2
-	r0 = syscall_enter_from_user_mode(regs, r0);
-	add_random_kstack_offset();
+	r0 = syscall_enter_from_user_mode_randomize_stack(regs, r0);
Quoted 3 lines


  if (unlikely(r0 >= NR_syscalls)) {
  if (unlikely(trap_is_unsupported_scv(regs))) {

Reviewed-by on v1 5/18
#31 lore raw

Re: [patch 05/18] powerpc/syscall: Use syscall_enter_from_user_mode_randomize_stack()

In reply to Thomas Gleixner
Quoted 29 lines · Thomas Gleixner

syscall_enter_from_user_mode_randomize_stack() replaces syscall_enter_from_user_mode() and the subsequent invocation of add_random_kstack_offset().

The advantage is that it applies the stack randomization right after enter_from_user_mode() and thereby avoids the overhead of get/put_cpu_var() as that code is invoked with interrupts disabled.

No functional change.

Cc Michael Ellerman <[email protected]>
Cc Shrikanth Hegde <[email protected]>
---
 arch/powerpc/kernel/syscall.c |    4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)
arch/powerpc/kernel/syscall.c +0 -1
@@ -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>

arch/powerpc/kernel/syscall.c notrace long system_call_exception(struc · line 21

Quoted 6 lines
arch/powerpc/kernel/syscall.c +1 -2
@@ -19,8 +18,7 @@ notrace long system_call_exception(struc
 	long ret;
 	syscall_fn f;
 
-	r0 = syscall_enter_from_user_mode(regs, r0);
-	add_random_kstack_offset();
+	r0 = syscall_enter_from_user_mode_randomize_stack(regs, r0);
Quoted 4 lines
arch/powerpc/kernel/syscall.c +0 -0
 	if (unlikely(r0 >= NR_syscalls)) {
 		if (unlikely(trap_is_unsupported_scv(regs))) {
 
Reviewed-by on v1 5/18
#32 lore raw

Re: [patch 05/18] powerpc/syscall: Use syscall_enter_from_user_mode_randomize_stack()

In reply to Thomas Gleixner
Quoted 10 lines · Thomas Gleixner

syscall_enter_from_user_mode_randomize_stack() replaces syscall_enter_from_user_mode() and the subsequent invocation of add_random_kstack_offset().

The advantage is that it applies the stack randomization right after enter_from_user_mode() and thereby avoids the overhead of get/put_cpu_var() as that code is invoked with interrupts disabled.

No functional change.

Quoted 7 lines
Cc Michael Ellerman <[email protected]>
Cc Shrikanth Hegde <[email protected]>
---
  arch/powerpc/kernel/syscall.c |    4 +---
  1 file changed, 1 insertion(+), 3 deletions(-)
Reviewed-by on v1 5/18
#33 lore raw

Re: [patch 05/18] powerpc/syscall: Use syscall_enter_from_user_mode_randomize_stack()

In reply to Thomas Gleixner
Quoted 30 lines · Thomas Gleixner

syscall_enter_from_user_mode_randomize_stack() replaces syscall_enter_from_user_mode() and the subsequent invocation of add_random_kstack_offset().

The advantage is that it applies the stack randomization right after enter_from_user_mode() and thereby avoids the overhead of get/put_cpu_var() as that code is invoked with interrupts disabled.

No functional change.

Cc Michael Ellerman <[email protected]>
Cc Shrikanth Hegde <[email protected]>
---
 arch/powerpc/kernel/syscall.c |    4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)
arch/powerpc/kernel/syscall.c +0 -1
@@ -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>

arch/powerpc/kernel/syscall.c notrace long system_call_exception(struc · line 24

Quoted 9 lines
arch/powerpc/kernel/syscall.c +1 -2
@@ -19,8 +18,7 @@ notrace long system_call_exception(struc
 	long ret;
 	syscall_fn f;
 
-	r0 = syscall_enter_from_user_mode(regs, r0);
-	add_random_kstack_offset();
+	r0 = syscall_enter_from_user_mode_randomize_stack(regs, r0);
 
 	if (unlikely(r0 >= NR_syscalls)) {
 		if (unlikely(trap_is_unsupported_scv(regs))) {
#34 lore raw

[tip: core/entry] powerpc/syscall: Use syscall_enter_from_user_mode_randomize_stack()

In reply to Thomas Gleixner
The following commit has been merged into the core/entry branch of tip:

The following commit has been merged into the core/entry branch of tip:

Commit-ID:     3b2b9c0198bbcf077f201cd693a0efc597d05405
Gitweb:        https://git.kernel.org/tip/3b2b9c0198bbcf077f201cd693a0efc597d05405
Author:        Thomas Gleixner <[email protected]>
AuthorDate:    Tue, 07 Jul 2026 21:06:15 +02:00
Committer:     Thomas Gleixner <[email protected]>
CommitterDate: Sun, 12 Jul 2026 12:38:01 +02:00

powerpc/syscall: Use syscall_enter_from_user_mode_randomize_stack()

syscall_enter_from_user_mode_randomize_stack() replaces syscall_enter_from_user_mode() and the subsequent invocation of add_random_kstack_offset().

The advantage is that it applies the stack randomization right after enter_from_user_mode() and thereby avoids the overhead of get/put_cpu_var() as that code is invoked with interrupts disabled.

No functional change.

---
 arch/powerpc/kernel/syscall.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)
arch/powerpc/kernel/syscall.c +1 -3
index ee07b2e..b4d0159 100644
@@ -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,7 @@ notrace long system_call_exception(struct pt_regs *regs, unsigned long r0)
 	long ret;
 	syscall_fn f;
 
-	r0 = syscall_enter_from_user_mode(regs, r0);
-	add_random_kstack_offset();
+	r0 = syscall_enter_from_user_mode_randomize_stack(regs, r0);
 
 	if (unlikely(r0 >= NR_syscalls)) {
 		if (unlikely(trap_is_unsupported_scv(regs))) {
author maintainer
#35 lore raw

PATCH 6/18 riscv/syscall: Use syscall_enter_from_user_mode_randomize_stack()

In reply to Thomas Gleixner

syscall_enter_from_user_mode_randomize_stack() replaces syscall_enter_from_user_mode() and the subsequent invocation of add_random_kstack_offset().

The advantage is that it applies the stack randomization right after enter_from_user_mode() and thereby avoids the overhead of get/put_cpu_var() as that code is invoked with interrupts disabled.

No functional change.

---
 arch/riscv/kernel/traps.c |    5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)
arch/riscv/kernel/traps.c +1 -4
@@ -7,7 +7,6 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/irqflags.h>
-#include <linux/randomize_kstack.h>
 #include <linux/sched.h>
 #include <linux/sched/debug.h>
 #include <linux/sched/signal.h>
@@ -333,9 +332,7 @@ void do_trap_ecall_u(struct pt_regs *reg
 
 		riscv_v_vstate_discard(regs);
 
-		syscall = syscall_enter_from_user_mode(regs, syscall);
-
-		add_random_kstack_offset();
+		syscall = syscall_enter_from_user_mode_randomize_stack(regs, syscall);
 
 		if (syscall >= 0 && syscall < NR_syscalls) {
 			syscall = array_index_nospec(syscall, NR_syscalls);
Reviewed-by on v1 6/18
#36 lore raw

Re: [patch 06/18] riscv/syscall: Use syscall_enter_from_user_mode_randomize_stack()

Quoted 36 lines · Thomas Gleixner

syscall_enter_from_user_mode_randomize_stack() replaces syscall_enter_from_user_mode() and the subsequent invocation of add_random_kstack_offset().

The advantage is that it applies the stack randomization right after enter_from_user_mode() and thereby avoids the overhead of get/put_cpu_var() as that code is invoked with interrupts disabled.

No functional change.

---
 arch/riscv/kernel/traps.c |    5 +----

 1 file changed, 1 insertion(+), 4 deletions(-)
arch/riscv/kernel/traps.c +0 -1
@@ -7,7 +7,6 @@
  #include <linux/kernel.h>
  #include <linux/init.h>
  #include <linux/irqflags.h>
-#include <linux/randomize_kstack.h>
  #include <linux/sched.h>
  #include <linux/sched/debug.h>
  #include <linux/sched/signal.h>
@@ -333,9 +332,7 @@ void do_trap_ecall_u(struct pt_regs *reg


  riscv_v_vstate_discard(regs);

arch/riscv/kernel/traps.c +1 -3
-		syscall = syscall_enter_from_user_mode(regs, syscall);
-
-		add_random_kstack_offset();
+		syscall = syscall_enter_from_user_mode_randomize_stack(regs, syscall);
Quoted 3 lines


  if (syscall >= 0 && syscall < NR_syscalls) { syscall = array_index_nospec(syscall, NR_syscalls);

Reviewed-by on v1 6/18
#37 lore raw

Re: [patch 06/18] riscv/syscall: Use syscall_enter_from_user_mode_randomize_stack()

In reply to Thomas Gleixner
Quoted 29 lines · Thomas Gleixner

syscall_enter_from_user_mode_randomize_stack() replaces syscall_enter_from_user_mode() and the subsequent invocation of add_random_kstack_offset().

The advantage is that it applies the stack randomization right after enter_from_user_mode() and thereby avoids the overhead of get/put_cpu_var() as that code is invoked with interrupts disabled.

No functional change.

---
 arch/riscv/kernel/traps.c |    5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)
arch/riscv/kernel/traps.c +0 -1
@@ -7,7 +7,6 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/irqflags.h>
-#include <linux/randomize_kstack.h>
 #include <linux/sched.h>
 #include <linux/sched/debug.h>
 #include <linux/sched/signal.h>

arch/riscv/kernel/traps.c void do_trap_ecall_u(struct pt_regs *reg · line 335

Quoted 7 lines
arch/riscv/kernel/traps.c +1 -3
@@ -333,9 +332,7 @@ void do_trap_ecall_u(struct pt_regs *reg
 
 		riscv_v_vstate_discard(regs);
 
-		syscall = syscall_enter_from_user_mode(regs, syscall);
-
-		add_random_kstack_offset();
+		syscall = syscall_enter_from_user_mode_randomize_stack(regs, syscall);
Quoted 4 lines
arch/riscv/kernel/traps.c +0 -0
 		if (syscall >= 0 && syscall < NR_syscalls) {
 			syscall = array_index_nospec(syscall, NR_syscalls);
 
Reviewed-by on v1 6/18
#38 lore raw

Re: [patch 06/18] riscv/syscall: Use syscall_enter_from_user_mode_randomize_stack()

In reply to Thomas Gleixner
Quoted 10 lines · Thomas Gleixner

syscall_enter_from_user_mode_randomize_stack() replaces syscall_enter_from_user_mode() and the subsequent invocation of add_random_kstack_offset().

The advantage is that it applies the stack randomization right after enter_from_user_mode() and thereby avoids the overhead of get/put_cpu_var() as that code is invoked with interrupts disabled.

No functional change.

Quoted 7 lines
---
  arch/riscv/kernel/traps.c |    5 +----
  1 file changed, 1 insertion(+), 4 deletions(-)
Reviewed-by on v1 6/18
#39 lore raw

Re: [patch 06/18] riscv/syscall: Use syscall_enter_from_user_mode_randomize_stack()

In reply to Thomas Gleixner
Quoted 30 lines · Thomas Gleixner

syscall_enter_from_user_mode_randomize_stack() replaces syscall_enter_from_user_mode() and the subsequent invocation of add_random_kstack_offset().

The advantage is that it applies the stack randomization right after enter_from_user_mode() and thereby avoids the overhead of get/put_cpu_var() as that code is invoked with interrupts disabled.

No functional change.

---
 arch/riscv/kernel/traps.c |    5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)
arch/riscv/kernel/traps.c +0 -1
@@ -7,7 +7,6 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/irqflags.h>
-#include <linux/randomize_kstack.h>
 #include <linux/sched.h>
 #include <linux/sched/debug.h>
 #include <linux/sched/signal.h>

arch/riscv/kernel/traps.c void do_trap_ecall_u(struct pt_regs *reg · line 338

Quoted 10 lines
arch/riscv/kernel/traps.c +1 -3
@@ -333,9 +332,7 @@ void do_trap_ecall_u(struct pt_regs *reg
 
 		riscv_v_vstate_discard(regs);
 
-		syscall = syscall_enter_from_user_mode(regs, syscall);
-
-		add_random_kstack_offset();
+		syscall = syscall_enter_from_user_mode_randomize_stack(regs, syscall);
 
 		if (syscall >= 0 && syscall < NR_syscalls) {
 			syscall = array_index_nospec(syscall, NR_syscalls);
#40 lore raw

[tip: core/entry] riscv/syscall: Use syscall_enter_from_user_mode_randomize_stack()

In reply to Thomas Gleixner
The following commit has been merged into the core/entry branch of tip:

The following commit has been merged into the core/entry branch of tip:

Commit-ID:     d023abfbc4dca9ad9c9928b5b5a38b1628ee1a5d
Gitweb:        https://git.kernel.org/tip/d023abfbc4dca9ad9c9928b5b5a38b1628ee1a5d
Author:        Thomas Gleixner <[email protected]>
AuthorDate:    Tue, 07 Jul 2026 21:06:19 +02:00
Committer:     Thomas Gleixner <[email protected]>
CommitterDate: Sun, 12 Jul 2026 12:38:01 +02:00

riscv/syscall: Use syscall_enter_from_user_mode_randomize_stack()

syscall_enter_from_user_mode_randomize_stack() replaces syscall_enter_from_user_mode() and the subsequent invocation of add_random_kstack_offset().

The advantage is that it applies the stack randomization right after enter_from_user_mode() and thereby avoids the overhead of get/put_cpu_var() as that code is invoked with interrupts disabled.

No functional change.

---
 arch/riscv/kernel/traps.c | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)
arch/riscv/kernel/traps.c +1 -4
index 8c62c77..bb18011 100644
@@ -7,7 +7,6 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/irqflags.h>
-#include <linux/randomize_kstack.h>
 #include <linux/sched.h>
 #include <linux/sched/debug.h>
 #include <linux/sched/signal.h>
@@ -333,9 +332,7 @@ void do_trap_ecall_u(struct pt_regs *regs)
 
 		riscv_v_vstate_discard(regs);
 
-		syscall = syscall_enter_from_user_mode(regs, syscall);
-
-		add_random_kstack_offset();
+		syscall = syscall_enter_from_user_mode_randomize_stack(regs, syscall);
 
 		if (syscall >= 0 && syscall < NR_syscalls) {
 			syscall = array_index_nospec(syscall, NR_syscalls);
maintainer Reviewed-by on v1 6/18
#41 lore raw

Re: [patch 06/18] riscv/syscall: Use syscall_enter_from_user_mode_randomize_stack()

In reply to Thomas Gleixner
Quoted 30 lines · Thomas Gleixner

syscall_enter_from_user_mode_randomize_stack() replaces syscall_enter_from_user_mode() and the subsequent invocation of add_random_kstack_offset().

The advantage is that it applies the stack randomization right after enter_from_user_mode() and thereby avoids the overhead of get/put_cpu_var() as that code is invoked with interrupts disabled.

No functional change.

---
 arch/riscv/kernel/traps.c |    5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)
arch/riscv/kernel/traps.c +0 -1
@@ -7,7 +7,6 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/irqflags.h>
-#include <linux/randomize_kstack.h>
 #include <linux/sched.h>
 #include <linux/sched/debug.h>
 #include <linux/sched/signal.h>

arch/riscv/kernel/traps.c void do_trap_ecall_u(struct pt_regs *reg · line 335

Quoted 7 lines
arch/riscv/kernel/traps.c +1 -3
@@ -333,9 +332,7 @@ void do_trap_ecall_u(struct pt_regs *reg
 
                riscv_v_vstate_discard(regs);
 
-               syscall = syscall_enter_from_user_mode(regs, syscall);
-
-               add_random_kstack_offset();
+               syscall = syscall_enter_from_user_mode_randomize_stack(regs, syscall);
Signature · 2 lines
Best Regards
 Guo Ren
author maintainer
#42 lore raw

PATCH 7/18 s390/syscall: Use enter_from_user_mode_randomize_stack()

In reply to Thomas Gleixner

enter_from_user_mode_randomize_stack() replaces enter_from_user_mode() and the subsequent invocation of add_random_kstack_offset_irqsoff().

As a bonus this avoids the overhead of get/put_cpu_var() in add_random_kstack_offset().

No functional change.

---
 arch/s390/kernel/syscall.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
arch/s390/kernel/syscall.c +2 -2
@@ -97,8 +97,8 @@ void noinstr __do_syscall(struct pt_regs
 {
 	unsigned long nr;
 
-	enter_from_user_mode(regs);
-	add_random_kstack_offset();
+	enter_from_user_mode_randomize_stack(regs);
+
 	regs->psw = get_lowcore()->svc_old_psw;
 	regs->int_code = get_lowcore()->svc_int_code;
 	update_timer_sys();
reviewer Reviewed-by on v1 7/18
#43 lore raw

Re: [patch 07/18] s390/syscall: Use enter_from_user_mode_randomize_stack()

Quoted 18 lines · Thomas Gleixner

enter_from_user_mode_randomize_stack() replaces enter_from_user_mode() and the subsequent invocation of add_random_kstack_offset_irqsoff().

As a bonus this avoids the overhead of get/put_cpu_var() in add_random_kstack_offset().

No functional change.

---
 arch/s390/kernel/syscall.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

arch/s390/kernel/syscall.c void noinstr __do_syscall(struct pt_regs · line 104

Quoted 10 lines
arch/s390/kernel/syscall.c +2 -2
@@ -97,8 +97,8 @@ void noinstr __do_syscall(struct pt_regs
 {
 	unsigned long nr;
 
-	enter_from_user_mode(regs);
-	add_random_kstack_offset();
+	enter_from_user_mode_randomize_stack(regs);
+
 	regs->psw = get_lowcore()->svc_old_psw;
 	regs->int_code = get_lowcore()->svc_int_code;
 	update_timer_sys();
Reviewed-by on v1 7/18
#44 lore raw

Re: [patch 07/18] s390/syscall: Use enter_from_user_mode_randomize_stack()

In reply to Thomas Gleixner
Quoted 25 lines · Thomas Gleixner

enter_from_user_mode_randomize_stack() replaces enter_from_user_mode() and the subsequent invocation of add_random_kstack_offset_irqsoff().

As a bonus this avoids the overhead of get/put_cpu_var() in add_random_kstack_offset().

No functional change.

---
 arch/s390/kernel/syscall.c |    4 ++--

 1 file changed, 2 insertions(+), 2 deletions(-)
arch/s390/kernel/syscall.c +0 -0
@@ -97,8 +97,8 @@ void noinstr __do_syscall(struct pt_regs
  {
  	unsigned long nr;

arch/s390/kernel/syscall.c +2 -2
-	enter_from_user_mode(regs);
-	add_random_kstack_offset();
+	enter_from_user_mode_randomize_stack(regs);
+
Quoted 3 lines

  regs->psw = get_lowcore()->svc_old_psw; regs->int_code = get_lowcore()->svc_int_code; update_timer_sys();

Reviewed-by on v1 7/18
#45 lore raw

Re: [patch 07/18] s390/syscall: Use enter_from_user_mode_randomize_stack()

In reply to Thomas Gleixner
Quoted 18 lines · Thomas Gleixner

enter_from_user_mode_randomize_stack() replaces enter_from_user_mode() and the subsequent invocation of add_random_kstack_offset_irqsoff().

As a bonus this avoids the overhead of get/put_cpu_var() in add_random_kstack_offset().

No functional change.

---
 arch/s390/kernel/syscall.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

arch/s390/kernel/syscall.c void noinstr __do_syscall(struct pt_regs · line 100

Quoted 6 lines
arch/s390/kernel/syscall.c +1 -2
@@ -97,8 +97,8 @@ void noinstr __do_syscall(struct pt_regs
 {
 	unsigned long nr;
 
-	enter_from_user_mode(regs);
-	add_random_kstack_offset();
+	enter_from_user_mode_randomize_stack(regs);
Quoted 5 lines
arch/s390/kernel/syscall.c +1 -0
+
 	regs->psw = get_lowcore()->svc_old_psw;
 	regs->int_code = get_lowcore()->svc_int_code;
 	update_timer_sys();
#46 lore raw

Re: [patch 07/18] s390/syscall: Use enter_from_user_mode_randomize_stack()

In reply to Thomas Gleixner
Quoted 18 lines · Thomas Gleixner

enter_from_user_mode_randomize_stack() replaces enter_from_user_mode() and the subsequent invocation of add_random_kstack_offset_irqsoff().

As a bonus this avoids the overhead of get/put_cpu_var() in add_random_kstack_offset().

No functional change.

---
 arch/s390/kernel/syscall.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

arch/s390/kernel/syscall.c void noinstr __do_syscall(struct pt_regs · line 100

Quoted 6 lines
arch/s390/kernel/syscall.c +1 -2
@@ -97,8 +97,8 @@ void noinstr __do_syscall(struct pt_regs
 {
 	unsigned long nr;
 
-	enter_from_user_mode(regs);
-	add_random_kstack_offset();
+	enter_from_user_mode_randomize_stack(regs);

The #include <linux/randomize_kstack.h> can be removed.

Quoted 5 lines
arch/s390/kernel/syscall.c +1 -0
+
 	regs->psw = get_lowcore()->svc_old_psw;
 	regs->int_code = get_lowcore()->svc_int_code;
 	update_timer_sys();
#47 lore raw

Re: [patch 07/18] s390/syscall: Use enter_from_user_mode_randomize_stack()

Quoted 24 lines · Jinjie Ruan
Quoted 21 lines · Thomas Gleixner

enter_from_user_mode_randomize_stack() replaces enter_from_user_mode() and the subsequent invocation of add_random_kstack_offset_irqsoff().

As a bonus this avoids the overhead of get/put_cpu_var() in add_random_kstack_offset().

No functional change.

---
  arch/s390/kernel/syscall.c |    4 ++--
  1 file changed, 2 insertions(+), 2 deletions(-)
arch/s390/kernel/syscall.c +0 -0
@@ -97,8 +97,8 @@ void noinstr __do_syscall(struct pt_regs
  {
  	unsigned long nr;
 
Quoted 5 lines

arch/s390/kernel/syscall.c void noinstr __do_syscall(struct pt_regs · line 100

Quoted 3 lines
arch/s390/kernel/syscall.c +1 -2
-	enter_from_user_mode(regs);
-	add_random_kstack_offset();
+	enter_from_user_mode_randomize_stack(regs);

The #include <linux/randomize_kstack.h> can be removed.

Reviewed-by on v1 7/18
#48 lore raw

Re: [patch 07/18] s390/syscall: Use enter_from_user_mode_randomize_stack()

In reply to Thomas Gleixner
Quoted 19 lines · Thomas Gleixner

enter_from_user_mode_randomize_stack() replaces enter_from_user_mode() and the subsequent invocation of add_random_kstack_offset_irqsoff().

As a bonus this avoids the overhead of get/put_cpu_var() in add_random_kstack_offset().

No functional change.

---
 arch/s390/kernel/syscall.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

arch/s390/kernel/syscall.c void noinstr __do_syscall(struct pt_regs · line 104

Quoted 10 lines
arch/s390/kernel/syscall.c +2 -2
@@ -97,8 +97,8 @@ void noinstr __do_syscall(struct pt_regs
 {
 	unsigned long nr;
 
-	enter_from_user_mode(regs);
-	add_random_kstack_offset();
+	enter_from_user_mode_randomize_stack(regs);
+
 	regs->psw = get_lowcore()->svc_old_psw;
 	regs->int_code = get_lowcore()->svc_int_code;
 	update_timer_sys();
#49 lore raw

[tip: core/entry] s390/syscall: Use enter_from_user_mode_randomize_stack()

In reply to Thomas Gleixner
The following commit has been merged into the core/entry branch of tip:

The following commit has been merged into the core/entry branch of tip:

Commit-ID:     05a194d8bd005e0887a1e089bbbbd2e1a641638f
Gitweb:        https://git.kernel.org/tip/05a194d8bd005e0887a1e089bbbbd2e1a641638f
Author:        Thomas Gleixner <[email protected]>
AuthorDate:    Tue, 07 Jul 2026 21:06:23 +02:00
Committer:     Thomas Gleixner <[email protected]>
CommitterDate: Sun, 12 Jul 2026 12:38:01 +02:00

s390/syscall: Use enter_from_user_mode_randomize_stack()

enter_from_user_mode_randomize_stack() replaces enter_from_user_mode() and the subsequent invocation of add_random_kstack_offset_irqsoff().

As a bonus this avoids the overhead of get/put_cpu_var() in add_random_kstack_offset().

No functional change.

---
 arch/s390/kernel/syscall.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
arch/s390/kernel/syscall.c +2 -2
index 75d5a3c..73abda2 100644
@@ -97,8 +97,8 @@ void noinstr __do_syscall(struct pt_regs *regs, int per_trap)
 {
 	unsigned long nr;
 
-	enter_from_user_mode(regs);
-	add_random_kstack_offset();
+	enter_from_user_mode_randomize_stack(regs);
+
 	regs->psw = get_lowcore()->svc_old_psw;
 	regs->int_code = get_lowcore()->svc_int_code;
 	update_timer_sys();
author maintainer
#50 lore raw

PATCH 8/18 x86/syscall: Use [syscall_]enter_from_user_mode_randomize_stack()

In reply to Thomas Gleixner

These functions integrate the stack randomization.

syscall_enter_from_user_mode_randomize_stack() has the advantage that the randomization happens early right after enter_from_user_mode().

In both cases also the overhead of get/put_cpu_var() in add_random_kstack_offset() is avoided.

No functional change.

---
 arch/x86/entry/syscall_32.c         |   19 +++++--------------
 arch/x86/entry/syscall_64.c         |    3 +--
 arch/x86/include/asm/entry-common.h |    1 -
 3 files changed, 6 insertions(+), 17 deletions(-)
arch/x86/entry/syscall_32.c +5 -14
@@ -142,10 +142,9 @@ static __always_inline bool int80_is_ext
 	 * int80_is_external() below which calls into the APIC driver.
 	 * Identical for soft and external interrupts.
 	 */
-	enter_from_user_mode(regs);
+	enter_from_user_mode_randomize_stack(regs);
 
 	instrumentation_begin();
-	add_random_kstack_offset();
 
 	/* Validate that this is a soft interrupt to the extent possible */
 	if (unlikely(int80_is_external()))
@@ -210,11 +209,9 @@ DEFINE_FREDENTRY_RAW(int80_emulation)
 {
 	int nr;
 
-	enter_from_user_mode(regs);
+	enter_from_user_mode_randomize_stack(regs);
 
 	instrumentation_begin();
-	add_random_kstack_offset();
-
 	/*
 	 * FRED pushed 0 into regs::orig_ax and regs::ax contains the
 	 * syscall number.
@@ -252,10 +249,10 @@ DEFINE_FREDENTRY_RAW(int80_emulation)
 	 * orig_ax, the int return value truncates it. This matches
 	 * the semantics of syscall_get_nr().
 	 */
-	nr = syscall_enter_from_user_mode(regs, nr);
+	nr = syscall_enter_from_user_mode_randomize_stack(regs, nr);
+
 	instrumentation_begin();
 
-	add_random_kstack_offset();
 	do_syscall_32_irqs_on(regs, nr);
 
 	instrumentation_end();
@@ -268,15 +265,9 @@ static noinstr bool __do_fast_syscall_32
 	int nr = syscall_32_enter(regs);
 	int res;
 
-	/*
-	 * This cannot use syscall_enter_from_user_mode() as it has to
-	 * fetch EBP before invoking any of the syscall entry work
-	 * functions.
-	 */
-	enter_from_user_mode(regs);
+	enter_from_user_mode_randomize_stack(regs);
 
 	instrumentation_begin();
-	add_random_kstack_offset();
 	local_irq_enable();
 	/* Fetch EBP from where the vDSO stashed it. */
 	if (IS_ENABLED(CONFIG_X86_64)) {
arch/x86/entry/syscall_64.c +1 -2
@@ -86,10 +86,9 @@ static __always_inline bool do_syscall_x
 /* Returns true to return using SYSRET, or false to use IRET */
 __visible noinstr bool do_syscall_64(struct pt_regs *regs, int nr)
 {
-	nr = syscall_enter_from_user_mode(regs, nr);
+	nr = syscall_enter_from_user_mode_randomize_stack(regs, nr);
 
 	instrumentation_begin();
-	add_random_kstack_offset();
 
 	if (!do_syscall_x64(regs, nr) && !do_syscall_x32(regs, nr) && nr != -1) {
 		/* Invalid system call, but still a system call. */
arch/x86/include/asm/entry-common.h +0 -1
@@ -2,7 +2,6 @@
 #ifndef _ASM_X86_ENTRY_COMMON_H
 #define _ASM_X86_ENTRY_COMMON_H
 
-#include <linux/randomize_kstack.h>
 #include <linux/user-return-notifier.h>
 
 #include <asm/nospec-branch.h>
Reviewed-by on v1 8/18
#51 lore raw

Re: [patch 08/18] x86/syscall: Use [syscall_]enter_from_user_mode_randomize_stack()

Quoted 94 lines · Thomas Gleixner

These functions integrate the stack randomization.

syscall_enter_from_user_mode_randomize_stack() has the advantage that the randomization happens early right after enter_from_user_mode().

In both cases also the overhead of get/put_cpu_var() in add_random_kstack_offset() is avoided.

No functional change.

---
 arch/x86/entry/syscall_32.c         |   19 +++++-------------- arch/x86/entry/syscall_64.c         |    3 +-- arch/x86/include/asm/entry-common.h |    1 -

 3 files changed, 6 insertions(+), 17 deletions(-)
arch/x86/entry/syscall_32.c +1 -1
@@ -142,10 +142,9 @@ static __always_inline bool int80_is_ext
  	 * int80_is_external() below which calls into the APIC driver.
  	 * Identical for soft and external interrupts.
  	 */
-	enter_from_user_mode(regs);
+	enter_from_user_mode_randomize_stack(regs);


  instrumentation_begin();

arch/x86/entry/syscall_32.c +0 -1
-	add_random_kstack_offset();


  /* Validate that this is a soft interrupt to the extent possible */ if (unlikely(int80_is_external()))

arch/x86/entry/syscall_32.c +0 -0
@@ -210,11 +209,9 @@ DEFINE_FREDENTRY_RAW(int80_emulation)
  {
  	int nr;

arch/x86/entry/syscall_32.c +1 -1
-	enter_from_user_mode(regs);
+	enter_from_user_mode_randomize_stack(regs);


  instrumentation_begin();

arch/x86/entry/syscall_32.c +0 -2
-	add_random_kstack_offset();
-

  /*
  * FRED pushed 0 into regs::orig_ax and regs::ax contains the
  * syscall number.

arch/x86/entry/syscall_32.c +2 -1
@@ -252,10 +249,10 @@ DEFINE_FREDENTRY_RAW(int80_emulation)
  	 * orig_ax, the int return value truncates it. This matches
  	 * the semantics of syscall_get_nr().
  	 */
-	nr = syscall_enter_from_user_mode(regs, nr);
+	nr = syscall_enter_from_user_mode_randomize_stack(regs, nr);
+
  	instrumentation_begin();

arch/x86/entry/syscall_32.c +0 -1
-	add_random_kstack_offset();

  do_syscall_32_irqs_on(regs, nr);

  instrumentation_end();

arch/x86/entry/syscall_32.c +0 -0
@@ -268,15 +265,9 @@ static noinstr bool __do_fast_syscall_32
  	int nr = syscall_32_enter(regs);
  	int res;

arch/x86/entry/syscall_32.c +1 -6
-	/*
-	 * This cannot use syscall_enter_from_user_mode() as it has to
-	 * fetch EBP before invoking any of the syscall entry work
-	 * functions.
-	 */
-	enter_from_user_mode(regs);
+	enter_from_user_mode_randomize_stack(regs);


  instrumentation_begin();

arch/x86/entry/syscall_32.c +0 -1
-	add_random_kstack_offset();

  local_irq_enable();
  /* Fetch EBP from where the vDSO stashed it. */ if (IS_ENABLED(CONFIG_X86_64)) {

arch/x86/entry/syscall_64.c +1 -1
@@ -86,10 +86,9 @@ static __always_inline bool do_syscall_x
  /* Returns true to return using SYSRET, or false to use IRET */
  __visible noinstr bool do_syscall_64(struct pt_regs *regs, int nr)
  {
-	nr = syscall_enter_from_user_mode(regs, nr);
+	nr = syscall_enter_from_user_mode_randomize_stack(regs, nr);


  instrumentation_begin();

arch/x86/entry/syscall_64.c +0 -1
-	add_random_kstack_offset();


  if (!do_syscall_x64(regs, nr) && !do_syscall_x32(regs, nr) && nr != -1) { /* Invalid system call, but still a system call. */

arch/x86/include/asm/entry-common.h +0 -0
@@ -2,7 +2,6 @@
  #ifndef _ASM_X86_ENTRY_COMMON_H
  #define _ASM_X86_ENTRY_COMMON_H
Quoted 5 lines


-#include <linux/randomize_kstack.h>
 #include <linux/user-return-notifier.h>

 #include <asm/nospec-branch.h>

Reviewed-by on v1 8/18
#52 lore raw

Re: [patch 08/18] x86/syscall: Use [syscall_]enter_from_user_mode_randomize_stack()

In reply to Thomas Gleixner
Quoted 10 lines · Thomas Gleixner

These functions integrate the stack randomization.

syscall_enter_from_user_mode_randomize_stack() has the advantage that the randomization happens early right after enter_from_user_mode().

In both cases also the overhead of get/put_cpu_var() in add_random_kstack_offset() is avoided.

No functional change.

Quoted 7 lines
---
 arch/x86/entry/syscall_32.c         |   19 +++++--------------
 arch/x86/entry/syscall_64.c         |    3 +--
 arch/x86/include/asm/entry-common.h |    1 -
 3 files changed, 6 insertions(+), 17 deletions(-)
Quoted 83 lines
arch/x86/entry/syscall_32.c +5 -14
@@ -142,10 +142,9 @@ static __always_inline bool int80_is_ext
 	 * int80_is_external() below which calls into the APIC driver.
 	 * Identical for soft and external interrupts.
 	 */
-	enter_from_user_mode(regs);
+	enter_from_user_mode_randomize_stack(regs);
 
 	instrumentation_begin();
-	add_random_kstack_offset();
 
 	/* Validate that this is a soft interrupt to the extent possible */
 	if (unlikely(int80_is_external()))
@@ -210,11 +209,9 @@ DEFINE_FREDENTRY_RAW(int80_emulation)
 {
 	int nr;
 
-	enter_from_user_mode(regs);
+	enter_from_user_mode_randomize_stack(regs);
 
 	instrumentation_begin();
-	add_random_kstack_offset();
-
 	/*
 	 * FRED pushed 0 into regs::orig_ax and regs::ax contains the
 	 * syscall number.
@@ -252,10 +249,10 @@ DEFINE_FREDENTRY_RAW(int80_emulation)
 	 * orig_ax, the int return value truncates it. This matches
 	 * the semantics of syscall_get_nr().
 	 */
-	nr = syscall_enter_from_user_mode(regs, nr);
+	nr = syscall_enter_from_user_mode_randomize_stack(regs, nr);
+
 	instrumentation_begin();
 
-	add_random_kstack_offset();
 	do_syscall_32_irqs_on(regs, nr);
 
 	instrumentation_end();
@@ -268,15 +265,9 @@ static noinstr bool __do_fast_syscall_32
 	int nr = syscall_32_enter(regs);
 	int res;
 
-	/*
-	 * This cannot use syscall_enter_from_user_mode() as it has to
-	 * fetch EBP before invoking any of the syscall entry work
-	 * functions.
-	 */
-	enter_from_user_mode(regs);
+	enter_from_user_mode_randomize_stack(regs);
 
 	instrumentation_begin();
-	add_random_kstack_offset();
 	local_irq_enable();
 	/* Fetch EBP from where the vDSO stashed it. */
 	if (IS_ENABLED(CONFIG_X86_64)) {
arch/x86/entry/syscall_64.c +1 -2
@@ -86,10 +86,9 @@ static __always_inline bool do_syscall_x
 /* Returns true to return using SYSRET, or false to use IRET */
 __visible noinstr bool do_syscall_64(struct pt_regs *regs, int nr)
 {
-	nr = syscall_enter_from_user_mode(regs, nr);
+	nr = syscall_enter_from_user_mode_randomize_stack(regs, nr);
 
 	instrumentation_begin();
-	add_random_kstack_offset();
 
 	if (!do_syscall_x64(regs, nr) && !do_syscall_x32(regs, nr) && nr != -1) {
 		/* Invalid system call, but still a system call. */
arch/x86/include/asm/entry-common.h +0 -1
@@ -2,7 +2,6 @@
 #ifndef _ASM_X86_ENTRY_COMMON_H
 #define _ASM_X86_ENTRY_COMMON_H
 
-#include <linux/randomize_kstack.h>
 #include <linux/user-return-notifier.h>
 
 #include <asm/nospec-branch.h>
Reviewed-by on v1 8/18
#53 lore raw

Re: [patch 08/18] x86/syscall: Use [syscall_]enter_from_user_mode_randomize_stack()

In reply to Thomas Gleixner
Quoted 10 lines · Thomas Gleixner

These functions integrate the stack randomization.

syscall_enter_from_user_mode_randomize_stack() has the advantage that the randomization happens early right after enter_from_user_mode().

In both cases also the overhead of get/put_cpu_var() in add_random_kstack_offset() is avoided.

No functional change.

Quoted 7 lines
---
  arch/x86/entry/syscall_32.c         |   19 +++++--------------
  arch/x86/entry/syscall_64.c         |    3 +--
  arch/x86/include/asm/entry-common.h |    1 -
  3 files changed, 6 insertions(+), 17 deletions(-)
Reviewed-by on v1 8/18
#54 lore raw

Re: [patch 08/18] x86/syscall: Use [syscall_]enter_from_user_mode_randomize_stack()

In reply to Thomas Gleixner
Quoted 93 lines · Thomas Gleixner

These functions integrate the stack randomization.

syscall_enter_from_user_mode_randomize_stack() has the advantage that the randomization happens early right after enter_from_user_mode().

In both cases also the overhead of get/put_cpu_var() in add_random_kstack_offset() is avoided.

No functional change.

---
 arch/x86/entry/syscall_32.c         |   19 +++++--------------
 arch/x86/entry/syscall_64.c         |    3 +--
 arch/x86/include/asm/entry-common.h |    1 -
 3 files changed, 6 insertions(+), 17 deletions(-)
arch/x86/entry/syscall_32.c +5 -14
@@ -142,10 +142,9 @@ static __always_inline bool int80_is_ext
 	 * int80_is_external() below which calls into the APIC driver.
 	 * Identical for soft and external interrupts.
 	 */
-	enter_from_user_mode(regs);
+	enter_from_user_mode_randomize_stack(regs);
 
 	instrumentation_begin();
-	add_random_kstack_offset();
 
 	/* Validate that this is a soft interrupt to the extent possible */
 	if (unlikely(int80_is_external()))
@@ -210,11 +209,9 @@ DEFINE_FREDENTRY_RAW(int80_emulation)
 {
 	int nr;
 
-	enter_from_user_mode(regs);
+	enter_from_user_mode_randomize_stack(regs);
 
 	instrumentation_begin();
-	add_random_kstack_offset();
-
 	/*
 	 * FRED pushed 0 into regs::orig_ax and regs::ax contains the
 	 * syscall number.
@@ -252,10 +249,10 @@ DEFINE_FREDENTRY_RAW(int80_emulation)
 	 * orig_ax, the int return value truncates it. This matches
 	 * the semantics of syscall_get_nr().
 	 */
-	nr = syscall_enter_from_user_mode(regs, nr);
+	nr = syscall_enter_from_user_mode_randomize_stack(regs, nr);
+
 	instrumentation_begin();
 
-	add_random_kstack_offset();
 	do_syscall_32_irqs_on(regs, nr);
 
 	instrumentation_end();
@@ -268,15 +265,9 @@ static noinstr bool __do_fast_syscall_32
 	int nr = syscall_32_enter(regs);
 	int res;
 
-	/*
-	 * This cannot use syscall_enter_from_user_mode() as it has to
-	 * fetch EBP before invoking any of the syscall entry work
-	 * functions.
-	 */
-	enter_from_user_mode(regs);
+	enter_from_user_mode_randomize_stack(regs);
 
 	instrumentation_begin();
-	add_random_kstack_offset();
 	local_irq_enable();
 	/* Fetch EBP from where the vDSO stashed it. */
 	if (IS_ENABLED(CONFIG_X86_64)) {
arch/x86/entry/syscall_64.c +1 -2
@@ -86,10 +86,9 @@ static __always_inline bool do_syscall_x
 /* Returns true to return using SYSRET, or false to use IRET */
 __visible noinstr bool do_syscall_64(struct pt_regs *regs, int nr)
 {
-	nr = syscall_enter_from_user_mode(regs, nr);
+	nr = syscall_enter_from_user_mode_randomize_stack(regs, nr);
 
 	instrumentation_begin();
-	add_random_kstack_offset();
 
 	if (!do_syscall_x64(regs, nr) && !do_syscall_x32(regs, nr) && nr != -1) {
 		/* Invalid system call, but still a system call. */

arch/x86/include/asm/entry-common.h line 7

Quoted 7 lines
arch/x86/include/asm/entry-common.h +0 -1
@@ -2,7 +2,6 @@
 #ifndef _ASM_X86_ENTRY_COMMON_H
 #define _ASM_X86_ENTRY_COMMON_H
 
-#include <linux/randomize_kstack.h>
 #include <linux/user-return-notifier.h>
 
 #include <asm/nospec-branch.h>
#55 lore raw

[tip: core/entry] x86/syscall: Use [syscall_]enter_from_user_mode_randomize_stack()

In reply to Thomas Gleixner
The following commit has been merged into the core/entry branch of tip:

The following commit has been merged into the core/entry branch of tip:

Commit-ID:     9d311796e2ce75b3aaded2719a01d7e248c3a24f
Gitweb:        https://git.kernel.org/tip/9d311796e2ce75b3aaded2719a01d7e248c3a24f
Author:        Thomas Gleixner <[email protected]>
AuthorDate:    Tue, 07 Jul 2026 21:06:27 +02:00
Committer:     Thomas Gleixner <[email protected]>
CommitterDate: Sun, 12 Jul 2026 12:38:01 +02:00

x86/syscall: Use [syscall_]enter_from_user_mode_randomize_stack()

These functions integrate the stack randomization.

syscall_enter_from_user_mode_randomize_stack() has the advantage that the randomization happens early right after enter_from_user_mode().

In both cases also the overhead of get/put_cpu_var() in add_random_kstack_offset() is avoided.

No functional change.

---
 arch/x86/entry/syscall_32.c         | 19 +++++--------------
 arch/x86/entry/syscall_64.c         |  3 +--
 arch/x86/include/asm/entry-common.h |  1 -
 3 files changed, 6 insertions(+), 17 deletions(-)
arch/x86/entry/syscall_32.c +5 -14
index 31b9492..2b13f1c 100644
@@ -142,10 +142,9 @@ __visible noinstr void do_int80_emulation(struct pt_regs *regs)
 	 * int80_is_external() below which calls into the APIC driver.
 	 * Identical for soft and external interrupts.
 	 */
-	enter_from_user_mode(regs);
+	enter_from_user_mode_randomize_stack(regs);
 
 	instrumentation_begin();
-	add_random_kstack_offset();
 
 	/* Validate that this is a soft interrupt to the extent possible */
 	if (unlikely(int80_is_external()))
@@ -210,11 +209,9 @@ DEFINE_FREDENTRY_RAW(int80_emulation)
 {
 	int nr;
 
-	enter_from_user_mode(regs);
+	enter_from_user_mode_randomize_stack(regs);
 
 	instrumentation_begin();
-	add_random_kstack_offset();
-
 	/*
 	 * FRED pushed 0 into regs::orig_ax and regs::ax contains the
 	 * syscall number.
@@ -252,10 +249,10 @@ __visible noinstr void do_int80_syscall_32(struct pt_regs *regs)
 	 * orig_ax, the int return value truncates it. This matches
 	 * the semantics of syscall_get_nr().
 	 */
-	nr = syscall_enter_from_user_mode(regs, nr);
+	nr = syscall_enter_from_user_mode_randomize_stack(regs, nr);
+
 	instrumentation_begin();
 
-	add_random_kstack_offset();
 	do_syscall_32_irqs_on(regs, nr);
 
 	instrumentation_end();
@@ -268,15 +265,9 @@ static noinstr bool __do_fast_syscall_32(struct pt_regs *regs)
 	int nr = syscall_32_enter(regs);
 	int res;
 
-	/*
-	 * This cannot use syscall_enter_from_user_mode() as it has to
-	 * fetch EBP before invoking any of the syscall entry work
-	 * functions.
-	 */
-	enter_from_user_mode(regs);
+	enter_from_user_mode_randomize_stack(regs);
 
 	instrumentation_begin();
-	add_random_kstack_offset();
 	local_irq_enable();
 	/* Fetch EBP from where the vDSO stashed it. */
 	if (IS_ENABLED(CONFIG_X86_64)) {
arch/x86/entry/syscall_64.c +1 -2
index 71f0325..0acd7e9 100644
@@ -86,10 +86,9 @@ static __always_inline bool do_syscall_x32(struct pt_regs *regs, int nr)
 /* Returns true to return using SYSRET, or false to use IRET */
 __visible noinstr bool do_syscall_64(struct pt_regs *regs, int nr)
 {
-	nr = syscall_enter_from_user_mode(regs, nr);
+	nr = syscall_enter_from_user_mode_randomize_stack(regs, nr);
 
 	instrumentation_begin();
-	add_random_kstack_offset();
 
 	if (!do_syscall_x64(regs, nr) && !do_syscall_x32(regs, nr) && nr != -1) {
 		/* Invalid system call, but still a system call. */
arch/x86/include/asm/entry-common.h +0 -1
index eca24b5..3fed46b 100644
@@ -2,7 +2,6 @@
 #ifndef _ASM_X86_ENTRY_COMMON_H
 #define _ASM_X86_ENTRY_COMMON_H
 
-#include <linux/randomize_kstack.h>
 #include <linux/user-return-notifier.h>
 
 #include <asm/nospec-branch.h>
author maintainer
#56 lore raw

PATCH 9/18 entry: Remove syscall_enter_from_user_mode()

In reply to Thomas Gleixner

All architecture use either:

    nr = enter_from_user_mode_randomize_stack(regs, nr);

or

    enter_from_user_mode_randomize_stack(regs);
    nr = syscall_enter_from_user_mode_work(regs, nr);

Remove the now unused function.

---
 Documentation/core-api/entry.rst |   17 +++++++++-------
 include/linux/entry-common.h     |   40 +++------------------------------------
 include/linux/irq-entry-common.h |    6 ++---
 3 files changed, 17 insertions(+), 46 deletions(-)
Documentation/core-api/entry.rst +10 -7
@@ -68,7 +68,7 @@ low-level C code must not be instrumente
   noinstr void syscall(struct pt_regs *regs, int nr)
   {
 	arch_syscall_enter(regs);
-	nr = syscall_enter_from_user_mode(regs, nr);
+	nr = syscall_enter_from_user_mode_randomize_stack(regs, nr);
 
 	instrumentation_begin();
 	if (!invoke_syscall(regs, nr) && nr != -1)
@@ -78,12 +78,14 @@ low-level C code must not be instrumente
 	syscall_exit_to_user_mode(regs);
   }
 
-syscall_enter_from_user_mode() first invokes enter_from_user_mode() which
-establishes state in the following order:
+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 +101,11 @@ that it invokes exit_to_user_mode() whic
   * 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
include/linux/entry-common.h +4 -36
@@ -19,7 +19,7 @@
 #endif
 
 /*
- * SYSCALL_WORK flags handled in syscall_enter_from_user_mode()
+ * SYSCALL_WORK flags handled in syscall_enter_from_user_mode_work()
  */
 #define SYSCALL_WORK_ENTER	(SYSCALL_WORK_SECCOMP |			\
 				 SYSCALL_WORK_SYSCALL_TRACEPOINT |	\
@@ -205,42 +205,10 @@ do {									\
 	_ret;								\
 })
 
-/**
- * syscall_enter_from_user_mode - Establish state and check and handle work
- *				  before invoking a syscall
- * @regs:	Pointer to currents pt_regs
- * @syscall:	The syscall number
- *
- * Invoked from architecture specific syscall entry code with interrupts
- * disabled. The calling code has to be non-instrumentable. When the
- * function returns all state is correct, interrupts are enabled and the
- * subsequent functions can be instrumented.
- *
- * This is the combination of enter_from_user_mode() and
- * syscall_enter_from_user_mode_work() to be used when there is no
- * architecture specific work to be done between the two.
- *
- * Returns: The original or a modified syscall number. See
- * syscall_enter_from_user_mode_work() for further explanation.
- */
-static __always_inline long syscall_enter_from_user_mode(struct pt_regs *regs, long syscall)
-{
-	long ret;
-
-	enter_from_user_mode(regs);
-
-	instrumentation_begin();
-	local_irq_enable();
-	ret = syscall_enter_from_user_mode_work(regs, syscall);
-	instrumentation_end();
-
-	return ret;
-}
-
 /*
- * If SYSCALL_EMU is set, then the only reason to report is when
- * SINGLESTEP is set (i.e. PTRACE_SYSEMU_SINGLESTEP).  This syscall
- * instruction has been already reported in syscall_enter_from_user_mode().
+ * If SYSCALL_EMU is set, then the only reason to report is when SINGLESTEP is
+ * set (i.e. PTRACE_SYSEMU_SINGLESTEP).  This syscall instruction has been
+ * already reported in syscall_enter_from_user_mode_work().
  */
 static __always_inline bool report_single_step(unsigned long work)
 {
include/linux/irq-entry-common.h +3 -3
@@ -49,9 +49,9 @@
  * Defaults to an empty implementation. Can be replaced by architecture
  * specific code.
  *
- * Invoked from syscall_enter_from_user_mode() in the non-instrumentable
- * section. Use __always_inline so the compiler cannot push it out of line
- * and make it instrumentable.
+ * Invoked from enter_from_user_mode_syscall_and_randomize_stack() in the
+ * non-instrumentable section. Use __always_inline so the compiler cannot push
+ * it out of line and make it instrumentable.
  */
 static __always_inline void arch_enter_from_user_mode(struct pt_regs *regs);
 
#57 lore raw

Re: [patch 09/18] entry: Remove syscall_enter_from_user_mode()

Quoted 3 lines · Thomas Gleixner

All architecture use either:

    nr = enter_from_user_mode_randomize_stack(regs, nr);

You probably mean syscall_enter_from_user_mode_randomize_stack.

Quoted 119 lines

or

    enter_from_user_mode_randomize_stack(regs); nr = syscall_enter_from_user_mode_work(regs, nr);

Remove the now unused function.

---
 Documentation/core-api/entry.rst |   17 +++++++++------- include/linux/entry-common.h     |   40 +++------------------------------------ include/linux/irq-entry-common.h |    6 ++---

 3 files changed, 17 insertions(+), 46 deletions(-)
Documentation/core-api/entry.rst +1 -1
@@ -68,7 +68,7 @@ low-level C code must not be instrumente
    noinstr void syscall(struct pt_regs *regs, int nr)
    {
  	arch_syscall_enter(regs);
-	nr = syscall_enter_from_user_mode(regs, nr);
+	nr = syscall_enter_from_user_mode_randomize_stack(regs, nr);


  instrumentation_begin();
  if (!invoke_syscall(regs, nr) && nr != -1)

Documentation/core-api/entry.rst +0 -0
@@ -78,12 +78,14 @@ low-level C code must not be instrumente
  	syscall_exit_to_user_mode(regs);
    }

Documentation/core-api/entry.rst +3 -2
-syscall_enter_from_user_mode() first invokes enter_from_user_mode() which
-establishes state in the following order:
+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

Documentation/core-api/entry.rst +0 -0
@@ -99,10 +101,11 @@ that it invokes exit_to_user_mode() whic
    * RCU / Context tracking
    * Lockdep

Documentation/core-api/entry.rst +5 -4
-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

include/linux/entry-common.h +0 -0
@@ -19,7 +19,7 @@
  #endif


 /*
- * SYSCALL_WORK flags handled in syscall_enter_from_user_mode()
+ * SYSCALL_WORK flags handled in syscall_enter_from_user_mode_work() */
 #define SYSCALL_WORK_ENTER (SYSCALL_WORK_SECCOMP | \
  SYSCALL_WORK_SYSCALL_TRACEPOINT | \

include/linux/entry-common.h +0 -0
@@ -205,42 +205,10 @@ do {									\
  	_ret;								\
  })

include/linux/entry-common.h +0 -32
-/**
- * syscall_enter_from_user_mode - Establish state and check and handle work
- *				  before invoking a syscall
- * @regs:	Pointer to currents pt_regs
- * @syscall:	The syscall number
- *
- * Invoked from architecture specific syscall entry code with interrupts
- * disabled. The calling code has to be non-instrumentable. When the
- * function returns all state is correct, interrupts are enabled and the
- * subsequent functions can be instrumented.
- *
- * This is the combination of enter_from_user_mode() and
- * syscall_enter_from_user_mode_work() to be used when there is no
- * architecture specific work to be done between the two.
- *
- * Returns: The original or a modified syscall number. See
- * syscall_enter_from_user_mode_work() for further explanation.
- */
-static __always_inline long syscall_enter_from_user_mode(struct pt_regs *regs, long syscall)
-{
-	long ret;
-
-	enter_from_user_mode(regs);
-
-	instrumentation_begin();
-	local_irq_enable();
-	ret = syscall_enter_from_user_mode_work(regs, syscall);
-	instrumentation_end();
-
-	return ret;
-}
-

 /*
- * If SYSCALL_EMU is set, then the only reason to report is when
- * SINGLESTEP is set (i.e. PTRACE_SYSEMU_SINGLESTEP).  This syscall
- * instruction has been already reported in syscall_enter_from_user_mode().
+ * If SYSCALL_EMU is set, then the only reason to report is when SINGLESTEP is
+ * set (i.e. PTRACE_SYSEMU_SINGLESTEP).  This syscall instruction has been
+ * already reported in syscall_enter_from_user_mode_work().
  */
 static __always_inline bool report_single_step(unsigned long work) {

include/linux/irq-entry-common.h line 52

Quoted 7 lines
include/linux/irq-entry-common.h +1 -3
@@ -49,9 +49,9 @@
   * Defaults to an empty implementation. Can be replaced by architecture
   * specific code.
   *
- * Invoked from syscall_enter_from_user_mode() in the non-instrumentable
- * section. Use __always_inline so the compiler cannot push it out of line
- * and make it instrumentable.
+ * Invoked from enter_from_user_mode_syscall_and_randomize_stack() in the
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Probably syscall_enter_from_user_mode_randomize_stack()? But the reality is it's only ever invoked from enter_from_user_mode(), which is below in the same file (include/linux/irq-entry-common.h).

Granted, that's an always inline function, and it's used by both macros you added (since the second one uses the first one).

Quoted 5 lines
include/linux/irq-entry-common.h +2 -0
+ * non-instrumentable section. Use __always_inline so the compiler cannot push
+ * it out of line and make it instrumentable.
   */
  static __always_inline void arch_enter_from_user_mode(struct pt_regs *regs);

author maintainer
#58 lore raw

Re: [patch 09/18] entry: Remove syscall_enter_from_user_mode()

Quoted 6 lines · Radu Rendec
Quoted 3 lines · Thomas Gleixner

All architecture use either:

    nr = enter_from_user_mode_randomize_stack(regs, nr);

You probably mean syscall_enter_from_user_mode_randomize_stack.

Duh. I obviously got that wrong in a hurry. Thanks for pointing it out!

Quoted 14 lines

include/linux/irq-entry-common.h line 52

Quoted 12 lines

 static __always_inline bool report_single_step(unsigned long work) {

include/linux/irq-entry-common.h +1 -3
@@ -49,9 +49,9 @@
   * Defaults to an empty implementation. Can be replaced by architecture
   * specific code.
   *
- * Invoked from syscall_enter_from_user_mode() in the non-instrumentable
- * section. Use __always_inline so the compiler cannot push it out of line
- * and make it instrumentable.
+ * Invoked from enter_from_user_mode_syscall_and_randomize_stack() in the
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Quoted 3 lines

Probably syscall_enter_from_user_mode_randomize_stack()? But the reality is it's only ever invoked from enter_from_user_mode(), which is below in the same file (include/linux/irq-entry-common.h).

Yes. Indeed.

Reviewed-by on v1 9/18
#59 lore raw

Re: [patch 09/18] entry: Remove syscall_enter_from_user_mode()

In reply to Thomas Gleixner
Quoted 122 lines · Thomas Gleixner

All architecture use either:

    nr = enter_from_user_mode_randomize_stack(regs, nr);

or

    enter_from_user_mode_randomize_stack(regs);
    nr = syscall_enter_from_user_mode_work(regs, nr);

Remove the now unused function.

---
 Documentation/core-api/entry.rst |   17 +++++++++-------
 include/linux/entry-common.h     |   40 +++------------------------------------
 include/linux/irq-entry-common.h |    6 ++---
 3 files changed, 17 insertions(+), 46 deletions(-)
Documentation/core-api/entry.rst +10 -7
@@ -68,7 +68,7 @@ low-level C code must not be instrumente
   noinstr void syscall(struct pt_regs *regs, int nr)
   {
 	arch_syscall_enter(regs);
-	nr = syscall_enter_from_user_mode(regs, nr);
+	nr = syscall_enter_from_user_mode_randomize_stack(regs, nr);
 
 	instrumentation_begin();
 	if (!invoke_syscall(regs, nr) && nr != -1)
@@ -78,12 +78,14 @@ low-level C code must not be instrumente
 	syscall_exit_to_user_mode(regs);
   }
 
-syscall_enter_from_user_mode() first invokes enter_from_user_mode() which
-establishes state in the following order:
+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 +101,11 @@ that it invokes exit_to_user_mode() whic
   * 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
include/linux/entry-common.h +4 -36
@@ -19,7 +19,7 @@
 #endif
 
 /*
- * SYSCALL_WORK flags handled in syscall_enter_from_user_mode()
+ * SYSCALL_WORK flags handled in syscall_enter_from_user_mode_work()
  */
 #define SYSCALL_WORK_ENTER	(SYSCALL_WORK_SECCOMP |			\
 				 SYSCALL_WORK_SYSCALL_TRACEPOINT |	\
@@ -205,42 +205,10 @@ do {									\
 	_ret;								\
 })
 
-/**
- * syscall_enter_from_user_mode - Establish state and check and handle work
- *				  before invoking a syscall
- * @regs:	Pointer to currents pt_regs
- * @syscall:	The syscall number
- *
- * Invoked from architecture specific syscall entry code with interrupts
- * disabled. The calling code has to be non-instrumentable. When the
- * function returns all state is correct, interrupts are enabled and the
- * subsequent functions can be instrumented.
- *
- * This is the combination of enter_from_user_mode() and
- * syscall_enter_from_user_mode_work() to be used when there is no
- * architecture specific work to be done between the two.
- *
- * Returns: The original or a modified syscall number. See
- * syscall_enter_from_user_mode_work() for further explanation.
- */
-static __always_inline long syscall_enter_from_user_mode(struct pt_regs *regs, long syscall)
-{
-	long ret;
-
-	enter_from_user_mode(regs);
-
-	instrumentation_begin();
-	local_irq_enable();
-	ret = syscall_enter_from_user_mode_work(regs, syscall);
-	instrumentation_end();
-
-	return ret;
-}
-
 /*
- * If SYSCALL_EMU is set, then the only reason to report is when
- * SINGLESTEP is set (i.e. PTRACE_SYSEMU_SINGLESTEP).  This syscall
- * instruction has been already reported in syscall_enter_from_user_mode().
+ * If SYSCALL_EMU is set, then the only reason to report is when SINGLESTEP is
+ * set (i.e. PTRACE_SYSEMU_SINGLESTEP).  This syscall instruction has been
+ * already reported in syscall_enter_from_user_mode_work().
  */
 static __always_inline bool report_single_step(unsigned long work)
 {

include/linux/irq-entry-common.h line 54

Quoted 9 lines
include/linux/irq-entry-common.h +3 -3
@@ -49,9 +49,9 @@
  * Defaults to an empty implementation. Can be replaced by architecture
  * specific code.
  *
- * Invoked from syscall_enter_from_user_mode() in the non-instrumentable
- * section. Use __always_inline so the compiler cannot push it out of line
- * and make it instrumentable.
+ * Invoked from enter_from_user_mode_syscall_and_randomize_stack() in the
+ * non-instrumentable section. Use __always_inline so the compiler cannot push
+ * it out of line and make it instrumentable.
Quoted 4 lines
include/linux/irq-entry-common.h +0 -0
  */
 static __always_inline void arch_enter_from_user_mode(struct pt_regs *regs);
 
Reviewed-by on v1 9/18
#60 lore raw

Re: [patch 09/18] entry: Remove syscall_enter_from_user_mode()

In reply to Thomas Gleixner
Quoted 125 lines · Thomas Gleixner

All architecture use either:

    nr = enter_from_user_mode_randomize_stack(regs, nr);

or

    enter_from_user_mode_randomize_stack(regs);
    nr = syscall_enter_from_user_mode_work(regs, nr);

Remove the now unused function.

---
 Documentation/core-api/entry.rst |   17 +++++++++-------
 include/linux/entry-common.h     |   40 +++------------------------------------
 include/linux/irq-entry-common.h |    6 ++---
 3 files changed, 17 insertions(+), 46 deletions(-)
Documentation/core-api/entry.rst +10 -7
@@ -68,7 +68,7 @@ low-level C code must not be instrumente
   noinstr void syscall(struct pt_regs *regs, int nr)
   {
 	arch_syscall_enter(regs);
-	nr = syscall_enter_from_user_mode(regs, nr);
+	nr = syscall_enter_from_user_mode_randomize_stack(regs, nr);
 
 	instrumentation_begin();
 	if (!invoke_syscall(regs, nr) && nr != -1)
@@ -78,12 +78,14 @@ low-level C code must not be instrumente
 	syscall_exit_to_user_mode(regs);
   }
 
-syscall_enter_from_user_mode() first invokes enter_from_user_mode() which
-establishes state in the following order:
+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 +101,11 @@ that it invokes exit_to_user_mode() whic
   * 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
include/linux/entry-common.h +4 -36
@@ -19,7 +19,7 @@
 #endif
 
 /*
- * SYSCALL_WORK flags handled in syscall_enter_from_user_mode()
+ * SYSCALL_WORK flags handled in syscall_enter_from_user_mode_work()
  */
 #define SYSCALL_WORK_ENTER	(SYSCALL_WORK_SECCOMP |			\
 				 SYSCALL_WORK_SYSCALL_TRACEPOINT |	\
@@ -205,42 +205,10 @@ do {									\
 	_ret;								\
 })
 
-/**
- * syscall_enter_from_user_mode - Establish state and check and handle work
- *				  before invoking a syscall
- * @regs:	Pointer to currents pt_regs
- * @syscall:	The syscall number
- *
- * Invoked from architecture specific syscall entry code with interrupts
- * disabled. The calling code has to be non-instrumentable. When the
- * function returns all state is correct, interrupts are enabled and the
- * subsequent functions can be instrumented.
- *
- * This is the combination of enter_from_user_mode() and
- * syscall_enter_from_user_mode_work() to be used when there is no
- * architecture specific work to be done between the two.
- *
- * Returns: The original or a modified syscall number. See
- * syscall_enter_from_user_mode_work() for further explanation.
- */
-static __always_inline long syscall_enter_from_user_mode(struct pt_regs *regs, long syscall)
-{
-	long ret;
-
-	enter_from_user_mode(regs);
-
-	instrumentation_begin();
-	local_irq_enable();
-	ret = syscall_enter_from_user_mode_work(regs, syscall);
-	instrumentation_end();
-
-	return ret;
-}
-
 /*
- * If SYSCALL_EMU is set, then the only reason to report is when
- * SINGLESTEP is set (i.e. PTRACE_SYSEMU_SINGLESTEP).  This syscall
- * instruction has been already reported in syscall_enter_from_user_mode().
+ * If SYSCALL_EMU is set, then the only reason to report is when SINGLESTEP is
+ * set (i.e. PTRACE_SYSEMU_SINGLESTEP).  This syscall instruction has been
+ * already reported in syscall_enter_from_user_mode_work().
  */
 static __always_inline bool report_single_step(unsigned long work)
 {
include/linux/irq-entry-common.h +0 -0
@@ -49,9 +49,9 @@
  * Defaults to an empty implementation. Can be replaced by architecture
  * specific code.

include/linux/irq-entry-common.h line 57

Quoted 10 lines
include/linux/irq-entry-common.h +3 -3
  *
- * Invoked from syscall_enter_from_user_mode() in the non-instrumentable
- * section. Use __always_inline so the compiler cannot push it out of line
- * and make it instrumentable.
+ * Invoked from enter_from_user_mode_syscall_and_randomize_stack() in the
+ * non-instrumentable section. Use __always_inline so the compiler cannot push
+ * it out of line and make it instrumentable.
  */
 static __always_inline void arch_enter_from_user_mode(struct pt_regs *regs);
 
#61 lore raw

[tip: core/entry] entry: Remove syscall_enter_from_user_mode()

In reply to Thomas Gleixner
The following commit has been merged into the core/entry branch of tip:

The following commit has been merged into the core/entry branch of tip:

Commit-ID:     bad2a27ba8c4a6bd2c47e598898d9dbd0f98511f
Gitweb:        https://git.kernel.org/tip/bad2a27ba8c4a6bd2c47e598898d9dbd0f98511f
Author:        Thomas Gleixner <[email protected]>
AuthorDate:    Tue, 07 Jul 2026 21:06:32 +02:00
Committer:     Thomas Gleixner <[email protected]>
CommitterDate: Sun, 12 Jul 2026 12:38:01 +02:00

entry: Remove syscall_enter_from_user_mode()

All architecture use either:

    nr = syscall_enter_from_user_mode_randomize_stack(regs, nr);

or

    enter_from_user_mode_randomize_stack(regs);
    nr = syscall_enter_from_user_mode_work(regs, nr);

Remove the now unused function.

---
 Documentation/core-api/entry.rst | 17 +++++++------
 include/linux/entry-common.h     | 40 +++----------------------------
 include/linux/irq-entry-common.h |  6 ++---
 3 files changed, 17 insertions(+), 46 deletions(-)
Documentation/core-api/entry.rst +10 -7
index 71d8eed..44e9608 100644
@@ -68,7 +68,7 @@ invoked from low-level assembly code looks like this:
   noinstr void syscall(struct pt_regs *regs, int nr)
   {
 	arch_syscall_enter(regs);
-	nr = syscall_enter_from_user_mode(regs, nr);
+	nr = syscall_enter_from_user_mode_randomize_stack(regs, nr);
 
 	instrumentation_begin();
 	if (!invoke_syscall(regs, nr) && nr != -1)
@@ -78,12 +78,14 @@ invoked from low-level assembly code looks like this:
 	syscall_exit_to_user_mode(regs);
   }
 
-syscall_enter_from_user_mode() first invokes enter_from_user_mode() which
-establishes state in the following order:
+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 +101,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
include/linux/entry-common.h +4 -36
index 166b1ed..c0f6464 100644
@@ -20,7 +20,7 @@
 #endif
 
 /*
- * SYSCALL_WORK flags handled in syscall_enter_from_user_mode()
+ * SYSCALL_WORK flags handled in syscall_enter_from_user_mode_work()
  */
 #define SYSCALL_WORK_ENTER	(SYSCALL_WORK_SECCOMP |			\
 				 SYSCALL_WORK_SYSCALL_TRACEPOINT |	\
@@ -205,42 +205,10 @@ do {									\
 	_ret;								\
 })
 
-/**
- * syscall_enter_from_user_mode - Establish state and check and handle work
- *				  before invoking a syscall
- * @regs:	Pointer to currents pt_regs
- * @syscall:	The syscall number
- *
- * Invoked from architecture specific syscall entry code with interrupts
- * disabled. The calling code has to be non-instrumentable. When the
- * function returns all state is correct, interrupts are enabled and the
- * subsequent functions can be instrumented.
- *
- * This is the combination of enter_from_user_mode() and
- * syscall_enter_from_user_mode_work() to be used when there is no
- * architecture specific work to be done between the two.
- *
- * Returns: The original or a modified syscall number. See
- * syscall_enter_from_user_mode_work() for further explanation.
- */
-static __always_inline long syscall_enter_from_user_mode(struct pt_regs *regs, long syscall)
-{
-	long ret;
-
-	enter_from_user_mode(regs);
-
-	instrumentation_begin();
-	local_irq_enable();
-	ret = syscall_enter_from_user_mode_work(regs, syscall);
-	instrumentation_end();
-
-	return ret;
-}
-
 /*
- * If SYSCALL_EMU is set, then the only reason to report is when
- * SINGLESTEP is set (i.e. PTRACE_SYSEMU_SINGLESTEP).  This syscall
- * instruction has been already reported in syscall_enter_from_user_mode().
+ * If SYSCALL_EMU is set, then the only reason to report is when SINGLESTEP is
+ * set (i.e. PTRACE_SYSEMU_SINGLESTEP).  This syscall instruction has been
+ * already reported in syscall_enter_from_user_mode_work().
  */
 static __always_inline bool report_single_step(unsigned long work)
 {
include/linux/irq-entry-common.h +3 -3
index 1fabf0f..0bb6c03 100644
@@ -49,9 +49,9 @@
  * Defaults to an empty implementation. Can be replaced by architecture
  * specific code.
  *
- * Invoked from syscall_enter_from_user_mode() in the non-instrumentable
- * section. Use __always_inline so the compiler cannot push it out of line
- * and make it instrumentable.
+ * Invoked from enter_from_user_mode() in the non-instrumentable section. Use
+ * __always_inline so the compiler cannot push it out of line and make it
+ * instrumentable.
  */
 static __always_inline void arch_enter_from_user_mode(struct pt_regs *regs);
 
author maintainer
#62 lore raw

PATCH 10/18 entry: Use syscall number instead of rereading it

In reply to Thomas Gleixner

rseq_syscall_enter_work() is invoked before the syscall number can be modified. So there is no point in rereading it from pt_regs.

---
 include/linux/entry-common.h |    9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)
include/linux/entry-common.h +5 -4
@@ -70,9 +70,10 @@ static inline void syscall_enter_audit(s
 	}
 }
 
-static __always_inline long syscall_trace_enter(struct pt_regs *regs, unsigned long work)
+static __always_inline long syscall_trace_enter(struct pt_regs *regs, unsigned long work,
+						long syscall)
 {
-	long syscall, ret = 0;
+	long ret = 0;
 
 	/*
 	 * Handle Syscall User Dispatch.  This must comes first, since
@@ -90,7 +91,7 @@ static __always_inline long syscall_trac
 	 * through hrtimer_interrupt().
 	 */
 	if (work & SYSCALL_WORK_SYSCALL_RSEQ_SLICE)
-		rseq_syscall_enter_work(syscall_get_nr(current, regs));
+		rseq_syscall_enter_work(syscall);
 
 	/* Handle ptrace */
 	if (work & (SYSCALL_WORK_SYSCALL_TRACE | SYSCALL_WORK_SYSCALL_EMU)) {
@@ -145,7 +146,7 @@ static __always_inline long syscall_ente
 	unsigned long work = READ_ONCE(current_thread_info()->syscall_work);
 
 	if (work & SYSCALL_WORK_ENTER)
-		syscall = syscall_trace_enter(regs, work);
+		syscall = syscall_trace_enter(regs, work, syscall);
 
 	return syscall;
 }
Reviewed-by on v1 10/18
#63 lore raw

Re: [patch 10/18] entry: Use syscall number instead of rereading it

Quoted 38 lines · Thomas Gleixner

rseq_syscall_enter_work() is invoked before the syscall number can be modified. So there is no point in rereading it from pt_regs.

---
 include/linux/entry-common.h |    9 +++++----

 1 file changed, 5 insertions(+), 4 deletions(-)
include/linux/entry-common.h +0 -0
@@ -70,9 +70,10 @@ static inline void syscall_enter_audit(s
  	}
  }

include/linux/entry-common.h +2 -1
-static __always_inline long syscall_trace_enter(struct pt_regs *regs, unsigned long work)
+static __always_inline long syscall_trace_enter(struct pt_regs *regs, unsigned long work,
+						long syscall)

 {

include/linux/entry-common.h +1 -1
-	long syscall, ret = 0;
+	long ret = 0;


  /*
  * Handle Syscall User Dispatch.  This must comes first, since

include/linux/entry-common.h +1 -1
@@ -90,7 +91,7 @@ static __always_inline long syscall_trac
  	 * through hrtimer_interrupt().
  	 */
  	if (work & SYSCALL_WORK_SYSCALL_RSEQ_SLICE)
-		rseq_syscall_enter_work(syscall_get_nr(current, regs));
+		rseq_syscall_enter_work(syscall);


  /* Handle ptrace */
  if (work & (SYSCALL_WORK_SYSCALL_TRACE | SYSCALL_WORK_SYSCALL_EMU)) {

include/linux/entry-common.h +0 -0
@@ -145,7 +146,7 @@ static __always_inline long syscall_ente
  	unsigned long work = READ_ONCE(current_thread_info()->syscall_work);


  if (work & SYSCALL_WORK_ENTER)

include/linux/entry-common.h +1 -1
-		syscall = syscall_trace_enter(regs, work);
+		syscall = syscall_trace_enter(regs, work, syscall);
Quoted 3 lines


  return syscall;
 }

Reviewed-by on v1 10/18
#64 lore raw

Re: [patch 10/18] entry: Use syscall number instead of rereading it

In reply to Thomas Gleixner
Quoted 33 lines · Thomas Gleixner

rseq_syscall_enter_work() is invoked before the syscall number can be modified. So there is no point in rereading it from pt_regs.

---
 include/linux/entry-common.h |    9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)
include/linux/entry-common.h +4 -3
@@ -70,9 +70,10 @@ static inline void syscall_enter_audit(s
 	}
 }
 
-static __always_inline long syscall_trace_enter(struct pt_regs *regs, unsigned long work)
+static __always_inline long syscall_trace_enter(struct pt_regs *regs, unsigned long work,
+						long syscall)
 {
-	long syscall, ret = 0;
+	long ret = 0;
 
 	/*
 	 * Handle Syscall User Dispatch.  This must comes first, since
@@ -90,7 +91,7 @@ static __always_inline long syscall_trac
 	 * through hrtimer_interrupt().
 	 */
 	if (work & SYSCALL_WORK_SYSCALL_RSEQ_SLICE)
-		rseq_syscall_enter_work(syscall_get_nr(current, regs));
+		rseq_syscall_enter_work(syscall);
 
 	/* Handle ptrace */
 	if (work & (SYSCALL_WORK_SYSCALL_TRACE | SYSCALL_WORK_SYSCALL_EMU)) {

include/linux/entry-common.h static __always_inline long syscall_ente · line 149

Quoted 5 lines
include/linux/entry-common.h +1 -1
@@ -145,7 +146,7 @@ static __always_inline long syscall_ente
 	unsigned long work = READ_ONCE(current_thread_info()->syscall_work);
 
 	if (work & SYSCALL_WORK_ENTER)
-		syscall = syscall_trace_enter(regs, work);
+		syscall = syscall_trace_enter(regs, work, syscall);
Quoted 4 lines
include/linux/entry-common.h +0 -0
 	return syscall;
 }
 
#66 lore raw

Re: [patch 10/18] entry: Use syscall number instead of rereading it

Quoted 8 lines · Philippe Mathieu-Daudé
Quoted 7 lines · Thomas Gleixner

rseq_syscall_enter_work() is invoked before the syscall number can be modified. So there is no point in rereading it from pt_regs.

---
  include/linux/entry-common.h |    9 +++++----

  1 file changed, 5 insertions(+), 4 deletions(-)
Reviewed-by on v1 10/18
#67 lore raw

Re: [patch 10/18] entry: Use syscall number instead of rereading it

In reply to Thomas Gleixner
Quoted 34 lines · Thomas Gleixner

rseq_syscall_enter_work() is invoked before the syscall number can be modified. So there is no point in rereading it from pt_regs.

---
 include/linux/entry-common.h |    9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)
include/linux/entry-common.h +4 -3
@@ -70,9 +70,10 @@ static inline void syscall_enter_audit(s
 	}
 }
 
-static __always_inline long syscall_trace_enter(struct pt_regs *regs, unsigned long work)
+static __always_inline long syscall_trace_enter(struct pt_regs *regs, unsigned long work,
+						long syscall)
 {
-	long syscall, ret = 0;
+	long ret = 0;
 
 	/*
 	 * Handle Syscall User Dispatch.  This must comes first, since
@@ -90,7 +91,7 @@ static __always_inline long syscall_trac
 	 * through hrtimer_interrupt().
 	 */
 	if (work & SYSCALL_WORK_SYSCALL_RSEQ_SLICE)
-		rseq_syscall_enter_work(syscall_get_nr(current, regs));
+		rseq_syscall_enter_work(syscall);
 
 	/* Handle ptrace */
 	if (work & (SYSCALL_WORK_SYSCALL_TRACE | SYSCALL_WORK_SYSCALL_EMU)) {

include/linux/entry-common.h static __always_inline long syscall_ente · line 152

Quoted 8 lines
include/linux/entry-common.h +1 -1
@@ -145,7 +146,7 @@ static __always_inline long syscall_ente
 	unsigned long work = READ_ONCE(current_thread_info()->syscall_work);
 
 	if (work & SYSCALL_WORK_ENTER)
-		syscall = syscall_trace_enter(regs, work);
+		syscall = syscall_trace_enter(regs, work, syscall);
 
 	return syscall;
 }
#68 lore raw

[tip: core/entry] entry: Use syscall number instead of rereading it

In reply to Thomas Gleixner
The following commit has been merged into the core/entry branch of tip:

The following commit has been merged into the core/entry branch of tip:

Commit-ID:     8af25d0a2e465f3cb73c47c605fddd1664ee79b2
Gitweb:        https://git.kernel.org/tip/8af25d0a2e465f3cb73c47c605fddd1664ee79b2
Author:        Thomas Gleixner <[email protected]>
AuthorDate:    Tue, 07 Jul 2026 21:06:36 +02:00
Committer:     Thomas Gleixner <[email protected]>
CommitterDate: Sun, 12 Jul 2026 12:38:01 +02:00

entry: Use syscall number instead of rereading it

rseq_syscall_enter_work() is invoked before the syscall number can be modified. So there is no point in rereading it from pt_regs.

---
 include/linux/entry-common.h |  9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)
include/linux/entry-common.h +5 -4
index c0f6464..c837352 100644
@@ -70,9 +70,10 @@ static inline void syscall_enter_audit(struct pt_regs *regs, long syscall)
 	}
 }
 
-static __always_inline long syscall_trace_enter(struct pt_regs *regs, unsigned long work)
+static __always_inline long syscall_trace_enter(struct pt_regs *regs, unsigned long work,
+						long syscall)
 {
-	long syscall, ret = 0;
+	long ret = 0;
 
 	/*
 	 * Handle Syscall User Dispatch.  This must comes first, since
@@ -90,7 +91,7 @@ static __always_inline long syscall_trace_enter(struct pt_regs *regs, unsigned l
 	 * through hrtimer_interrupt().
 	 */
 	if (work & SYSCALL_WORK_SYSCALL_RSEQ_SLICE)
-		rseq_syscall_enter_work(syscall_get_nr(current, regs));
+		rseq_syscall_enter_work(syscall);
 
 	/* Handle ptrace */
 	if (work & (SYSCALL_WORK_SYSCALL_TRACE | SYSCALL_WORK_SYSCALL_EMU)) {
@@ -145,7 +146,7 @@ static __always_inline long syscall_enter_from_user_mode_work(struct pt_regs *re
 	unsigned long work = READ_ONCE(current_thread_info()->syscall_work);
 
 	if (work & SYSCALL_WORK_ENTER)
-		syscall = syscall_trace_enter(regs, work);
+		syscall = syscall_trace_enter(regs, work, syscall);
 
 	return syscall;
 }
author maintainer
#69 lore raw

PATCH 11/18 seccomp, treewide: Rename and convert __secure_computing() to return boolean

In reply to Thomas Gleixner

From: Jinjie Ruan <[email protected]>

The return value of __secure_computing() currently uses 0 to indicate that a system call should be allowed, and -1 to indicate that it should be blocked/killed. This 0/-1 pattern is non-intuitive for a security check function and makes the control flow at the call sites less readable.

Furthermore, any potential future changes to these return values would require a high-risk, error-prone audit of all its users across different architectures.

Sanitize this logic by converting the return type of __secure_computing() to a proper boolean, where 'true' explicitly means 'allow' and 'false' means 'fail/deny'.

Update all the two dozen or so call sites across the tree to align with this new boolean semantic. No functional changes are intended, as the callers still return -1 to the lower-level assembly entry code upon seccomp denial.

Rename the function to __seccomp_permit_syscall() so that the purpose is entirely clear.

[ tglx: Rename the function ]

---
 arch/alpha/kernel/ptrace.c            |    2 -
 arch/arm/kernel/ptrace.c              |    2 -
 arch/arm64/kernel/ptrace.c            |    2 -
 arch/csky/kernel/ptrace.c             |    2 -
 arch/m68k/kernel/ptrace.c             |    2 -
 arch/mips/kernel/ptrace.c             |    2 -
 arch/parisc/kernel/ptrace.c           |    2 -
 arch/sh/kernel/ptrace_32.c            |    2 -
 arch/um/kernel/skas/syscall.c         |    2 -
 arch/x86/entry/vsyscall/vsyscall_64.c |   14 ++++++-------
 arch/xtensa/kernel/ptrace.c           |    3 --
 include/linux/entry-common.h          |    9 +++-----
 include/linux/seccomp.h               |   12 +++++------
 kernel/seccomp.c                      |   35 +++++++++++++++++-----------------
 14 files changed, 45 insertions(+), 46 deletions(-)
arch/alpha/kernel/ptrace.c +1 -1
@@ -387,7 +387,7 @@ asmlinkage unsigned long syscall_trace_e
 	 * 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);
arch/arm/kernel/ptrace.c +1 -1
@@ -855,7 +855,7 @@ asmlinkage int syscall_trace_enter(struc
 
 	/* 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 */
arch/arm64/kernel/ptrace.c +1 -1
@@ -2420,7 +2420,7 @@ int syscall_trace_enter(struct pt_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))
arch/csky/kernel/ptrace.c +1 -1
@@ -323,7 +323,7 @@ asmlinkage int syscall_trace_enter(struc
 		if (ptrace_report_syscall_entry(regs))
 			return -1;
 
-	if (secure_computing() == -1)
+	if (!seccomp_permit_syscall())
 		return -1;
 
 	if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
arch/m68k/kernel/ptrace.c +1 -1
@@ -281,7 +281,7 @@ asmlinkage int syscall_trace_enter(void)
 	if (test_thread_flag(TIF_SYSCALL_TRACE))
 		ret = ptrace_report_syscall_entry(task_pt_regs(current));
 
-	if (secure_computing() == -1)
+	if (!seccomp_permit_syscall())
 		return -1;
 
 	return ret;
arch/mips/kernel/ptrace.c +1 -1
@@ -1328,7 +1328,7 @@ asmlinkage long syscall_trace_enter(stru
 			return -1;
 	}
 
-	if (secure_computing())
+	if (!seccomp_permit_syscall())
 		return -1;
 
 	if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
arch/parisc/kernel/ptrace.c +1 -1
@@ -351,7 +351,7 @@ long do_syscall_trace_enter(struct pt_re
 	}
 
 	/* Do the secure computing check after ptrace. */
-	if (secure_computing() == -1)
+	if (!seccomp_permit_syscall())
 		return -1;
 
 #ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS
arch/sh/kernel/ptrace_32.c +1 -1
@@ -460,7 +460,7 @@ asmlinkage long do_syscall_trace_enter(s
 		return -1;
 	}
 
-	if (secure_computing() == -1)
+	if (!seccomp_permit_syscall())
 		return -1;
 
 	if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
arch/um/kernel/skas/syscall.c +1 -1
@@ -27,7 +27,7 @@ void handle_syscall(struct uml_pt_regs *
 		goto out;
 
 	/* Do the seccomp check after ptrace; failures should be fast. */
-	if (secure_computing() == -1)
+	if (!seccomp_permit_syscall())
 		goto out;
 
 	syscall = UPT_SYSCALL_NR(r);
arch/x86/entry/vsyscall/vsyscall_64.c +7 -7
@@ -118,10 +118,10 @@ static bool write_ok_or_segv(unsigned lo
 
 static bool __emulate_vsyscall(struct pt_regs *regs, unsigned long address)
 {
-	unsigned long caller;
-	int vsyscall_nr, syscall_nr, tmp;
+	unsigned long caller, orig_dx;
+	int vsyscall_nr, syscall_nr;
+	bool skip;
 	long ret;
-	unsigned long orig_dx;
 
 	/* Confirm that the fault happened in 64-bit user mode */
 	if (!user_64bit_mode(regs))
@@ -197,16 +197,16 @@ static bool __emulate_vsyscall(struct pt
 	 */
 	regs->orig_ax = syscall_nr;
 	regs->ax = -ENOSYS;
-	tmp = secure_computing();
-	if ((!tmp && regs->orig_ax != syscall_nr) || regs->ip != address) {
+	skip = !seccomp_permit_syscall();
+	if ((!skip && regs->orig_ax != syscall_nr) || regs->ip != address) {
 		warn_bad_vsyscall(KERN_DEBUG, regs,
 				  "seccomp tried to change syscall nr or ip");
 		force_exit_sig(SIGSYS);
 		return true;
 	}
 	regs->orig_ax = -1;
-	if (tmp)
-		goto do_ret;  /* skip requested */
+	if (skip)
+		goto do_ret;
 
 	/*
 	 * With a real vsyscall, page faults cause SIGSEGV.
arch/xtensa/kernel/ptrace.c +1 -2
@@ -553,8 +553,7 @@ int do_syscall_trace_enter(struct pt_reg
 		return 0;
 	}
 
-	if (regs->syscall == NO_SYSCALL ||
-	    secure_computing() == -1) {
+	if (regs->syscall == NO_SYSCALL || !seccomp_permit_syscall()) {
 		do_syscall_trace_leave(regs);
 		return 0;
 	}
include/linux/entry-common.h +4 -5
@@ -102,9 +102,8 @@ static __always_inline long syscall_trac
 
 	/* Do seccomp after ptrace, to catch any tracer changes. */
 	if (work & SYSCALL_WORK_SECCOMP) {
-		ret = __secure_computing();
-		if (ret == -1L)
-			return ret;
+		if (!__seccomp_permit_syscall())
+			return -1L;
 	}
 
 	/* Either of the above might have changed the syscall number */
@@ -115,7 +114,7 @@ static __always_inline long syscall_trac
 
 	syscall_enter_audit(regs, syscall);
 
-	return ret ? : syscall;
+	return syscall;
 }
 
 /**
@@ -138,7 +137,7 @@ static __always_inline long syscall_trac
  * It handles the following work items:
  *
  *  1) syscall_work flag dependent invocations of
- *     ptrace_report_syscall_entry(), __secure_computing(), trace_sys_enter()
+ *     ptrace_report_syscall_entry(), __seccomp_permit_syscall(), trace_sys_enter()
  *  2) Invocation of audit_syscall_entry()
  */
 static __always_inline long syscall_enter_from_user_mode_work(struct pt_regs *regs, long syscall)
include/linux/seccomp.h +6 -6
@@ -22,14 +22,14 @@
 #include <linux/atomic.h>
 #include <asm/seccomp.h>
 
-extern int __secure_computing(void);
+extern bool __seccomp_permit_syscall(void);
 
 #ifdef CONFIG_HAVE_ARCH_SECCOMP_FILTER
-static inline int secure_computing(void)
+static __always_inline bool seccomp_permit_syscall(void)
 {
 	if (unlikely(test_syscall_work(SECCOMP)))
-		return  __secure_computing();
-	return 0;
+		return  __seccomp_permit_syscall();
+	return true;
 }
 #else
 extern void secure_computing_strict(int this_syscall);
@@ -50,11 +50,11 @@ static inline int seccomp_mode(struct se
 struct seccomp_data;
 
 #ifdef CONFIG_HAVE_ARCH_SECCOMP_FILTER
-static inline int secure_computing(void) { return 0; }
+static inline bool seccomp_permit_syscall(void) { return true; }
 #else
 static inline void secure_computing_strict(int this_syscall) { return; }
 #endif
-static inline int __secure_computing(void) { return 0; }
+static inline bool __seccomp_permit_syscall(void) { return true; }
 
 static inline long prctl_get_seccomp(void)
 {
kernel/seccomp.c +18 -17
@@ -1100,12 +1100,13 @@ void secure_computing_strict(int this_sy
 	else
 		BUG();
 }
-int __secure_computing(void)
+
+bool __seccomp_permit_syscall(void)
 {
 	int this_syscall = syscall_get_nr(current, current_pt_regs());
 
 	secure_computing_strict(this_syscall);
-	return 0;
+	return true;
 }
 #else
 
@@ -1256,7 +1257,7 @@ static int seccomp_do_user_notification(
 	return -1;
 }
 
-static int __seccomp_filter(int this_syscall, const bool recheck_after_trace)
+static bool __seccomp_filter(int this_syscall, const bool recheck_after_trace)
 {
 	u32 filter_ret, action;
 	struct seccomp_data sd;
@@ -1294,7 +1295,7 @@ static int __seccomp_filter(int this_sys
 	case SECCOMP_RET_TRACE:
 		/* We've been put in this state by the ptracer already. */
 		if (recheck_after_trace)
-			return 0;
+			return true;
 
 		/* ENOSYS these calls if there is no tracer attached. */
 		if (!ptrace_event_enabled(current, PTRACE_EVENT_SECCOMP)) {
@@ -1330,19 +1331,19 @@ static int __seccomp_filter(int this_sys
 		 * a skip would have already been reported.
 		 */
 		if (__seccomp_filter(this_syscall, true))
-			return -1;
+			return false;
 
-		return 0;
+		return true;
 
 	case SECCOMP_RET_USER_NOTIF:
 		if (seccomp_do_user_notification(this_syscall, match, &sd))
 			goto skip;
 
-		return 0;
+		return true;
 
 	case SECCOMP_RET_LOG:
 		seccomp_log(this_syscall, 0, action, true);
-		return 0;
+		return true;
 
 	case SECCOMP_RET_ALLOW:
 		/*
@@ -1350,7 +1351,7 @@ static int __seccomp_filter(int this_sys
 		 * this action since SECCOMP_RET_ALLOW is the starting
 		 * state in seccomp_run_filters().
 		 */
-		return 0;
+		return true;
 
 	case SECCOMP_RET_KILL_THREAD:
 	case SECCOMP_RET_KILL_PROCESS:
@@ -1367,46 +1368,46 @@ static int __seccomp_filter(int this_sys
 		} else {
 			do_exit(SIGSYS);
 		}
-		return -1; /* skip the syscall go directly to signal handling */
+		return false; /* skip the syscall go directly to signal handling */
 	}
 
 	unreachable();
 
 skip:
 	seccomp_log(this_syscall, 0, action, match ? match->log : false);
-	return -1;
+	return false;
 }
 #else
-static int __seccomp_filter(int this_syscall, const bool recheck_after_trace)
+static bool __seccomp_filter(int this_syscall, const bool recheck_after_trace)
 {
 	BUG();
 
-	return -1;
+	return false;
 }
 #endif
 
-int __secure_computing(void)
+bool __seccomp_permit_syscall(void)
 {
 	int mode = current->seccomp.mode;
 	int this_syscall;
 
 	if (IS_ENABLED(CONFIG_CHECKPOINT_RESTORE) &&
 	    unlikely(current->ptrace & PT_SUSPEND_SECCOMP))
-		return 0;
+		return true;
 
 	this_syscall = syscall_get_nr(current, current_pt_regs());
 
 	switch (mode) {
 	case SECCOMP_MODE_STRICT:
 		__secure_computing_strict(this_syscall);  /* may call do_exit */
-		return 0;
+		return true;
 	case SECCOMP_MODE_FILTER:
 		return __seccomp_filter(this_syscall, false);
 	/* Surviving SECCOMP_RET_KILL_* must be proactively impossible. */
 	case SECCOMP_MODE_DEAD:
 		WARN_ON_ONCE(1);
 		do_exit(SIGKILL);
-		return -1;
+		return false;
 	default:
 		BUG();
 	}
Reviewed-by on v1 11/18
#70 lore raw

Re: [patch 11/18] seccomp, treewide: Rename and convert __secure_computing() to return boolean

Quoted 50 lines · Thomas Gleixner

From: Jinjie Ruan <[email protected]>

The return value of __secure_computing() currently uses 0 to indicate that a system call should be allowed, and -1 to indicate that it should be blocked/killed. This 0/-1 pattern is non-intuitive for a security check function and makes the control flow at the call sites less readable.

Furthermore, any potential future changes to these return values would require a high-risk, error-prone audit of all its users across different architectures.

Sanitize this logic by converting the return type of __secure_computing() to a proper boolean, where 'true' explicitly means 'allow' and 'false' means 'fail/deny'.

Update all the two dozen or so call sites across the tree to align with this new boolean semantic. No functional changes are intended, as the callers still return -1 to the lower-level assembly entry code upon seccomp denial.

Rename the function to __seccomp_permit_syscall() so that the purpose is entirely clear.

[ tglx: Rename the function ]

Quoted 16 lines
---
 arch/alpha/kernel/ptrace.c            |    2 -
 arch/arm/kernel/ptrace.c              |    2 -
 arch/arm64/kernel/ptrace.c            |    2 -
 arch/csky/kernel/ptrace.c             |    2 -
 arch/m68k/kernel/ptrace.c             |    2 -
 arch/mips/kernel/ptrace.c             |    2 -
 arch/parisc/kernel/ptrace.c           |    2 -
 arch/sh/kernel/ptrace_32.c            |    2 -
 arch/um/kernel/skas/syscall.c         |    2 -
 arch/x86/entry/vsyscall/vsyscall_64.c |   14 ++++++-------
 arch/xtensa/kernel/ptrace.c           |    3 --
 include/linux/entry-common.h          |    9 +++-----
 include/linux/seccomp.h               |   12 +++++------
 kernel/seccomp.c                      |   35 +++++++++++++++++-----------------
 14 files changed, 45 insertions(+), 46 deletions(-)

As Ada pointed out, the description of secure_computing in arch/Kconfig need to be updated, a possible suggestion:

arch/Kconfig +0 -2
@@ -636,8 +636,8 @@ config HAVE_ARCH_SECCOMP_FILTER
          - syscall_rollback()
          - 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
+ - seccomp_permits_syscall is called from a ptrace_event()-safe
context
+ - seccomp_permits_syscall return value is checked and if false

Link:
https://lore.kernel.org/all/[email protected]/

Quoted 11 lines
arch/alpha/kernel/ptrace.c +1 -1
@@ -387,7 +387,7 @@ asmlinkage unsigned long syscall_trace_e
 	 * 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);

[...]

Quoted 15 lines
arch/alpha/kernel/ptrace.c +2 -2
-static int __seccomp_filter(int this_syscall, const bool recheck_after_trace)
+static bool __seccomp_filter(int this_syscall, const bool recheck_after_trace)
 {
 	u32 filter_ret, action;
 	struct seccomp_data sd;
@@ -1294,7 +1295,7 @@ static int __seccomp_filter(int this_sys
 	case SECCOMP_RET_TRACE:
 		/* We've been put in this state by the ptracer already. */
 		if (recheck_after_trace)
-			return 0;
+			return true;
 
 		/* ENOSYS these calls if there is no tracer attached. */
 		if (!ptrace_event_enabled(current, PTRACE_EVENT_SECCOMP)) {

arch/alpha/kernel/ptrace.c static int __seccomp_filter(int this_sys · line 1334

Quoted 5 lines
arch/alpha/kernel/ptrace.c +1 -1
@@ -1330,19 +1331,19 @@ static int __seccomp_filter(int this_sys
 		 * a skip would have already been reported.
 		 */
 		if (__seccomp_filter(this_syscall, true))
-			return -1;
+			return false;

The return value of __seccomp_filter is checked in the wrong way, check -1 should be replaced with check false, maybe:

- if (__seccomp_filter(this_syscall, true))
- return -1;
+ if (!__seccomp_filter(this_syscall, true))
+ return false;

otherwise,

LGTM

Quoted 83 lines
arch/alpha/kernel/ptrace.c +12 -12
-		return 0;
+		return true;
 
 	case SECCOMP_RET_USER_NOTIF:
 		if (seccomp_do_user_notification(this_syscall, match, &sd))
 			goto skip;
 
-		return 0;
+		return true;
 
 	case SECCOMP_RET_LOG:
 		seccomp_log(this_syscall, 0, action, true);
-		return 0;
+		return true;
 
 	case SECCOMP_RET_ALLOW:
 		/*
@@ -1350,7 +1351,7 @@ static int __seccomp_filter(int this_sys
 		 * this action since SECCOMP_RET_ALLOW is the starting
 		 * state in seccomp_run_filters().
 		 */
-		return 0;
+		return true;
 
 	case SECCOMP_RET_KILL_THREAD:
 	case SECCOMP_RET_KILL_PROCESS:
@@ -1367,46 +1368,46 @@ static int __seccomp_filter(int this_sys
 		} else {
 			do_exit(SIGSYS);
 		}
-		return -1; /* skip the syscall go directly to signal handling */
+		return false; /* skip the syscall go directly to signal handling */
 	}
 
 	unreachable();
 
 skip:
 	seccomp_log(this_syscall, 0, action, match ? match->log : false);
-	return -1;
+	return false;
 }
 #else
-static int __seccomp_filter(int this_syscall, const bool recheck_after_trace)
+static bool __seccomp_filter(int this_syscall, const bool recheck_after_trace)
 {
 	BUG();
 
-	return -1;
+	return false;
 }
 #endif
 
-int __secure_computing(void)
+bool __seccomp_permit_syscall(void)
 {
 	int mode = current->seccomp.mode;
 	int this_syscall;
 
 	if (IS_ENABLED(CONFIG_CHECKPOINT_RESTORE) &&
 	    unlikely(current->ptrace & PT_SUSPEND_SECCOMP))
-		return 0;
+		return true;
 
 	this_syscall = syscall_get_nr(current, current_pt_regs());
 
 	switch (mode) {
 	case SECCOMP_MODE_STRICT:
 		__secure_computing_strict(this_syscall);  /* may call do_exit */
-		return 0;
+		return true;
 	case SECCOMP_MODE_FILTER:
 		return __seccomp_filter(this_syscall, false);
 	/* Surviving SECCOMP_RET_KILL_* must be proactively impossible. */
 	case SECCOMP_MODE_DEAD:
 		WARN_ON_ONCE(1);
 		do_exit(SIGKILL);
-		return -1;
+		return false;
 	default:
 		BUG();
 	}
author maintainer
#71 lore raw

Re: [patch 11/18] seccomp, treewide: Rename and convert __secure_computing() to return boolean

Quoted 12 lines · Jinjie Ruan

On 7/8/2026 3:06 AM, Thomas Gleixner wrote:
As Ada pointed out, the description of secure_computing in arch/Kconfig need to be updated, a possible suggestion:

arch/Kconfig +0 -2
@@ -636,8 +636,8 @@ config HAVE_ARCH_SECCOMP_FILTER
          - syscall_rollback()
          - 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
Quoted 4 lines

of -1
+ - seccomp_permits_syscall is called from a ptrace_event()-safe
context
+ - seccomp_permits_syscall return value is checked and if false

Makes sense.

arch/Kconfig

Quoted 11 lines

Review

Quoted 3 lines
(quoted diff) +1 -1
 		if (__seccomp_filter(this_syscall, true))
-			return -1;
+			return false;

The return value of __seccomp_filter is checked in the wrong way, check -1 should be replaced with check false, maybe:

arch/Kconfig +2 -2
-               if (__seccomp_filter(this_syscall, true))
-                       return -1;
+               if (!__seccomp_filter(this_syscall, true))
+                       return false;

Ooops.

maintainer Acked-by
#72 lore raw

Re: [patch 11/18] seccomp, treewide: Rename and convert __secure_computing() to return boolean

Quoted 10 lines · Thomas Gleixner

Review

Quoted 8 lines · Jinjie Ruan

The return value of __seccomp_filter is checked in the wrong way, check -1 should be replaced with check false, maybe:

(quoted diff) +2 -2
-               if (__seccomp_filter(this_syscall, true))
-                       return -1;
+               if (!__seccomp_filter(this_syscall, true))
+                       return false;

Or simply

	return __seccomp_filter(this_syscall, true);

and remove "return true" below ?

Either way, I personally like this change, I was always confused by these -1's.

author maintainer
#73 lore raw

Re: [patch 11/18] seccomp, treewide: Rename and convert __secure_computing() to return boolean

Quoted 12 lines · Oleg Nesterov
Quoted 10 lines · Thomas Gleixner

Review

Quoted 8 lines · Jinjie Ruan

The return value of __seccomp_filter is checked in the wrong way, check -1 should be replaced with check false, maybe:

(quoted diff) +2 -2
-               if (__seccomp_filter(this_syscall, true))
-                       return -1;
+               if (!__seccomp_filter(this_syscall, true))
+                       return false;
Quoted 5 lines

Or simply

	return __seccomp_filter(this_syscall, true);

and remove "return true" below ?

Duh. Obvious now that you point it out :)

Quoted 1 line

Either way, I personally like this change, I was always confused by these -1's.

Welcome to the club!

maintainer
#74 lore raw

Re: [patch 11/18] seccomp, treewide: Rename and convert __secure_computing() to return boolean

In reply to Thomas Gleixner
Quoted 6 lines · Thomas Gleixner

From: Jinjie Ruan <[email protected]>

The return value of __secure_computing() currently uses 0 to indicate that a system call should be allowed, and -1 to indicate that it should be blocked/killed. This 0/-1 pattern is non-intuitive for a security check function and makes the control flow at the call sites less readable.

Conceptually, I'm good with this. Just make sure that the tools/testing/selftests/seccomp/seccomp_bpf tests still passes. :)

Signature · 1 line
Kees Cook
Reviewed-by on v1 11/18
#75 lore raw

Re: [patch 11/18] seccomp, treewide: Rename and convert __secure_computing() to return boolean

In reply to Thomas Gleixner
Quoted 396 lines · Thomas Gleixner

From: Jinjie Ruan <[email protected]>

The return value of __secure_computing() currently uses 0 to indicate that a system call should be allowed, and -1 to indicate that it should be blocked/killed. This 0/-1 pattern is non-intuitive for a security check function and makes the control flow at the call sites less readable.

Furthermore, any potential future changes to these return values would require a high-risk, error-prone audit of all its users across different architectures.

Sanitize this logic by converting the return type of __secure_computing() to a proper boolean, where 'true' explicitly means 'allow' and 'false' means 'fail/deny'.

Update all the two dozen or so call sites across the tree to align with this new boolean semantic. No functional changes are intended, as the callers still return -1 to the lower-level assembly entry code upon seccomp denial.

Rename the function to __seccomp_permit_syscall() so that the purpose is entirely clear.

[ tglx: Rename the function ]

---
 arch/alpha/kernel/ptrace.c            |    2 -
 arch/arm/kernel/ptrace.c              |    2 -
 arch/arm64/kernel/ptrace.c            |    2 -
 arch/csky/kernel/ptrace.c             |    2 -
 arch/m68k/kernel/ptrace.c             |    2 -
 arch/mips/kernel/ptrace.c             |    2 -
 arch/parisc/kernel/ptrace.c           |    2 -
 arch/sh/kernel/ptrace_32.c            |    2 -
 arch/um/kernel/skas/syscall.c         |    2 -
 arch/x86/entry/vsyscall/vsyscall_64.c |   14 ++++++-------
 arch/xtensa/kernel/ptrace.c           |    3 --
 include/linux/entry-common.h          |    9 +++-----
 include/linux/seccomp.h               |   12 +++++------
 kernel/seccomp.c                      |   35 +++++++++++++++++-----------------
 14 files changed, 45 insertions(+), 46 deletions(-)
arch/alpha/kernel/ptrace.c +1 -1
@@ -387,7 +387,7 @@ asmlinkage unsigned long syscall_trace_e
 	 * 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);
arch/arm/kernel/ptrace.c +1 -1
@@ -855,7 +855,7 @@ asmlinkage int syscall_trace_enter(struc
 
 	/* 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 */
arch/arm64/kernel/ptrace.c +1 -1
@@ -2420,7 +2420,7 @@ int syscall_trace_enter(struct pt_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))
arch/csky/kernel/ptrace.c +1 -1
@@ -323,7 +323,7 @@ asmlinkage int syscall_trace_enter(struc
 		if (ptrace_report_syscall_entry(regs))
 			return -1;
 
-	if (secure_computing() == -1)
+	if (!seccomp_permit_syscall())
 		return -1;
 
 	if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
arch/m68k/kernel/ptrace.c +1 -1
@@ -281,7 +281,7 @@ asmlinkage int syscall_trace_enter(void)
 	if (test_thread_flag(TIF_SYSCALL_TRACE))
 		ret = ptrace_report_syscall_entry(task_pt_regs(current));
 
-	if (secure_computing() == -1)
+	if (!seccomp_permit_syscall())
 		return -1;
 
 	return ret;
arch/mips/kernel/ptrace.c +1 -1
@@ -1328,7 +1328,7 @@ asmlinkage long syscall_trace_enter(stru
 			return -1;
 	}
 
-	if (secure_computing())
+	if (!seccomp_permit_syscall())
 		return -1;
 
 	if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
arch/parisc/kernel/ptrace.c +1 -1
@@ -351,7 +351,7 @@ long do_syscall_trace_enter(struct pt_re
 	}
 
 	/* Do the secure computing check after ptrace. */
-	if (secure_computing() == -1)
+	if (!seccomp_permit_syscall())
 		return -1;
 
 #ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS
arch/sh/kernel/ptrace_32.c +1 -1
@@ -460,7 +460,7 @@ asmlinkage long do_syscall_trace_enter(s
 		return -1;
 	}
 
-	if (secure_computing() == -1)
+	if (!seccomp_permit_syscall())
 		return -1;
 
 	if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
arch/um/kernel/skas/syscall.c +1 -1
@@ -27,7 +27,7 @@ void handle_syscall(struct uml_pt_regs *
 		goto out;
 
 	/* Do the seccomp check after ptrace; failures should be fast. */
-	if (secure_computing() == -1)
+	if (!seccomp_permit_syscall())
 		goto out;
 
 	syscall = UPT_SYSCALL_NR(r);
arch/x86/entry/vsyscall/vsyscall_64.c +7 -7
@@ -118,10 +118,10 @@ static bool write_ok_or_segv(unsigned lo
 
 static bool __emulate_vsyscall(struct pt_regs *regs, unsigned long address)
 {
-	unsigned long caller;
-	int vsyscall_nr, syscall_nr, tmp;
+	unsigned long caller, orig_dx;
+	int vsyscall_nr, syscall_nr;
+	bool skip;
 	long ret;
-	unsigned long orig_dx;
 
 	/* Confirm that the fault happened in 64-bit user mode */
 	if (!user_64bit_mode(regs))
@@ -197,16 +197,16 @@ static bool __emulate_vsyscall(struct pt
 	 */
 	regs->orig_ax = syscall_nr;
 	regs->ax = -ENOSYS;
-	tmp = secure_computing();
-	if ((!tmp && regs->orig_ax != syscall_nr) || regs->ip != address) {
+	skip = !seccomp_permit_syscall();
+	if ((!skip && regs->orig_ax != syscall_nr) || regs->ip != address) {
 		warn_bad_vsyscall(KERN_DEBUG, regs,
 				  "seccomp tried to change syscall nr or ip");
 		force_exit_sig(SIGSYS);
 		return true;
 	}
 	regs->orig_ax = -1;
-	if (tmp)
-		goto do_ret;  /* skip requested */
+	if (skip)
+		goto do_ret;
 
 	/*
 	 * With a real vsyscall, page faults cause SIGSEGV.
arch/xtensa/kernel/ptrace.c +1 -2
@@ -553,8 +553,7 @@ int do_syscall_trace_enter(struct pt_reg
 		return 0;
 	}
 
-	if (regs->syscall == NO_SYSCALL ||
-	    secure_computing() == -1) {
+	if (regs->syscall == NO_SYSCALL || !seccomp_permit_syscall()) {
 		do_syscall_trace_leave(regs);
 		return 0;
 	}
include/linux/entry-common.h +4 -5
@@ -102,9 +102,8 @@ static __always_inline long syscall_trac
 
 	/* Do seccomp after ptrace, to catch any tracer changes. */
 	if (work & SYSCALL_WORK_SECCOMP) {
-		ret = __secure_computing();
-		if (ret == -1L)
-			return ret;
+		if (!__seccomp_permit_syscall())
+			return -1L;
 	}
 
 	/* Either of the above might have changed the syscall number */
@@ -115,7 +114,7 @@ static __always_inline long syscall_trac
 
 	syscall_enter_audit(regs, syscall);
 
-	return ret ? : syscall;
+	return syscall;
 }
 
 /**
@@ -138,7 +137,7 @@ static __always_inline long syscall_trac
  * It handles the following work items:
  *
  *  1) syscall_work flag dependent invocations of
- *     ptrace_report_syscall_entry(), __secure_computing(), trace_sys_enter()
+ *     ptrace_report_syscall_entry(), __seccomp_permit_syscall(), trace_sys_enter()
  *  2) Invocation of audit_syscall_entry()
  */
 static __always_inline long syscall_enter_from_user_mode_work(struct pt_regs *regs, long syscall)
include/linux/seccomp.h +6 -6
@@ -22,14 +22,14 @@
 #include <linux/atomic.h>
 #include <asm/seccomp.h>
 
-extern int __secure_computing(void);
+extern bool __seccomp_permit_syscall(void);
 
 #ifdef CONFIG_HAVE_ARCH_SECCOMP_FILTER
-static inline int secure_computing(void)
+static __always_inline bool seccomp_permit_syscall(void)
 {
 	if (unlikely(test_syscall_work(SECCOMP)))
-		return  __secure_computing();
-	return 0;
+		return  __seccomp_permit_syscall();
+	return true;
 }
 #else
 extern void secure_computing_strict(int this_syscall);
@@ -50,11 +50,11 @@ static inline int seccomp_mode(struct se
 struct seccomp_data;
 
 #ifdef CONFIG_HAVE_ARCH_SECCOMP_FILTER
-static inline int secure_computing(void) { return 0; }
+static inline bool seccomp_permit_syscall(void) { return true; }
 #else
 static inline void secure_computing_strict(int this_syscall) { return; }
 #endif
-static inline int __secure_computing(void) { return 0; }
+static inline bool __seccomp_permit_syscall(void) { return true; }
 
 static inline long prctl_get_seccomp(void)
 {
kernel/seccomp.c +17 -16
@@ -1100,12 +1100,13 @@ void secure_computing_strict(int this_sy
 	else
 		BUG();
 }
-int __secure_computing(void)
+
+bool __seccomp_permit_syscall(void)
 {
 	int this_syscall = syscall_get_nr(current, current_pt_regs());
 
 	secure_computing_strict(this_syscall);
-	return 0;
+	return true;
 }
 #else
 
@@ -1256,7 +1257,7 @@ static int seccomp_do_user_notification(
 	return -1;
 }
 
-static int __seccomp_filter(int this_syscall, const bool recheck_after_trace)
+static bool __seccomp_filter(int this_syscall, const bool recheck_after_trace)
 {
 	u32 filter_ret, action;
 	struct seccomp_data sd;
@@ -1294,7 +1295,7 @@ static int __seccomp_filter(int this_sys
 	case SECCOMP_RET_TRACE:
 		/* We've been put in this state by the ptracer already. */
 		if (recheck_after_trace)
-			return 0;
+			return true;
 
 		/* ENOSYS these calls if there is no tracer attached. */
 		if (!ptrace_event_enabled(current, PTRACE_EVENT_SECCOMP)) {
@@ -1330,19 +1331,19 @@ static int __seccomp_filter(int this_sys
 		 * a skip would have already been reported.
 		 */
 		if (__seccomp_filter(this_syscall, true))
-			return -1;
+			return false;
 
-		return 0;
+		return true;
 
 	case SECCOMP_RET_USER_NOTIF:
 		if (seccomp_do_user_notification(this_syscall, match, &sd))
 			goto skip;
 
-		return 0;
+		return true;
 
 	case SECCOMP_RET_LOG:
 		seccomp_log(this_syscall, 0, action, true);
-		return 0;
+		return true;
 
 	case SECCOMP_RET_ALLOW:
 		/*
@@ -1350,7 +1351,7 @@ static int __seccomp_filter(int this_sys
 		 * this action since SECCOMP_RET_ALLOW is the starting
 		 * state in seccomp_run_filters().
 		 */
-		return 0;
+		return true;
 
 	case SECCOMP_RET_KILL_THREAD:
 	case SECCOMP_RET_KILL_PROCESS:
@@ -1367,46 +1368,46 @@ static int __seccomp_filter(int this_sys
 		} else {
 			do_exit(SIGSYS);
 		}
-		return -1; /* skip the syscall go directly to signal handling */
+		return false; /* skip the syscall go directly to signal handling */
 	}
 
 	unreachable();
 
 skip:
 	seccomp_log(this_syscall, 0, action, match ? match->log : false);
-	return -1;
+	return false;
 }
 #else
-static int __seccomp_filter(int this_syscall, const bool recheck_after_trace)
+static bool __seccomp_filter(int this_syscall, const bool recheck_after_trace)
 {
 	BUG();
 
-	return -1;
+	return false;
 }
 #endif
 
-int __secure_computing(void)
+bool __seccomp_permit_syscall(void)
 {
 	int mode = current->seccomp.mode;
 	int this_syscall;
 
 	if (IS_ENABLED(CONFIG_CHECKPOINT_RESTORE) &&
 	    unlikely(current->ptrace & PT_SUSPEND_SECCOMP))
-		return 0;
+		return true;
 
 	this_syscall = syscall_get_nr(current, current_pt_regs());
 
 	switch (mode) {
 	case SECCOMP_MODE_STRICT:
 		__secure_computing_strict(this_syscall);  /* may call do_exit */
-		return 0;
+		return true;
 	case SECCOMP_MODE_FILTER:

kernel/seccomp.c static int __seccomp_filter(int this_sys · line 1413

Quoted 10 lines
kernel/seccomp.c +1 -1
 		return __seccomp_filter(this_syscall, false);
 	/* Surviving SECCOMP_RET_KILL_* must be proactively impossible. */
 	case SECCOMP_MODE_DEAD:
 		WARN_ON_ONCE(1);
 		do_exit(SIGKILL);
-		return -1;
+		return false;
 	default:
 		BUG();
 	}
merge bot Applied
#76 lore raw

[tip: core/entry] seccomp, treewide: Rename and convert __secure_computing() to return boolean

In reply to Thomas Gleixner
The following commit has been merged into the core/entry branch of tip:

The following commit has been merged into the core/entry branch of tip:

Commit-ID:     7ba2ba74713c83408cc942b60dd869ab2c34c84f
Gitweb:        https://git.kernel.org/tip/7ba2ba74713c83408cc942b60dd869ab2c34c84f
Author:        Jinjie Ruan <[email protected]>
AuthorDate:    Tue, 07 Jul 2026 21:06:40 +02:00
Committer:     Thomas Gleixner <[email protected]>
CommitterDate: Sun, 12 Jul 2026 12:38:02 +02:00

seccomp, treewide: Rename and convert __secure_computing() to return boolean

The return value of __secure_computing() currently uses 0 to indicate that a system call should be allowed, and -1 to indicate that it should be blocked/killed. This 0/-1 pattern is non-intuitive for a security check function and makes the control flow at the call sites less readable.

Furthermore, any potential future changes to these return values would require a high-risk, error-prone audit of all its users across different architectures.

Sanitize this logic by converting the return type of __secure_computing() to a proper boolean, where 'true' explicitly means 'allow' and 'false' means 'fail/deny'.

Update all the two dozen or so call sites across the tree to align with this new boolean semantic. No functional changes are intended, as the callers still return -1 to the lower-level assembly entry code upon seccomp denial.

Rename the function to __seccomp_permit_syscall() so that the purpose is entirely clear.

[ tglx: Rename the function ]

---
 arch/Kconfig                          |  2 +-
 arch/alpha/kernel/ptrace.c            |  2 +-
 arch/arm/kernel/ptrace.c              |  2 +-
 arch/arm64/kernel/ptrace.c            |  2 +-
 arch/csky/kernel/ptrace.c             |  2 +-
 arch/m68k/kernel/ptrace.c             |  2 +-
 arch/mips/kernel/ptrace.c             |  2 +-
 arch/parisc/kernel/ptrace.c           |  2 +-
 arch/sh/kernel/ptrace_32.c            |  2 +-
 arch/um/kernel/skas/syscall.c         |  2 +-
 arch/x86/entry/vsyscall/vsyscall_64.c | 14 +++++-----
 arch/xtensa/kernel/ptrace.c           |  3 +--
 include/linux/entry-common.h          |  9 +++----
 include/linux/seccomp.h               | 12 ++++-----
 kernel/seccomp.c                      | 36 ++++++++++++--------------
 15 files changed, 45 insertions(+), 49 deletions(-)
arch/Kconfig +1 -1
index 0c01521..d2dbed5 100644
@@ -647,7 +647,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,
arch/alpha/kernel/ptrace.c +1 -1
index 0687760..2870101 100644
@@ -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);
arch/arm/kernel/ptrace.c +1 -1
index 7951b2c..45076fc 100644
@@ -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 */
arch/arm64/kernel/ptrace.c +1 -1
index 4d08598..253ce5d 100644
@@ -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))
arch/csky/kernel/ptrace.c +1 -1
index 6bb685a..b902358 100644
@@ -323,7 +323,7 @@ asmlinkage int syscall_trace_enter(struct pt_regs *regs)
 		if (ptrace_report_syscall_entry(regs))
 			return -1;
 
-	if (secure_computing() == -1)
+	if (!seccomp_permit_syscall())
 		return -1;
 
 	if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
arch/m68k/kernel/ptrace.c +1 -1
index cfa2df2..28546d7 100644
@@ -281,7 +281,7 @@ asmlinkage int syscall_trace_enter(void)
 	if (test_thread_flag(TIF_SYSCALL_TRACE))
 		ret = ptrace_report_syscall_entry(task_pt_regs(current));
 
-	if (secure_computing() == -1)
+	if (!seccomp_permit_syscall())
 		return -1;
 
 	return ret;
arch/mips/kernel/ptrace.c +1 -1
index 3f4c94c..af1e005 100644
@@ -1328,7 +1328,7 @@ asmlinkage long syscall_trace_enter(struct pt_regs *regs)
 			return -1;
 	}
 
-	if (secure_computing())
+	if (!seccomp_permit_syscall())
 		return -1;
 
 	if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
arch/parisc/kernel/ptrace.c +1 -1
index 8a17ab7..ac5d077 100644
@@ -351,7 +351,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
arch/sh/kernel/ptrace_32.c +1 -1
index 06f765d..7594bd5 100644
@@ -460,7 +460,7 @@ asmlinkage long do_syscall_trace_enter(struct pt_regs *regs)
 		return -1;
 	}
 
-	if (secure_computing() == -1)
+	if (!seccomp_permit_syscall())
 		return -1;
 
 	if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
arch/um/kernel/skas/syscall.c +1 -1
index ba7494f..bc11773 100644
@@ -27,7 +27,7 @@ void handle_syscall(struct uml_pt_regs *r)
 		goto out;
 
 	/* Do the seccomp check after ptrace; failures should be fast. */
-	if (secure_computing() == -1)
+	if (!seccomp_permit_syscall())
 		goto out;
 
 	syscall = UPT_SYSCALL_NR(r);
arch/x86/entry/vsyscall/vsyscall_64.c +7 -7
index ea36de9..1b68c1c 100644
@@ -118,10 +118,10 @@ static bool write_ok_or_segv(unsigned long ptr, size_t size)
 
 static bool __emulate_vsyscall(struct pt_regs *regs, unsigned long address)
 {
-	unsigned long caller;
-	int vsyscall_nr, syscall_nr, tmp;
+	unsigned long caller, orig_dx;
+	int vsyscall_nr, syscall_nr;
+	bool skip;
 	long ret;
-	unsigned long orig_dx;
 
 	/* Confirm that the fault happened in 64-bit user mode */
 	if (!user_64bit_mode(regs))
@@ -197,16 +197,16 @@ static bool __emulate_vsyscall(struct pt_regs *regs, unsigned long address)
 	 */
 	regs->orig_ax = syscall_nr;
 	regs->ax = -ENOSYS;
-	tmp = secure_computing();
-	if ((!tmp && regs->orig_ax != syscall_nr) || regs->ip != address) {
+	skip = !seccomp_permit_syscall();
+	if ((!skip && regs->orig_ax != syscall_nr) || regs->ip != address) {
 		warn_bad_vsyscall(KERN_DEBUG, regs,
 				  "seccomp tried to change syscall nr or ip");
 		force_exit_sig(SIGSYS);
 		return true;
 	}
 	regs->orig_ax = -1;
-	if (tmp)
-		goto do_ret;  /* skip requested */
+	if (skip)
+		goto do_ret;
 
 	/*
 	 * With a real vsyscall, page faults cause SIGSEGV.
arch/xtensa/kernel/ptrace.c +1 -2
index b80d54b..5c3ebb0 100644
@@ -553,8 +553,7 @@ int do_syscall_trace_enter(struct pt_regs *regs)
 		return 0;
 	}
 
-	if (regs->syscall == NO_SYSCALL ||
-	    secure_computing() == -1) {
+	if (regs->syscall == NO_SYSCALL || !seccomp_permit_syscall()) {
 		do_syscall_trace_leave(regs);
 		return 0;
 	}
include/linux/entry-common.h +4 -5
index c837352..99c49a4 100644
@@ -102,9 +102,8 @@ static __always_inline long syscall_trace_enter(struct pt_regs *regs, unsigned l
 
 	/* Do seccomp after ptrace, to catch any tracer changes. */
 	if (work & SYSCALL_WORK_SECCOMP) {
-		ret = __secure_computing();
-		if (ret == -1L)
-			return ret;
+		if (!__seccomp_permit_syscall())
+			return -1L;
 	}
 
 	/* Either of the above might have changed the syscall number */
@@ -115,7 +114,7 @@ static __always_inline long syscall_trace_enter(struct pt_regs *regs, unsigned l
 
 	syscall_enter_audit(regs, syscall);
 
-	return ret ? : syscall;
+	return syscall;
 }
 
 /**
@@ -138,7 +137,7 @@ static __always_inline long syscall_trace_enter(struct pt_regs *regs, unsigned l
  * It handles the following work items:
  *
  *  1) syscall_work flag dependent invocations of
- *     ptrace_report_syscall_entry(), __secure_computing(), trace_sys_enter()
+ *     ptrace_report_syscall_entry(), __seccomp_permit_syscall(), trace_sys_enter()
  *  2) Invocation of audit_syscall_entry()
  */
 static __always_inline long syscall_enter_from_user_mode_work(struct pt_regs *regs, long syscall)
include/linux/seccomp.h +6 -6
index 9b95997..fcb3eb9 100644
@@ -22,14 +22,14 @@
 #include <linux/atomic.h>
 #include <asm/seccomp.h>
 
-extern int __secure_computing(void);
+extern bool __seccomp_permit_syscall(void);
 
 #ifdef CONFIG_HAVE_ARCH_SECCOMP_FILTER
-static inline int secure_computing(void)
+static __always_inline bool seccomp_permit_syscall(void)
 {
 	if (unlikely(test_syscall_work(SECCOMP)))
-		return  __secure_computing();
-	return 0;
+		return  __seccomp_permit_syscall();
+	return true;
 }
 #else
 extern void secure_computing_strict(int this_syscall);
@@ -50,11 +50,11 @@ static inline int seccomp_mode(struct seccomp *s)
 struct seccomp_data;
 
 #ifdef CONFIG_HAVE_ARCH_SECCOMP_FILTER
-static inline int secure_computing(void) { return 0; }
+static inline bool seccomp_permit_syscall(void) { return true; }
 #else
 static inline void secure_computing_strict(int this_syscall) { return; }
 #endif
-static inline int __secure_computing(void) { return 0; }
+static inline bool __seccomp_permit_syscall(void) { return true; }
 
 static inline long prctl_get_seccomp(void)
 {
kernel/seccomp.c +17 -19
index 0669093..86cf446 100644
@@ -1100,12 +1100,13 @@ void secure_computing_strict(int this_syscall)
 	else
 		BUG();
 }
-int __secure_computing(void)
+
+bool __seccomp_permit_syscall(void)
 {
 	int this_syscall = syscall_get_nr(current, current_pt_regs());
 
 	secure_computing_strict(this_syscall);
-	return 0;
+	return true;
 }
 #else
 
@@ -1256,7 +1257,7 @@ out:
 	return -1;
 }
 
-static int __seccomp_filter(int this_syscall, const bool recheck_after_trace)
+static bool __seccomp_filter(int this_syscall, const bool recheck_after_trace)
 {
 	u32 filter_ret, action;
 	struct seccomp_data sd;
@@ -1294,7 +1295,7 @@ static int __seccomp_filter(int this_syscall, const bool recheck_after_trace)
 	case SECCOMP_RET_TRACE:
 		/* We've been put in this state by the ptracer already. */
 		if (recheck_after_trace)
-			return 0;
+			return true;
 
 		/* ENOSYS these calls if there is no tracer attached. */
 		if (!ptrace_event_enabled(current, PTRACE_EVENT_SECCOMP)) {
@@ -1329,20 +1330,17 @@ static int __seccomp_filter(int this_syscall, const bool recheck_after_trace)
 		 * a reload of all registers. This does not goto skip since
 		 * a skip would have already been reported.
 		 */
-		if (__seccomp_filter(this_syscall, true))
-			return -1;
-
-		return 0;
+		return __seccomp_filter(this_syscall, true);
 
 	case SECCOMP_RET_USER_NOTIF:
 		if (seccomp_do_user_notification(this_syscall, match, &sd))
 			goto skip;
 
-		return 0;
+		return true;
 
 	case SECCOMP_RET_LOG:
 		seccomp_log(this_syscall, 0, action, true);
-		return 0;
+		return true;
 
 	case SECCOMP_RET_ALLOW:
 		/*
@@ -1350,7 +1348,7 @@ static int __seccomp_filter(int this_syscall, const bool recheck_after_trace)
 		 * this action since SECCOMP_RET_ALLOW is the starting
 		 * state in seccomp_run_filters().
 		 */
-		return 0;
+		return true;
 
 	case SECCOMP_RET_KILL_THREAD:
 	case SECCOMP_RET_KILL_PROCESS:
@@ -1367,46 +1365,46 @@ static int __seccomp_filter(int this_syscall, const bool recheck_after_trace)
 		} else {
 			do_exit(SIGSYS);
 		}
-		return -1; /* skip the syscall go directly to signal handling */
+		return false; /* skip the syscall go directly to signal handling */
 	}
 
 	unreachable();
 
 skip:
 	seccomp_log(this_syscall, 0, action, match ? match->log : false);
-	return -1;
+	return false;
 }
 #else
-static int __seccomp_filter(int this_syscall, const bool recheck_after_trace)
+static bool __seccomp_filter(int this_syscall, const bool recheck_after_trace)
 {
 	BUG();
 
-	return -1;
+	return false;
 }
 #endif
 
-int __secure_computing(void)
+bool __seccomp_permit_syscall(void)
 {
 	int mode = current->seccomp.mode;
 	int this_syscall;
 
 	if (IS_ENABLED(CONFIG_CHECKPOINT_RESTORE) &&
 	    unlikely(current->ptrace & PT_SUSPEND_SECCOMP))
-		return 0;
+		return true;
 
 	this_syscall = syscall_get_nr(current, current_pt_regs());
 
 	switch (mode) {
 	case SECCOMP_MODE_STRICT:
 		__secure_computing_strict(this_syscall);  /* may call do_exit */
-		return 0;
+		return true;
 	case SECCOMP_MODE_FILTER:
 		return __seccomp_filter(this_syscall, false);
 	/* Surviving SECCOMP_RET_KILL_* must be proactively impossible. */
 	case SECCOMP_MODE_DEAD:
 		WARN_ON_ONCE(1);
 		do_exit(SIGKILL);
-		return -1;
+		return false;
 	default:
 		BUG();
 	}
author maintainer
#77 lore raw

PATCH 12/18 ptrace, treewide: Rename ptrace_report_syscall_entry() to ptrace_report_syscall_permit_entry()

In reply to Thomas Gleixner

The return value of that function is boolean and tells the caller whether to permit the syscall processing or not.

Rename the function so the purpose is clear and make the return type bool.

Cc Arnd Bergmann <[email protected]>
Cc Oleg Nesterov <[email protected]>
Cc Richard Henderson <[email protected]>
Cc Vineet Gupta <[email protected]>
Cc Russell King <[email protected]>
Cc Catalin Marinas <[email protected]>
Cc Will Deacon <[email protected]>
Cc Guo Ren <[email protected]>
Cc Brian Cain <[email protected]>
Cc Geert Uytterhoeven <[email protected]>
Cc Michal Simek <[email protected]>
Cc Thomas Bogendoerfer <[email protected]>
Cc Dinh Nguyen <[email protected]>
Cc Helge Deller <[email protected]>
Cc Yoshinori Sato <[email protected]>
Cc "David S. Miller" <[email protected]>
Cc Andreas Larsson <[email protected]>
Cc Chris Zankel <[email protected]>
---
 arch/alpha/kernel/ptrace.c      |    2 +-
 arch/arc/kernel/ptrace.c        |    2 +-
 arch/arm/kernel/ptrace.c        |    2 +-
 arch/arm64/kernel/ptrace.c      |    2 +-
 arch/csky/kernel/ptrace.c       |    2 +-
 arch/hexagon/kernel/traps.c     |    2 +-
 arch/m68k/kernel/ptrace.c       |    2 +-
 arch/microblaze/kernel/ptrace.c |    2 +-
 arch/mips/kernel/ptrace.c       |    2 +-
 arch/nios2/kernel/ptrace.c      |    2 +-
 arch/openrisc/kernel/ptrace.c   |    2 +-
 arch/parisc/kernel/ptrace.c     |   10 ++++------
 arch/sh/kernel/ptrace_32.c      |    2 +-
 arch/sparc/kernel/ptrace_32.c   |    2 +-
 arch/sparc/kernel/ptrace_64.c   |    2 +-
 arch/um/kernel/ptrace.c         |    2 +-
 arch/xtensa/kernel/ptrace.c     |    2 +-
 include/asm-generic/syscall.h   |    4 ++--
 include/linux/entry-common.h    |   25 ++++++++++++-------------
 include/linux/ptrace.h          |   13 ++++++-------
 20 files changed, 40 insertions(+), 44 deletions(-)
arch/alpha/kernel/ptrace.c +1 -1
@@ -375,7 +375,7 @@ asmlinkage unsigned long syscall_trace_e
 	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);
arch/arc/kernel/ptrace.c +1 -1
@@ -342,7 +342,7 @@ long arch_ptrace(struct task_struct *chi
 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
arch/arm/kernel/ptrace.c +1 -1
@@ -840,7 +840,7 @@ static void report_syscall(struct pt_reg
 
 	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;
arch/arm64/kernel/ptrace.c +1 -1
@@ -2379,7 +2379,7 @@ static int report_syscall_entry(struct p
 	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;
arch/csky/kernel/ptrace.c +1 -1
@@ -320,7 +320,7 @@ long arch_ptrace(struct task_struct *chi
 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 (!seccomp_permit_syscall())
arch/hexagon/kernel/traps.c +1 -1
@@ -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 */
arch/m68k/kernel/ptrace.c +1 -1
@@ -279,7 +279,7 @@ 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 (!seccomp_permit_syscall())
 		return -1;
arch/microblaze/kernel/ptrace.c +1 -1
@@ -139,7 +139,7 @@ asmlinkage unsigned long do_syscall_trac
 	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
arch/mips/kernel/ptrace.c +1 -1
@@ -1324,7 +1324,7 @@ asmlinkage long syscall_trace_enter(stru
 	user_exit();
 
 	if (test_thread_flag(TIF_SYSCALL_TRACE)) {
-		if (ptrace_report_syscall_entry(regs))
+		if (!ptrace_report_syscall_permit_entry(regs))
 			return -1;
 	}
 
arch/nios2/kernel/ptrace.c +1 -1
@@ -133,7 +133,7 @@ asmlinkage int do_syscall_trace_enter(vo
 	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;
 }
arch/openrisc/kernel/ptrace.c +1 -1
@@ -293,7 +293,7 @@ asmlinkage long do_syscall_trace_enter(s
 	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
arch/parisc/kernel/ptrace.c +4 -6
@@ -326,7 +326,7 @@ long compat_arch_ptrace(struct task_stru
 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_re
 		 */
 		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,
arch/sh/kernel/ptrace_32.c +1 -1
@@ -455,7 +455,7 @@ long arch_ptrace(struct task_struct *chi
 asmlinkage long do_syscall_trace_enter(struct pt_regs *regs)
 {
 	if (test_thread_flag(TIF_SYSCALL_TRACE) &&
-	    ptrace_report_syscall_entry(regs)) {
+	    !ptrace_report_syscall_permit_entry(regs)) {
 		regs->regs[0] = -ENOSYS;
 		return -1;
 	}
arch/sparc/kernel/ptrace_32.c +1 -1
@@ -441,7 +441,7 @@ asmlinkage int syscall_trace(struct pt_r
 		if (syscall_exit_p)
 			ptrace_report_syscall_exit(regs, 0);
 		else
-			ret = ptrace_report_syscall_entry(regs);
+			ret = !ptrace_report_syscall_permit_entry(regs);
 	}
 
 	return ret;
arch/sparc/kernel/ptrace_64.c +1 -1
@@ -1093,7 +1093,7 @@ asmlinkage int syscall_trace_enter(struc
 		user_exit();
 
 	if (test_thread_flag(TIF_SYSCALL_TRACE))
-		ret = ptrace_report_syscall_entry(regs);
+		ret = !ptrace_report_syscall_permit_entry(regs);
 
 	if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
 		trace_sys_enter(regs, regs->u_regs[UREG_G1]);
arch/um/kernel/ptrace.c +1 -1
@@ -135,7 +135,7 @@ int syscall_trace_enter(struct pt_regs *
 	if (!test_thread_flag(TIF_SYSCALL_TRACE))
 		return 0;
 
-	return ptrace_report_syscall_entry(regs);
+	return !ptrace_report_syscall_permit_entry(regs);
 }
 
 void syscall_trace_leave(struct pt_regs *regs)
arch/xtensa/kernel/ptrace.c +1 -1
@@ -547,7 +547,7 @@ int do_syscall_trace_enter(struct pt_reg
 		regs->areg[2] = -ENOSYS;
 
 	if (test_thread_flag(TIF_SYSCALL_TRACE) &&
-	    ptrace_report_syscall_entry(regs)) {
+	    !ptrace_report_syscall_permit_entry(regs)) {
 		regs->areg[2] = -ENOSYS;
 		regs->syscall = NO_SYSCALL;
 		return 0;
include/asm-generic/syscall.h +2 -2
@@ -58,8 +58,8 @@ void syscall_set_nr(struct task_struct *
  *
  * It's only valid to call this when @task is stopped for system
  * call exit tracing (due to %SYSCALL_WORK_SYSCALL_TRACE or
- * %SYSCALL_WORK_SYSCALL_AUDIT), after ptrace_report_syscall_entry()
- * returned nonzero to prevent the system call from taking place.
+ * %SYSCALL_WORK_SYSCALL_AUDIT), after ptrace_report_syscall_permit_entry()
+ * returned False to prevent the system call from taking place.
  *
  * This rolls back the register state in @regs so it's as if the
  * system call instruction was a no-op.  The registers containing
include/linux/entry-common.h +12 -13
@@ -38,21 +38,22 @@
 				 SYSCALL_WORK_SYSCALL_EXIT_TRAP)
 
 /**
- * arch_ptrace_report_syscall_entry - Architecture specific ptrace_report_syscall_entry() wrapper
+ * arch_ptrace_report_syscall_permit_entry - Architecture specific wrapper for
+ *					     ptrace_report_syscall_permit_entry()
  * @regs: Pointer to the register state at syscall entry
  *
- * Invoked from syscall_trace_enter() to wrap ptrace_report_syscall_entry().
+ * Invoked from syscall_trace_enter() to wrap ptrace_report_syscall_permit_entry().
  *
- * This allows architecture specific ptrace_report_syscall_entry()
+ * This allows architecture specific ptrace_report_syscall_permit_entry()
  * implementations. If not defined by the architecture this falls back to
- * to ptrace_report_syscall_entry().
+ * to ptrace_report_syscall_permit_entry().
  */
-static __always_inline int arch_ptrace_report_syscall_entry(struct pt_regs *regs);
+static __always_inline bool arch_ptrace_report_syscall_permit_entry(struct pt_regs *regs);
 
-#ifndef arch_ptrace_report_syscall_entry
-static __always_inline int arch_ptrace_report_syscall_entry(struct pt_regs *regs)
+#ifndef arch_ptrace_report_syscall_permit_entry
+static __always_inline bool arch_ptrace_report_syscall_permit_entry(struct pt_regs *regs)
 {
-	return ptrace_report_syscall_entry(regs);
+	return ptrace_report_syscall_permit_entry(regs);
 }
 #endif
 
@@ -73,8 +74,6 @@ static inline void syscall_enter_audit(s
 static __always_inline long syscall_trace_enter(struct pt_regs *regs, unsigned long work,
 						long syscall)
 {
-	long ret = 0;
-
 	/*
 	 * Handle Syscall User Dispatch.  This must comes first, since
 	 * the ABI here can be something that doesn't make sense for
@@ -95,8 +94,8 @@ static __always_inline long syscall_trac
 
 	/* Handle ptrace */
 	if (work & (SYSCALL_WORK_SYSCALL_TRACE | SYSCALL_WORK_SYSCALL_EMU)) {
-		ret = arch_ptrace_report_syscall_entry(regs);
-		if (ret || (work & SYSCALL_WORK_SYSCALL_EMU))
+		if (!arch_ptrace_report_syscall_permit_entry(regs) ||
+		    (work & SYSCALL_WORK_SYSCALL_EMU))
 			return -1L;
 	}
 
@@ -137,7 +136,7 @@ static __always_inline long syscall_trac
  * It handles the following work items:
  *
  *  1) syscall_work flag dependent invocations of
- *     ptrace_report_syscall_entry(), __seccomp_permit_syscall(), trace_sys_enter()
+ *     ptrace_report_syscall_permit_entry(), __seccomp_permit_syscall(), trace_sys_enter()
  *  2) Invocation of audit_syscall_entry()
  */
 static __always_inline long syscall_enter_from_user_mode_work(struct pt_regs *regs, long syscall)
include/linux/ptrace.h +6 -7
@@ -405,13 +405,13 @@ extern void sigaction_compat_abi(struct
 /*
  * ptrace report for syscall entry and exit looks identical.
  */
-static inline int ptrace_report_syscall(unsigned long message)
+static inline bool ptrace_report_syscall(unsigned long message)
 {
 	int ptrace = current->ptrace;
 	int signr;
 
 	if (!(ptrace & PT_PTRACED))
-		return 0;
+		return true;
 
 	signr = ptrace_notify(SIGTRAP | ((ptrace & PT_TRACESYSGOOD) ? 0x80 : 0),
 			      message);
@@ -424,11 +424,11 @@ static inline int ptrace_report_syscall(
 	if (signr)
 		send_sig(signr, current, 1);
 
-	return fatal_signal_pending(current);
+	return !fatal_signal_pending(current);
 }
 
 /**
- * ptrace_report_syscall_entry - task is about to attempt a system call
+ * ptrace_report_syscall_permit_entry - task is about to attempt a system call
  * @regs:		user register state of current task
  *
  * This will be called if %SYSCALL_WORK_SYSCALL_TRACE or
@@ -438,7 +438,7 @@ static inline int ptrace_report_syscall(
  * call number and arguments to be tried.  It is safe to block here,
  * preventing the system call from beginning.
  *
- * Returns zero normally, or nonzero if the calling arch code should abort
+ * Returns True normally, or False if the calling architecture code should abort
  * the system call.  That must prevent normal entry so no system call is
  * made.  If @task ever returns to user mode after this, its register state
  * is unspecified, but should be something harmless like an %ENOSYS error
@@ -447,8 +447,7 @@ static inline int ptrace_report_syscall(
  *
  * Called without locks, just after entering kernel mode.
  */
-static inline __must_check int ptrace_report_syscall_entry(
-	struct pt_regs *regs)
+static inline __must_check bool ptrace_report_syscall_permit_entry(struct pt_regs *regs)
 {
 	return ptrace_report_syscall(PTRACE_EVENTMSG_SYSCALL_ENTRY);
 }
maintainer Acked-by on v1 12/18
#78 lore raw

Re: [patch 12/18] ptrace, treewide: Rename ptrace_report_syscall_entry() to ptrace_report_syscall_permit_entry()

Quoted 5 lines · Thomas Gleixner

The return value of that function is boolean and tells the caller whether to permit the syscall processing or not.

Rename the function so the purpose is clear and make the return type bool.

Just in case,

Reviewed-by on v1 12/18
#79 lore raw

Re: [patch 12/18] ptrace, treewide: Rename ptrace_report_syscall_entry() to ptrace_report_syscall_permit_entry()

In reply to Thomas Gleixner
Quoted 380 lines · Thomas Gleixner

The return value of that function is boolean and tells the caller whether to permit the syscall processing or not.

Rename the function so the purpose is clear and make the return type bool.

Cc Arnd Bergmann <[email protected]>
Cc Oleg Nesterov <[email protected]>
Cc Richard Henderson <[email protected]>
Cc Vineet Gupta <[email protected]>
Cc Russell King <[email protected]>
Cc Catalin Marinas <[email protected]>
Cc Will Deacon <[email protected]>
Cc Guo Ren <[email protected]>
Cc Brian Cain <[email protected]>
Cc Geert Uytterhoeven <[email protected]>
Cc Michal Simek <[email protected]>
Cc Thomas Bogendoerfer <[email protected]>
Cc Dinh Nguyen <[email protected]>
Cc Helge Deller <[email protected]>
Cc Yoshinori Sato <[email protected]>
Cc "David S. Miller" <[email protected]>
Cc Andreas Larsson <[email protected]>
Cc Chris Zankel <[email protected]>
---
 arch/alpha/kernel/ptrace.c      |    2 +-
 arch/arc/kernel/ptrace.c        |    2 +-
 arch/arm/kernel/ptrace.c        |    2 +-
 arch/arm64/kernel/ptrace.c      |    2 +-
 arch/csky/kernel/ptrace.c       |    2 +-
 arch/hexagon/kernel/traps.c     |    2 +-
 arch/m68k/kernel/ptrace.c       |    2 +-
 arch/microblaze/kernel/ptrace.c |    2 +-
 arch/mips/kernel/ptrace.c       |    2 +-
 arch/nios2/kernel/ptrace.c      |    2 +-
 arch/openrisc/kernel/ptrace.c   |    2 +-
 arch/parisc/kernel/ptrace.c     |   10 ++++------
 arch/sh/kernel/ptrace_32.c      |    2 +-
 arch/sparc/kernel/ptrace_32.c   |    2 +-
 arch/sparc/kernel/ptrace_64.c   |    2 +-
 arch/um/kernel/ptrace.c         |    2 +-
 arch/xtensa/kernel/ptrace.c     |    2 +-
 include/asm-generic/syscall.h   |    4 ++--
 include/linux/entry-common.h    |   25 ++++++++++++-------------
 include/linux/ptrace.h          |   13 ++++++-------
 20 files changed, 40 insertions(+), 44 deletions(-)
arch/alpha/kernel/ptrace.c +1 -1
@@ -375,7 +375,7 @@ asmlinkage unsigned long syscall_trace_e
 	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);
arch/arc/kernel/ptrace.c +1 -1
@@ -342,7 +342,7 @@ long arch_ptrace(struct task_struct *chi
 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
arch/arm/kernel/ptrace.c +1 -1
@@ -840,7 +840,7 @@ static void report_syscall(struct pt_reg
 
 	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;
arch/arm64/kernel/ptrace.c +1 -1
@@ -2379,7 +2379,7 @@ static int report_syscall_entry(struct p
 	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;
arch/csky/kernel/ptrace.c +1 -1
@@ -320,7 +320,7 @@ long arch_ptrace(struct task_struct *chi
 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 (!seccomp_permit_syscall())
arch/hexagon/kernel/traps.c +1 -1
@@ -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 */
arch/m68k/kernel/ptrace.c +1 -1
@@ -279,7 +279,7 @@ 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 (!seccomp_permit_syscall())
 		return -1;
arch/microblaze/kernel/ptrace.c +1 -1
@@ -139,7 +139,7 @@ asmlinkage unsigned long do_syscall_trac
 	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
arch/mips/kernel/ptrace.c +1 -1
@@ -1324,7 +1324,7 @@ asmlinkage long syscall_trace_enter(stru
 	user_exit();
 
 	if (test_thread_flag(TIF_SYSCALL_TRACE)) {
-		if (ptrace_report_syscall_entry(regs))
+		if (!ptrace_report_syscall_permit_entry(regs))
 			return -1;
 	}
 
arch/nios2/kernel/ptrace.c +1 -1
@@ -133,7 +133,7 @@ asmlinkage int do_syscall_trace_enter(vo
 	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;
 }
arch/openrisc/kernel/ptrace.c +1 -1
@@ -293,7 +293,7 @@ asmlinkage long do_syscall_trace_enter(s
 	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
arch/parisc/kernel/ptrace.c +4 -6
@@ -326,7 +326,7 @@ long compat_arch_ptrace(struct task_stru
 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_re
 		 */
 		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,
arch/sh/kernel/ptrace_32.c +1 -1
@@ -455,7 +455,7 @@ long arch_ptrace(struct task_struct *chi
 asmlinkage long do_syscall_trace_enter(struct pt_regs *regs)
 {
 	if (test_thread_flag(TIF_SYSCALL_TRACE) &&
-	    ptrace_report_syscall_entry(regs)) {
+	    !ptrace_report_syscall_permit_entry(regs)) {
 		regs->regs[0] = -ENOSYS;
 		return -1;
 	}
arch/sparc/kernel/ptrace_32.c +1 -1
@@ -441,7 +441,7 @@ asmlinkage int syscall_trace(struct pt_r
 		if (syscall_exit_p)
 			ptrace_report_syscall_exit(regs, 0);
 		else
-			ret = ptrace_report_syscall_entry(regs);
+			ret = !ptrace_report_syscall_permit_entry(regs);
 	}
 
 	return ret;
arch/sparc/kernel/ptrace_64.c +1 -1
@@ -1093,7 +1093,7 @@ asmlinkage int syscall_trace_enter(struc
 		user_exit();
 
 	if (test_thread_flag(TIF_SYSCALL_TRACE))
-		ret = ptrace_report_syscall_entry(regs);
+		ret = !ptrace_report_syscall_permit_entry(regs);
 
 	if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
 		trace_sys_enter(regs, regs->u_regs[UREG_G1]);
arch/um/kernel/ptrace.c +1 -1
@@ -135,7 +135,7 @@ int syscall_trace_enter(struct pt_regs *
 	if (!test_thread_flag(TIF_SYSCALL_TRACE))
 		return 0;
 
-	return ptrace_report_syscall_entry(regs);
+	return !ptrace_report_syscall_permit_entry(regs);
 }
 
 void syscall_trace_leave(struct pt_regs *regs)
arch/xtensa/kernel/ptrace.c +1 -1
@@ -547,7 +547,7 @@ int do_syscall_trace_enter(struct pt_reg
 		regs->areg[2] = -ENOSYS;
 
 	if (test_thread_flag(TIF_SYSCALL_TRACE) &&
-	    ptrace_report_syscall_entry(regs)) {
+	    !ptrace_report_syscall_permit_entry(regs)) {
 		regs->areg[2] = -ENOSYS;
 		regs->syscall = NO_SYSCALL;
 		return 0;
include/asm-generic/syscall.h +2 -2
@@ -58,8 +58,8 @@ void syscall_set_nr(struct task_struct *
  *
  * It's only valid to call this when @task is stopped for system
  * call exit tracing (due to %SYSCALL_WORK_SYSCALL_TRACE or
- * %SYSCALL_WORK_SYSCALL_AUDIT), after ptrace_report_syscall_entry()
- * returned nonzero to prevent the system call from taking place.
+ * %SYSCALL_WORK_SYSCALL_AUDIT), after ptrace_report_syscall_permit_entry()
+ * returned False to prevent the system call from taking place.
  *
  * This rolls back the register state in @regs so it's as if the
  * system call instruction was a no-op.  The registers containing
include/linux/entry-common.h +12 -13
@@ -38,21 +38,22 @@
 				 SYSCALL_WORK_SYSCALL_EXIT_TRAP)
 
 /**
- * arch_ptrace_report_syscall_entry - Architecture specific ptrace_report_syscall_entry() wrapper
+ * arch_ptrace_report_syscall_permit_entry - Architecture specific wrapper for
+ *					     ptrace_report_syscall_permit_entry()
  * @regs: Pointer to the register state at syscall entry
  *
- * Invoked from syscall_trace_enter() to wrap ptrace_report_syscall_entry().
+ * Invoked from syscall_trace_enter() to wrap ptrace_report_syscall_permit_entry().
  *
- * This allows architecture specific ptrace_report_syscall_entry()
+ * This allows architecture specific ptrace_report_syscall_permit_entry()
  * implementations. If not defined by the architecture this falls back to
- * to ptrace_report_syscall_entry().
+ * to ptrace_report_syscall_permit_entry().
  */
-static __always_inline int arch_ptrace_report_syscall_entry(struct pt_regs *regs);
+static __always_inline bool arch_ptrace_report_syscall_permit_entry(struct pt_regs *regs);
 
-#ifndef arch_ptrace_report_syscall_entry
-static __always_inline int arch_ptrace_report_syscall_entry(struct pt_regs *regs)
+#ifndef arch_ptrace_report_syscall_permit_entry
+static __always_inline bool arch_ptrace_report_syscall_permit_entry(struct pt_regs *regs)
 {
-	return ptrace_report_syscall_entry(regs);
+	return ptrace_report_syscall_permit_entry(regs);
 }
 #endif
 
@@ -73,8 +74,6 @@ static inline void syscall_enter_audit(s
 static __always_inline long syscall_trace_enter(struct pt_regs *regs, unsigned long work,
 						long syscall)
 {
-	long ret = 0;
-
 	/*
 	 * Handle Syscall User Dispatch.  This must comes first, since
 	 * the ABI here can be something that doesn't make sense for
@@ -95,8 +94,8 @@ static __always_inline long syscall_trac
 
 	/* Handle ptrace */
 	if (work & (SYSCALL_WORK_SYSCALL_TRACE | SYSCALL_WORK_SYSCALL_EMU)) {
-		ret = arch_ptrace_report_syscall_entry(regs);
-		if (ret || (work & SYSCALL_WORK_SYSCALL_EMU))
+		if (!arch_ptrace_report_syscall_permit_entry(regs) ||
+		    (work & SYSCALL_WORK_SYSCALL_EMU))
 			return -1L;
 	}
 
@@ -137,7 +136,7 @@ static __always_inline long syscall_trac
  * It handles the following work items:
  *
  *  1) syscall_work flag dependent invocations of
- *     ptrace_report_syscall_entry(), __seccomp_permit_syscall(), trace_sys_enter()
+ *     ptrace_report_syscall_permit_entry(), __seccomp_permit_syscall(), trace_sys_enter()
  *  2) Invocation of audit_syscall_entry()
  */
 static __always_inline long syscall_enter_from_user_mode_work(struct pt_regs *regs, long syscall)
include/linux/ptrace.h +5 -5
@@ -405,13 +405,13 @@ extern void sigaction_compat_abi(struct
 /*
  * ptrace report for syscall entry and exit looks identical.
  */
-static inline int ptrace_report_syscall(unsigned long message)
+static inline bool ptrace_report_syscall(unsigned long message)
 {
 	int ptrace = current->ptrace;
 	int signr;
 
 	if (!(ptrace & PT_PTRACED))
-		return 0;
+		return true;
 
 	signr = ptrace_notify(SIGTRAP | ((ptrace & PT_TRACESYSGOOD) ? 0x80 : 0),
 			      message);
@@ -424,11 +424,11 @@ static inline int ptrace_report_syscall(
 	if (signr)
 		send_sig(signr, current, 1);
 
-	return fatal_signal_pending(current);
+	return !fatal_signal_pending(current);
 }
 
 /**
- * ptrace_report_syscall_entry - task is about to attempt a system call
+ * ptrace_report_syscall_permit_entry - task is about to attempt a system call
  * @regs:		user register state of current task
  *
  * This will be called if %SYSCALL_WORK_SYSCALL_TRACE or
@@ -438,7 +438,7 @@ static inline int ptrace_report_syscall(
  * call number and arguments to be tried.  It is safe to block here,
  * preventing the system call from beginning.
  *
- * Returns zero normally, or nonzero if the calling arch code should abort
+ * Returns True normally, or False if the calling architecture code should abort
  * the system call.  That must prevent normal entry so no system call is
  * made.  If @task ever returns to user mode after this, its register state
  * is unspecified, but should be something harmless like an %ENOSYS error

include/linux/ptrace.h static inline int ptrace_report_syscall( · line 453

Quoted 9 lines
include/linux/ptrace.h +1 -2
@@ -447,8 +447,7 @@ static inline int ptrace_report_syscall(
  *
  * Called without locks, just after entering kernel mode.
  */
-static inline __must_check int ptrace_report_syscall_entry(
-	struct pt_regs *regs)
+static inline __must_check bool ptrace_report_syscall_permit_entry(struct pt_regs *regs)
 {
 	return ptrace_report_syscall(PTRACE_EVENTMSG_SYSCALL_ENTRY);
 }
Quoted 1 line
maintainer Acked-by on v1 12/18
#80 lore raw

Re: [patch 12/18] ptrace, treewide: Rename ptrace_report_syscall_entry() to ptrace_report_syscall_permit_entry()

In reply to Thomas Gleixner
Quoted 6 lines · Thomas Gleixner

The return value of that function is boolean and tells the caller whether to permit the syscall processing or not.

Rename the function so the purpose is clear and make the return type bool.

 arch/m68k/kernel/ptrace.c       |    2 +-

Gr{oetje,eeting}s,

Geert

Signature · 5 lines
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- [email protected]

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds
Reviewed-by on v1 12/18
#81 lore raw

Re: [patch 12/18] ptrace, treewide: Rename ptrace_report_syscall_entry() to ptrace_report_syscall_permit_entry()

In reply to Thomas Gleixner
Quoted 380 lines · Thomas Gleixner

The return value of that function is boolean and tells the caller whether to permit the syscall processing or not.

Rename the function so the purpose is clear and make the return type bool.

Cc Arnd Bergmann <[email protected]>
Cc Oleg Nesterov <[email protected]>
Cc Richard Henderson <[email protected]>
Cc Vineet Gupta <[email protected]>
Cc Russell King <[email protected]>
Cc Catalin Marinas <[email protected]>
Cc Will Deacon <[email protected]>
Cc Guo Ren <[email protected]>
Cc Brian Cain <[email protected]>
Cc Geert Uytterhoeven <[email protected]>
Cc Michal Simek <[email protected]>
Cc Thomas Bogendoerfer <[email protected]>
Cc Dinh Nguyen <[email protected]>
Cc Helge Deller <[email protected]>
Cc Yoshinori Sato <[email protected]>
Cc "David S. Miller" <[email protected]>
Cc Andreas Larsson <[email protected]>
Cc Chris Zankel <[email protected]>

---
 arch/alpha/kernel/ptrace.c      |    2 +- arch/arc/kernel/ptrace.c        |    2 +- arch/arm/kernel/ptrace.c        |    2 +- arch/arm64/kernel/ptrace.c      |    2 +- arch/csky/kernel/ptrace.c       |    2 +- arch/hexagon/kernel/traps.c     |    2 +- arch/m68k/kernel/ptrace.c       |    2 +- arch/microblaze/kernel/ptrace.c |    2 +- arch/mips/kernel/ptrace.c       |    2 +- arch/nios2/kernel/ptrace.c      |    2 +- arch/openrisc/kernel/ptrace.c   |    2 +- arch/parisc/kernel/ptrace.c     |   10 ++++------ arch/sh/kernel/ptrace_32.c      |    2 +- arch/sparc/kernel/ptrace_32.c   |    2 +- arch/sparc/kernel/ptrace_64.c   |    2 +- arch/um/kernel/ptrace.c         |    2 +- arch/xtensa/kernel/ptrace.c     |    2 +- include/asm-generic/syscall.h   |    4 ++-- include/linux/entry-common.h    |   25 ++++++++++++------------- include/linux/ptrace.h          |   13 ++++++-------

 20 files changed, 40 insertions(+), 44 deletions(-)
arch/alpha/kernel/ptrace.c +0 -0
@@ -375,7 +375,7 @@ asmlinkage unsigned long syscall_trace_e
  	struct pt_regs *regs = current_pt_regs();


  if (test_thread_flag(TIF_SYSCALL_TRACE) &&

arch/alpha/kernel/ptrace.c +1 -1
-		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);

arch/arc/kernel/ptrace.c +1 -1
@@ -342,7 +342,7 @@ long arch_ptrace(struct task_struct *chi
  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

arch/arm/kernel/ptrace.c +0 -0
@@ -840,7 +840,7 @@ static void report_syscall(struct pt_reg


  if (dir == PTRACE_SYSCALL_EXIT) ptrace_report_syscall_exit(regs, 0);

arch/arm/kernel/ptrace.c +1 -1
-	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;

arch/arm64/kernel/ptrace.c +0 -0
@@ -2379,7 +2379,7 @@ static int report_syscall_entry(struct p
  	int regno, ret;


  saved_reg = ptrace_save_reg(regs, PTRACE_SYSCALL_ENTER, &regno);

arch/arm64/kernel/ptrace.c +1 -1
-	ret = ptrace_report_syscall_entry(regs);
+	ret = !ptrace_report_syscall_permit_entry(regs);

  if (ret)
  forget_syscall(regs);
  regs->regs[regno] = saved_reg;

arch/csky/kernel/ptrace.c +1 -1
@@ -320,7 +320,7 @@ long arch_ptrace(struct task_struct *chi
  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 (!seccomp_permit_syscall())

arch/hexagon/kernel/traps.c +0 -0
@@ -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) &&

arch/hexagon/kernel/traps.c +1 -1
-			ptrace_report_syscall_entry(regs)))
+			!ptrace_report_syscall_permit_entry(regs)))

  return;  /*  return -ENOSYS somewhere?  */
  /* Interrupts should be re-enabled for syscall processing */

arch/m68k/kernel/ptrace.c +0 -0
@@ -279,7 +279,7 @@ asmlinkage int syscall_trace_enter(void)
  	int ret = 0;


  if (test_thread_flag(TIF_SYSCALL_TRACE))

arch/m68k/kernel/ptrace.c +1 -1
-		ret = ptrace_report_syscall_entry(task_pt_regs(current));
+		ret = !ptrace_report_syscall_permit_entry(task_pt_regs(current));


  if (!seccomp_permit_syscall())
  return -1;

arch/microblaze/kernel/ptrace.c +0 -0
@@ -139,7 +139,7 @@ asmlinkage unsigned long do_syscall_trac
  	secure_computing_strict(regs->r12);


  if (test_thread_flag(TIF_SYSCALL_TRACE) &&

arch/microblaze/kernel/ptrace.c +1 -1
-	    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

arch/mips/kernel/ptrace.c +0 -0
@@ -1324,7 +1324,7 @@ asmlinkage long syscall_trace_enter(stru
  	user_exit();


  if (test_thread_flag(TIF_SYSCALL_TRACE)) {

arch/mips/kernel/ptrace.c +1 -1
-		if (ptrace_report_syscall_entry(regs))
+		if (!ptrace_report_syscall_permit_entry(regs))

  return -1;
  }

arch/nios2/kernel/ptrace.c +0 -0
@@ -133,7 +133,7 @@ asmlinkage int do_syscall_trace_enter(vo
  	int ret = 0;


  if (test_thread_flag(TIF_SYSCALL_TRACE))

arch/nios2/kernel/ptrace.c +1 -1
-		ret = ptrace_report_syscall_entry(task_pt_regs(current));
+		ret = !ptrace_report_syscall_permit_entry(task_pt_regs(current));


  return ret;
 }

arch/openrisc/kernel/ptrace.c +0 -0
@@ -293,7 +293,7 @@ asmlinkage long do_syscall_trace_enter(s
  	long ret = 0;


  if (test_thread_flag(TIF_SYSCALL_TRACE) &&

arch/openrisc/kernel/ptrace.c +1 -1
-	    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

arch/parisc/kernel/ptrace.c +1 -1
@@ -326,7 +326,7 @@ long compat_arch_ptrace(struct task_stru
  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

arch/parisc/kernel/ptrace.c +0 -0
@@ -334,12 +334,10 @@ long do_syscall_trace_enter(struct pt_re
  		 */
  		regs->gr[28] = -ENOSYS;

arch/parisc/kernel/ptrace.c +1 -1
-		if (rc) {
+		if (!permit) {

  /*

arch/parisc/kernel/ptrace.c +2 -4
-			 * 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,

arch/sh/kernel/ptrace_32.c +0 -0
@@ -455,7 +455,7 @@ long arch_ptrace(struct task_struct *chi
  asmlinkage long do_syscall_trace_enter(struct pt_regs *regs)
  {

  if (test_thread_flag(TIF_SYSCALL_TRACE) &&

arch/sh/kernel/ptrace_32.c +1 -1
-	    ptrace_report_syscall_entry(regs)) {
+	    !ptrace_report_syscall_permit_entry(regs)) {

  regs->regs[0] = -ENOSYS;
  return -1;
  }

arch/sparc/kernel/ptrace_32.c +0 -0
@@ -441,7 +441,7 @@ asmlinkage int syscall_trace(struct pt_r
  		if (syscall_exit_p)
  			ptrace_report_syscall_exit(regs, 0);

  else

arch/sparc/kernel/ptrace_32.c +1 -1
-			ret = ptrace_report_syscall_entry(regs);
+			ret = !ptrace_report_syscall_permit_entry(regs);

  }

  return ret;

arch/sparc/kernel/ptrace_64.c +0 -0
@@ -1093,7 +1093,7 @@ asmlinkage int syscall_trace_enter(struc
  		user_exit();


  if (test_thread_flag(TIF_SYSCALL_TRACE))

arch/sparc/kernel/ptrace_64.c +1 -1
-		ret = ptrace_report_syscall_entry(regs);
+		ret = !ptrace_report_syscall_permit_entry(regs);


  if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) trace_sys_enter(regs, regs->u_regs[UREG_G1]);

arch/um/kernel/ptrace.c +0 -0
@@ -135,7 +135,7 @@ int syscall_trace_enter(struct pt_regs *
  	if (!test_thread_flag(TIF_SYSCALL_TRACE))
  		return 0;

arch/um/kernel/ptrace.c +1 -1
-	return ptrace_report_syscall_entry(regs);
+	return !ptrace_report_syscall_permit_entry(regs);

 }

 void syscall_trace_leave(struct pt_regs *regs)

arch/xtensa/kernel/ptrace.c +0 -0
@@ -547,7 +547,7 @@ int do_syscall_trace_enter(struct pt_reg
  		regs->areg[2] = -ENOSYS;


  if (test_thread_flag(TIF_SYSCALL_TRACE) &&

arch/xtensa/kernel/ptrace.c +1 -1
-	    ptrace_report_syscall_entry(regs)) {
+	    !ptrace_report_syscall_permit_entry(regs)) {

  regs->areg[2] = -ENOSYS;
  regs->syscall = NO_SYSCALL;
  return 0;

include/asm-generic/syscall.h +2 -2
@@ -58,8 +58,8 @@ void syscall_set_nr(struct task_struct *
   *
   * It's only valid to call this when @task is stopped for system
   * call exit tracing (due to %SYSCALL_WORK_SYSCALL_TRACE or
- * %SYSCALL_WORK_SYSCALL_AUDIT), after ptrace_report_syscall_entry()
- * returned nonzero to prevent the system call from taking place.
+ * %SYSCALL_WORK_SYSCALL_AUDIT), after ptrace_report_syscall_permit_entry()
+ * returned False to prevent the system call from taking place.
   *
   * This rolls back the register state in @regs so it's as if the
   * system call instruction was a no-op.  The registers containing
include/linux/entry-common.h +0 -0
@@ -38,21 +38,22 @@
  				 SYSCALL_WORK_SYSCALL_EXIT_TRAP)


 /**
- * arch_ptrace_report_syscall_entry - Architecture specific ptrace_report_syscall_entry() wrapper
+ * arch_ptrace_report_syscall_permit_entry - Architecture specific wrapper for
+ *      ptrace_report_syscall_permit_entry()
  * @regs: Pointer to the register state at syscall entry
  *
- * Invoked from syscall_trace_enter() to wrap ptrace_report_syscall_entry().
+ * Invoked from syscall_trace_enter() to wrap ptrace_report_syscall_permit_entry(). *
- * This allows architecture specific ptrace_report_syscall_entry()
+ * This allows architecture specific ptrace_report_syscall_permit_entry()
  * implementations. If not defined by the architecture this falls back to
- * to ptrace_report_syscall_entry().
+ * to ptrace_report_syscall_permit_entry().
  */

include/linux/entry-common.h +1 -1
-static __always_inline int arch_ptrace_report_syscall_entry(struct pt_regs *regs);
+static __always_inline bool arch_ptrace_report_syscall_permit_entry(struct pt_regs *regs);

include/linux/entry-common.h +2 -2
-#ifndef arch_ptrace_report_syscall_entry
-static __always_inline int arch_ptrace_report_syscall_entry(struct pt_regs *regs)
+#ifndef arch_ptrace_report_syscall_permit_entry
+static __always_inline bool arch_ptrace_report_syscall_permit_entry(struct pt_regs *regs)

 {

include/linux/entry-common.h +1 -1
-	return ptrace_report_syscall_entry(regs);
+	return ptrace_report_syscall_permit_entry(regs);

 }
 #endif

include/linux/entry-common.h +0 -2
@@ -73,8 +74,6 @@ static inline void syscall_enter_audit(s
  static __always_inline long syscall_trace_enter(struct pt_regs *regs, unsigned long work,
  						long syscall)
  {
-	long ret = 0;
-
  	/*
  	 * Handle Syscall User Dispatch.  This must comes first, since
  	 * the ABI here can be something that doesn't make sense for
@@ -95,8 +94,8 @@ static __always_inline long syscall_trac


  /* Handle ptrace */
  if (work & (SYSCALL_WORK_SYSCALL_TRACE | SYSCALL_WORK_SYSCALL_EMU)) {

include/linux/entry-common.h +2 -2
-		ret = arch_ptrace_report_syscall_entry(regs);
-		if (ret || (work & SYSCALL_WORK_SYSCALL_EMU))
+		if (!arch_ptrace_report_syscall_permit_entry(regs) ||
+		    (work & SYSCALL_WORK_SYSCALL_EMU))

  return -1L;
  }

include/linux/entry-common.h +1 -1
@@ -137,7 +136,7 @@ static __always_inline long syscall_trac
   * It handles the following work items:
   *
   *  1) syscall_work flag dependent invocations of
- *     ptrace_report_syscall_entry(), __seccomp_permit_syscall(), trace_sys_enter()
+ *     ptrace_report_syscall_permit_entry(), __seccomp_permit_syscall(), trace_sys_enter()
   *  2) Invocation of audit_syscall_entry()
   */
  static __always_inline long syscall_enter_from_user_mode_work(struct pt_regs *regs, long syscall)
include/linux/ptrace.h +1 -1
@@ -405,13 +405,13 @@ extern void sigaction_compat_abi(struct
  /*
   * ptrace report for syscall entry and exit looks identical.
   */
-static inline int ptrace_report_syscall(unsigned long message)
+static inline bool ptrace_report_syscall(unsigned long message)
  {
  	int ptrace = current->ptrace;
  	int signr;


  if (!(ptrace & PT_PTRACED))

include/linux/ptrace.h +1 -1
-		return 0;
+		return true;


  signr = ptrace_notify(SIGTRAP | ((ptrace & PT_TRACESYSGOOD) ? 0x80 : 0), message);

include/linux/ptrace.h +0 -0
@@ -424,11 +424,11 @@ static inline int ptrace_report_syscall(
  	if (signr)
  		send_sig(signr, current, 1);

include/linux/ptrace.h +1 -1
-	return fatal_signal_pending(current);
+	return !fatal_signal_pending(current);

 }

 /**
- * ptrace_report_syscall_entry - task is about to attempt a system call
+ * ptrace_report_syscall_permit_entry - task is about to attempt a system call
  * @regs: user register state of current task
  *
  * This will be called if %SYSCALL_WORK_SYSCALL_TRACE or

include/linux/ptrace.h +1 -1
@@ -438,7 +438,7 @@ static inline int ptrace_report_syscall(
   * call number and arguments to be tried.  It is safe to block here,
   * preventing the system call from beginning.
   *
- * Returns zero normally, or nonzero if the calling arch code should abort
+ * Returns True normally, or False if the calling architecture code should abort
   * the system call.  That must prevent normal entry so no system call is
   * made.  If @task ever returns to user mode after this, its register state
   * is unspecified, but should be something harmless like an %ENOSYS error

include/linux/ptrace.h static inline int ptrace_report_syscall( · line 453

Quoted 9 lines
include/linux/ptrace.h +1 -2
@@ -447,8 +447,7 @@ static inline int ptrace_report_syscall(
   *
   * Called without locks, just after entering kernel mode.
   */
-static inline __must_check int ptrace_report_syscall_entry(
-	struct pt_regs *regs)
+static inline __must_check bool ptrace_report_syscall_permit_entry(struct pt_regs *regs)
  {
  	return ptrace_report_syscall(PTRACE_EVENTMSG_SYSCALL_ENTRY);
  }
Reviewed-by on v1 12/18
#82 lore raw

Re: [patch 12/18] ptrace, treewide: Rename ptrace_report_syscall_entry() to ptrace_report_syscall_permit_entry()

In reply to Thomas Gleixner
Quoted 60 lines · Thomas Gleixner

The return value of that function is boolean and tells the caller whether to permit the syscall processing or not.

Rename the function so the purpose is clear and make the return type bool.

Cc Arnd Bergmann <[email protected]>
Cc Oleg Nesterov <[email protected]>
Cc Richard Henderson <[email protected]>
Cc Vineet Gupta <[email protected]>
Cc Russell King <[email protected]>
Cc Catalin Marinas <[email protected]>
Cc Will Deacon <[email protected]>
Cc Guo Ren <[email protected]>
Cc Brian Cain <[email protected]>
Cc Geert Uytterhoeven <[email protected]>
Cc Michal Simek <[email protected]>
Cc Thomas Bogendoerfer <[email protected]>
Cc Dinh Nguyen <[email protected]>
Cc Helge Deller <[email protected]>
Cc Yoshinori Sato <[email protected]>
Cc "David S. Miller" <[email protected]>
Cc Andreas Larsson <[email protected]>
Cc Chris Zankel <[email protected]>
---
 arch/alpha/kernel/ptrace.c      |    2 +-
 arch/arc/kernel/ptrace.c        |    2 +-
 arch/arm/kernel/ptrace.c        |    2 +-
 arch/arm64/kernel/ptrace.c      |    2 +-
 arch/csky/kernel/ptrace.c       |    2 +-
 arch/hexagon/kernel/traps.c     |    2 +-
 arch/m68k/kernel/ptrace.c       |    2 +-
 arch/microblaze/kernel/ptrace.c |    2 +-
 arch/mips/kernel/ptrace.c       |    2 +-
 arch/nios2/kernel/ptrace.c      |    2 +-
 arch/openrisc/kernel/ptrace.c   |    2 +-
 arch/parisc/kernel/ptrace.c     |   10 ++++------
 arch/sh/kernel/ptrace_32.c      |    2 +-
 arch/sparc/kernel/ptrace_32.c   |    2 +-
 arch/sparc/kernel/ptrace_64.c   |    2 +-
 arch/um/kernel/ptrace.c         |    2 +-
 arch/xtensa/kernel/ptrace.c     |    2 +-
 include/asm-generic/syscall.h   |    4 ++--
 include/linux/entry-common.h    |   25 ++++++++++++-------------
 include/linux/ptrace.h          |   13 ++++++-------
 20 files changed, 40 insertions(+), 44 deletions(-)

[...]

Quoted 14 lines
arch/parisc/kernel/ptrace.c +1 -1
@@ -326,7 +326,7 @@ long compat_arch_ptrace(struct task_stru
 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_re
 		 */
 		regs->gr[28] = -ENOSYS;

arch/parisc/kernel/ptrace.c long do_syscall_trace_enter(struct pt_re · line 340

Quoted 10 lines
arch/parisc/kernel/ptrace.c +3 -5
 
-		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.

Hey Thomas,

This comment syscall call sounds a bit weird.

Apart from this, Everything looks good.

Regards,
Mukesh

#83 lore raw

Re: [patch 12/18] ptrace, treewide: Rename ptrace_report_syscall_entry() to ptrace_report_syscall_permit_entry()

In reply to Thomas Gleixner

Hello,

why is the syscall -1 special-cased here?

Wouldn't any invalid syscall number such as -2 work equally well, making this whole 'permit' pinned on the -1 value bogus?

Quoted 63 lines · Thomas Gleixner

The return value of that function is boolean and tells the caller whether to permit the syscall processing or not.

Rename the function so the purpose is clear and make the return type bool.

Cc Arnd Bergmann <[email protected]>
Cc Oleg Nesterov <[email protected]>
Cc Richard Henderson <[email protected]>
Cc Vineet Gupta <[email protected]>
Cc Russell King <[email protected]>
Cc Catalin Marinas <[email protected]>
Cc Will Deacon <[email protected]>
Cc Guo Ren <[email protected]>
Cc Brian Cain <[email protected]>
Cc Geert Uytterhoeven <[email protected]>
Cc Michal Simek <[email protected]>
Cc Thomas Bogendoerfer <[email protected]>
Cc Dinh Nguyen <[email protected]>
Cc Helge Deller <[email protected]>
Cc Yoshinori Sato <[email protected]>
Cc "David S. Miller" <[email protected]>
Cc Andreas Larsson <[email protected]>
Cc Chris Zankel <[email protected]>
---
 arch/alpha/kernel/ptrace.c      |    2 +-
 arch/arc/kernel/ptrace.c        |    2 +-
 arch/arm/kernel/ptrace.c        |    2 +-
 arch/arm64/kernel/ptrace.c      |    2 +-
 arch/csky/kernel/ptrace.c       |    2 +-
 arch/hexagon/kernel/traps.c     |    2 +-
 arch/m68k/kernel/ptrace.c       |    2 +-
 arch/microblaze/kernel/ptrace.c |    2 +-
 arch/mips/kernel/ptrace.c       |    2 +-
 arch/nios2/kernel/ptrace.c      |    2 +-
 arch/openrisc/kernel/ptrace.c   |    2 +-
 arch/parisc/kernel/ptrace.c     |   10 ++++------
 arch/sh/kernel/ptrace_32.c      |    2 +-
 arch/sparc/kernel/ptrace_32.c   |    2 +-
 arch/sparc/kernel/ptrace_64.c   |    2 +-
 arch/um/kernel/ptrace.c         |    2 +-
 arch/xtensa/kernel/ptrace.c     |    2 +-
 include/asm-generic/syscall.h   |    4 ++--
 include/linux/entry-common.h    |   25 ++++++++++++-------------
 include/linux/ptrace.h          |   13 ++++++-------
 20 files changed, 40 insertions(+), 44 deletions(-)

arch/alpha/kernel/ptrace.c asmlinkage unsigned long syscall_trace_e · line 379

Quoted 6 lines
arch/alpha/kernel/ptrace.c +1 -1
@@ -375,7 +375,7 @@ asmlinkage unsigned long syscall_trace_e
 	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);

Why is this done here?

Presumably the ptrace_report_syscall_entry returns false here becasue the tracer put -1 into whatever register specifies the syscall number (or it was there to start with) which was then read back, compared to -1, leading to returning false. Now it's set to -1 again?

Thanks

Michal

Quoted 321 lines
arch/alpha/kernel/ptrace.c +0 -0
 		if (regs->r19 == 0 && regs->r0 == (unsigned long)-1)
 			syscall_set_return_value(current, regs, -ENOSYS, 0);
arch/arc/kernel/ptrace.c +1 -1
@@ -342,7 +342,7 @@ long arch_ptrace(struct task_struct *chi
 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
arch/arm/kernel/ptrace.c +1 -1
@@ -840,7 +840,7 @@ static void report_syscall(struct pt_reg
 
 	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;
arch/arm64/kernel/ptrace.c +1 -1
@@ -2379,7 +2379,7 @@ static int report_syscall_entry(struct p
 	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;
arch/csky/kernel/ptrace.c +1 -1
@@ -320,7 +320,7 @@ long arch_ptrace(struct task_struct *chi
 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 (!seccomp_permit_syscall())
arch/hexagon/kernel/traps.c +1 -1
@@ -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 */
arch/m68k/kernel/ptrace.c +1 -1
@@ -279,7 +279,7 @@ 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 (!seccomp_permit_syscall())
 		return -1;
arch/microblaze/kernel/ptrace.c +1 -1
@@ -139,7 +139,7 @@ asmlinkage unsigned long do_syscall_trac
 	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
arch/mips/kernel/ptrace.c +1 -1
@@ -1324,7 +1324,7 @@ asmlinkage long syscall_trace_enter(stru
 	user_exit();
 
 	if (test_thread_flag(TIF_SYSCALL_TRACE)) {
-		if (ptrace_report_syscall_entry(regs))
+		if (!ptrace_report_syscall_permit_entry(regs))
 			return -1;
 	}
 
arch/nios2/kernel/ptrace.c +1 -1
@@ -133,7 +133,7 @@ asmlinkage int do_syscall_trace_enter(vo
 	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;
 }
arch/openrisc/kernel/ptrace.c +1 -1
@@ -293,7 +293,7 @@ asmlinkage long do_syscall_trace_enter(s
 	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
arch/parisc/kernel/ptrace.c +4 -6
@@ -326,7 +326,7 @@ long compat_arch_ptrace(struct task_stru
 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_re
 		 */
 		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,
arch/sh/kernel/ptrace_32.c +1 -1
@@ -455,7 +455,7 @@ long arch_ptrace(struct task_struct *chi
 asmlinkage long do_syscall_trace_enter(struct pt_regs *regs)
 {
 	if (test_thread_flag(TIF_SYSCALL_TRACE) &&
-	    ptrace_report_syscall_entry(regs)) {
+	    !ptrace_report_syscall_permit_entry(regs)) {
 		regs->regs[0] = -ENOSYS;
 		return -1;
 	}
arch/sparc/kernel/ptrace_32.c +1 -1
@@ -441,7 +441,7 @@ asmlinkage int syscall_trace(struct pt_r
 		if (syscall_exit_p)
 			ptrace_report_syscall_exit(regs, 0);
 		else
-			ret = ptrace_report_syscall_entry(regs);
+			ret = !ptrace_report_syscall_permit_entry(regs);
 	}
 
 	return ret;
arch/sparc/kernel/ptrace_64.c +1 -1
@@ -1093,7 +1093,7 @@ asmlinkage int syscall_trace_enter(struc
 		user_exit();
 
 	if (test_thread_flag(TIF_SYSCALL_TRACE))
-		ret = ptrace_report_syscall_entry(regs);
+		ret = !ptrace_report_syscall_permit_entry(regs);
 
 	if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
 		trace_sys_enter(regs, regs->u_regs[UREG_G1]);
arch/um/kernel/ptrace.c +1 -1
@@ -135,7 +135,7 @@ int syscall_trace_enter(struct pt_regs *
 	if (!test_thread_flag(TIF_SYSCALL_TRACE))
 		return 0;
 
-	return ptrace_report_syscall_entry(regs);
+	return !ptrace_report_syscall_permit_entry(regs);
 }
 
 void syscall_trace_leave(struct pt_regs *regs)
arch/xtensa/kernel/ptrace.c +1 -1
@@ -547,7 +547,7 @@ int do_syscall_trace_enter(struct pt_reg
 		regs->areg[2] = -ENOSYS;
 
 	if (test_thread_flag(TIF_SYSCALL_TRACE) &&
-	    ptrace_report_syscall_entry(regs)) {
+	    !ptrace_report_syscall_permit_entry(regs)) {
 		regs->areg[2] = -ENOSYS;
 		regs->syscall = NO_SYSCALL;
 		return 0;
include/asm-generic/syscall.h +2 -2
@@ -58,8 +58,8 @@ void syscall_set_nr(struct task_struct *
  *
  * It's only valid to call this when @task is stopped for system
  * call exit tracing (due to %SYSCALL_WORK_SYSCALL_TRACE or
- * %SYSCALL_WORK_SYSCALL_AUDIT), after ptrace_report_syscall_entry()
- * returned nonzero to prevent the system call from taking place.
+ * %SYSCALL_WORK_SYSCALL_AUDIT), after ptrace_report_syscall_permit_entry()
+ * returned False to prevent the system call from taking place.
  *
  * This rolls back the register state in @regs so it's as if the
  * system call instruction was a no-op.  The registers containing
include/linux/entry-common.h +12 -13
@@ -38,21 +38,22 @@
 				 SYSCALL_WORK_SYSCALL_EXIT_TRAP)
 
 /**
- * arch_ptrace_report_syscall_entry - Architecture specific ptrace_report_syscall_entry() wrapper
+ * arch_ptrace_report_syscall_permit_entry - Architecture specific wrapper for
+ *					     ptrace_report_syscall_permit_entry()
  * @regs: Pointer to the register state at syscall entry
  *
- * Invoked from syscall_trace_enter() to wrap ptrace_report_syscall_entry().
+ * Invoked from syscall_trace_enter() to wrap ptrace_report_syscall_permit_entry().
  *
- * This allows architecture specific ptrace_report_syscall_entry()
+ * This allows architecture specific ptrace_report_syscall_permit_entry()
  * implementations. If not defined by the architecture this falls back to
- * to ptrace_report_syscall_entry().
+ * to ptrace_report_syscall_permit_entry().
  */
-static __always_inline int arch_ptrace_report_syscall_entry(struct pt_regs *regs);
+static __always_inline bool arch_ptrace_report_syscall_permit_entry(struct pt_regs *regs);
 
-#ifndef arch_ptrace_report_syscall_entry
-static __always_inline int arch_ptrace_report_syscall_entry(struct pt_regs *regs)
+#ifndef arch_ptrace_report_syscall_permit_entry
+static __always_inline bool arch_ptrace_report_syscall_permit_entry(struct pt_regs *regs)
 {
-	return ptrace_report_syscall_entry(regs);
+	return ptrace_report_syscall_permit_entry(regs);
 }
 #endif
 
@@ -73,8 +74,6 @@ static inline void syscall_enter_audit(s
 static __always_inline long syscall_trace_enter(struct pt_regs *regs, unsigned long work,
 						long syscall)
 {
-	long ret = 0;
-
 	/*
 	 * Handle Syscall User Dispatch.  This must comes first, since
 	 * the ABI here can be something that doesn't make sense for
@@ -95,8 +94,8 @@ static __always_inline long syscall_trac
 
 	/* Handle ptrace */
 	if (work & (SYSCALL_WORK_SYSCALL_TRACE | SYSCALL_WORK_SYSCALL_EMU)) {
-		ret = arch_ptrace_report_syscall_entry(regs);
-		if (ret || (work & SYSCALL_WORK_SYSCALL_EMU))
+		if (!arch_ptrace_report_syscall_permit_entry(regs) ||
+		    (work & SYSCALL_WORK_SYSCALL_EMU))
 			return -1L;
 	}
 
@@ -137,7 +136,7 @@ static __always_inline long syscall_trac
  * It handles the following work items:
  *
  *  1) syscall_work flag dependent invocations of
- *     ptrace_report_syscall_entry(), __seccomp_permit_syscall(), trace_sys_enter()
+ *     ptrace_report_syscall_permit_entry(), __seccomp_permit_syscall(), trace_sys_enter()
  *  2) Invocation of audit_syscall_entry()
  */
 static __always_inline long syscall_enter_from_user_mode_work(struct pt_regs *regs, long syscall)
include/linux/ptrace.h +6 -7
@@ -405,13 +405,13 @@ extern void sigaction_compat_abi(struct
 /*
  * ptrace report for syscall entry and exit looks identical.
  */
-static inline int ptrace_report_syscall(unsigned long message)
+static inline bool ptrace_report_syscall(unsigned long message)
 {
 	int ptrace = current->ptrace;
 	int signr;
 
 	if (!(ptrace & PT_PTRACED))
-		return 0;
+		return true;
 
 	signr = ptrace_notify(SIGTRAP | ((ptrace & PT_TRACESYSGOOD) ? 0x80 : 0),
 			      message);
@@ -424,11 +424,11 @@ static inline int ptrace_report_syscall(
 	if (signr)
 		send_sig(signr, current, 1);
 
-	return fatal_signal_pending(current);
+	return !fatal_signal_pending(current);
 }
 
 /**
- * ptrace_report_syscall_entry - task is about to attempt a system call
+ * ptrace_report_syscall_permit_entry - task is about to attempt a system call
  * @regs:		user register state of current task
  *
  * This will be called if %SYSCALL_WORK_SYSCALL_TRACE or
@@ -438,7 +438,7 @@ static inline int ptrace_report_syscall(
  * call number and arguments to be tried.  It is safe to block here,
  * preventing the system call from beginning.
  *
- * Returns zero normally, or nonzero if the calling arch code should abort
+ * Returns True normally, or False if the calling architecture code should abort
  * the system call.  That must prevent normal entry so no system call is
  * made.  If @task ever returns to user mode after this, its register state
  * is unspecified, but should be something harmless like an %ENOSYS error
@@ -447,8 +447,7 @@ static inline int ptrace_report_syscall(
  *
  * Called without locks, just after entering kernel mode.
  */
-static inline __must_check int ptrace_report_syscall_entry(
-	struct pt_regs *regs)
+static inline __must_check bool ptrace_report_syscall_permit_entry(struct pt_regs *regs)
 {
 	return ptrace_report_syscall(PTRACE_EVENTMSG_SYSCALL_ENTRY);
 }
maintainer
#84 lore raw

Re: [patch 12/18] ptrace, treewide: Rename ptrace_report_syscall_entry() to ptrace_report_syscall_permit_entry()

Quoted 13 lines · Michal Suchánek

arch/alpha/kernel/ptrace.c asmlinkage unsigned long syscall_trace_e · line 379

Quoted 10 lines
arch/alpha/kernel/ptrace.c +1 -1
@@ -375,7 +375,7 @@ asmlinkage unsigned long syscall_trace_e
 	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);

Why is this done here?

Quoted 4 lines

Presumably the ptrace_report_syscall_entry returns false here becasue the tracer put -1 into whatever register specifies the syscall number (or it was there to start with) which was then read back, compared to -1, leading to returning false. Now it's set to -1 again?

I don't know why arch/alpha/ does syscall_set_nr(-1).

But note that ptrace_report_syscall_entry() doesn't even check whether the syscall number was changed. It only checks fatal_signal_pending().

Oleg.

#85 lore raw

[tip: core/entry] ptrace, treewide: Rename ptrace_report_syscall_entry() to ptrace_report_syscall_permit_entry()

In reply to Thomas Gleixner
The following commit has been merged into the core/entry branch of tip:

The following commit has been merged into the core/entry branch of tip:

Commit-ID:     622f04e97415e62bd2ab61f7a27e7a296e8467b7
Gitweb:        https://git.kernel.org/tip/622f04e97415e62bd2ab61f7a27e7a296e8467b7
Author:        Thomas Gleixner <[email protected]>
AuthorDate:    Tue, 07 Jul 2026 21:06:44 +02:00
Committer:     Thomas Gleixner <[email protected]>
CommitterDate: Sun, 12 Jul 2026 12:38:02 +02:00

ptrace, treewide: Rename ptrace_report_syscall_entry() to ptrace_report_syscall_permit_entry()

The return value of that function is boolean and tells the caller whether to permit the syscall processing or not.

Rename the function so the purpose is clear and make the return type bool.

---
 arch/alpha/kernel/ptrace.c      |  2 +-
 arch/arc/kernel/ptrace.c        |  2 +-
 arch/arm/kernel/ptrace.c        |  2 +-
 arch/arm64/kernel/ptrace.c      |  2 +-
 arch/csky/kernel/ptrace.c       |  2 +-
 arch/hexagon/kernel/traps.c     |  2 +-
 arch/m68k/kernel/ptrace.c       |  2 +-
 arch/microblaze/kernel/ptrace.c |  2 +-
 arch/mips/kernel/ptrace.c       |  2 +-
 arch/nios2/kernel/ptrace.c      |  2 +-
 arch/openrisc/kernel/ptrace.c   |  2 +-
 arch/parisc/kernel/ptrace.c     | 10 ++++------
 arch/sh/kernel/ptrace_32.c      |  2 +-
 arch/sparc/kernel/ptrace_32.c   |  2 +-
 arch/sparc/kernel/ptrace_64.c   |  2 +-
 arch/um/kernel/ptrace.c         |  2 +-
 arch/xtensa/kernel/ptrace.c     |  2 +-
 include/asm-generic/syscall.h   |  4 ++--
 include/linux/entry-common.h    | 25 ++++++++++++-------------
 include/linux/ptrace.h          | 13 ++++++-------
 20 files changed, 40 insertions(+), 44 deletions(-)
arch/alpha/kernel/ptrace.c +1 -1
index 2870101..768b092 100644
@@ -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);
arch/arc/kernel/ptrace.c +1 -1
index cad5367..fe2b657 100644
@@ -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
arch/arm/kernel/ptrace.c +1 -1
index 45076fc..ed7a2a8 100644
@@ -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;
arch/arm64/kernel/ptrace.c +1 -1
index 253ce5d..5709e9d 100644
@@ -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;
arch/csky/kernel/ptrace.c +1 -1
index b902358..ee2867a 100644
@@ -320,7 +320,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 -1;
 
 	if (!seccomp_permit_syscall())
arch/hexagon/kernel/traps.c +1 -1
index e732aa0..6fe0c1b 100644
@@ -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 */
arch/m68k/kernel/ptrace.c +1 -1
index 28546d7..4575f64 100644
@@ -279,7 +279,7 @@ 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 (!seccomp_permit_syscall())
 		return -1;
arch/microblaze/kernel/ptrace.c +1 -1
index 5234d0c..236264e 100644
@@ -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
arch/mips/kernel/ptrace.c +1 -1
index af1e005..5a0e298 100644
@@ -1324,7 +1324,7 @@ 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;
 	}
 
arch/nios2/kernel/ptrace.c +1 -1
index c88f5ca..2cd7e1e 100644
@@ -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;
 }
arch/openrisc/kernel/ptrace.c +1 -1
index 552489b..287a971 100644
@@ -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
arch/parisc/kernel/ptrace.c +4 -6
index ac5d077..1d9e210 100644
@@ -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,
arch/sh/kernel/ptrace_32.c +1 -1
index 7594bd5..8794081 100644
@@ -455,7 +455,7 @@ long arch_ptrace(struct task_struct *child, long request,
 asmlinkage long do_syscall_trace_enter(struct pt_regs *regs)
 {
 	if (test_thread_flag(TIF_SYSCALL_TRACE) &&
-	    ptrace_report_syscall_entry(regs)) {
+	    !ptrace_report_syscall_permit_entry(regs)) {
 		regs->regs[0] = -ENOSYS;
 		return -1;
 	}
arch/sparc/kernel/ptrace_32.c +1 -1
index c563339..5991b17 100644
@@ -441,7 +441,7 @@ asmlinkage int syscall_trace(struct pt_regs *regs, int syscall_exit_p)
 		if (syscall_exit_p)
 			ptrace_report_syscall_exit(regs, 0);
 		else
-			ret = ptrace_report_syscall_entry(regs);
+			ret = !ptrace_report_syscall_permit_entry(regs);
 	}
 
 	return ret;
arch/sparc/kernel/ptrace_64.c +1 -1
index 9fc67fa..825ddf5 100644
@@ -1093,7 +1093,7 @@ asmlinkage int syscall_trace_enter(struct pt_regs *regs)
 		user_exit();
 
 	if (test_thread_flag(TIF_SYSCALL_TRACE))
-		ret = ptrace_report_syscall_entry(regs);
+		ret = !ptrace_report_syscall_permit_entry(regs);
 
 	if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
 		trace_sys_enter(regs, regs->u_regs[UREG_G1]);
arch/um/kernel/ptrace.c +1 -1
index fdbb37b..7da0a52 100644
@@ -135,7 +135,7 @@ int syscall_trace_enter(struct pt_regs *regs)
 	if (!test_thread_flag(TIF_SYSCALL_TRACE))
 		return 0;
 
-	return ptrace_report_syscall_entry(regs);
+	return !ptrace_report_syscall_permit_entry(regs);
 }
 
 void syscall_trace_leave(struct pt_regs *regs)
arch/xtensa/kernel/ptrace.c +1 -1
index 5c3ebb0..364e4fd 100644
@@ -547,7 +547,7 @@ int do_syscall_trace_enter(struct pt_regs *regs)
 		regs->areg[2] = -ENOSYS;
 
 	if (test_thread_flag(TIF_SYSCALL_TRACE) &&
-	    ptrace_report_syscall_entry(regs)) {
+	    !ptrace_report_syscall_permit_entry(regs)) {
 		regs->areg[2] = -ENOSYS;
 		regs->syscall = NO_SYSCALL;
 		return 0;
include/asm-generic/syscall.h +2 -2
index c5a3ad5..b53bdd3 100644
@@ -58,8 +58,8 @@ void syscall_set_nr(struct task_struct *task, struct pt_regs *regs, int nr);
  *
  * It's only valid to call this when @task is stopped for system
  * call exit tracing (due to %SYSCALL_WORK_SYSCALL_TRACE or
- * %SYSCALL_WORK_SYSCALL_AUDIT), after ptrace_report_syscall_entry()
- * returned nonzero to prevent the system call from taking place.
+ * %SYSCALL_WORK_SYSCALL_AUDIT), after ptrace_report_syscall_permit_entry()
+ * returned False to prevent the system call from taking place.
  *
  * This rolls back the register state in @regs so it's as if the
  * system call instruction was a no-op.  The registers containing
include/linux/entry-common.h +12 -13
index 99c49a4..07d97de 100644
@@ -39,21 +39,22 @@
 				 SYSCALL_WORK_SYSCALL_EXIT_TRAP)
 
 /**
- * arch_ptrace_report_syscall_entry - Architecture specific ptrace_report_syscall_entry() wrapper
+ * arch_ptrace_report_syscall_permit_entry - Architecture specific wrapper for
+ *					     ptrace_report_syscall_permit_entry()
  * @regs: Pointer to the register state at syscall entry
  *
- * Invoked from syscall_trace_enter() to wrap ptrace_report_syscall_entry().
+ * Invoked from syscall_trace_enter() to wrap ptrace_report_syscall_permit_entry().
  *
- * This allows architecture specific ptrace_report_syscall_entry()
+ * This allows architecture specific ptrace_report_syscall_permit_entry()
  * implementations. If not defined by the architecture this falls back to
- * to ptrace_report_syscall_entry().
+ * to ptrace_report_syscall_permit_entry().
  */
-static __always_inline int arch_ptrace_report_syscall_entry(struct pt_regs *regs);
+static __always_inline bool arch_ptrace_report_syscall_permit_entry(struct pt_regs *regs);
 
-#ifndef arch_ptrace_report_syscall_entry
-static __always_inline int arch_ptrace_report_syscall_entry(struct pt_regs *regs)
+#ifndef arch_ptrace_report_syscall_permit_entry
+static __always_inline bool arch_ptrace_report_syscall_permit_entry(struct pt_regs *regs)
 {
-	return ptrace_report_syscall_entry(regs);
+	return ptrace_report_syscall_permit_entry(regs);
 }
 #endif
 
@@ -73,8 +74,6 @@ static inline void syscall_enter_audit(struct pt_regs *regs, long syscall)
 static __always_inline long syscall_trace_enter(struct pt_regs *regs, unsigned long work,
 						long syscall)
 {
-	long ret = 0;
-
 	/*
 	 * Handle Syscall User Dispatch.  This must comes first, since
 	 * the ABI here can be something that doesn't make sense for
@@ -95,8 +94,8 @@ static __always_inline long syscall_trace_enter(struct pt_regs *regs, unsigned l
 
 	/* Handle ptrace */
 	if (work & (SYSCALL_WORK_SYSCALL_TRACE | SYSCALL_WORK_SYSCALL_EMU)) {
-		ret = arch_ptrace_report_syscall_entry(regs);
-		if (ret || (work & SYSCALL_WORK_SYSCALL_EMU))
+		if (!arch_ptrace_report_syscall_permit_entry(regs) ||
+		    (work & SYSCALL_WORK_SYSCALL_EMU))
 			return -1L;
 	}
 
@@ -137,7 +136,7 @@ static __always_inline long syscall_trace_enter(struct pt_regs *regs, unsigned l
  * It handles the following work items:
  *
  *  1) syscall_work flag dependent invocations of
- *     ptrace_report_syscall_entry(), __seccomp_permit_syscall(), trace_sys_enter()
+ *     ptrace_report_syscall_permit_entry(), __seccomp_permit_syscall(), trace_sys_enter()
  *  2) Invocation of audit_syscall_entry()
  */
 static __always_inline long syscall_enter_from_user_mode_work(struct pt_regs *regs, long syscall)
include/linux/ptrace.h +6 -7
index ef314f7..2839d5c 100644
@@ -405,13 +405,13 @@ extern void sigaction_compat_abi(struct k_sigaction *act, struct k_sigaction *oa
 /*
  * ptrace report for syscall entry and exit looks identical.
  */
-static inline int ptrace_report_syscall(unsigned long message)
+static inline bool ptrace_report_syscall(unsigned long message)
 {
 	int ptrace = current->ptrace;
 	int signr;
 
 	if (!(ptrace & PT_PTRACED))
-		return 0;
+		return true;
 
 	signr = ptrace_notify(SIGTRAP | ((ptrace & PT_TRACESYSGOOD) ? 0x80 : 0),
 			      message);
@@ -424,11 +424,11 @@ static inline int ptrace_report_syscall(unsigned long message)
 	if (signr)
 		send_sig(signr, current, 1);
 
-	return fatal_signal_pending(current);
+	return !fatal_signal_pending(current);
 }
 
 /**
- * ptrace_report_syscall_entry - task is about to attempt a system call
+ * ptrace_report_syscall_permit_entry - task is about to attempt a system call
  * @regs:		user register state of current task
  *
  * This will be called if %SYSCALL_WORK_SYSCALL_TRACE or
@@ -438,7 +438,7 @@ static inline int ptrace_report_syscall(unsigned long message)
  * call number and arguments to be tried.  It is safe to block here,
  * preventing the system call from beginning.
  *
- * Returns zero normally, or nonzero if the calling arch code should abort
+ * Returns True normally, or False if the calling architecture code should abort
  * the system call.  That must prevent normal entry so no system call is
  * made.  If @task ever returns to user mode after this, its register state
  * is unspecified, but should be something harmless like an %ENOSYS error
@@ -447,8 +447,7 @@ static inline int ptrace_report_syscall(unsigned long message)
  *
  * Called without locks, just after entering kernel mode.
  */
-static inline __must_check int ptrace_report_syscall_entry(
-	struct pt_regs *regs)
+static inline __must_check bool ptrace_report_syscall_permit_entry(struct pt_regs *regs)
 {
 	return ptrace_report_syscall(PTRACE_EVENTMSG_SYSCALL_ENTRY);
 }
author maintainer
#86 lore raw

PATCH 13/18 entry: Make trace_syscall_enter() return type bool

In reply to Thomas Gleixner

In preparation of converting the return value of syscall_enter_from_user_mode[_work]() bool, rework trace_syscall_enter() to

- update the syscall number via a pointer argument

- Return True if the syscall number is != -1, False otherwise

That aligns with ptrace_report_syscall_permit_enter() and seccomp_permit_syscall().

The only difference is that this also returns False, when the syscall number was already -1 to begin with, but there is not much which can be done about that. As the architecture has to preset the return value to -ENOSYS anyway, that results in the correct return value for such an invalid syscall.

---
 include/linux/entry-common.h  |    8 +++++---
 kernel/entry/syscall-common.c |    7 ++++---
 2 files changed, 9 insertions(+), 6 deletions(-)
include/linux/entry-common.h +5 -3
@@ -58,7 +58,7 @@ static __always_inline bool arch_ptrace_
 #endif
 
 bool syscall_user_dispatch(struct pt_regs *regs);
-long trace_syscall_enter(struct pt_regs *regs, long syscall);
+bool trace_syscall_enter(struct pt_regs *regs, long *syscall);
 void trace_syscall_exit(struct pt_regs *regs, long ret);
 
 static inline void syscall_enter_audit(struct pt_regs *regs, long syscall)
@@ -108,8 +108,10 @@ static __always_inline long syscall_trac
 	/* Either of the above might have changed the syscall number */
 	syscall = syscall_get_nr(current, regs);
 
-	if (unlikely(work & SYSCALL_WORK_SYSCALL_TRACEPOINT))
-		syscall = trace_syscall_enter(regs, syscall);
+	if (unlikely(work & SYSCALL_WORK_SYSCALL_TRACEPOINT)) {
+		if (!trace_syscall_enter(regs, &syscall))
+			return -1L;
+	}
 
 	syscall_enter_audit(regs, syscall);
 
kernel/entry/syscall-common.c +4 -3
@@ -7,14 +7,15 @@
 
 /* Out of line to prevent tracepoint code duplication */
 
-long trace_syscall_enter(struct pt_regs *regs, long syscall)
+bool trace_syscall_enter(struct pt_regs *regs, long *syscall)
 {
-	trace_sys_enter(regs, syscall);
+	trace_sys_enter(regs, *syscall);
 	/*
 	 * Probes or BPF hooks in the tracepoint may have changed the
 	 * system call number. Reread it.
 	 */
-	return syscall_get_nr(current, regs);
+	*syscall = syscall_get_nr(current, regs);
+	return *syscall != -1L;
 }
 
 void trace_syscall_exit(struct pt_regs *regs, long ret)
#87 lore raw

Re: [patch 13/18] entry: Make trace_syscall_enter() return type bool

Hello,

Quoted 6 lines · Thomas Gleixner

In preparation of converting the return value of syscall_enter_from_user_mode[_work]() bool, rework trace_syscall_enter() to

- update the syscall number via a pointer argument

- Return True if the syscall number is != -1, False otherwise

This does not achieve the goal of the initial RFC: To detangle the return value of syscall_enter_from_user_mode from the syscall number.

This still conflates them, making it impossible to tell if the syscall was rejected or syscall number was -1 to start with. Now also obfuscated by performing the check deeper inside the common code.

Quoted 8 lines

That aligns with ptrace_report_syscall_permit_enter() and seccomp_permit_syscall().

The only difference is that this also returns False, when the syscall number was already -1 to begin with, but there is not much which can be done about that. As the architecture has to preset the return value to -ENOSYS anyway, that results in the correct return value for such an invalid syscall.

That's not possible to do for architectures where the syscall number and the syscall return value are in the same register.

You suggested that it is possible to not write the return value into an actual register but use an additional field for that, and have the exit code write the register.

However, that's not what is documented, nor what is currently done.

While this is an improvement in some respects the goal to have clear and intelligible API around the generic entry is not acheived.

Thanks

Michal

Quoted 53 lines
---
 include/linux/entry-common.h  |    8 +++++---
 kernel/entry/syscall-common.c |    7 ++++---
 2 files changed, 9 insertions(+), 6 deletions(-)
include/linux/entry-common.h +5 -3
@@ -58,7 +58,7 @@ static __always_inline bool arch_ptrace_
 #endif
 
 bool syscall_user_dispatch(struct pt_regs *regs);
-long trace_syscall_enter(struct pt_regs *regs, long syscall);
+bool trace_syscall_enter(struct pt_regs *regs, long *syscall);
 void trace_syscall_exit(struct pt_regs *regs, long ret);
 
 static inline void syscall_enter_audit(struct pt_regs *regs, long syscall)
@@ -108,8 +108,10 @@ static __always_inline long syscall_trac
 	/* Either of the above might have changed the syscall number */
 	syscall = syscall_get_nr(current, regs);
 
-	if (unlikely(work & SYSCALL_WORK_SYSCALL_TRACEPOINT))
-		syscall = trace_syscall_enter(regs, syscall);
+	if (unlikely(work & SYSCALL_WORK_SYSCALL_TRACEPOINT)) {
+		if (!trace_syscall_enter(regs, &syscall))
+			return -1L;
+	}
 
 	syscall_enter_audit(regs, syscall);
 
kernel/entry/syscall-common.c +4 -3
@@ -7,14 +7,15 @@
 
 /* Out of line to prevent tracepoint code duplication */
 
-long trace_syscall_enter(struct pt_regs *regs, long syscall)
+bool trace_syscall_enter(struct pt_regs *regs, long *syscall)
 {
-	trace_sys_enter(regs, syscall);
+	trace_sys_enter(regs, *syscall);
 	/*
 	 * Probes or BPF hooks in the tracepoint may have changed the
 	 * system call number. Reread it.
 	 */
-	return syscall_get_nr(current, regs);
+	*syscall = syscall_get_nr(current, regs);
+	return *syscall != -1L;
 }
 
 void trace_syscall_exit(struct pt_regs *regs, long ret)
author maintainer
#88 lore raw

Re: [patch 13/18] entry: Make trace_syscall_enter() return type bool

Quoted 10 lines · Michal Suchánek
Quoted 6 lines · Thomas Gleixner

In preparation of converting the return value of syscall_enter_from_user_mode[_work]() bool, rework trace_syscall_enter() to

- update the syscall number via a pointer argument

- Return True if the syscall number is != -1, False otherwise

This does not achieve the goal of the initial RFC: To detangle the return value of syscall_enter_from_user_mode from the syscall number.

As I explained to you before: Your RFC broke the implicit assumption of tracing, which is way worse than having this oddity.

Quoted 3 lines

This still conflates them, making it impossible to tell if the syscall was rejected or syscall number was -1 to start with. Now also obfuscated by performing the check deeper inside the common code.

That's where it belongs. It's a problem to solve within the given semantics of trace_syscall_enter() and not a problem to be worked around at the call sites if you want to have consolidated semantics.

Quoted 6 lines
Quoted 5 lines

The only difference is that this also returns False, when the syscall number was already -1 to begin with, but there is not much which can be done about that. As the architecture has to preset the return value to -ENOSYS anyway, that results in the correct return value for such an invalid syscall.

Quoted 8 lines

That's not possible to do for architectures where the syscall number and the syscall return value are in the same register.

You suggested that it is possible to not write the return value into an actual register but use an additional field for that, and have the exit code write the register.

However, that's not what is documented, nor what is currently done.

Just because S390 screwed up their ABI and then on top of that failed to do what _every_ other architecture in the kernel does, i.e. having a result storage which is preset to -ENOSYS does not mean that S390 did the right thing just because it was not documented. Kernel documentation is known to be incomplete and I fixed it up in the last patch as you might have noticed.

Just for the record. Presetting the return value to -ENOSYS has been practice for three decades. I couldn't be bothered to do a full search in the history trees to figure out the exact point, but as of 2.1.9, which was released in Nov. 1996, this is definitely the case.

So don't tell me that because S390 missed the train when it was added to mainline in 2007 (, i.e. 11 years _after_ this "undocumented" rule was established that now 20 years later the world has to revolve around S390 and your personal idea of "clear and intelligible":

Quoted 2 lines

While this is an improvement in some respects the goal to have clear and intelligible API around the generic entry is not acheived.

I'm honestly not sure whether I should laugh or cry.

You are completely missing the point:

1) The set in stone rule is that if the entry code returns -1L as the syscall number then the architecture code has to skip the syscall invocation _and_ is not supposed to change the return value.

2) There is no guarantee and never has been that any of the involved mechanisms (ptrace, seccomp, tracing) will change the return value when it sets the syscall number to -1L.

Quite the contrary there has been a long time (30 years at least) expectation that the return value has been preset to -ENOSYS.

3) It's trivial as demonstrated to make ptrace and seccomp more comprehensible but that does not invalidate #2

4) Due to the historical integration of tracing (+probes/BPF) there is an implicit assumption that the return code is preset to -ENOSYS. See #2

5) There is an obvious ambiguity between the initial syscall number being -1 and the change of syscall number to -1 in the case of tracing, but that's not unique to tracing:

If e.g. seccomp() observes the handed in syscall number to be -1 and tells in the return code to skip the syscall, then it can rightfully assume that the return code will be -ENOSYS and has no obligation to set it explicitly. See #2

Q: Is it perfect?
A: No

Q: Can it be made perfect?
A: No, because you can't change history and established practice.

Just for illustration. Changing the logic in trace_syscall_enter() to:

kernel/entry/syscall-common.c +3 -1
@@ -9,13 +9,15 @@
 
 bool trace_syscall_enter(struct pt_regs *regs, long *syscall)
 {
+	long orig_syscall = *syscall;
+
 	trace_sys_enter(regs, *syscall);
 	/*
 	 * Probes or BPF hooks in the tracepoint may have changed the
 	 * system call number. Reread it.
 	 */
 	*syscall = syscall_get_nr(current, regs);
-	return *syscall != -1L;
+	return *syscall == orig_syscall || *syscall != -1L;
 }
 
 void trace_syscall_exit(struct pt_regs *regs, long ret)

does not make #2 magically go away. It's still the same problem whether you like it or not.

Thanks,

tglx
---
Ignorance is bliss -- Thomas Gray, 1742

author maintainer
#89 lore raw

Re: [patch 13/18] entry: Make trace_syscall_enter() return type bool

Quoted 29 lines · Thomas Gleixner

On Wed, Jul 08 2026 at 17:52, Michal Suchánek wrote:
Q: Is it perfect?
A: No

Q: Can it be made perfect?
A: No, because you can't change history and established practice.

Just for illustration. Changing the logic in trace_syscall_enter() to:

kernel/entry/syscall-common.c +3 -1
@@ -9,13 +9,15 @@
 
 bool trace_syscall_enter(struct pt_regs *regs, long *syscall)
 {
+	long orig_syscall = *syscall;
+
 	trace_sys_enter(regs, *syscall);
 	/*
 	 * Probes or BPF hooks in the tracepoint may have changed the
 	 * system call number. Reread it.
 	 */
 	*syscall = syscall_get_nr(current, regs);
-	return *syscall != -1L;
+	return *syscall == orig_syscall || *syscall != -1L;
 }
 
 void trace_syscall_exit(struct pt_regs *regs, long ret)
Quoted 2 lines

does not make #2 magically go away. It's still the same problem whether you like it or not.

And just to be entirely clear, the syscall() interface has to be correct in the first place, but then it's all about performance.

So the sequence of:

   pt_regs = PUSH_REGS();
   syscall = pt_regs->syscall_reg;
   pt_regs->result = -ENOSYS;

   arch_syscall(pt_regs, syscall) {
      if (likely(syscall_enter_from_user_mode(pt_regs, &syscall) {
         if (syscall < SYSCALL_max)
            pt_regs->result = invoke_syscall(pt_regs, syscall);
      }
      ,,,,
   }
   pt_regs->($RETURN_VALUE) = pt_regs->result;
   POP_REGS();
   return;

is the correct and obviuosly most efficient way idependent of the -1L return value overload in the original implementation, which this series gets rid of for clarity.

If an architecture decide[sd] to do otherwise and makes up it's own rules which only cover parts of the problem then it _is_ an architecture problem and not something which has to be solved by claiming that every architecture has to implement the same nonsense as you falsely claimed in your RFC^WPOC^Whack thread:

"However, the API should be specified in a way that does not require
everyone implementing such flag."

There is _ZERO_ requirement for any architecture to implement that flag. Just because S390 decided it's a brilliant idea to do so does not make it a requirement for everyone.

No. Every other architecture got it right because they looked at the historical patterns despite having correct documentation at hand.

Feel free to prove me wrong with actual facts.

Thanks,

tglx

#90 lore raw

Re: [patch 13/18] entry: Make trace_syscall_enter() return type bool

Quoted 36 lines · On Thu, 09 Jul 2026 01:14:24 +0200 Thomas Gleixner <[email protected]> wrote:
Quoted 29 lines · Thomas Gleixner

On Wed, Jul 08 2026 at 17:52, Michal Suchánek wrote:
Q: Is it perfect?
A: No

Q: Can it be made perfect?
A: No, because you can't change history and established practice.

Just for illustration. Changing the logic in trace_syscall_enter() to:

kernel/entry/syscall-common.c +3 -1
@@ -9,13 +9,15 @@
 
 bool trace_syscall_enter(struct pt_regs *regs, long *syscall)
 {
+	long orig_syscall = *syscall;
+
 	trace_sys_enter(regs, *syscall);
 	/*
 	 * Probes or BPF hooks in the tracepoint may have changed the
 	 * system call number. Reread it.
 	 */
 	*syscall = syscall_get_nr(current, regs);
-	return *syscall != -1L;
+	return *syscall == orig_syscall || *syscall != -1L;
 }
 
 void trace_syscall_exit(struct pt_regs *regs, long ret)
Quoted 2 lines

does not make #2 magically go away. It's still the same problem whether you like it or not.

And just to be entirely clear, the syscall() interface has to be correct in the first place, but then it's all about performance.

Quoted 8 lines

So the sequence of:

   pt_regs = PUSH_REGS();
   syscall = pt_regs->syscall_reg;
   pt_regs->result = -ENOSYS;

   arch_syscall(pt_regs, syscall) {
      if (likely(syscall_enter_from_user_mode(pt_regs, &syscall) {

I guess most architectures inline that to avoid the &syscall. Otherwise you'd want:

	syscall = syscall_enter_from_user_mode(pt_regs, syscall);

with the 'error' return being selected to fail the test below (which -1L converted to ~0UL will do nicely).

David

Quoted 35 lines
         if (syscall < SYSCALL_max)
            pt_regs->result = invoke_syscall(pt_regs, syscall);
      }
      ,,,,
   }
   pt_regs->($RETURN_VALUE) = pt_regs->result;
   POP_REGS();
   return;

is the correct and obviuosly most efficient way idependent of the -1L return value overload in the original implementation, which this series gets rid of for clarity.

If an architecture decide[sd] to do otherwise and makes up it's own rules which only cover parts of the problem then it _is_ an architecture problem and not something which has to be solved by claiming that every architecture has to implement the same nonsense as you falsely claimed in your RFC^WPOC^Whack thread:

"However, the API should be specified in a way that does not require
everyone implementing such flag."

There is _ZERO_ requirement for any architecture to implement that flag. Just because S390 decided it's a brilliant idea to do so does not make it a requirement for everyone.

No. Every other architecture got it right because they looked at the historical patterns despite having correct documentation at hand.

Feel free to prove me wrong with actual facts.

Thanks,

tglx

#91 lore raw

Re: [patch 13/18] entry: Make trace_syscall_enter() return type bool

In reply to Thomas Gleixner
Quoted 7 lines · Thomas Gleixner
Quoted 6 lines · Michal Suchánek
Quoted 5 lines · Thomas Gleixner

In preparation of converting the return value of syscall_enter_from_user_mode[_work]() bool, rework trace_syscall_enter() to

- update the syscall number via a pointer argument

Quoted 7 lines
Quoted 4 lines
Quoted 1 line

- Return True if the syscall number is != -1, False otherwise

This does not achieve the goal of the initial RFC: To detangle the return value of syscall_enter_from_user_mode from the syscall number.

As I explained to you before: Your RFC broke the implicit assumption of tracing, which is way worse than having this oddity.

It would be so nice to make the assumptions about the entry API explicit so that platforms can agree on the semantics.

Quoted 31 lines
Quoted 4 lines

This still conflates them, making it impossible to tell if the syscall was rejected or syscall number was -1 to start with. Now also obfuscated by performing the check deeper inside the common code.

That's where it belongs. It's a problem to solve within the given semantics of trace_syscall_enter() and not a problem to be worked around at the call sites if you want to have consolidated semantics.

Quoted 6 lines
Quoted 5 lines

The only difference is that this also returns False, when the syscall number was already -1 to begin with, but there is not much which can be done about that. As the architecture has to preset the return value to -ENOSYS anyway, that results in the correct return value for such an invalid syscall.

Quoted 8 lines

That's not possible to do for architectures where the syscall number and the syscall return value are in the same register.

You suggested that it is possible to not write the return value into an actual register but use an additional field for that, and have the exit code write the register.

However, that's not what is documented, nor what is currently done.

Just because S390 screwed up their ABI and then on top of that failed to do what _every_ other architecture in the kernel does, i.e. having a result storage which is preset to -ENOSYS does not mean that S390 did the right thing just because it was not documented. Kernel documentation is known to be incomplete and I fixed it up in the last patch as you might have noticed.

Quoted 2 lines

Just for the record. Presetting the return value to -ENOSYS has been practice for three decades. I couldn't be bothered to do a full search

No, it isn't practice anymore for decades.

The moment ppc and s390 support was merged they do not preset the syscall return value to -ENOSYS, for obvious reason.

That is how the undocumented, implicit, 'as implemented' API goes. It silently changes as the implementation evolves.

Quoted 7 lines

in the history trees to figure out the exact point, but as of 2.1.9, which was released in Nov. 1996, this is definitely the case.

So don't tell me that because S390 missed the train when it was added to mainline in 2007 (, i.e. 11 years _after_ this "undocumented" rule was established that now 20 years later the world has to revolve around S390 and your personal idea of "clear and intelligible":

Don't tell me you missed the train on what the actual API of syscall entry is.

Quoted 11 lines
Quoted 3 lines

While this is an improvement in some respects the goal to have clear and intelligible API around the generic entry is not acheived.

I'm honestly not sure whether I should laugh or cry.

You are completely missing the point:

1) The set in stone rule is that if the entry code returns -1L as the syscall number then the architecture code has to skip the syscall invocation _and_ is not supposed to change the return value.

Which stone?

Pics or it did not happen.

Quoted 4 lines

2) There is no guarantee and never has been that any of the involved mechanisms (ptrace, seccomp, tracing) will change the return value when it sets the syscall number to -1L.

For ptrace to correctly emulate a syscall it needs to set the syscall nr to an invalid value on entry, and the desired result if the syscall on exit AFAICT.

Relying on platfrom quirk to assume that the return valu is set to ENOSYS is insufficient.

I doubt many platfroms have an ABI that dictates that the register that has the syscal nr is set to -1 on exit from syscal. Then even if the -ENOSYS is preset by the kernel the syscall nr needs to be poked back on exit for the emulation to be correct.

Quoted 3 lines

Quite the contrary there has been a long time (30 years at least) expectation that the return value has been preset to -ENOSYS.

That is your opinion, not the fact. Multiple platforms do not work like that.

Quoted 7 lines

3) It's trivial as demonstrated to make ptrace and seccomp more comprehensible but that does not invalidate #2

4) Due to the historical integration of tracing (+probes/BPF) there is an implicit assumption that the return code is preset to -ENOSYS. See #2

False again

Quoted 9 lines

5) There is an obvious ambiguity between the initial syscall number being -1 and the change of syscall number to -1 in the case of tracing, but that's not unique to tracing:

If e.g. seccomp() observes the handed in syscall number to be -1 and tells in the return code to skip the syscall, then it can rightfully assume that the return code will be -ENOSYS and has no obligation to set it explicitly. See #2

False again

Quoted 29 lines

Q: Is it perfect?
A: No

Q: Can it be made perfect?
A: No, because you can't change history and established practice.

Just for illustration. Changing the logic in trace_syscall_enter() to:

kernel/entry/syscall-common.c +3 -1
@@ -9,13 +9,15 @@
 
 bool trace_syscall_enter(struct pt_regs *regs, long *syscall)
 {
+	long orig_syscall = *syscall;
+
 	trace_sys_enter(regs, *syscall);
 	/*
 	 * Probes or BPF hooks in the tracepoint may have changed the
 	 * system call number. Reread it.
 	 */
 	*syscall = syscall_get_nr(current, regs);
-	return *syscall != -1L;
+	return *syscall == orig_syscall || *syscall != -1L;
 }
 
 void trace_syscall_exit(struct pt_regs *regs, long ret)
Quoted 2 lines

does not make #2 magically go away. It's still the same problem whether you like it or not.

However, reading the syscall number from pt_regs only after syscall_enter_from_user_mode exits does.

Thanks

Michal

maintainer
#92 lore raw

Re: [patch 13/18] entry: Make trace_syscall_enter() return type bool

Quoted 12 lines · Michal Suchánek
Quoted 4 lines · Thomas Gleixner

1) The set in stone rule is that if the entry code returns -1L as the syscall number then the architecture code has to skip the syscall invocation _and_ is not supposed to change the return value.

Which stone?

Pics or it did not happen.

Quoted 1 line
Quoted 7 lines
Quoted 3 lines

2) There is no guarantee and never has been that any of the involved mechanisms (ptrace, seccomp, tracing) will change the return value when it sets the syscall number to -1L.

For ptrace to correctly emulate a syscall it needs to set the syscall nr to an invalid value on entry, and the desired result if the syscall on exit AFAICT.

I can only say that ptrace users do want to skip the syscall and set the return value on entry.

See

	[PATCH v5 1/2] ptrace: add PTRACE_SET_SYSCALL_INFO syscall skipping support
	https://lore.kernel.org/all/[email protected]/

The changelog explains that currently this doesn't work because among the arches which define HAVE_ARCH_TRACEHOOK (at least) arch/mips is broken in this regard.

Oleg.

#93 lore raw

Re: [patch 13/18] entry: Make trace_syscall_enter() return type bool

Quoted 24 lines · Oleg Nesterov
Quoted 12 lines · Michal Suchánek
Quoted 4 lines · Thomas Gleixner

1) The set in stone rule is that if the entry code returns -1L as the syscall number then the architecture code has to skip the syscall invocation _and_ is not supposed to change the return value.

Which stone?

Pics or it did not happen.

Quoted 1 line
Quoted 7 lines
Quoted 3 lines

2) There is no guarantee and never has been that any of the involved mechanisms (ptrace, seccomp, tracing) will change the return value when it sets the syscall number to -1L.

For ptrace to correctly emulate a syscall it needs to set the syscall nr to an invalid value on entry, and the desired result if the syscall on exit AFAICT.

I can only say that ptrace users do want to skip the syscall and set the return value on entry.

Quoted 7 lines

See

	[PATCH v5 1/2] ptrace: add PTRACE_SET_SYSCALL_INFO syscall skipping support
	https://lore.kernel.org/all/[email protected]/

The changelog explains that currently this doesn't work because among the arches which define HAVE_ARCH_TRACEHOOK (at least) arch/mips is broken in this regard.

Or it could be documented that setting the return value has to be done in the exit trace, and that would than work on any architecture AFAICT.

With ppc and s390 using the same register for the syscall number and syscall return value it's very much impossible to poke the return value on entry into a register using the generic register access function. As of now there is no place to store the value ot of the return value outside of the registers, either.

And the current PTRACE_SET_SYSCALL_INFO indeed sets the syscall nr and arguments on entry and the syscall return value on exit, that disctincion is implemented.

Not sure how the patchset you point out is relevant, it only adds changes in the exit case.

Thanks

Michal

maintainer
#94 lore raw

Re: [patch 13/18] entry: Make trace_syscall_enter() return type bool

Quoted 10 lines · Michal Suchánek
Quoted 8 lines · Oleg Nesterov

I can only say that ptrace users do want to skip the syscall and set the return value on entry.

See

	[PATCH v5 1/2] ptrace: add PTRACE_SET_SYSCALL_INFO syscall skipping support
	https://lore.kernel.org/all/[email protected]/
Quoted 6 lines
Quoted 3 lines

The changelog explains that currently this doesn't work because among the arches which define HAVE_ARCH_TRACEHOOK (at least) arch/mips is broken in this regard.

Or it could be documented that setting the return value has to be done in the exit trace, and that would than work on any architecture AFAICT.

Well, ptrace users know the problem. And this what they have to do currently.

Quoted 5 lines

With ppc and s390 using the same register for the syscall number and syscall return value it's very much impossible to poke the return value on entry into a register using the generic register access function. As of now there is no place to store the value ot of the return value outside of the registers, either.

I know nothing about ppc and s390. Can't comment right now.

Quoted 6 lines

And the current PTRACE_SET_SYSCALL_INFO indeed sets the syscall nr and arguments on entry and the syscall return value on exit, that disctincion is implemented.

Not sure how the patchset you point out is relevant, it only adds changes in the exit case.

No. It allows to skip-and-set-retval on PTRACE_EVENT_SECCOMP.

But ENTRY -> EXIT transition is not yet allowed due to the problems above.

Oleg.

#95 lore raw

Re: [patch 13/18] entry: Make trace_syscall_enter() return type bool

Quoted 29 lines · Oleg Nesterov
Quoted 10 lines · Michal Suchánek
Quoted 8 lines · Oleg Nesterov

I can only say that ptrace users do want to skip the syscall and set the return value on entry.

See

	[PATCH v5 1/2] ptrace: add PTRACE_SET_SYSCALL_INFO syscall skipping support
	https://lore.kernel.org/all/[email protected]/
Quoted 6 lines
Quoted 3 lines

The changelog explains that currently this doesn't work because among the arches which define HAVE_ARCH_TRACEHOOK (at least) arch/mips is broken in this regard.

Or it could be documented that setting the return value has to be done in the exit trace, and that would than work on any architecture AFAICT.

Well, ptrace users know the problem. And this what they have to do currently.

Quoted 5 lines

With ppc and s390 using the same register for the syscall number and syscall return value it's very much impossible to poke the return value on entry into a register using the generic register access function. As of now there is no place to store the value ot of the return value outside of the registers, either.

I know nothing about ppc and s390. Can't comment right now.

Quoted 8 lines
Quoted 6 lines

And the current PTRACE_SET_SYSCALL_INFO indeed sets the syscall nr and arguments on entry and the syscall return value on exit, that disctincion is implemented.

Not sure how the patchset you point out is relevant, it only adds changes in the exit case.

No. It allows to skip-and-set-retval on PTRACE_EVENT_SECCOMP.

And if it was hooked correctly to seccomp indicating to seccomp that the syscall needs to be skipped it could work but it is not, and will fail on ppc.

Thanks

Michal

Quoted 6 lines

But ENTRY -> EXIT transition is not yet allowed due to the problems above.

Oleg.

author maintainer
#96 lore raw

Re: [patch 13/18] entry: Make trace_syscall_enter() return type bool

In reply to Michal Suchánek

Michal!

Quoted 6 lines · Michal Suchánek
Quoted 2 lines · Thomas Gleixner

does not make #2 magically go away. It's still the same problem whether you like it or not.

However, reading the syscall number from pt_regs only after syscall_enter_from_user_mode exits does.

That does not solve anything at all.

TBH, your communication style is annoying as hell. You fail to provide any useful arguments and explanations despite me giving you a proper analysis. And I'm absolutely tired of this.

So let me try again for _ONE_ last time to explain you why your ppc/s390 world view is broken and let's look at the current code (irrelevant portions omitted).

static __always_inline long syscall_trace_enter(struct pt_regs *regs, unsigned long work)

{
	if (work & SYSCALL_WORK_SYSCALL_USER_DISPATCH) {
#1		if (syscall_user_dispatch(regs))
			return -1L;
	}
        
	if (work & (SYSCALL_WORK_SYSCALL_TRACE | SYSCALL_WORK_SYSCALL_EMU)) {
#2		ret = arch_ptrace_report_syscall_entry(regs);
		if (ret || (work & SYSCALL_WORK_SYSCALL_EMU))
			return -1L;
	}

	/* Do seccomp after ptrace, to catch any tracer changes. */
	if (work & SYSCALL_WORK_SECCOMP) {
#3		ret = __secure_computing();
		if (ret == -1L)
			return ret;
	}

	/* Either of the above might have changed the syscall number */

#4 syscall = syscall_get_nr(current, regs);

if (unlikely(work & SYSCALL_WORK_SYSCALL_TRACEPOINT))
#5 syscall = trace_syscall_enter(regs, syscall);

        return syscall;
}

#1) The user dispatch mechanism does not modify the syscall return
value, but it can rollback the syscall and tell the call site to skip the invocation.

The mechanism used in upstream today is to return -1L as the syscall number which makes the architecture specific entry code skip the syscall and refrain from touching the return value.

#2) ptrace

ptrace can poke whatever it wants into the syscall number storage via ptrace_set_syscall_info_entry() -> syscall_set_nr()

It does not set the return code.

It does not abort the syscall when the poked syscall number is -1L.

It only aborts when a fatal signal is pending.

#3) seccomp

seccomp reads the syscall number, which might have been modified by ptrace and acts upon it.

It can rewrite the syscall number even if it is -1 to begin with.

It can rewrite the return code if it decides to refuse the syscall to be executed.

If it refuses the syscall to be executed it returns -1L.

#4) Rereading the syscall number after ptrace/seccomp

That's required to give the eventually modified number to the tracer.

Obviously the tracer could do that on it's own, but with the current implementation it expects the eventually modified syscall number

Changing that to make the tracer do it, is possible but does not change any of the actual expectations. That's just cosmetic wankery.

#5) tracing

tracing can have a probe or bpf attached, which in turn can

- rewrite the syscall number

- set the return code in case that it sets the syscall number to -1L

It can even set it in case it sets it to some other value, but the architecture code has to be resilent against that no matter what.

- if it does not set the return code when it sets the syscall number to -1L then it has a historical expectation that the syscall returns -ENOSYS

That's how it is and you can argue in circles and it's not going away unless you have a great argument why you can break existing user space probes/bpf scripts.

So now please provide in coherent sentences the argument why this solves anything:

Quoted 2 lines

However, reading the syscall number from pt_regs only after syscall_enter_from_user_mode exits does.

If you can, which I doubt, then please send a patch [series] against:

git://git.kernel.org/pub/scm/linux/kernel/git/tglx/devel.git entry/rework

with proper change logs explaining the superiour solution.

If not, please spare us the next set of incoherent "I wan't a pony" mails.

Thanks,

tglx

#97 lore raw

Re: [patch 13/18] entry: Make trace_syscall_enter() return type bool

Quoted 57 lines · Thomas Gleixner

Michal!

Quoted 6 lines · Michal Suchánek
Quoted 2 lines · Thomas Gleixner

does not make #2 magically go away. It's still the same problem whether you like it or not.

However, reading the syscall number from pt_regs only after syscall_enter_from_user_mode exits does.

That does not solve anything at all.

TBH, your communication style is annoying as hell. You fail to provide any useful arguments and explanations despite me giving you a proper analysis. And I'm absolutely tired of this.

So let me try again for _ONE_ last time to explain you why your ppc/s390 world view is broken and let's look at the current code (irrelevant portions omitted).

static __always_inline long syscall_trace_enter(struct pt_regs *regs, unsigned long work)

{
	if (work & SYSCALL_WORK_SYSCALL_USER_DISPATCH) {
#1		if (syscall_user_dispatch(regs))
			return -1L;
	}
        
	if (work & (SYSCALL_WORK_SYSCALL_TRACE | SYSCALL_WORK_SYSCALL_EMU)) {
#2		ret = arch_ptrace_report_syscall_entry(regs);
		if (ret || (work & SYSCALL_WORK_SYSCALL_EMU))
			return -1L;
	}

	/* Do seccomp after ptrace, to catch any tracer changes. */
	if (work & SYSCALL_WORK_SECCOMP) {
#3		ret = __secure_computing();
		if (ret == -1L)
			return ret;
	}

	/* Either of the above might have changed the syscall number */

#4 syscall = syscall_get_nr(current, regs);

if (unlikely(work & SYSCALL_WORK_SYSCALL_TRACEPOINT))
#5 syscall = trace_syscall_enter(regs, syscall);

        return syscall;
}

#1) The user dispatch mechanism does not modify the syscall return
value, but it can rollback the syscall and tell the call site to skip the invocation.

The mechanism used in upstream today is to return -1L as the syscall number which makes the architecture specific entry code skip the syscall and refrain from touching the return value.

Quoted 8 lines

#2) ptrace

ptrace can poke whatever it wants into the syscall number storage via ptrace_set_syscall_info_entry() -> syscall_set_nr()

It does not set the return code.

It does not abort the syscall when the poked syscall number is -1L.

Indeed, it does not abort on -1 syscall number anymore although there are still comments around that claim that setting the syscall number to -1 is special.

Thanks

Michal

author maintainer
#98 lore raw

PATCH 14/18 entry: Make return type of syscall_trace_enter() bool

In reply to Thomas Gleixner

This prepares for changing the return types of syscall_enter_from_user_mode[_work]() to bool, which in turn separates the decision of invoking the syscall from the syscall number, which might have been changed in the call by ptrace, seccomp, tracing.

---
 include/linux/entry-common.h |   28 +++++++++++++++-------------
 1 file changed, 15 insertions(+), 13 deletions(-)
include/linux/entry-common.h +15 -13
@@ -71,8 +71,8 @@ static inline void syscall_enter_audit(s
 	}
 }
 
-static __always_inline long syscall_trace_enter(struct pt_regs *regs, unsigned long work,
-						long syscall)
+static __always_inline bool syscall_trace_enter(struct pt_regs *regs, unsigned long work,
+						long *syscall)
 {
 	/*
 	 * Handle Syscall User Dispatch.  This must comes first, since
@@ -81,7 +81,7 @@ static __always_inline long syscall_trac
 	 */
 	if (work & SYSCALL_WORK_SYSCALL_USER_DISPATCH) {
 		if (syscall_user_dispatch(regs))
-			return -1L;
+			return false;
 	}
 
 	/*
@@ -90,32 +90,32 @@ static __always_inline long syscall_trac
 	 * through hrtimer_interrupt().
 	 */
 	if (work & SYSCALL_WORK_SYSCALL_RSEQ_SLICE)
-		rseq_syscall_enter_work(syscall);
+		rseq_syscall_enter_work(*syscall);
 
 	/* Handle ptrace */
 	if (work & (SYSCALL_WORK_SYSCALL_TRACE | SYSCALL_WORK_SYSCALL_EMU)) {
 		if (!arch_ptrace_report_syscall_permit_entry(regs) ||
 		    (work & SYSCALL_WORK_SYSCALL_EMU))
-			return -1L;
+			return false;
 	}
 
 	/* Do seccomp after ptrace, to catch any tracer changes. */
 	if (work & SYSCALL_WORK_SECCOMP) {
 		if (!__seccomp_permit_syscall())
-			return -1L;
+			return false;
 	}
 
 	/* Either of the above might have changed the syscall number */
-	syscall = syscall_get_nr(current, regs);
+	*syscall = syscall_get_nr(current, regs);
 
 	if (unlikely(work & SYSCALL_WORK_SYSCALL_TRACEPOINT)) {
-		if (!trace_syscall_enter(regs, &syscall))
-			return -1L;
+		if (!trace_syscall_enter(regs, syscall))
+			return false;
 	}
 
-	syscall_enter_audit(regs, syscall);
+	syscall_enter_audit(regs, *syscall);
 
-	return syscall;
+	return true;
 }
 
 /**
@@ -145,8 +145,10 @@ static __always_inline long syscall_ente
 {
 	unsigned long work = READ_ONCE(current_thread_info()->syscall_work);
 
-	if (work & SYSCALL_WORK_ENTER)
-		syscall = syscall_trace_enter(regs, work, syscall);
+	if (work & SYSCALL_WORK_ENTER) {
+		if (!syscall_trace_enter(regs, work, &syscall))
+			return -1L;
+	}
 
 	return syscall;
 }
Reviewed-by on v1 14/18
#99 lore raw

Re: [patch 14/18] entry: Make return type of syscall_trace_enter() bool

Quoted 77 lines · Thomas Gleixner

This prepares for changing the return types of syscall_enter_from_user_mode[_work]() to bool, which in turn separates the decision of invoking the syscall from the syscall number, which might have been changed in the call by ptrace, seccomp, tracing.

---
 include/linux/entry-common.h |   28 +++++++++++++++-------------
 1 file changed, 15 insertions(+), 13 deletions(-)
include/linux/entry-common.h +11 -11
@@ -71,8 +71,8 @@ static inline void syscall_enter_audit(s
 	}
 }
 
-static __always_inline long syscall_trace_enter(struct pt_regs *regs, unsigned long work,
-						long syscall)
+static __always_inline bool syscall_trace_enter(struct pt_regs *regs, unsigned long work,
+						long *syscall)
 {
 	/*
 	 * Handle Syscall User Dispatch.  This must comes first, since
@@ -81,7 +81,7 @@ static __always_inline long syscall_trac
 	 */
 	if (work & SYSCALL_WORK_SYSCALL_USER_DISPATCH) {
 		if (syscall_user_dispatch(regs))
-			return -1L;
+			return false;
 	}
 
 	/*
@@ -90,32 +90,32 @@ static __always_inline long syscall_trac
 	 * through hrtimer_interrupt().
 	 */
 	if (work & SYSCALL_WORK_SYSCALL_RSEQ_SLICE)
-		rseq_syscall_enter_work(syscall);
+		rseq_syscall_enter_work(*syscall);
 
 	/* Handle ptrace */
 	if (work & (SYSCALL_WORK_SYSCALL_TRACE | SYSCALL_WORK_SYSCALL_EMU)) {
 		if (!arch_ptrace_report_syscall_permit_entry(regs) ||
 		    (work & SYSCALL_WORK_SYSCALL_EMU))
-			return -1L;
+			return false;
 	}
 
 	/* Do seccomp after ptrace, to catch any tracer changes. */
 	if (work & SYSCALL_WORK_SECCOMP) {
 		if (!__seccomp_permit_syscall())
-			return -1L;
+			return false;
 	}
 
 	/* Either of the above might have changed the syscall number */
-	syscall = syscall_get_nr(current, regs);
+	*syscall = syscall_get_nr(current, regs);
 
 	if (unlikely(work & SYSCALL_WORK_SYSCALL_TRACEPOINT)) {
-		if (!trace_syscall_enter(regs, &syscall))
-			return -1L;
+		if (!trace_syscall_enter(regs, syscall))
+			return false;
 	}
 
-	syscall_enter_audit(regs, syscall);
+	syscall_enter_audit(regs, *syscall);
 
-	return syscall;
+	return true;
 }
 
 /**
@@ -145,8 +145,10 @@ static __always_inline long syscall_ente
 {
 	unsigned long work = READ_ONCE(current_thread_info()->syscall_work);

include/linux/entry-common.h static __always_inline long syscall_ente · line 154

Quoted 10 lines
include/linux/entry-common.h +4 -2
 
-	if (work & SYSCALL_WORK_ENTER)
-		syscall = syscall_trace_enter(regs, work, syscall);
+	if (work & SYSCALL_WORK_ENTER) {
+		if (!syscall_trace_enter(regs, work, &syscall))
+			return -1L;
+	}
 
 	return syscall;
 }
author maintainer
#100 lore raw

PATCH 15/18 x86/entry: Make syscall functions static

In reply to Thomas Gleixner

They are only used in the respective source files. No point in exposing them.

---
 arch/x86/entry/syscall_32.c    |    2 +-
 arch/x86/entry/syscall_64.c    |   10 ++++++----
 arch/x86/include/asm/syscall.h |    8 --------
 3 files changed, 7 insertions(+), 13 deletions(-)
arch/x86/entry/syscall_32.c +1 -1
@@ -41,7 +41,7 @@ const sys_call_ptr_t sys_call_table[] =
 #endif
 
 #define __SYSCALL(nr, sym) case nr: return __ia32_##sym(regs);
-long ia32_sys_call(const struct pt_regs *regs, unsigned int nr)
+static noinline long ia32_sys_call(const struct pt_regs *regs, unsigned int nr)
 {
 	switch (nr) {
 	#include <asm/syscalls_32.h>
arch/x86/entry/syscall_64.c +6 -4
@@ -32,7 +32,7 @@ const sys_call_ptr_t sys_call_table[] =
 #undef  __SYSCALL
 
 #define __SYSCALL(nr, sym) case nr: return __x64_##sym(regs);
-long x64_sys_call(const struct pt_regs *regs, unsigned int nr)
+static noinline long x64_sys_call(const struct pt_regs *regs, unsigned int nr)
 {
 	switch (nr) {
 	#include <asm/syscalls_64.h>
@@ -40,15 +40,17 @@ long x64_sys_call(const struct pt_regs *
 	}
 }
 
-#ifdef CONFIG_X86_X32_ABI
-long x32_sys_call(const struct pt_regs *regs, unsigned int nr)
+static noinline long x32_sys_call(const struct pt_regs *regs, unsigned int nr)
 {
+#ifdef CONFIG_X86_X32_ABI
 	switch (nr) {
 	#include <asm/syscalls_x32.h>
 	default: return __x64_sys_ni_syscall(regs);
 	}
-}
+#else
+	return -ENOSYS;
 #endif
+}
 
 static __always_inline bool do_syscall_x64(struct pt_regs *regs, int nr)
 {
arch/x86/include/asm/syscall.h +0 -8
@@ -21,14 +21,6 @@ typedef long (*sys_call_ptr_t)(const str
 extern const sys_call_ptr_t sys_call_table[];
 
 /*
- * These may not exist, but still put the prototypes in so we
- * can use IS_ENABLED().
- */
-extern long ia32_sys_call(const struct pt_regs *, unsigned int nr);
-extern long x32_sys_call(const struct pt_regs *, unsigned int nr);
-extern long x64_sys_call(const struct pt_regs *, unsigned int nr);
-
-/*
  * Only the low 32 bits of orig_ax are meaningful, so we return int.
  * This importantly ignores the high bits on 64-bit, so comparisons
  * sign-extend the low 32 bits.
Reviewed-by on v1 15/18
#101 lore raw

Re: [patch 15/18] x86/entry: Make syscall functions static

Quoted 56 lines · Thomas Gleixner

They are only used in the respective source files. No point in exposing them.

---
 arch/x86/entry/syscall_32.c    |    2 +-
 arch/x86/entry/syscall_64.c    |   10 ++++++----
 arch/x86/include/asm/syscall.h |    8 --------
 3 files changed, 7 insertions(+), 13 deletions(-)
arch/x86/entry/syscall_32.c +1 -1
@@ -41,7 +41,7 @@ const sys_call_ptr_t sys_call_table[] =
 #endif
 
 #define __SYSCALL(nr, sym) case nr: return __ia32_##sym(regs);
-long ia32_sys_call(const struct pt_regs *regs, unsigned int nr)
+static noinline long ia32_sys_call(const struct pt_regs *regs, unsigned int nr)
 {
 	switch (nr) {
 	#include <asm/syscalls_32.h>
arch/x86/entry/syscall_64.c +6 -4
@@ -32,7 +32,7 @@ const sys_call_ptr_t sys_call_table[] =
 #undef  __SYSCALL
 
 #define __SYSCALL(nr, sym) case nr: return __x64_##sym(regs);
-long x64_sys_call(const struct pt_regs *regs, unsigned int nr)
+static noinline long x64_sys_call(const struct pt_regs *regs, unsigned int nr)
 {
 	switch (nr) {
 	#include <asm/syscalls_64.h>
@@ -40,15 +40,17 @@ long x64_sys_call(const struct pt_regs *
 	}
 }
 
-#ifdef CONFIG_X86_X32_ABI
-long x32_sys_call(const struct pt_regs *regs, unsigned int nr)
+static noinline long x32_sys_call(const struct pt_regs *regs, unsigned int nr)
 {
+#ifdef CONFIG_X86_X32_ABI
 	switch (nr) {
 	#include <asm/syscalls_x32.h>
 	default: return __x64_sys_ni_syscall(regs);
 	}
-}
+#else
+	return -ENOSYS;
 #endif
+}
 
 static __always_inline bool do_syscall_x64(struct pt_regs *regs, int nr)
 {

arch/x86/include/asm/syscall.h typedef long (*sys_call_ptr_t)(const str · line 30

Quoted 10 lines
arch/x86/include/asm/syscall.h +0 -7
@@ -21,14 +21,6 @@ typedef long (*sys_call_ptr_t)(const str
 extern const sys_call_ptr_t sys_call_table[];
 
 /*
- * These may not exist, but still put the prototypes in so we
- * can use IS_ENABLED().
- */
-extern long ia32_sys_call(const struct pt_regs *, unsigned int nr);
-extern long x32_sys_call(const struct pt_regs *, unsigned int nr);
-extern long x64_sys_call(const struct pt_regs *, unsigned int nr);
-
Quoted 5 lines
arch/x86/include/asm/syscall.h +0 -1
-/*
  * Only the low 32 bits of orig_ax are meaningful, so we return int.
  * This importantly ignores the high bits on 64-bit, so comparisons
  * sign-extend the low 32 bits.
Reviewed-by on v1 15/18
#102 lore raw

Re: [patch 15/18] x86/entry: Make syscall functions static

In reply to Thomas Gleixner
Quoted 61 lines · Thomas Gleixner

They are only used in the respective source files. No point in exposing them.

---
 arch/x86/entry/syscall_32.c    |    2 +-
 arch/x86/entry/syscall_64.c    |   10 ++++++----
 arch/x86/include/asm/syscall.h |    8 --------
 3 files changed, 7 insertions(+), 13 deletions(-)
arch/x86/entry/syscall_32.c +1 -1
@@ -41,7 +41,7 @@ const sys_call_ptr_t sys_call_table[] =
 #endif
 
 #define __SYSCALL(nr, sym) case nr: return __ia32_##sym(regs);
-long ia32_sys_call(const struct pt_regs *regs, unsigned int nr)
+static noinline long ia32_sys_call(const struct pt_regs *regs, unsigned int nr)
 {
 	switch (nr) {
 	#include <asm/syscalls_32.h>
arch/x86/entry/syscall_64.c +6 -4
@@ -32,7 +32,7 @@ const sys_call_ptr_t sys_call_table[] =
 #undef  __SYSCALL
 
 #define __SYSCALL(nr, sym) case nr: return __x64_##sym(regs);
-long x64_sys_call(const struct pt_regs *regs, unsigned int nr)
+static noinline long x64_sys_call(const struct pt_regs *regs, unsigned int nr)
 {
 	switch (nr) {
 	#include <asm/syscalls_64.h>
@@ -40,15 +40,17 @@ long x64_sys_call(const struct pt_regs *
 	}
 }
 
-#ifdef CONFIG_X86_X32_ABI
-long x32_sys_call(const struct pt_regs *regs, unsigned int nr)
+static noinline long x32_sys_call(const struct pt_regs *regs, unsigned int nr)
 {
+#ifdef CONFIG_X86_X32_ABI
 	switch (nr) {
 	#include <asm/syscalls_x32.h>
 	default: return __x64_sys_ni_syscall(regs);
 	}
-}
+#else
+	return -ENOSYS;
 #endif
+}
 
 static __always_inline bool do_syscall_x64(struct pt_regs *regs, int nr)
 {
arch/x86/include/asm/syscall.h +0 -1
@@ -21,14 +21,6 @@ typedef long (*sys_call_ptr_t)(const str
 extern const sys_call_ptr_t sys_call_table[];
 
 /*
- * These may not exist, but still put the prototypes in so we

arch/x86/include/asm/syscall.h typedef long (*sys_call_ptr_t)(const str · line 26

Quoted 10 lines
arch/x86/include/asm/syscall.h +0 -7
- * can use IS_ENABLED().
- */
-extern long ia32_sys_call(const struct pt_regs *, unsigned int nr);
-extern long x32_sys_call(const struct pt_regs *, unsigned int nr);
-extern long x64_sys_call(const struct pt_regs *, unsigned int nr);
-
-/*
  * Only the low 32 bits of orig_ax are meaningful, so we return int.
  * This importantly ignores the high bits on 64-bit, so comparisons
  * sign-extend the low 32 bits.
#103 lore raw

[tip: core/entry] x86/entry: Make syscall functions static

In reply to Thomas Gleixner
The following commit has been merged into the core/entry branch of tip:

The following commit has been merged into the core/entry branch of tip:

Commit-ID:     2b341c74dbf8864b6dd32119b761ceaab516249e
Gitweb:        https://git.kernel.org/tip/2b341c74dbf8864b6dd32119b761ceaab516249e
Author:        Thomas Gleixner <[email protected]>
AuthorDate:    Tue, 07 Jul 2026 21:06:57 +02:00
Committer:     Thomas Gleixner <[email protected]>
CommitterDate: Sun, 12 Jul 2026 12:38:02 +02:00

x86/entry: Make syscall functions static

They are only used in the respective source files. No point in exposing them.

---
 arch/x86/entry/syscall_32.c    |  2 +-
 arch/x86/entry/syscall_64.c    | 10 ++++++----
 arch/x86/include/asm/syscall.h |  8 --------
 3 files changed, 7 insertions(+), 13 deletions(-)
arch/x86/entry/syscall_32.c +1 -1
index 2b13f1c..6e00929 100644
@@ -41,7 +41,7 @@ const sys_call_ptr_t sys_call_table[] = {
 #endif
 
 #define __SYSCALL(nr, sym) case nr: return __ia32_##sym(regs);
-long ia32_sys_call(const struct pt_regs *regs, unsigned int nr)
+static noinline long ia32_sys_call(const struct pt_regs *regs, unsigned int nr)
 {
 	switch (nr) {
 	#include <asm/syscalls_32.h>
arch/x86/entry/syscall_64.c +6 -4
index 0acd7e9..837aee7 100644
@@ -32,7 +32,7 @@ const sys_call_ptr_t sys_call_table[] = {
 #undef  __SYSCALL
 
 #define __SYSCALL(nr, sym) case nr: return __x64_##sym(regs);
-long x64_sys_call(const struct pt_regs *regs, unsigned int nr)
+static noinline long x64_sys_call(const struct pt_regs *regs, unsigned int nr)
 {
 	switch (nr) {
 	#include <asm/syscalls_64.h>
@@ -40,15 +40,17 @@ long x64_sys_call(const struct pt_regs *regs, unsigned int nr)
 	}
 }
 
-#ifdef CONFIG_X86_X32_ABI
-long x32_sys_call(const struct pt_regs *regs, unsigned int nr)
+static noinline long x32_sys_call(const struct pt_regs *regs, unsigned int nr)
 {
+#ifdef CONFIG_X86_X32_ABI
 	switch (nr) {
 	#include <asm/syscalls_x32.h>
 	default: return __x64_sys_ni_syscall(regs);
 	}
-}
+#else
+	return -ENOSYS;
 #endif
+}
 
 static __always_inline bool do_syscall_x64(struct pt_regs *regs, int nr)
 {
arch/x86/include/asm/syscall.h +0 -8
index c10dbb7..59a4060 100644
@@ -21,14 +21,6 @@ typedef long (*sys_call_ptr_t)(const struct pt_regs *);
 extern const sys_call_ptr_t sys_call_table[];
 
 /*
- * These may not exist, but still put the prototypes in so we
- * can use IS_ENABLED().
- */
-extern long ia32_sys_call(const struct pt_regs *, unsigned int nr);
-extern long x32_sys_call(const struct pt_regs *, unsigned int nr);
-extern long x64_sys_call(const struct pt_regs *, unsigned int nr);
-
-/*
  * Only the low 32 bits of orig_ax are meaningful, so we return int.
  * This importantly ignores the high bits on 64-bit, so comparisons
  * sign-extend the low 32 bits.
author maintainer
#104 lore raw

PATCH 16/18 x86/entry: Get rid of the sys_ni_syscall() indirection

In reply to Thomas Gleixner

Invoking sys_ni_syscall() from a code path, which already knows that the syscall number is invalid just to assign -ENOSYS to regs->ax is a pointless exercise. It's even redundant as the low level entry code already has set regs->ax to -ENOSYS on entry.

Remove the extra conditionals and the function calls.

---
 arch/x86/entry/syscall_32.c |    2 --
 arch/x86/entry/syscall_64.c |   10 +++-------
 2 files changed, 3 insertions(+), 9 deletions(-)
arch/x86/entry/syscall_32.c +0 -2
@@ -81,8 +81,6 @@ static __always_inline void do_syscall_3
 	if (likely(unr < IA32_NR_syscalls)) {
 		unr = array_index_nospec(unr, IA32_NR_syscalls);
 		regs->ax = ia32_sys_call(regs, unr);
-	} else if (nr != -1) {
-		regs->ax = __ia32_sys_ni_syscall(regs);
 	}
 }
 
arch/x86/entry/syscall_64.c +3 -7
@@ -68,7 +68,7 @@ static __always_inline bool do_syscall_x
 	return false;
 }
 
-static __always_inline bool do_syscall_x32(struct pt_regs *regs, int nr)
+static __always_inline void do_syscall_x32(struct pt_regs *regs, int nr)
 {
 	/*
 	 * Adjust the starting offset of the table, and convert numbers
@@ -80,9 +80,7 @@ static __always_inline bool do_syscall_x
 	if (IS_ENABLED(CONFIG_X86_X32_ABI) && likely(xnr < X32_NR_syscalls)) {
 		xnr = array_index_nospec(xnr, X32_NR_syscalls);
 		regs->ax = x32_sys_call(regs, xnr);
-		return true;
 	}
-	return false;
 }
 
 /* Returns true to return using SYSRET, or false to use IRET */
@@ -92,10 +90,8 @@ static __always_inline bool do_syscall_x
 
 	instrumentation_begin();
 
-	if (!do_syscall_x64(regs, nr) && !do_syscall_x32(regs, nr) && nr != -1) {
-		/* Invalid system call, but still a system call. */
-		regs->ax = __x64_sys_ni_syscall(regs);
-	}
+	if (!do_syscall_x64(regs, nr))
+		do_syscall_x32(regs, nr);
 
 	instrumentation_end();
 	syscall_exit_to_user_mode(regs);
Reviewed-by on v1 16/18
#105 lore raw

Re: [patch 16/18] x86/entry: Get rid of the sys_ni_syscall() indirection

Quoted 4 lines · Thomas Gleixner

Invoking sys_ni_syscall() from a code path, which already knows that the syscall number is invalid just to assign -ENOSYS to regs->ax is a pointless exercise. It's even redundant as the low level entry code already has set regs->ax to -ENOSYS on entry.

Makes sense, the all reltaed entry has already initialized regs->ax to -ENOSYS.

This makes the code very concise.

LGTM

Quoted 55 lines

Remove the extra conditionals and the function calls.

---
 arch/x86/entry/syscall_32.c |    2 --
 arch/x86/entry/syscall_64.c |   10 +++-------
 2 files changed, 3 insertions(+), 9 deletions(-)
arch/x86/entry/syscall_32.c +0 -2
@@ -81,8 +81,6 @@ static __always_inline void do_syscall_3
 	if (likely(unr < IA32_NR_syscalls)) {
 		unr = array_index_nospec(unr, IA32_NR_syscalls);
 		regs->ax = ia32_sys_call(regs, unr);
-	} else if (nr != -1) {
-		regs->ax = __ia32_sys_ni_syscall(regs);
 	}
 }
 
arch/x86/entry/syscall_64.c +3 -7
@@ -68,7 +68,7 @@ static __always_inline bool do_syscall_x
 	return false;
 }
 
-static __always_inline bool do_syscall_x32(struct pt_regs *regs, int nr)
+static __always_inline void do_syscall_x32(struct pt_regs *regs, int nr)
 {
 	/*
 	 * Adjust the starting offset of the table, and convert numbers
@@ -80,9 +80,7 @@ static __always_inline bool do_syscall_x
 	if (IS_ENABLED(CONFIG_X86_X32_ABI) && likely(xnr < X32_NR_syscalls)) {
 		xnr = array_index_nospec(xnr, X32_NR_syscalls);
 		regs->ax = x32_sys_call(regs, xnr);
-		return true;
 	}
-	return false;
 }
 
 /* Returns true to return using SYSRET, or false to use IRET */
@@ -92,10 +90,8 @@ static __always_inline bool do_syscall_x
 
 	instrumentation_begin();
 
-	if (!do_syscall_x64(regs, nr) && !do_syscall_x32(regs, nr) && nr != -1) {
-		/* Invalid system call, but still a system call. */
-		regs->ax = __x64_sys_ni_syscall(regs);
-	}
+	if (!do_syscall_x64(regs, nr))
+		do_syscall_x32(regs, nr);
 
 	instrumentation_end();
 	syscall_exit_to_user_mode(regs);
#106 lore raw

[tip: core/entry] x86/entry: Get rid of the sys_ni_syscall() indirection

In reply to Thomas Gleixner
The following commit has been merged into the core/entry branch of tip:

The following commit has been merged into the core/entry branch of tip:

Commit-ID:     1b1f3b3e1b3945ae6e49081fd3586a6833d4a555
Gitweb:        https://git.kernel.org/tip/1b1f3b3e1b3945ae6e49081fd3586a6833d4a555
Author:        Thomas Gleixner <[email protected]>
AuthorDate:    Tue, 07 Jul 2026 21:07:01 +02:00
Committer:     Thomas Gleixner <[email protected]>
CommitterDate: Sun, 12 Jul 2026 12:38:02 +02:00

x86/entry: Get rid of the sys_ni_syscall() indirection

Invoking sys_ni_syscall() from a code path, which already knows that the syscall number is invalid just to assign -ENOSYS to regs->ax is a pointless exercise. It's even redundant as the low level entry code already has set regs->ax to -ENOSYS on entry.

Remove the extra conditionals and the function calls.

---
 arch/x86/entry/syscall_32.c |  2 --
 arch/x86/entry/syscall_64.c | 10 +++-------
 2 files changed, 3 insertions(+), 9 deletions(-)
arch/x86/entry/syscall_32.c +0 -2
index 6e00929..68e2f13 100644
@@ -81,8 +81,6 @@ static __always_inline void do_syscall_32_irqs_on(struct pt_regs *regs, int nr)
 	if (likely(unr < IA32_NR_syscalls)) {
 		unr = array_index_nospec(unr, IA32_NR_syscalls);
 		regs->ax = ia32_sys_call(regs, unr);
-	} else if (nr != -1) {
-		regs->ax = __ia32_sys_ni_syscall(regs);
 	}
 }
 
arch/x86/entry/syscall_64.c +3 -7
index 837aee7..c716e0f 100644
@@ -68,7 +68,7 @@ static __always_inline bool do_syscall_x64(struct pt_regs *regs, int nr)
 	return false;
 }
 
-static __always_inline bool do_syscall_x32(struct pt_regs *regs, int nr)
+static __always_inline void do_syscall_x32(struct pt_regs *regs, int nr)
 {
 	/*
 	 * Adjust the starting offset of the table, and convert numbers
@@ -80,9 +80,7 @@ static __always_inline bool do_syscall_x32(struct pt_regs *regs, int nr)
 	if (IS_ENABLED(CONFIG_X86_X32_ABI) && likely(xnr < X32_NR_syscalls)) {
 		xnr = array_index_nospec(xnr, X32_NR_syscalls);
 		regs->ax = x32_sys_call(regs, xnr);
-		return true;
 	}
-	return false;
 }
 
 /* Returns true to return using SYSRET, or false to use IRET */
@@ -92,10 +90,8 @@ __visible noinstr bool do_syscall_64(struct pt_regs *regs, int nr)
 
 	instrumentation_begin();
 
-	if (!do_syscall_x64(regs, nr) && !do_syscall_x32(regs, nr) && nr != -1) {
-		/* Invalid system call, but still a system call. */
-		regs->ax = __x64_sys_ni_syscall(regs);
-	}
+	if (!do_syscall_x64(regs, nr))
+		do_syscall_x32(regs, nr);
 
 	instrumentation_end();
 	syscall_exit_to_user_mode(regs);
#107 lore raw

Re: [patch 16/18] x86/entry: Get rid of the sys_ni_syscall() indirection

In reply to Thomas Gleixner
Quoted 6 lines · Thomas Gleixner

Invoking sys_ni_syscall() from a code path, which already knows that the syscall number is invalid just to assign -ENOSYS to regs->ax is a pointless exercise. It's even redundant as the low level entry code already has set regs->ax to -ENOSYS on entry.

Remove the extra conditionals and the function calls.

Since this patch, tools/testing/selftests/x86/syscall_numbering_64 throws in this:

|[RUN]   Running tests under ptrace: modifying the default return
|[RUN]       Checking system calls with msb = 0 (0x0)
|[RUN]           Checking some common syscalls as 64 bit
|[OK]                x64 syscall 0:0 returned 0 as expected
|[OK]                x64 syscall 0:1 returned 0 as expected
|[RUN]           Checking some 64-bit only syscalls as 64 bit
|[OK]                x64 syscall 0:19 returned 0 as expected
|[OK]                x64 syscall 0:20 returned 0 as expected
|[RUN]           Checking out of range system calls
|[FAIL]                  x32 syscall 0:-64 returned -9999, but it should have returned -ENOSYS
…
|[FAIL]                  x32 syscall 0:-2 returned -9999, but it should have returned -ENOSYS
|[FAIL]              x32 syscalls 0:-64..-2 had 63 failure
|[OK]                x32 syscall 0:-1 returned MODIFIED_BY_PTRACE as expected
|[FAIL]                  x64 syscall 0:1073741760 returned -9999, but it should have returned -ENOSYS
…
|[FAIL]                  x64 syscall 0:1073741823 returned -9999, but it should have returned -ENOSYS
|[FAIL]              x64 syscalls 0:1073741760..1073741823 had 64 failure
|[FAIL]                  x64 syscall 0:-64 returned -9999, but it should have returned -ENOSYS
…
|[FAIL]                  x64 syscall 0:547 returned -9999, but it should have returned -ENOSYS
|[FAIL]              x64 syscalls 0:512..547 had 36 failure
|[RUN]           Checking some common syscalls as x32
|[OK]                x32 syscall 0:0 returned 0 as expected
…
|[RUN]           Checking out of range system calls
|[FAIL]                  x32 syscall 1:-64 returned -9999, but it should have returned -ENOSYS
|[FAIL]              x32 syscalls 1:-64..-2 had 63 failure
|[OK]                x32 syscall 1:-1 returned MODIFIED_BY_PTRACE as expected
|[FAIL]                  x64 syscall 1:1073741760 returned -9999, but it should have returned -ENOSYS

…

and so on… The test has

| #define MODIFIED_BY_PTRACE -9999

and the ptracer modifies the return code. However not always. Not sure if this was indeed a pointless exercise or not.

The test could be updated via the hunk below in case the new behaviour is what is expected. hpa made the extension to the test in commit 795e2a023b808 ("selftests/x86/syscall: Add tests under ptrace to syscall_numbering_64").

tools/testing/selftests/x86/syscall_numbering.c +13 -8
index ca0eca7b9dced..1435394fba022 100644
@@ -250,6 +250,7 @@ static bool test_x32(void)
 static void test_syscalls_common(int msb)
 {
 	enum ptrace_pass pass = sh->ptrace_pass;
+	int expected_ret = -ENOSYS;
 
 	run("Checking some common syscalls as 64 bit\n");
 	check_zero(msb, SYS_READ);
@@ -260,18 +261,22 @@ static void test_syscalls_common(int msb)
 	check_zero(msb, X64_WRITEV);
 
 	run("Checking out of range system calls\n");
-	check_for(msb, -64, -2, -ENOSYS);
 	if (pass >= PTP_FUZZRET)
-		check_for(msb, -1, -1, MODIFIED_BY_PTRACE);
-	else
-		check_for(msb, -1, -1, -ENOSYS);
-	check_for(msb, X32_BIT-64, X32_BIT-1, -ENOSYS);
-	check_for(msb, -64-X32_BIT, -1-X32_BIT, -ENOSYS);
-	check_for(msb, INT_MAX-64, INT_MAX-1, -ENOSYS);
+		expected_ret = MODIFIED_BY_PTRACE;
+	check_for(msb, -64, -2, expected_ret);
+	check_for(msb, -1, -1, expected_ret);
+	check_for(msb, X32_BIT-64, X32_BIT-1, expected_ret);
+	check_for(msb, -64-X32_BIT, -1-X32_BIT, expected_ret);
+	check_for(msb, INT_MAX-64, INT_MAX-1, expected_ret);
 }
 
 static void test_syscalls_with_x32(int msb)
 {
+	enum ptrace_pass pass = sh->ptrace_pass;
+	int expected_ret = -ENOSYS;
+
+	if (pass >= PTP_FUZZRET)
+		expected_ret = MODIFIED_BY_PTRACE;
 	/*
 	 * Syscalls 512-547 are "x32" syscalls.  They are
 	 * intended to be called with the x32 (0x40000000) bit
@@ -279,7 +284,7 @@ static void test_syscalls_with_x32(int msb)
 	 * nonsense and should not work.
 	 */
 	run("Checking x32 syscalls as 64 bit\n");
-	check_for(msb, 512, 547, -ENOSYS);
+	check_for(msb, 512, 547, expected_ret);
 
 	run("Checking some common syscalls as x32\n");
 	check_zero(msb, SYS_READ   | X32_BIT);

Sebastian

#108 lore raw

Re: [patch 16/18] x86/entry: Get rid of the sys_ni_syscall() indirection

tools/testing/selftests/x86/syscall_numbering.c

Quoted 9 lines · To Thomas Gleixner

The test could be updated via the hunk below in case the new behaviour is what is expected. hpa made the extension to the test in commit 795e2a023b808 ("selftests/x86/syscall: Add tests under ptrace to syscall_numbering_64").

tools/testing/selftests/x86/syscall_numbering.c +0 -0
index ca0eca7b9dced..1435394fba022 100644

Now I notice the fix depends on CONFIG_X86_X32_ABI=y (fails for =n). But we want to get rid of it anyway so… CONFIG_IA32_EMULATION is not affected (with the fix).

Sebastian

#109 lore raw

Re: [patch 16/18] x86/entry: Get rid of the sys_ni_syscall() indirection

Quoted 6 lines · Sebastian Andrzej Siewior
Quoted 5 lines · To Thomas Gleixner

The test could be updated via the hunk below in case the new behaviour is what is expected. hpa made the extension to the test in commit 795e2a023b808 ("selftests/x86/syscall: Add tests under ptrace to syscall_numbering_64").

Quoted 9 lines

tools/testing/selftests/x86/syscall_numbering.c

Quoted 4 lines
tools/testing/selftests/x86/syscall_numbering.c +0 -0
index ca0eca7b9dced..1435394fba022 100644

Now I notice the fix depends on CONFIG_X86_X32_ABI=y (fails for =n). But we want to get rid of it anyway so… CONFIG_IA32_EMULATION is not affected (with the fix).

It would be very simple to probe for by issuing a simple system call like getppid() with the x32 bit set.

-hpa

_______________________________________________
linux-snps-arc mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-snps-arc

author maintainer
#110 lore raw

Re: [patch 16/18] x86/entry: Get rid of the sys_ni_syscall() indirection

In reply to Sebastian Andrzej Siewior
Quoted 40 lines · Sebastian Andrzej Siewior
Quoted 6 lines · Thomas Gleixner

Invoking sys_ni_syscall() from a code path, which already knows that the syscall number is invalid just to assign -ENOSYS to regs->ax is a pointless exercise. It's even redundant as the low level entry code already has set regs->ax to -ENOSYS on entry.

Remove the extra conditionals and the function calls.

Since this patch, tools/testing/selftests/x86/syscall_numbering_64 throws in this:

|[RUN]   Running tests under ptrace: modifying the default return
|[RUN]       Checking system calls with msb = 0 (0x0)
|[RUN]           Checking some common syscalls as 64 bit
|[OK]                x64 syscall 0:0 returned 0 as expected
|[OK]                x64 syscall 0:1 returned 0 as expected
|[RUN]           Checking some 64-bit only syscalls as 64 bit
|[OK]                x64 syscall 0:19 returned 0 as expected
|[OK]                x64 syscall 0:20 returned 0 as expected
|[RUN]           Checking out of range system calls
|[FAIL]                  x32 syscall 0:-64 returned -9999, but it should have returned -ENOSYS
…
|[FAIL]                  x32 syscall 0:-2 returned -9999, but it should have returned -ENOSYS
|[FAIL]              x32 syscalls 0:-64..-2 had 63 failure
|[OK]                x32 syscall 0:-1 returned MODIFIED_BY_PTRACE as expected
|[FAIL]                  x64 syscall 0:1073741760 returned -9999, but it should have returned -ENOSYS
…
|[FAIL]                  x64 syscall 0:1073741823 returned -9999, but it should have returned -ENOSYS
|[FAIL]              x64 syscalls 0:1073741760..1073741823 had 64 failure
|[FAIL]                  x64 syscall 0:-64 returned -9999, but it should have returned -ENOSYS
…
|[FAIL]                  x64 syscall 0:547 returned -9999, but it should have returned -ENOSYS
|[FAIL]              x64 syscalls 0:512..547 had 36 failure
|[RUN]           Checking some common syscalls as x32
|[OK]                x32 syscall 0:0 returned 0 as expected
…
|[RUN]           Checking out of range system calls
|[FAIL]                  x32 syscall 1:-64 returned -9999, but it should have returned -ENOSYS
|[FAIL]              x32 syscalls 1:-64..-2 had 63 failure
|[OK]                x32 syscall 1:-1 returned MODIFIED_BY_PTRACE as expected
|[FAIL]                  x64 syscall 1:1073741760 returned -9999, but it should have returned -ENOSYS
Quoted 8 lines

…

and so on… The test has

| #define MODIFIED_BY_PTRACE -9999

and the ptracer modifies the return code. However not always. Not sure if this was indeed a pointless exercise or not.

Hrmm. That's weird. Let me have a look.

author maintainer
#111 lore raw

Re: [patch 16/18] x86/entry: Get rid of the sys_ni_syscall() indirection

Quoted 9 lines · Thomas Gleixner
Quoted 8 lines · Sebastian Andrzej Siewior

On 2026-07-07 21:07:01 [+0200], Thomas Gleixner wrote:

|[RUN]           Checking out of range system calls
|[FAIL]                  x32 syscall 1:-64 returned -9999, but it should have returned -ENOSYS
|[FAIL]              x32 syscalls 1:-64..-2 had 63 failure
|[OK]                x32 syscall 1:-1 returned MODIFIED_BY_PTRACE as expected
|[FAIL]                  x64 syscall 1:1073741760 returned -9999, but it should have returned -ENOSYS

…

Quoted 8 lines
Quoted 6 lines

and so on… The test has

| #define MODIFIED_BY_PTRACE -9999

and the ptracer modifies the return code. However not always. Not sure if this was indeed a pointless exercise or not.

Hrmm. That's weird. Let me have a look.

So I clearly failed to decode the overloading of the -1L return value correctly and then failed to run the stupid test.

TBH, this whole thing was a horrid and inconsistent mess.

The logic in the original code was:

    When the entry work code returned an invalid syscall number then the
    return value in regs->ax was set to -ENOSYS, except when the
    returned syscall number was -1. Syscall number "-1" indicated that
    the syscall has to be aborted.

     regs->ax = -ENOSYS;
     syscall = enter_work(regs, syscall);
     if (syscall_in_range(syscall))
        regs->ax = do_syscall(syscall);
     else if (syscall != -1)
        regs->ax = -ENOSYS;

So if the ptrace check in enter_work() overwrote regs->ax and the syscall number (either as supplied by user space or rewritten) was out of range and not -1 then the x86 entry code overwrote regs->ax to -ENOSYS again. IOW, there is no distinction between a check induced abort and a syscall with syscall number -1.

The rework changed the return value to boolean, which is true when the syscall should be invoked and false when one of the checks requests to abort the syscall. In that case the return code does not touch the return value in regs->ax.

If the eventually modified syscall number is out of range then the code relies on the fact that regs->ax was preset with -ENOSYS, i.e.:

     regs->ax = -ENOSYS;
     // True indicates to proceed
     if (enter_work(regs, &syscall)) {
         if (syscall_in_range(syscall))
            regs->ax = do_syscall(syscall);
     }

That seems to be equivalent, but it is not when ptrace() modifies the return value in regs->ax and also rewrites the syscall number to an invalid value or leaves the user supplied invalid value intact and does _NOT_ abort the syscall.

So the reworked code does not overwrite the tracer modified return value with -ENOSYS in that case and returns whatever the tracer decided to put into it.

TBH, that makes a lot more sense than the original behavior. If the tracer decides to fiddle with the default return value then that's what the tracer intended.

That makes the behavior consistent vs. other abort scenarios:

ptrace()
regs->ax = MAGIC;
return true; // Allow syscall

seccomp()
return false; // Abort syscall

So when the tracer modified the return value and seccomp aborts the syscall then the tracer induced value is preserved. That was the case in the original code as well because seccomp() indicated the abort by returning -1 as the modified syscall number. Similar effects when ftrace (BPF, kprobe) decided to overwrite the syscall number).

Bringing the original behaviour back is trivial enough, but I'm not convinced that it makes any sense and is worth it. At least this confines the x32 specific insanity of treating -1 special to x32...

Thanks,

tglx
---

arch/x86/entry/syscall_32.c +2 -0
@@ -77,6 +77,8 @@ static __always_inline void do_syscall_3
 	if (likely(nr < IA32_NR_syscalls)) {
 		nr = array_index_nospec(nr, IA32_NR_syscalls);
 		regs->ax = ia32_sys_call(regs, (unsigned int)nr);
+	} else {
+		regs->ax = -ENOSYS;
 	}
 }
 
arch/x86/entry/syscall_64.c +15 -4
@@ -64,15 +64,24 @@ static __always_inline bool do_syscall_x
 	return false;
 }
 
-static __always_inline void do_syscall_x32(struct pt_regs *regs, unsigned long nr)
+static __always_inline bool do_syscall_x32(struct pt_regs *regs, unsigned long nr)
 {
+	if (!IS_ENABLED(CONFIG_X86_X32_ABI))
+		return false;
+
+	/* Preserve the historic insanity of treating -1 special on x32 */
+	if (nr == ULONG_MAX)
+		return true;
+
 	/* Adjust the starting offset of the table */
 	nr -= __X32_SYSCALL_BIT;
 
-	if (IS_ENABLED(CONFIG_X86_X32_ABI) && likely(nr < X32_NR_syscalls)) {
+	if (likely(nr < X32_NR_syscalls)) {
 		nr = array_index_nospec(nr, X32_NR_syscalls);
 		regs->ax = x32_sys_call(regs, (unsigned int)nr);
+		return true;
 	}
+	return false;
 }
 
 /* Returns true to return using SYSRET, or false to use IRET */
@@ -81,8 +90,10 @@ static __always_inline void do_syscall_x
 	if (likely(syscall_enter_from_user_mode_randomize_stack(regs, &nr))) {
 		instrumentation_begin();
 
-		if (!do_syscall_x64(regs, nr))
-			do_syscall_x32(regs, nr);
+		if (unlikely(!do_syscall_x64(regs, nr))) {
+			if (!do_syscall_x32(regs, nr))
+				regs->ax = -ENOSYS;
+		}
 
 		instrumentation_end();
 	}
#112 lore raw

Re: [patch 16/18] x86/entry: Get rid of the sys_ni_syscall() indirection

Quoted 149 lines · Thomas Gleixner
Quoted 9 lines · Thomas Gleixner
Quoted 8 lines · Sebastian Andrzej Siewior

On 2026-07-07 21:07:01 [+0200], Thomas Gleixner wrote:

|[RUN]           Checking out of range system calls
|[FAIL]                  x32 syscall 1:-64 returned -9999, but it should have returned -ENOSYS
|[FAIL]              x32 syscalls 1:-64..-2 had 63 failure
|[OK]                x32 syscall 1:-1 returned MODIFIED_BY_PTRACE as expected
|[FAIL]                  x64 syscall 1:1073741760 returned -9999, but it should have returned -ENOSYS

…

Quoted 8 lines
Quoted 6 lines

and so on… The test has

| #define MODIFIED_BY_PTRACE -9999

and the ptracer modifies the return code. However not always. Not sure if this was indeed a pointless exercise or not.

Hrmm. That's weird. Let me have a look.

So I clearly failed to decode the overloading of the -1L return value correctly and then failed to run the stupid test.

TBH, this whole thing was a horrid and inconsistent mess.

The logic in the original code was:

   When the entry work code returned an invalid syscall number then the
   return value in regs->ax was set to -ENOSYS, except when the
   returned syscall number was -1. Syscall number "-1" indicated that
   the syscall has to be aborted.

    regs->ax = -ENOSYS;
    syscall = enter_work(regs, syscall);
    if (syscall_in_range(syscall))
       regs->ax = do_syscall(syscall);
    else if (syscall != -1)
       regs->ax = -ENOSYS;

So if the ptrace check in enter_work() overwrote regs->ax and the syscall number (either as supplied by user space or rewritten) was out of range and not -1 then the x86 entry code overwrote regs->ax to -ENOSYS again. IOW, there is no distinction between a check induced abort and a syscall with syscall number -1.

The rework changed the return value to boolean, which is true when the syscall should be invoked and false when one of the checks requests to abort the syscall. In that case the return code does not touch the return value in regs->ax.

If the eventually modified syscall number is out of range then the code relies on the fact that regs->ax was preset with -ENOSYS, i.e.:

    regs->ax = -ENOSYS;
    // True indicates to proceed
    if (enter_work(regs, &syscall)) {
        if (syscall_in_range(syscall))
           regs->ax = do_syscall(syscall);
    }

That seems to be equivalent, but it is not when ptrace() modifies the return value in regs->ax and also rewrites the syscall number to an invalid value or leaves the user supplied invalid value intact and does _NOT_ abort the syscall.

So the reworked code does not overwrite the tracer modified return value with -ENOSYS in that case and returns whatever the tracer decided to put into it.

TBH, that makes a lot more sense than the original behavior. If the tracer decides to fiddle with the default return value then that's what the tracer intended.

That makes the behavior consistent vs. other abort scenarios:

   ptrace()
     regs->ax = MAGIC;
     return true;            // Allow syscall

seccomp()
return false; // Abort syscall

So when the tracer modified the return value and seccomp aborts the syscall then the tracer induced value is preserved. That was the case in the original code as well because seccomp() indicated the abort by returning -1 as the modified syscall number. Similar effects when ftrace (BPF, kprobe) decided to overwrite the syscall number).

Bringing the original behaviour back is trivial enough, but I'm not convinced that it makes any sense and is worth it. At least this confines the x32 specific insanity of treating -1 special to x32...

Thanks,

tglx
---

arch/x86/entry/syscall_32.c +2 -0
@@ -77,6 +77,8 @@ static __always_inline void do_syscall_3
 	if (likely(nr < IA32_NR_syscalls)) {
 		nr = array_index_nospec(nr, IA32_NR_syscalls);
 		regs->ax = ia32_sys_call(regs, (unsigned int)nr);
+	} else {
+		regs->ax = -ENOSYS;
 	}
 }
 
arch/x86/entry/syscall_64.c +11 -2
@@ -64,15 +64,24 @@ static __always_inline bool do_syscall_x
 	return false;
 }
 
-static __always_inline void do_syscall_x32(struct pt_regs *regs, unsigned long nr)
+static __always_inline bool do_syscall_x32(struct pt_regs *regs, unsigned long nr)
 {
+	if (!IS_ENABLED(CONFIG_X86_X32_ABI))
+		return false;
+
+	/* Preserve the historic insanity of treating -1 special on x32 */
+	if (nr == ULONG_MAX)
+		return true;
+
 	/* Adjust the starting offset of the table */
 	nr -= __X32_SYSCALL_BIT;
 
-	if (IS_ENABLED(CONFIG_X86_X32_ABI) && likely(nr < X32_NR_syscalls)) {
+	if (likely(nr < X32_NR_syscalls)) {
 		nr = array_index_nospec(nr, X32_NR_syscalls);
 		regs->ax = x32_sys_call(regs, (unsigned int)nr);
+		return true;
 	}
+	return false;
 }
 
 /* Returns true to return using SYSRET, or false to use IRET */
@@ -81,8 +90,10 @@ static __always_inline void do_syscall_x
 	if (likely(syscall_enter_from_user_mode_randomize_stack(regs, &nr))) {
 		instrumentation_begin();

arch/x86/entry/syscall_64.c static __always_inline void do_syscall_x · line 99

Quoted 10 lines
arch/x86/entry/syscall_64.c +4 -2
 
-		if (!do_syscall_x64(regs, nr))
-			do_syscall_x32(regs, nr);
+		if (unlikely(!do_syscall_x64(regs, nr))) {
+			if (!do_syscall_x32(regs, nr))
+				regs->ax = -ENOSYS;
+		}
 
 		instrumentation_end();
 	}

It was never limited to x32...

author maintainer
#113 lore raw

Re: [patch 16/18] x86/entry: Get rid of the sys_ni_syscall() indirection

Quoted 12 lines · H. Peter Anvin

arch/x86/entry/syscall_64.c static __always_inline bool do_syscall_x · line 74

Quoted 9 lines · Thomas Gleixner
arch/x86/entry/syscall_64.c +1 -1
-static __always_inline void do_syscall_x32(struct pt_regs *regs, unsigned long nr)
+static __always_inline bool do_syscall_x32(struct pt_regs *regs, unsigned long nr)

{

arch/x86/entry/syscall_64.c +6 -0
+	if (!IS_ENABLED(CONFIG_X86_X32_ABI))
+		return false;
+
+	/* Preserve the historic insanity of treating -1 special on x32 */
+	if (nr == ULONG_MAX)
+		return true;

It was never limited to x32...

Tired brain misread the test output:

[RUN] Running tests under ptrace: modifying the default return
[RUN] Checking system calls with msb = 0 (0x0)

[OK]                x32 syscalls 0:-64..-2 returned -ENOSYS as expected
[OK]                x32 syscall 0:-1 returned MODIFIED_BY_PTRACE as expected
[OK]                x64 syscalls 0:-64..-1 returned -ENOSYS as expected

But that's because the "-1" on x32 is actually 0xFFFFFFFF while on x64 it's 0x7FFFFFFF.

The whole mess comes from using -1 as indicator for syscall abort which is undistinguishable from a syscall(nr=-1).

Bah. Let me restore this nonsense.

Thanks,

tglx

author maintainer
#114 lore raw

Re: [patch 16/18] x86/entry: Get rid of the sys_ni_syscall() indirection

Quoted 9 lines · Thomas Gleixner

On Thu, Oct 22 2026 at 17:22, H. Peter Anvin wrote:
Tired brain misread the test output:

[RUN] Running tests under ptrace: modifying the default return
[RUN] Checking system calls with msb = 0 (0x0)

[OK]                x32 syscalls 0:-64..-2 returned -ENOSYS as expected
[OK]                x32 syscall 0:-1 returned MODIFIED_BY_PTRACE as expected
[OK]                x64 syscalls 0:-64..-1 returned -ENOSYS as expected
Quoted 7 lines

But that's because the "-1" on x32 is actually 0xFFFFFFFF while on x64 it's 0x7FFFFFFF.

The whole mess comes from using -1 as indicator for syscall abort which is undistinguishable from a syscall(nr=-1).

Bah. Let me restore this nonsense.

The real question is how we ended up there. By design or as an implementation detail which got later set in stone and the selftest was written to test the implementation instead of testing against a specification.

I went back in history and in 2.6.12 the behavior was for both i386 and x86_64:

  regs->ax = -ENOSYS;
  syscall_trace_enter();
  if (syscall_nr < MAX)
  	do_syscall();
  ....

IOW, a tracer modification of regs->ax is not overwritten when the syscall number is out of range.

Between 2.6.19-rc2 and -rc3 x86_64 was changed to _always_ overwrite regs->ax when the syscall number is out of range.

In the 3.8 merge window seccomp introduced the -1 == skip bogosity which got fixed up and made "consistent" in several changes afterwards. Just that it never reached a state of consistency due to the overloading.

So are we stuck with this behavior or do we sit down and define what the correct behavior should be?

Thanks,

tglx

#115 lore raw

Re: [patch 16/18] x86/entry: Get rid of the sys_ni_syscall() indirection

Quoted 42 lines · Thomas Gleixner
Quoted 9 lines · Thomas Gleixner

On Thu, Oct 22 2026 at 17:22, H. Peter Anvin wrote:
Tired brain misread the test output:

[RUN] Running tests under ptrace: modifying the default return
[RUN] Checking system calls with msb = 0 (0x0)

[OK]                x32 syscalls 0:-64..-2 returned -ENOSYS as expected
[OK]                x32 syscall 0:-1 returned MODIFIED_BY_PTRACE as expected
[OK]                x64 syscalls 0:-64..-1 returned -ENOSYS as expected
Quoted 7 lines

But that's because the "-1" on x32 is actually 0xFFFFFFFF while on x64 it's 0x7FFFFFFF.

The whole mess comes from using -1 as indicator for syscall abort which is undistinguishable from a syscall(nr=-1).

Bah. Let me restore this nonsense.

The real question is how we ended up there. By design or as an implementation detail which got later set in stone and the selftest was written to test the implementation instead of testing against a specification.

I went back in history and in 2.6.12 the behavior was for both i386 and x86_64:

regs->ax = -ENOSYS;
syscall_trace_enter();
if (syscall_nr < MAX)
do_syscall();
....

IOW, a tracer modification of regs->ax is not overwritten when the syscall number is out of range.

Between 2.6.19-rc2 and -rc3 x86_64 was changed to _always_ overwrite regs->ax when the syscall number is out of range.

In the 3.8 merge window seccomp introduced the -1 == skip bogosity which got fixed up and made "consistent" in several changes afterwards. Just that it never reached a state of consistency due to the overloading.

Quoted 8 lines

So are we stuck with this behavior or do we sit down and define what the correct behavior should be?

Thanks,

tglx

Going back on something from 3.8 that is actively used seems unwise. I fear that that ship sailed a long time ago, even though I hate it just as much as you do.

author maintainer
#116 lore raw

Re: [patch 16/18] x86/entry: Get rid of the sys_ni_syscall() indirection

Quoted 25 lines · H. Peter Anvin
Quoted 24 lines · Thomas Gleixner

The real question is how we ended up there. By design or as an implementation detail which got later set in stone and the selftest was written to test the implementation instead of testing against a specification.

I went back in history and in 2.6.12 the behavior was for both i386 and x86_64:

regs->ax = -ENOSYS;
syscall_trace_enter();
if (syscall_nr < MAX)
do_syscall();
....

IOW, a tracer modification of regs->ax is not overwritten when the syscall number is out of range.

Between 2.6.19-rc2 and -rc3 x86_64 was changed to _always_ overwrite regs->ax when the syscall number is out of range.

In the 3.8 merge window seccomp introduced the -1 == skip bogosity which got fixed up and made "consistent" in several changes afterwards. Just that it never reached a state of consistency due to the overloading.

Quoted 7 lines
Quoted 3 lines

So are we stuck with this behavior or do we sit down and define what the correct behavior should be?

Going back on something from 3.8 that is actively used seems unwise. I fear that that ship sailed a long time ago, even though I hate it just as much as you do.

Well, overwriting the tracer written value for invalid syscall numbers is something we can't undo. Though the interesting question is whether the -1 overloading needs to be preserved. The new code uses returns false when the syscall has to be aborted and that leaves the return code untouched. When syscall_enter_trace() returns true, the syscall is invoked, so it would be consistent to overwrite the return code with -ENOSYS even for -1. But yeah, some esoteric nonsense might rely on that behaviour for the wrong reasons.

Fix below.

Thanks,

tglx
---

arch/x86/entry/syscall_32.c +2 -0
@@ -77,6 +77,8 @@ static __always_inline void do_syscall_3
 	if (likely(nr < IA32_NR_syscalls)) {
 		nr = array_index_nospec(nr, IA32_NR_syscalls);
 		regs->ax = ia32_sys_call(regs, (unsigned int)nr);
+	} else {
+		regs->ax = -ENOSYS;
 	}
 }
 
arch/x86/entry/syscall_64.c +22 -4
@@ -64,15 +64,20 @@ static __always_inline bool do_syscall_x
 	return false;
 }
 
-static __always_inline void do_syscall_x32(struct pt_regs *regs, unsigned long nr)
+static __always_inline bool do_syscall_x32(struct pt_regs *regs, unsigned long nr)
 {
+	if (!IS_ENABLED(CONFIG_X86_X32_ABI))
+		return false;
+
 	/* Adjust the starting offset of the table */
 	nr -= __X32_SYSCALL_BIT;
 
-	if (IS_ENABLED(CONFIG_X86_X32_ABI) && likely(nr < X32_NR_syscalls)) {
+	if (likely(nr < X32_NR_syscalls)) {
 		nr = array_index_nospec(nr, X32_NR_syscalls);
 		regs->ax = x32_sys_call(regs, (unsigned int)nr);
+		return true;
 	}
+	return false;
 }
 
 /* Returns true to return using SYSRET, or false to use IRET */
@@ -81,8 +86,21 @@ static __always_inline void do_syscall_x
 	if (likely(syscall_enter_from_user_mode_randomize_stack(regs, &nr))) {
 		instrumentation_begin();
 
-		if (!do_syscall_x64(regs, nr))
-			do_syscall_x32(regs, nr);
+		if (unlikely(!do_syscall_x64(regs, nr))) {
+			/*
+			 * The special treatment of syscall number -1 is a
+			 * historical bogosity as the original code used -1 to
+			 * indicate syscall abort, which is not distinguishable
+			 * from a syscall which is invoked with syscall number
+			 * -1. The historic behavior is to keep the return value
+			 * in regs->ax unmodified in that case, which means it's
+			 * either the preset value -ENOSYS or a value which was
+			 * written by a tracer. If the syscall number is invalid
+			 * but not -1 then overwrite any tracer modification.
+			 */
+			if (!do_syscall_x32(regs, nr) && nr != -1L)
+				regs->ax = -ENOSYS;
+		}
 
 		instrumentation_end();
 	}
author maintainer
#117 lore raw

PATCH 1/1 x86/entry: Fix ptrace regression

The recent rework of the syscall entry code missed the historical detail of the abuse of syscall number -1L to abort a syscall and keep modifications by tracers to the return value, while a rewrite of the syscall number to an invalid value undoes eventual tracer modification to the return value and overwrites it with -ENOSYS.

Restore the original behaviour.

Fixes 1b1f3b3e1b39 ("x86/entry: Get rid of the sys_ni_syscall() indirection")
---
 arch/x86/entry/syscall_32.c |    2 ++
 arch/x86/entry/syscall_64.c |   26 ++++++++++++++++++++++----
 2 files changed, 24 insertions(+), 4 deletions(-)
arch/x86/entry/syscall_32.c +2 -0
@@ -77,6 +77,8 @@ static __always_inline void do_syscall_3
 	if (likely(nr < IA32_NR_syscalls)) {
 		nr = array_index_nospec(nr, IA32_NR_syscalls);
 		regs->ax = ia32_sys_call(regs, (unsigned int)nr);
+	} else {
+		regs->ax = -ENOSYS;
 	}
 }
 
arch/x86/entry/syscall_64.c +22 -4
@@ -64,15 +64,20 @@ static __always_inline bool do_syscall_x
 	return false;
 }
 
-static __always_inline void do_syscall_x32(struct pt_regs *regs, unsigned long nr)
+static __always_inline bool do_syscall_x32(struct pt_regs *regs, unsigned long nr)
 {
+	if (!IS_ENABLED(CONFIG_X86_X32_ABI))
+		return false;
+
 	/* Adjust the starting offset of the table */
 	nr -= __X32_SYSCALL_BIT;
 
-	if (IS_ENABLED(CONFIG_X86_X32_ABI) && likely(nr < X32_NR_syscalls)) {
+	if (likely(nr < X32_NR_syscalls)) {
 		nr = array_index_nospec(nr, X32_NR_syscalls);
 		regs->ax = x32_sys_call(regs, (unsigned int)nr);
+		return true;
 	}
+	return false;
 }
 
 /* Returns true to return using SYSRET, or false to use IRET */
@@ -81,8 +86,21 @@ static __always_inline void do_syscall_x
 	if (likely(syscall_enter_from_user_mode_randomize_stack(regs, &nr))) {
 		instrumentation_begin();
 
-		if (!do_syscall_x64(regs, nr))
-			do_syscall_x32(regs, nr);
+		if (unlikely(!do_syscall_x64(regs, nr))) {
+			/*
+			 * The special treatment of syscall number -1 is a
+			 * historical bogosity as the original code used -1 to
+			 * indicate syscall abort, which is not distinguishable
+			 * from a syscall which is invoked with syscall number
+			 * -1. The historic behavior is to keep the return value
+			 * in regs->ax unmodified in that case, which means it's
+			 * either the preset value -ENOSYS or a value which was
+			 * written by a tracer. If the syscall number is invalid
+			 * but not -1 then overwrite any tracer modification.
+			 */
+			if (!do_syscall_x32(regs, nr) && nr != -1L)
+				regs->ax = -ENOSYS;
+		}
 
 		instrumentation_end();
 	}
#118 lore raw

Re: [PATCH] x86/entry: Fix ptrace regression

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [High] x86/entry: missing nr != -1L check in do_syscall_32_irqs_on() --

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] x86/entry: missing nr != -1L check in do_syscall_32_irqs_on()
--

commit 99103a6b0e601cd2293cec25712d5b3e23db9efc
Author: Thomas Gleixner <[email protected]>

x86/entry: Fix ptrace regression

This commit restores the historical syscall entry behavior of preserving tracer modifications to regs->ax when a syscall is aborted with -1L while overwriting regs->ax with -ENOSYS when the syscall number is rewritten to an invalid value.

arch/x86/entry/syscall_32.c static __always_inline void do_syscall_32_irqs_on(struct pt_regs *regs, unsigned · line 83

Quoted 12 lines
arch/x86/entry/syscall_32.c +2 -0
index a59509bb460ab..1f91444d01a8e 100644
@@ -77,6 +77,8 @@ static __always_inline void do_syscall_32_irqs_on(struct pt_regs *regs, unsigned
 	if (likely(nr < IA32_NR_syscalls)) {
 		nr = array_index_nospec(nr, IA32_NR_syscalls);
 		regs->ax = ia32_sys_call(regs, (unsigned int)nr);
+	} else {
+		regs->ax = -ENOSYS;
 	}
 }

[Severity: High]
Should the else branch in do_syscall_32_irqs_on() in arch/x86/entry/syscall_32.c also check that nr != -1L before setting regs->ax = -ENOSYS, matching the check added to do_syscall_64() in arch/x86/entry/syscall_64.c and the logic prior to commit 1b1f3b3e1b39 ("x86/entry: Get rid of the sys_ni_syscall() indirection")?

When a 32-bit syscall (entered via do_int80_emulation(), fred_int80_emulation(), do_int80_syscall_32(), or __do_fast_syscall_32()) is traced with PTRACE_SYSCALL without SYSCALL_WORK_SYSCALL_EMU, syscall_enter_from_user_mode_work() runs:

include/linux/entry-common.h:syscall_enter_from_user_mode_work() {
    ...
	if (unlikely(!syscall_trace_enter(regs, work, *syscall)))
		return false;

	/* Reread the syscall number as it might have been modified */
	*syscall = syscall_get_nr(current, regs);

	return true;
}

If the tracer aborts the syscall at the syscall-entry stop by setting orig_ax to -1 and writing a return value into regs->ax, syscall_trace_enter() -> arch_ptrace_report_syscall_permit_entry() -> ptrace_report_syscall_permit_entry() returns true (unless a fatal signal is pending). syscall_enter_from_user_mode_work() then updates *syscall to -1L and returns true.

The caller then passes nr == (unsigned long)-1L into do_syscall_32_irqs_on(), where nr < IA32_NR_syscalls is false and the unconditional else branch overwrites the tracer-supplied regs->ax value with -ENOSYS.

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/87mrrvxaty.ffs@fw13?part=1
author maintainer
#119 lore raw

PATCH v2 1/1 x86/entry: Fix ptrace regression

In reply to Thomas Gleixner

The recent rework of the syscall entry code missed the historical detail of the abuse of syscall number -1L to abort a syscall and keep modifications by tracers to the return value, while a rewrite of the syscall number to an invalid value undoes eventual tracer modification to the return value and overwrite it with -ENOSYS.

Restore the original behaviour.

Fixes 1b1f3b3e1b39 ("x86/entry: Get rid of the sys_ni_syscall() indirection")

---
V2: Add the missing -1 check in the 32bit path - sashiko

---
 arch/x86/entry/syscall_32.c |    4 ++++
 arch/x86/entry/syscall_64.c |   26 ++++++++++++++++++++++----
 2 files changed, 26 insertions(+), 4 deletions(-)
arch/x86/entry/syscall_32.c +4 -0
@@ -77,6 +77,10 @@ static __always_inline void do_syscall_3
 	if (likely(nr < IA32_NR_syscalls)) {
 		nr = array_index_nospec(nr, IA32_NR_syscalls);
 		regs->ax = ia32_sys_call(regs, (unsigned int)nr);
+	} else {
+		/* See comment in do_syscall_64() */
+		if (nr != -1UL) {
+			regs->ax = -ENOSYS;
 	}
 }
 
arch/x86/entry/syscall_64.c +22 -4
@@ -64,15 +64,20 @@ static __always_inline bool do_syscall_x
 	return false;
 }
 
-static __always_inline void do_syscall_x32(struct pt_regs *regs, unsigned long nr)
+static __always_inline bool do_syscall_x32(struct pt_regs *regs, unsigned long nr)
 {
+	if (!IS_ENABLED(CONFIG_X86_X32_ABI))
+		return false;
+
 	/* Adjust the starting offset of the table */
 	nr -= __X32_SYSCALL_BIT;
 
-	if (IS_ENABLED(CONFIG_X86_X32_ABI) && likely(nr < X32_NR_syscalls)) {
+	if (likely(nr < X32_NR_syscalls)) {
 		nr = array_index_nospec(nr, X32_NR_syscalls);
 		regs->ax = x32_sys_call(regs, (unsigned int)nr);
+		return true;
 	}
+	return false;
 }
 
 /* Returns true to return using SYSRET, or false to use IRET */
@@ -81,8 +86,21 @@ static __always_inline void do_syscall_x
 	if (likely(syscall_enter_from_user_mode_randomize_stack(regs, &nr))) {
 		instrumentation_begin();
 
-		if (!do_syscall_x64(regs, nr))
-			do_syscall_x32(regs, nr);
+		if (unlikely(!do_syscall_x64(regs, nr))) {
+			/*
+			 * The special treatment of syscall number -1 is a
+			 * historical bogosity as the original code used -1 to
+			 * indicate syscall abort, which is not distinguishable
+			 * from a syscall which is invoked with syscall number
+			 * -1. The historic behavior is to keep the return value
+			 * in regs->ax unmodified in that case, which means it's
+			 * either the preset value -ENOSYS or a value which was
+			 * written by a tracer. If the syscall number is invalid
+			 * but not -1 then overwrite any tracer modification.
+			 */
+			if (!do_syscall_x32(regs, nr) && nr != -1L)
+				regs->ax = -ENOSYS;
+		}
 
 		instrumentation_end();
 	}
#120 lore raw

Re: [PATCH V2] x86/entry: Fix ptrace regression

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [High] x86/entry: unmatched opening brace in do_syscall_32_irqs_on() breaks build --

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] x86/entry: unmatched opening brace in do_syscall_32_irqs_on() breaks build --

commit b8945a5f45d9b3a8ab21f8b9c553fa0b34f2a69f
Author: Thomas Gleixner <[email protected]>

x86/entry: Fix ptrace regression

This commit restores the historic syscall entry behavior where syscall number -1L keeps tracer modifications to regs->ax while other invalid syscall numbers overwrite regs->ax with -ENOSYS.

Quoted 5 lines
arch/x86/entry/syscall_32.c +0 -0
index a59509bb460ab..e409de28445f9 100644

arch/x86/entry/syscall_32.c static __always_inline void do_syscall_32_irqs_on(struct pt_regs *regs, unsigned · line 85

Quoted 9 lines
arch/x86/entry/syscall_32.c +4 -0
@@ -77,6 +77,10 @@ static __always_inline void do_syscall_32_irqs_on(struct pt_regs *regs, unsigned
 	if (likely(nr < IA32_NR_syscalls)) {
 		nr = array_index_nospec(nr, IA32_NR_syscalls);
 		regs->ax = ia32_sys_call(regs, (unsigned int)nr);
+	} else {
+		/* See comment in do_syscall_64() */
+		if (nr != -1UL) {
+			regs->ax = -ENOSYS;
 	}
 }

[Severity: High]
Does the inner if (nr != -1UL) statement in do_syscall_32_irqs_on() have an unmatched opening brace that leaves the function unclosed and breaks the build when CONFIG_X86_32 or CONFIG_IA32_EMULATION is enabled?

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/87ecd4xwlr.ffs@fw13?part=1
author maintainer
#121 lore raw

Re: [PATCH V2] x86/entry: Fix ptrace regression

Quoted 4 lines · On Sun, Nov 01 2026 at 18:07, [email protected] wrote:

[Severity: High]
Does the inner if (nr != -1UL) statement in do_syscall_32_irqs_on() have an unmatched opening brace that leaves the function unclosed and breaks the build when CONFIG_X86_32 or CONFIG_IA32_EMULATION is enabled?

Duh. Yes.

Tested-by on v2 1/1
#122 lore raw

Re: [PATCH V2] x86/entry: Fix ptrace regression

In reply to Thomas Gleixner

arch/x86/entry/syscall_32.c static __always_inline void do_syscall_3 · line 83

Quoted 10 lines · Thomas Gleixner
arch/x86/entry/syscall_32.c +4 -0
@@ -77,6 +77,10 @@ static __always_inline void do_syscall_3
 	if (likely(nr < IA32_NR_syscalls)) {
 		nr = array_index_nospec(nr, IA32_NR_syscalls);
 		regs->ax = ia32_sys_call(regs, (unsigned int)nr);
+	} else {
+		/* See comment in do_syscall_64() */
+		if (nr != -1UL) {
+			regs->ax = -ENOSYS;

A curly closing bracket here and then it compiles for me. Or remove the one in the "if" line.

arch/x86/entry/syscall_32.c static __always_inline void do_syscall_3 · line 85

Quoted 2 lines
arch/x86/entry/syscall_32.c +0 -0
 	}
 }

With either of the suggested changes:

Sebastian

#123 lore raw

[tip: x86/urgent] x86/entry: Fix ptrace regression

In reply to Thomas Gleixner
The following commit has been merged into the x86/urgent branch of tip:

The following commit has been merged into the x86/urgent branch of tip:

Commit-ID:     b697faab2c92653ee13bd950c8de13551a78971d
Gitweb:        https://git.kernel.org/tip/b697faab2c92653ee13bd950c8de13551a78971d
Author:        Thomas Gleixner <[email protected]>
AuthorDate:    Sun, 01 Nov 2026 18:58:08 +01:00
Committer:     Thomas Gleixner <[email protected]>
CommitterDate: Tue, 03 Nov 2026 21:29:35 +01:00

x86/entry: Fix ptrace regression

The recent rework of the syscall entry code missed the historical detail of the abuse of syscall number -1L to abort a syscall and keep modifications by tracers to the return value, while a rewrite of the syscall number to an invalid value undoes eventual tracer modification to the return value and overwrite it with -ENOSYS.

Restore the original behaviour.

---
 arch/x86/entry/syscall_32.c |  4 ++++
 arch/x86/entry/syscall_64.c | 26 ++++++++++++++++++++++----
 2 files changed, 26 insertions(+), 4 deletions(-)
arch/x86/entry/syscall_32.c +4 -0
index a59509b..ca97fa3 100644
@@ -77,6 +77,10 @@ static __always_inline void do_syscall_32_irqs_on(struct pt_regs *regs, unsigned
 	if (likely(nr < IA32_NR_syscalls)) {
 		nr = array_index_nospec(nr, IA32_NR_syscalls);
 		regs->ax = ia32_sys_call(regs, (unsigned int)nr);
+	} else {
+		/* See comment in do_syscall_64() */
+		if (nr != -1UL)
+			regs->ax = -ENOSYS;
 	}
 }
 
arch/x86/entry/syscall_64.c +22 -4
index 966d3d1..bb95ad0 100644
@@ -64,15 +64,20 @@ static __always_inline bool do_syscall_x64(struct pt_regs *regs, unsigned long n
 	return false;
 }
 
-static __always_inline void do_syscall_x32(struct pt_regs *regs, unsigned long nr)
+static __always_inline bool do_syscall_x32(struct pt_regs *regs, unsigned long nr)
 {
+	if (!IS_ENABLED(CONFIG_X86_X32_ABI))
+		return false;
+
 	/* Adjust the starting offset of the table */
 	nr -= __X32_SYSCALL_BIT;
 
-	if (IS_ENABLED(CONFIG_X86_X32_ABI) && likely(nr < X32_NR_syscalls)) {
+	if (likely(nr < X32_NR_syscalls)) {
 		nr = array_index_nospec(nr, X32_NR_syscalls);
 		regs->ax = x32_sys_call(regs, (unsigned int)nr);
+		return true;
 	}
+	return false;
 }
 
 /* Returns true to return using SYSRET, or false to use IRET */
@@ -81,8 +86,21 @@ __visible noinstr bool do_syscall_64(struct pt_regs *regs, long nr)
 	if (likely(syscall_enter_from_user_mode_randomize_stack(regs, &nr))) {
 		instrumentation_begin();
 
-		if (!do_syscall_x64(regs, nr))
-			do_syscall_x32(regs, nr);
+		if (unlikely(!do_syscall_x64(regs, nr))) {
+			/*
+			 * The special treatment of syscall number -1 is a
+			 * historical bogosity as the original code used -1 to
+			 * indicate syscall abort, which is not distinguishable
+			 * from a syscall which is invoked with syscall number
+			 * -1. The historic behavior is to keep the return value
+			 * in regs->ax unmodified in that case, which means it's
+			 * either the preset value -ENOSYS or a value which was
+			 * written by a tracer. If the syscall number is invalid
+			 * but not -1 then overwrite any tracer modification.
+			 */
+			if (!do_syscall_x32(regs, nr) && nr != -1L)
+				regs->ax = -ENOSYS;
+		}
 
 		instrumentation_end();
 	}
#124 lore raw

Re: [patch 16/18] x86/entry: Get rid of the sys_ni_syscall() indirection

In reply to Thomas Gleixner
Quoted 6 lines · Thomas Gleixner

IOW, a tracer modification of regs->ax is not overwritten when the syscall number is out of range.

Between 2.6.19-rc2 and -rc3 x86_64 was changed to _always_ overwrite regs->ax when the syscall number is out of range.

Quoted 6 lines

In the 3.8 merge window seccomp introduced the -1 == skip bogosity which got fixed up and made "consistent" in several changes afterwards. Just that it never reached a state of consistency due to the overloading.

So are we stuck with this behavior or do we sit down and define what the correct behavior should be?

I wouldn't say we are stuck. The test did reassemble the status we had at the moment. As you wrote yourself the behaviour changed a few times and not on purpose.
I would say we define what correct behaviour should be and make sure it is consistent across all the architectures.

Quoted 3 lines

Thanks,

tglx

Sebastian

#125 lore raw

Re: [patch 16/18] x86/entry: Get rid of the sys_ni_syscall() indirection

In reply to Thomas Gleixner
Quoted 25 lines · Thomas Gleixner
Quoted 12 lines · H. Peter Anvin

arch/x86/entry/syscall_64.c static __always_inline bool do_syscall_x · line 74

Quoted 9 lines · Thomas Gleixner
arch/x86/entry/syscall_64.c +1 -1
-static __always_inline void do_syscall_x32(struct pt_regs *regs, unsigned long nr)
+static __always_inline bool do_syscall_x32(struct pt_regs *regs, unsigned long nr)

{

arch/x86/entry/syscall_64.c +6 -0
+	if (!IS_ENABLED(CONFIG_X86_X32_ABI))
+		return false;
+
+	/* Preserve the historic insanity of treating -1 special on x32 */
+	if (nr == ULONG_MAX)
+		return true;

It was never limited to x32...

Tired brain misread the test output:

[RUN] Running tests under ptrace: modifying the default return
[RUN] Checking system calls with msb = 0 (0x0)

[OK]                x32 syscalls 0:-64..-2 returned -ENOSYS as expected
[OK]                x32 syscall 0:-1 returned MODIFIED_BY_PTRACE as expected
[OK]                x64 syscalls 0:-64..-1 returned -ENOSYS as expected

But that's because the "-1" on x32 is actually 0xFFFFFFFF while on x64 it's 0x7FFFFFFF.

Quoted 11 lines

The whole mess comes from using -1 as indicator for syscall abort which is undistinguishable from a syscall(nr=-1).

Bah. Let me restore this nonsense.

Thanks,

tglx

Yeah, that was always a WTF.

author maintainer
#126 lore raw

PATCH 17/18 x86/entry: Simplify the syscall number logic

In reply to Thomas Gleixner

Converting from int to long, back to int and then to unsigned int is confusing at best.

None of this voodoo is required. Negative syscall numbers including -1 don't need any of this treatment and the low level ASM code already does the sign extension to 64-bit on a 64-bit kernel.

The only point where signedness matters is the comparison against the maximum syscall number, but that can be simplified by just using a unsigned argument for the various syscall invocation functions.

---
 arch/x86/entry/syscall_32.c    |   26 +++++++++++---------------
 arch/x86/entry/syscall_64.c    |   36 ++++++++++++++----------------------
 arch/x86/include/asm/syscall.h |    2 +-
 3 files changed, 26 insertions(+), 38 deletions(-)
arch/x86/entry/syscall_32.c +11 -15
@@ -41,6 +41,8 @@ const sys_call_ptr_t sys_call_table[] =
 #endif
 
 #define __SYSCALL(nr, sym) case nr: return __ia32_##sym(regs);
+
+/* The unsigned int @nr argument is intentional as it creates denser code in a 64-bit build */
 static noinline long ia32_sys_call(const struct pt_regs *regs, unsigned int nr)
 {
 	switch (nr) {
@@ -49,7 +51,7 @@ static noinline long ia32_sys_call(const
 	}
 }
 
-static __always_inline int syscall_32_enter(struct pt_regs *regs)
+static __always_inline long syscall_32_enter(struct pt_regs *regs)
 {
 	if (IS_ENABLED(CONFIG_IA32_EMULATION))
 		current_thread_info()->status |= TS_COMPAT;
@@ -70,17 +72,11 @@ early_param("ia32_emulation", ia32_emula
 /*
  * Invoke a 32-bit syscall.  Called with IRQs on in CT_STATE_KERNEL.
  */
-static __always_inline void do_syscall_32_irqs_on(struct pt_regs *regs, int nr)
+static __always_inline void do_syscall_32_irqs_on(struct pt_regs *regs, unsigned long nr)
 {
-	/*
-	 * Convert negative numbers to very high and thus out of range
-	 * numbers for comparisons.
-	 */
-	unsigned int unr = nr;
-
-	if (likely(unr < IA32_NR_syscalls)) {
-		unr = array_index_nospec(unr, IA32_NR_syscalls);
-		regs->ax = ia32_sys_call(regs, unr);
+	if (likely(nr < IA32_NR_syscalls)) {
+		nr = array_index_nospec(nr, IA32_NR_syscalls);
+		regs->ax = ia32_sys_call(regs, (unsigned int)nr);
 	}
 }
 
@@ -126,7 +122,7 @@ static __always_inline bool int80_is_ext
  */
 __visible noinstr void do_int80_emulation(struct pt_regs *regs)
 {
-	int nr;
+	long nr;
 
 	/* Kernel does not use INT $0x80! */
 	if (unlikely(!user_mode(regs))) {
@@ -205,7 +201,7 @@ static __always_inline bool int80_is_ext
  */
 DEFINE_FREDENTRY_RAW(int80_emulation)
 {
-	int nr;
+	long nr;
 
 	enter_from_user_mode_randomize_stack(regs);
 
@@ -240,7 +236,7 @@ DEFINE_FREDENTRY_RAW(int80_emulation)
 /* Handles int $0x80 on a 32bit kernel */
 __visible noinstr void do_int80_syscall_32(struct pt_regs *regs)
 {
-	int nr = syscall_32_enter(regs);
+	long nr = syscall_32_enter(regs);
 
 	/*
 	 * Subtlety here: if ptrace pokes something larger than 2^31-1 into
@@ -260,7 +256,7 @@ DEFINE_FREDENTRY_RAW(int80_emulation)
 
 static noinstr bool __do_fast_syscall_32(struct pt_regs *regs)
 {
-	int nr = syscall_32_enter(regs);
+	long nr = syscall_32_enter(regs);
 	int res;
 
 	enter_from_user_mode_randomize_stack(regs);
arch/x86/entry/syscall_64.c +14 -22
@@ -32,6 +32,8 @@ const sys_call_ptr_t sys_call_table[] =
 #undef  __SYSCALL
 
 #define __SYSCALL(nr, sym) case nr: return __x64_##sym(regs);
+
+/* The unsigned int @nr argument is intentional as it creates denser code */
 static noinline long x64_sys_call(const struct pt_regs *regs, unsigned int nr)
 {
 	switch (nr) {
@@ -52,39 +54,29 @@ static noinline long x32_sys_call(const
 #endif
 }
 
-static __always_inline bool do_syscall_x64(struct pt_regs *regs, int nr)
+static __always_inline bool do_syscall_x64(struct pt_regs *regs, unsigned long nr)
 {
-	/*
-	 * Convert negative numbers to very high and thus out of range
-	 * numbers for comparisons.
-	 */
-	unsigned int unr = nr;
-
-	if (likely(unr < NR_syscalls)) {
-		unr = array_index_nospec(unr, NR_syscalls);
-		regs->ax = x64_sys_call(regs, unr);
+	if (likely(nr < NR_syscalls)) {
+		nr = array_index_nospec(nr, NR_syscalls);
+		regs->ax = x64_sys_call(regs, (unsigned int)nr);
 		return true;
 	}
 	return false;
 }
 
-static __always_inline void do_syscall_x32(struct pt_regs *regs, int nr)
+static __always_inline void do_syscall_x32(struct pt_regs *regs, unsigned long nr)
 {
-	/*
-	 * Adjust the starting offset of the table, and convert numbers
-	 * < __X32_SYSCALL_BIT to very high and thus out of range
-	 * numbers for comparisons.
-	 */
-	unsigned int xnr = nr - __X32_SYSCALL_BIT;
-
-	if (IS_ENABLED(CONFIG_X86_X32_ABI) && likely(xnr < X32_NR_syscalls)) {
-		xnr = array_index_nospec(xnr, X32_NR_syscalls);
-		regs->ax = x32_sys_call(regs, xnr);
+	/* Adjust the starting offset of the table */
+	nr -= __X32_SYSCALL_BIT;
+
+	if (IS_ENABLED(CONFIG_X86_X32_ABI) && likely(nr < X32_NR_syscalls)) {
+		nr = array_index_nospec(nr, X32_NR_syscalls);
+		regs->ax = x32_sys_call(regs, (unsigned int)nr);
 	}
 }
 
 /* Returns true to return using SYSRET, or false to use IRET */
-__visible noinstr bool do_syscall_64(struct pt_regs *regs, int nr)
+__visible noinstr bool do_syscall_64(struct pt_regs *regs, long nr)
 {
 	nr = syscall_enter_from_user_mode_randomize_stack(regs, nr);
 
arch/x86/include/asm/syscall.h +1 -1
@@ -164,7 +164,7 @@ static inline int syscall_get_arch(struc
 		? AUDIT_ARCH_I386 : AUDIT_ARCH_X86_64;
 }
 
-bool do_syscall_64(struct pt_regs *regs, int nr);
+bool do_syscall_64(struct pt_regs *regs, long nr);
 void do_int80_emulation(struct pt_regs *regs);
 
 #endif	/* CONFIG_X86_32 */
#127 lore raw

[tip: core/entry] x86/entry: Simplify the syscall number logic

The following commit has been merged into the core/entry branch of tip:

The following commit has been merged into the core/entry branch of tip:

Commit-ID:     fb419d53f2619e29bf4f96613d9a614e1c263736
Gitweb:        https://git.kernel.org/tip/fb419d53f2619e29bf4f96613d9a614e1c263736
Author:        Thomas Gleixner <[email protected]>
AuthorDate:    Tue, 07 Jul 2026 21:07:05 +02:00
Committer:     Thomas Gleixner <[email protected]>
CommitterDate: Sun, 12 Jul 2026 12:38:02 +02:00

x86/entry: Simplify the syscall number logic

Converting from int to long, back to int and then to unsigned int is confusing at best.

None of this voodoo is required. Negative syscall numbers including -1 don't need any of this treatment and the low level ASM code already does the sign extension to 64-bit on a 64-bit kernel.

The only point where signedness matters is the comparison against the maximum syscall number, but that can be simplified by just using a unsigned argument for the various syscall invocation functions.

---
 arch/x86/entry/syscall_32.c    | 26 ++++++++++---------------
 arch/x86/entry/syscall_64.c    | 34 ++++++++++++---------------------
 arch/x86/include/asm/syscall.h |  2 +-
 3 files changed, 25 insertions(+), 37 deletions(-)
arch/x86/entry/syscall_32.c +11 -15
index 68e2f13..92369d8 100644
@@ -41,6 +41,8 @@ const sys_call_ptr_t sys_call_table[] = {
 #endif
 
 #define __SYSCALL(nr, sym) case nr: return __ia32_##sym(regs);
+
+/* The unsigned int @nr argument is intentional as it creates denser code in a 64-bit build */
 static noinline long ia32_sys_call(const struct pt_regs *regs, unsigned int nr)
 {
 	switch (nr) {
@@ -49,7 +51,7 @@ static noinline long ia32_sys_call(const struct pt_regs *regs, unsigned int nr)
 	}
 }
 
-static __always_inline int syscall_32_enter(struct pt_regs *regs)
+static __always_inline long syscall_32_enter(struct pt_regs *regs)
 {
 	if (IS_ENABLED(CONFIG_IA32_EMULATION))
 		current_thread_info()->status |= TS_COMPAT;
@@ -70,17 +72,11 @@ early_param("ia32_emulation", ia32_emulation_override_cmdline);
 /*
  * Invoke a 32-bit syscall.  Called with IRQs on in CT_STATE_KERNEL.
  */
-static __always_inline void do_syscall_32_irqs_on(struct pt_regs *regs, int nr)
+static __always_inline void do_syscall_32_irqs_on(struct pt_regs *regs, unsigned long nr)
 {
-	/*
-	 * Convert negative numbers to very high and thus out of range
-	 * numbers for comparisons.
-	 */
-	unsigned int unr = nr;
-
-	if (likely(unr < IA32_NR_syscalls)) {
-		unr = array_index_nospec(unr, IA32_NR_syscalls);
-		regs->ax = ia32_sys_call(regs, unr);
+	if (likely(nr < IA32_NR_syscalls)) {
+		nr = array_index_nospec(nr, IA32_NR_syscalls);
+		regs->ax = ia32_sys_call(regs, (unsigned int)nr);
 	}
 }
 
@@ -126,7 +122,7 @@ static __always_inline bool int80_is_external(void)
  */
 __visible noinstr void do_int80_emulation(struct pt_regs *regs)
 {
-	int nr;
+	long nr;
 
 	/* Kernel does not use INT $0x80! */
 	if (unlikely(!user_mode(regs))) {
@@ -205,7 +201,7 @@ __visible noinstr void do_int80_emulation(struct pt_regs *regs)
  */
 DEFINE_FREDENTRY_RAW(int80_emulation)
 {
-	int nr;
+	long nr;
 
 	enter_from_user_mode_randomize_stack(regs);
 
@@ -240,7 +236,7 @@ DEFINE_FREDENTRY_RAW(int80_emulation)
 /* Handles int $0x80 on a 32bit kernel */
 __visible noinstr void do_int80_syscall_32(struct pt_regs *regs)
 {
-	int nr = syscall_32_enter(regs);
+	long nr = syscall_32_enter(regs);
 
 	/*
 	 * Subtlety here: if ptrace pokes something larger than 2^31-1 into
@@ -260,7 +256,7 @@ __visible noinstr void do_int80_syscall_32(struct pt_regs *regs)
 
 static noinstr bool __do_fast_syscall_32(struct pt_regs *regs)
 {
-	int nr = syscall_32_enter(regs);
+	long nr = syscall_32_enter(regs);
 	int res;
 
 	enter_from_user_mode_randomize_stack(regs);
arch/x86/entry/syscall_64.c +13 -21
index c716e0f..9a2762e 100644
@@ -32,6 +32,8 @@ const sys_call_ptr_t sys_call_table[] = {
 #undef  __SYSCALL
 
 #define __SYSCALL(nr, sym) case nr: return __x64_##sym(regs);
+
+/* The unsigned int @nr argument is intentional as it creates denser code */
 static noinline long x64_sys_call(const struct pt_regs *regs, unsigned int nr)
 {
 	switch (nr) {
@@ -52,39 +54,29 @@ static noinline long x32_sys_call(const struct pt_regs *regs, unsigned int nr)
 #endif
 }
 
-static __always_inline bool do_syscall_x64(struct pt_regs *regs, int nr)
+static __always_inline bool do_syscall_x64(struct pt_regs *regs, unsigned long nr)
 {
-	/*
-	 * Convert negative numbers to very high and thus out of range
-	 * numbers for comparisons.
-	 */
-	unsigned int unr = nr;
-
-	if (likely(unr < NR_syscalls)) {
-		unr = array_index_nospec(unr, NR_syscalls);
-		regs->ax = x64_sys_call(regs, unr);
+	if (likely(nr < NR_syscalls)) {
+		nr = array_index_nospec(nr, NR_syscalls);
+		regs->ax = x64_sys_call(regs, (unsigned int)nr);
 		return true;
 	}
 	return false;
 }
 
-static __always_inline void do_syscall_x32(struct pt_regs *regs, int nr)
+static __always_inline void do_syscall_x32(struct pt_regs *regs, unsigned long nr)
 {
-	/*
-	 * Adjust the starting offset of the table, and convert numbers
-	 * < __X32_SYSCALL_BIT to very high and thus out of range
-	 * numbers for comparisons.
-	 */
-	unsigned int xnr = nr - __X32_SYSCALL_BIT;
+	/* Adjust the starting offset of the table */
+	nr -= __X32_SYSCALL_BIT;
 
-	if (IS_ENABLED(CONFIG_X86_X32_ABI) && likely(xnr < X32_NR_syscalls)) {
-		xnr = array_index_nospec(xnr, X32_NR_syscalls);
-		regs->ax = x32_sys_call(regs, xnr);
+	if (IS_ENABLED(CONFIG_X86_X32_ABI) && likely(nr < X32_NR_syscalls)) {
+		nr = array_index_nospec(nr, X32_NR_syscalls);
+		regs->ax = x32_sys_call(regs, (unsigned int)nr);
 	}
 }
 
 /* Returns true to return using SYSRET, or false to use IRET */
-__visible noinstr bool do_syscall_64(struct pt_regs *regs, int nr)
+__visible noinstr bool do_syscall_64(struct pt_regs *regs, long nr)
 {
 	nr = syscall_enter_from_user_mode_randomize_stack(regs, nr);
 
arch/x86/include/asm/syscall.h +1 -1
index 59a4060..cfe4251 100644
@@ -164,7 +164,7 @@ static inline int syscall_get_arch(struct task_struct *task)
 		? AUDIT_ARCH_I386 : AUDIT_ARCH_X86_64;
 }
 
-bool do_syscall_64(struct pt_regs *regs, int nr);
+bool do_syscall_64(struct pt_regs *regs, long nr);
 void do_int80_emulation(struct pt_regs *regs);
 
 #endif	/* CONFIG_X86_32 */
author maintainer
#128 lore raw

PATCH 18/18 entry, treewide: Make syscall_enter_from_user_mode[_work]() indicate syscall execution

In reply to Thomas Gleixner

From: Michal Suchánek <[email protected]>

The return values of syscall_enter_from_user_mode[_work]() are non-intuitive. Both functions return the syscall number which should be invoked by the architecture specific syscall entry code. The returned number can be:

- the unmodified syscall number which was handed in by the caller

- a modified syscall number (ptrace, seccomp, trace/probe/bpf)

That has an additional twist. If the return value is -1L then the caller is not allowed to modify the return value as that indicates that the modifying entity requests to abort the syscall and set the return value already. That can obviously not be differentiated from a syscall which handed in -1 as syscall number.

The established way to deal with that is:

    set_return_value(regs, -ENOSYS);
    nr = syscall_enter_from_user_mode(regs, nr);
    if ((unsigned)nr < SYSCALLNR_MAX)
    	handle_syscall(regs, nr);
    else if (nr != -1)
    	set_return_value(regs, -ENOSYS);

The latter is obviously redundant, but that's just a leftover of the historical evolution of this code. S390 has some special requirements here, which can be avoided when the return value is not ambiguous.

Now that the functions which modify the syscall number and want to abort are converted to indicate that with a boolean return value, it's obvious to hand this through to the callers.

Rework syscall_enter_from_user_mode[_work]) so they take a pointer to the syscall number and return a boolean, which indicates whether the syscall should be handled or not.

That's not only more intuitive, it also results in slightly denser executable code on x86 at least, but perf results are neutral and within the noise.

[ tglx: Adopted it to the changes in the generic entry code, fixed up the
32-bit fallout and rewrote change log ]

Cc Jonathan Corbet <[email protected]>
Cc Arnd Bergmann <[email protected]>
Cc Mark Rutland <[email protected]>
Cc Huacai Chen <[email protected]>
Cc Michael Ellerman <[email protected]>
Cc Shrikanth Hegde <[email protected]>
Cc Paul Walmsley <[email protected]>
Cc Palmer Dabbelt <[email protected]>
Cc Sven Schnelle <[email protected]>
---
 Documentation/core-api/entry.rst |   18 +++++++++++-------
 arch/loongarch/kernel/syscall.c  |   14 +++++++-------
 arch/powerpc/kernel/syscall.c    |    3 ++-
 arch/riscv/kernel/traps.c        |   11 +++++------
 arch/s390/kernel/syscall.c       |    7 +++++--
 arch/x86/entry/syscall_32.c      |   25 ++++++++++++-------------
 arch/x86/entry/syscall_64.c      |   12 ++++++------
 include/linux/entry-common.h     |   12 +++++-------
 8 files changed, 53 insertions(+), 49 deletions(-)
Documentation/core-api/entry.rst +11 -7
@@ -68,16 +68,20 @@ low-level C code must not be instrumente
   noinstr void syscall(struct pt_regs *regs, int nr)
   {
 	arch_syscall_enter(regs);
-	nr = syscall_enter_from_user_mode_randomize_stack(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 (!invoke_syscall(regs, nr))
+			result_reg(regs) = __sys_ni_syscall(regs);
+		instrumentation_end();
+	}
 	syscall_exit_to_user_mode(regs);
   }
 
+It is required that either the low level assembly code or the syscall
+function sets the result register to -ENOSYS before invoking the generic
+code.
+
 syscall_enter_from_user_mode_randomize_stack() first invokes
 enter_from_user_mode_randomize_stack() which establishes state in the
 following order:
arch/loongarch/kernel/syscall.c +7 -7
@@ -57,8 +57,8 @@ typedef long (*sys_call_fn)(unsigned lon
 
 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 */
@@ -69,12 +69,12 @@ void noinstr __no_stack_protector do_sys
 	regs->orig_a0 = regs->regs[4];
 	regs->regs[4] = -ENOSYS;
 
-	nr = 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]);
+	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);
arch/powerpc/kernel/syscall.c +2 -1
@@ -18,7 +18,8 @@ notrace long system_call_exception(struc
 	long ret;
 	syscall_fn f;
 
-	r0 = syscall_enter_from_user_mode_randomize_stack(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))) {
arch/riscv/kernel/traps.c +5 -6
@@ -332,13 +332,12 @@ void do_trap_ecall_u(struct pt_regs *reg
 
 		riscv_v_vstate_discard(regs);
 
-		syscall = syscall_enter_from_user_mode_randomize_stack(regs, syscall);
-
-		if (syscall >= 0 && syscall < NR_syscalls) {
-			syscall = array_index_nospec(syscall, NR_syscalls);
-			syscall_handler(regs, syscall);
+		if (syscall_enter_from_user_mode_randomize_stack(regs, &syscall)) {
+			if (syscall >= 0 && syscall < NR_syscalls) {
+				syscall = array_index_nospec(syscall, NR_syscalls);
+				syscall_handler(regs, syscall);
+			}
 		}
-
 		syscall_exit_to_user_mode(regs);
 	} else {
 		irqentry_state_t state = irqentry_nmi_enter(regs);
arch/s390/kernel/syscall.c +5 -2
@@ -96,6 +96,7 @@ SYSCALL_DEFINE0(ni_syscall)
 void noinstr __do_syscall(struct pt_regs *regs, int per_trap)
 {
 	unsigned long nr;
+	bool permit;
 
 	enter_from_user_mode_randomize_stack(regs);
 
@@ -121,7 +122,9 @@ void noinstr __do_syscall(struct pt_regs
 		regs->psw.addr = current->restart_block.arch_data;
 		current->restart_block.arch_data = 1;
 	}
-	nr = syscall_enter_from_user_mode_work(regs, nr);
+
+	permit = syscall_enter_from_user_mode_work(regs, &nr);
+
 	/*
 	 * In the s390 ptrace ABI, both the syscall number and the return value
 	 * use gpr2. However, userspace puts the syscall number either in the
@@ -129,7 +132,7 @@ void noinstr __do_syscall(struct pt_regs
 	 * work, the ptrace code sets PIF_SYSCALL_RET_SET, which is checked here
 	 * and if set, the syscall will be skipped.
 	 */
-	if (unlikely(test_and_clear_pt_regs_flag(regs, PIF_SYSCALL_RET_SET)))
+	if (unlikely(test_and_clear_pt_regs_flag(regs, PIF_SYSCALL_RET_SET) || !permit))
 		goto out;
 	regs->gprs[2] = -ENOSYS;
 	if (likely(nr < NR_syscalls)) {
arch/x86/entry/syscall_32.c +12 -13
@@ -161,8 +161,9 @@ static __always_inline bool int80_is_ext
 	nr = syscall_32_enter(regs);
 
 	local_irq_enable();
-	nr = syscall_enter_from_user_mode_work(regs, nr);
-	do_syscall_32_irqs_on(regs, nr);
+
+	if (likely(syscall_enter_from_user_mode_work(regs, &nr)))
+		do_syscall_32_irqs_on(regs, nr);
 
 	instrumentation_end();
 	syscall_exit_to_user_mode(regs);
@@ -223,8 +224,8 @@ DEFINE_FREDENTRY_RAW(int80_emulation)
 	nr = syscall_32_enter(regs);
 
 	local_irq_enable();
-	nr = syscall_enter_from_user_mode_work(regs, nr);
-	do_syscall_32_irqs_on(regs, nr);
+	if (likely(syscall_enter_from_user_mode_work(regs, &nr)))
+		do_syscall_32_irqs_on(regs, nr);
 
 	instrumentation_end();
 	syscall_exit_to_user_mode(regs);
@@ -243,13 +244,13 @@ DEFINE_FREDENTRY_RAW(int80_emulation)
 	 * orig_ax, the int return value truncates it. This matches
 	 * the semantics of syscall_get_nr().
 	 */
-	nr = syscall_enter_from_user_mode_randomize_stack(regs, nr);
-
-	instrumentation_begin();
+	if (likely(syscall_enter_from_user_mode_randomize_stack(regs, &nr))) {
+		instrumentation_begin();
 
-	do_syscall_32_irqs_on(regs, nr);
+		do_syscall_32_irqs_on(regs, nr);
 
-	instrumentation_end();
+		instrumentation_end();
+	}
 	syscall_exit_to_user_mode(regs);
 }
 #endif /* !CONFIG_IA32_EMULATION */
@@ -286,10 +287,8 @@ static noinstr bool __do_fast_syscall_32
 		return false;
 	}
 
-	nr = syscall_enter_from_user_mode_work(regs, nr);
-
-	/* Now this is just like a normal syscall. */
-	do_syscall_32_irqs_on(regs, nr);
+	if (likely(syscall_enter_from_user_mode_work(regs, &nr)))
+		do_syscall_32_irqs_on(regs, nr);
 
 	instrumentation_end();
 	syscall_exit_to_user_mode(regs);
arch/x86/entry/syscall_64.c +6 -6
@@ -78,14 +78,14 @@ static __always_inline void do_syscall_x
 /* Returns true to return using SYSRET, or false to use IRET */
 __visible noinstr bool do_syscall_64(struct pt_regs *regs, long nr)
 {
-	nr = syscall_enter_from_user_mode_randomize_stack(regs, nr);
+	if (likely(syscall_enter_from_user_mode_randomize_stack(regs, &nr))) {
+		instrumentation_begin();
 
-	instrumentation_begin();
+		if (!do_syscall_x64(regs, nr))
+			do_syscall_x32(regs, nr);
 
-	if (!do_syscall_x64(regs, nr))
-		do_syscall_x32(regs, nr);
-
-	instrumentation_end();
+		instrumentation_end();
+	}
 	syscall_exit_to_user_mode(regs);
 
 	/*
include/linux/entry-common.h +5 -7
@@ -71,7 +71,7 @@ static inline void syscall_enter_audit(s
 	}
 }
 
-static __always_inline bool syscall_trace_enter(struct pt_regs *regs, unsigned long work,
+static __always_inline long syscall_trace_enter(struct pt_regs *regs, unsigned long work,
 						long *syscall)
 {
 	/*
@@ -141,16 +141,14 @@ static __always_inline bool syscall_trac
  *     ptrace_report_syscall_permit_entry(), __seccomp_permit_syscall(), trace_sys_enter()
  *  2) Invocation of audit_syscall_entry()
  */
-static __always_inline long syscall_enter_from_user_mode_work(struct pt_regs *regs, long syscall)
+static __always_inline bool syscall_enter_from_user_mode_work(struct pt_regs *regs, long *syscall)
 {
 	unsigned long work = READ_ONCE(current_thread_info()->syscall_work);
 
-	if (work & SYSCALL_WORK_ENTER) {
-		if (!syscall_trace_enter(regs, work, &syscall))
-			return -1L;
-	}
+	if (unlikely(work & SYSCALL_WORK_ENTER))
+		return syscall_trace_enter(regs, work, syscall);
 
-	return syscall;
+	return true;
 }
 
 /**
#129 lore raw

Re: [patch 18/18] entry, treewide: Make syscall_enter_from_user_mode[_work]() indicate syscall execution

Hi Thomas.

Quoted 136 lines · Thomas Gleixner

From: Michal Suchánek <[email protected]>

The return values of syscall_enter_from_user_mode[_work]() are non-intuitive. Both functions return the syscall number which should be invoked by the architecture specific syscall entry code. The returned number can be:

- the unmodified syscall number which was handed in by the caller

- a modified syscall number (ptrace, seccomp, trace/probe/bpf)

That has an additional twist. If the return value is -1L then the caller is not allowed to modify the return value as that indicates that the modifying entity requests to abort the syscall and set the return value already. That can obviously not be differentiated from a syscall which handed in -1 as syscall number.

The established way to deal with that is:

     set_return_value(regs, -ENOSYS);
     nr = syscall_enter_from_user_mode(regs, nr);
     if ((unsigned)nr < SYSCALLNR_MAX)
     	handle_syscall(regs, nr);
     else if (nr != -1)
     	set_return_value(regs, -ENOSYS);

The latter is obviously redundant, but that's just a leftover of the historical evolution of this code. S390 has some special requirements here, which can be avoided when the return value is not ambiguous.

Now that the functions which modify the syscall number and want to abort are converted to indicate that with a boolean return value, it's obvious to hand this through to the callers.

Rework syscall_enter_from_user_mode[_work]) so they take a pointer to the syscall number and return a boolean, which indicates whether the syscall should be handled or not.

That's not only more intuitive, it also results in slightly denser executable code on x86 at least, but perf results are neutral and within the noise.

[ tglx: Adopted it to the changes in the generic entry code, fixed up the
32-bit fallout and rewrote change log ]

Cc Jonathan Corbet <[email protected]>
Cc Arnd Bergmann <[email protected]>
Cc Mark Rutland <[email protected]>
Cc Huacai Chen <[email protected]>
Cc Michael Ellerman <[email protected]>
Cc Shrikanth Hegde <[email protected]>
Cc Paul Walmsley <[email protected]>
Cc Palmer Dabbelt <[email protected]>
Cc Sven Schnelle <[email protected]>
---
  Documentation/core-api/entry.rst |   18 +++++++++++-------
  arch/loongarch/kernel/syscall.c  |   14 +++++++-------
  arch/powerpc/kernel/syscall.c    |    3 ++-
  arch/riscv/kernel/traps.c        |   11 +++++------
  arch/s390/kernel/syscall.c       |    7 +++++--
  arch/x86/entry/syscall_32.c      |   25 ++++++++++++-------------
  arch/x86/entry/syscall_64.c      |   12 ++++++------
  include/linux/entry-common.h     |   12 +++++-------
  8 files changed, 53 insertions(+), 49 deletions(-)
Documentation/core-api/entry.rst +11 -7
@@ -68,16 +68,20 @@ low-level C code must not be instrumente
    noinstr void syscall(struct pt_regs *regs, int nr)
    {
  	arch_syscall_enter(regs);
-	nr = syscall_enter_from_user_mode_randomize_stack(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 (!invoke_syscall(regs, nr))
+			result_reg(regs) = __sys_ni_syscall(regs);
+		instrumentation_end();
+	}
  	syscall_exit_to_user_mode(regs);
    }
 
+It is required that either the low level assembly code or the syscall
+function sets the result register to -ENOSYS before invoking the generic
+code.
+
  syscall_enter_from_user_mode_randomize_stack() first invokes
  enter_from_user_mode_randomize_stack() which establishes state in the
  following order:
arch/loongarch/kernel/syscall.c +7 -7
@@ -57,8 +57,8 @@ typedef long (*sys_call_fn)(unsigned lon
 
  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 */
@@ -69,12 +69,12 @@ void noinstr __no_stack_protector do_sys
  	regs->orig_a0 = regs->regs[4];
  	regs->regs[4] = -ENOSYS;
 
-	nr = 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]);
+	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);

arch/powerpc/kernel/syscall.c notrace long system_call_exception(struc · line 23

Quoted 7 lines
arch/powerpc/kernel/syscall.c +2 -1
@@ -18,7 +18,8 @@ notrace long system_call_exception(struc
  	long ret;
  	syscall_fn f;
 
-	r0 = syscall_enter_from_user_mode_randomize_stack(regs, r0);
+	if (unlikely(!syscall_enter_from_user_mode_randomize_stack(regs, &r0))
+		return syscall_get_error(current, regs);
 

There is one missing )

arch/powerpc/kernel/syscall.c +1 -1
index d85894bdb6a2..1440dcabe052 100644
@@ -18,7 +18,7 @@ notrace long system_call_exception(struct pt_regs *regs, unsigned long r0)
        long ret;
        syscall_fn f;
 
-       if (unlikely(!syscall_enter_from_user_mode_randomize_stack(regs, &r0))
+       if (unlikely(!syscall_enter_from_user_mode_randomize_stack(regs, &r0)))
                return syscall_get_error(current, regs);
 
        if (unlikely(r0 >= NR_syscalls)) {
Quoted 166 lines
arch/powerpc/kernel/syscall.c +0 -0
  	if (unlikely(r0 >= NR_syscalls)) {
  		if (unlikely(trap_is_unsupported_scv(regs))) {
arch/riscv/kernel/traps.c +5 -6
@@ -332,13 +332,12 @@ void do_trap_ecall_u(struct pt_regs *reg
 
  		riscv_v_vstate_discard(regs);
 
-		syscall = syscall_enter_from_user_mode_randomize_stack(regs, syscall);
-
-		if (syscall >= 0 && syscall < NR_syscalls) {
-			syscall = array_index_nospec(syscall, NR_syscalls);
-			syscall_handler(regs, syscall);
+		if (syscall_enter_from_user_mode_randomize_stack(regs, &syscall)) {
+			if (syscall >= 0 && syscall < NR_syscalls) {
+				syscall = array_index_nospec(syscall, NR_syscalls);
+				syscall_handler(regs, syscall);
+			}
  		}
-
  		syscall_exit_to_user_mode(regs);
  	} else {
  		irqentry_state_t state = irqentry_nmi_enter(regs);
arch/s390/kernel/syscall.c +5 -2
@@ -96,6 +96,7 @@ SYSCALL_DEFINE0(ni_syscall)
  void noinstr __do_syscall(struct pt_regs *regs, int per_trap)
  {
  	unsigned long nr;
+	bool permit;
 
  	enter_from_user_mode_randomize_stack(regs);
 
@@ -121,7 +122,9 @@ void noinstr __do_syscall(struct pt_regs
  		regs->psw.addr = current->restart_block.arch_data;
  		current->restart_block.arch_data = 1;
  	}
-	nr = syscall_enter_from_user_mode_work(regs, nr);
+
+	permit = syscall_enter_from_user_mode_work(regs, &nr);
+
  	/*
  	 * In the s390 ptrace ABI, both the syscall number and the return value
  	 * use gpr2. However, userspace puts the syscall number either in the
@@ -129,7 +132,7 @@ void noinstr __do_syscall(struct pt_regs
  	 * work, the ptrace code sets PIF_SYSCALL_RET_SET, which is checked here
  	 * and if set, the syscall will be skipped.
  	 */
-	if (unlikely(test_and_clear_pt_regs_flag(regs, PIF_SYSCALL_RET_SET)))
+	if (unlikely(test_and_clear_pt_regs_flag(regs, PIF_SYSCALL_RET_SET) || !permit))
  		goto out;
  	regs->gprs[2] = -ENOSYS;
  	if (likely(nr < NR_syscalls)) {
arch/x86/entry/syscall_32.c +12 -13
@@ -161,8 +161,9 @@ static __always_inline bool int80_is_ext
  	nr = syscall_32_enter(regs);
 
  	local_irq_enable();
-	nr = syscall_enter_from_user_mode_work(regs, nr);
-	do_syscall_32_irqs_on(regs, nr);
+
+	if (likely(syscall_enter_from_user_mode_work(regs, &nr)))
+		do_syscall_32_irqs_on(regs, nr);
 
  	instrumentation_end();
  	syscall_exit_to_user_mode(regs);
@@ -223,8 +224,8 @@ DEFINE_FREDENTRY_RAW(int80_emulation)
  	nr = syscall_32_enter(regs);
 
  	local_irq_enable();
-	nr = syscall_enter_from_user_mode_work(regs, nr);
-	do_syscall_32_irqs_on(regs, nr);
+	if (likely(syscall_enter_from_user_mode_work(regs, &nr)))
+		do_syscall_32_irqs_on(regs, nr);
 
  	instrumentation_end();
  	syscall_exit_to_user_mode(regs);
@@ -243,13 +244,13 @@ DEFINE_FREDENTRY_RAW(int80_emulation)
  	 * orig_ax, the int return value truncates it. This matches
  	 * the semantics of syscall_get_nr().
  	 */
-	nr = syscall_enter_from_user_mode_randomize_stack(regs, nr);
-
-	instrumentation_begin();
+	if (likely(syscall_enter_from_user_mode_randomize_stack(regs, &nr))) {
+		instrumentation_begin();
 
-	do_syscall_32_irqs_on(regs, nr);
+		do_syscall_32_irqs_on(regs, nr);
 
-	instrumentation_end();
+		instrumentation_end();
+	}
  	syscall_exit_to_user_mode(regs);
  }
  #endif /* !CONFIG_IA32_EMULATION */
@@ -286,10 +287,8 @@ static noinstr bool __do_fast_syscall_32
  		return false;
  	}
 
-	nr = syscall_enter_from_user_mode_work(regs, nr);
-
-	/* Now this is just like a normal syscall. */
-	do_syscall_32_irqs_on(regs, nr);
+	if (likely(syscall_enter_from_user_mode_work(regs, &nr)))
+		do_syscall_32_irqs_on(regs, nr);
 
  	instrumentation_end();
  	syscall_exit_to_user_mode(regs);
arch/x86/entry/syscall_64.c +6 -6
@@ -78,14 +78,14 @@ static __always_inline void do_syscall_x
  /* Returns true to return using SYSRET, or false to use IRET */
  __visible noinstr bool do_syscall_64(struct pt_regs *regs, long nr)
  {
-	nr = syscall_enter_from_user_mode_randomize_stack(regs, nr);
+	if (likely(syscall_enter_from_user_mode_randomize_stack(regs, &nr))) {
+		instrumentation_begin();
 
-	instrumentation_begin();
+		if (!do_syscall_x64(regs, nr))
+			do_syscall_x32(regs, nr);
 
-	if (!do_syscall_x64(regs, nr))
-		do_syscall_x32(regs, nr);
-
-	instrumentation_end();
+		instrumentation_end();
+	}
  	syscall_exit_to_user_mode(regs);
 
  	/*
include/linux/entry-common.h +5 -7
@@ -71,7 +71,7 @@ static inline void syscall_enter_audit(s
  	}
  }
 
-static __always_inline bool syscall_trace_enter(struct pt_regs *regs, unsigned long work,
+static __always_inline long syscall_trace_enter(struct pt_regs *regs, unsigned long work,
  						long *syscall)
  {
  	/*
@@ -141,16 +141,14 @@ static __always_inline bool syscall_trac
   *     ptrace_report_syscall_permit_entry(), __seccomp_permit_syscall(), trace_sys_enter()
   *  2) Invocation of audit_syscall_entry()
   */
-static __always_inline long syscall_enter_from_user_mode_work(struct pt_regs *regs, long syscall)
+static __always_inline bool syscall_enter_from_user_mode_work(struct pt_regs *regs, long *syscall)
  {
  	unsigned long work = READ_ONCE(current_thread_info()->syscall_work);
 
-	if (work & SYSCALL_WORK_ENTER) {
-		if (!syscall_trace_enter(regs, work, &syscall))
-			return -1L;
-	}
+	if (unlikely(work & SYSCALL_WORK_ENTER))
+		return syscall_trace_enter(regs, work, syscall);
 
-	return syscall;
+	return true;
  }
 
  /**
author maintainer
#130 lore raw

Re: [patch 18/18] entry, treewide: Make syscall_enter_from_user_mode[_work]() indicate syscall execution

Quoted 7 lines · Shrikanth Hegde

Review

Quoted 4 lines · Thomas Gleixner
(quoted diff) +2 -1
-	r0 = syscall_enter_from_user_mode_randomize_stack(regs, r0);
+	if (unlikely(!syscall_enter_from_user_mode_randomize_stack(regs, &r0))
+		return syscall_get_error(current, regs);

There is one missing )

Bah.

Reviewed-by on v1 18/18
#131 lore raw

Re: [patch 18/18] entry, treewide: Make syscall_enter_from_user_mode[_work]() indicate syscall execution

In reply to Thomas Gleixner
Quoted 73 lines · Thomas Gleixner

From: Michal Suchánek <[email protected]>

The return values of syscall_enter_from_user_mode[_work]() are non-intuitive. Both functions return the syscall number which should be invoked by the architecture specific syscall entry code. The returned number can be:

- the unmodified syscall number which was handed in by the caller

- a modified syscall number (ptrace, seccomp, trace/probe/bpf)

That has an additional twist. If the return value is -1L then the caller is not allowed to modify the return value as that indicates that the modifying entity requests to abort the syscall and set the return value already. That can obviously not be differentiated from a syscall which handed in -1 as syscall number.

The established way to deal with that is:

    set_return_value(regs, -ENOSYS);
    nr = syscall_enter_from_user_mode(regs, nr);
    if ((unsigned)nr < SYSCALLNR_MAX)
    	handle_syscall(regs, nr);
    else if (nr != -1)
    	set_return_value(regs, -ENOSYS);

The latter is obviously redundant, but that's just a leftover of the historical evolution of this code. S390 has some special requirements here, which can be avoided when the return value is not ambiguous.

Now that the functions which modify the syscall number and want to abort are converted to indicate that with a boolean return value, it's obvious to hand this through to the callers.

Rework syscall_enter_from_user_mode[_work]) so they take a pointer to the syscall number and return a boolean, which indicates whether the syscall should be handled or not.

That's not only more intuitive, it also results in slightly denser executable code on x86 at least, but perf results are neutral and within the noise.

[ tglx: Adopted it to the changes in the generic entry code, fixed up the
32-bit fallout and rewrote change log ]

Cc Jonathan Corbet <[email protected]>
Cc Arnd Bergmann <[email protected]>
Cc Mark Rutland <[email protected]>
Cc Huacai Chen <[email protected]>
Cc Michael Ellerman <[email protected]>
Cc Shrikanth Hegde <[email protected]>
Cc Paul Walmsley <[email protected]>
Cc Palmer Dabbelt <[email protected]>
Cc Sven Schnelle <[email protected]>
---
 Documentation/core-api/entry.rst |   18 +++++++++++-------
 arch/loongarch/kernel/syscall.c  |   14 +++++++-------
 arch/powerpc/kernel/syscall.c    |    3 ++-
 arch/riscv/kernel/traps.c        |   11 +++++------
 arch/s390/kernel/syscall.c       |    7 +++++--
 arch/x86/entry/syscall_32.c      |   25 ++++++++++++-------------
 arch/x86/entry/syscall_64.c      |   12 ++++++------
 include/linux/entry-common.h     |   12 +++++-------
 8 files changed, 53 insertions(+), 49 deletions(-)

[...]

arch/powerpc/kernel/syscall.c notrace long system_call_exception(struc · line 21

Quoted 9 lines
(quoted diff) +0 -0
 	syscall_exit_to_user_mode(regs);
arch/powerpc/kernel/syscall.c +1 -1
@@ -18,7 +18,8 @@ notrace long system_call_exception(struc
 	long ret;
 	syscall_fn f;
 
-	r0 = syscall_enter_from_user_mode_randomize_stack(regs, r0);
+	if (unlikely(!syscall_enter_from_user_mode_randomize_stack(regs, &r0))

Missing one closing ')'.

arch/powerpc/kernel/syscall.c notrace long system_call_exception(struc · line 25

Quoted 4 lines
arch/powerpc/kernel/syscall.c +1 -0
+		return syscall_get_error(current, regs);
 
 	if (unlikely(r0 >= NR_syscalls)) {
 		if (unlikely(trap_is_unsupported_scv(regs))) {

Apart from this.

Tested-by on the v1 series
#132 lore raw
In reply to Thomas Gleixner
Quoted 150 lines · Thomas Gleixner

Sorry for the long CC list, but this is a treewide change.

Michal recently posted a RFC patch to separate the potential syscall number modifications in syscall_enter_user_mode_work() from the information whether the syscall should be processed and the return value modified:

https://lore.kernel.org/lkml/[email protected]

The existing logic is:

arch_syscall()

	regs->result = -ENOSYS;

	syscallnr = syscall_enter_from_user_mode(regs, syscall);

	if (syscallnr != -1L)
		regs->result = invoke_syscall(regs, syscall;

syscall_enter_from_user_mode() invokes ptrace, seccomp and tracing/BPF/Probes. All of them can modify the syscall number.

ptrace and seccomp explicitly set the syscall number to -1L to indicate that the syscall invocation needs to be skipped and the result has not to be modified as it might have been modified by ptrace or seccomp. The tracer/BPF/Probes mechanism can modify the syscall number as well and relies implicitly on the -1L logic.

This can obviously not be differentiated from a syscall invocation where userspace provided -1 as syscall number.

The general agreement of the discussion was that the current mechanism, while functionally correct is non-intuitive and something like Michals proposal would make that code clearer and easier to handle on the architecture side:

arch_syscall()

	regs->result = -ENOSYS;

	if (syscall_enter_from_user_mode(regs, &syscall)) 
		regs->result = invoke_syscall(regs, syscall;

That discussion made me look deeper into the related code and as usual there were a lot of other things to discover.

1) Stack randomization

add_random_kstack_offset() can only be invoked after enter_from_user_mode() established proper state as it calls into instrumentable code.

PowerPC got that wrong and the other architectures either invoke it after enter_from_user_mode() or after syscall_enter_from_user_mode().

The latter is suboptimal as the randomization takes place after all the user mode entry work. Aside of that add_random_kstack_offset() uses get/put_cpu_var(), which makes it usable in preemptible code, but when invoked in the interrupt disabled region that's pointless overhead.

2) As discussed in the above thread just changing the function signature of syscall_enter_from_user_mode[_work]() so they take a pointer argument for the syscall and then return 0 on success is not really intuitive either. Aside of that this breaks the implicit assumption of the tracer when setting the syscall number to -1.

3) The x86 entry code has some historically accumulated oddities

The following series addresses this by:

1) Providing new [syscall_]enter_from_user_mode() variants, which include stack randomization and utilize a new add_random_kstack_offset_irqsoff() variant, which avoids the get/put_cpu_var() overhead and converting all usage sites over

2) Picking up Jinjie's seccomp patch from:

https://lore.kernel.org/lkml/[email protected]

and addressing the feedback (renaming the seccomp functions)

3) Making the ptrace and tracer related functions return a boolean value to indicate syscall permission

4) Addressing the x86 oddities

5) Converting the tree over to the new scheme

With that all architectures using the generic syscall entry code follow the same scheme, apply stack randomization at the correct and earliest possible place and skip syscall processing depending on the boolean return value of syscall_enter_from_user_mode[_work]().

There should be no functional changes, at least there are none intended.

The resulting text size for the syscall entry code on x8664 is slightly smaller than before these changes.

Testing syscall heavy workloads and micro benchmarks shows a small performance gain for the general rework, but the last patch, which changes the logic to be more understandable has no measurable impact in either direction.

The series applies on Linus tree and is also available from git:

git://git.kernel.org/pub/scm/linux/kernel/git/tglx/devel.git entry-rework-v1

Thanks,

tglx

---
 Documentation/core-api/entry.rst      |   33 +++++---
 arch/alpha/kernel/ptrace.c            |    4 -
 arch/arc/kernel/ptrace.c              |    2 
 arch/arm/kernel/ptrace.c              |    4 -
 arch/arm64/kernel/ptrace.c            |    4 -
 arch/csky/kernel/ptrace.c             |    4 -
 arch/hexagon/kernel/traps.c           |    2 
 arch/loongarch/kernel/syscall.c       |   17 +---
 arch/m68k/kernel/ptrace.c             |    4 -
 arch/microblaze/kernel/ptrace.c       |    2 
 arch/mips/kernel/ptrace.c             |    4 -
 arch/nios2/kernel/ptrace.c            |    2 
 arch/openrisc/kernel/ptrace.c         |    2 
 arch/parisc/kernel/ptrace.c           |   12 +--
 arch/powerpc/kernel/syscall.c         |    5 -
 arch/riscv/kernel/traps.c             |   14 +--
 arch/s390/kernel/syscall.c            |   11 +-
 arch/sh/kernel/ptrace_32.c            |    4 -
 arch/sparc/kernel/ptrace_32.c         |    2 
 arch/sparc/kernel/ptrace_64.c         |    2 
 arch/um/kernel/ptrace.c               |    2 
 arch/um/kernel/skas/syscall.c         |    2 
 arch/x86/entry/syscall_32.c           |   70 +++++++------------
 arch/x86/entry/syscall_64.c           |   61 ++++++----------
 arch/x86/entry/vsyscall/vsyscall_64.c |   14 +--
 arch/x86/include/asm/entry-common.h   |    1 
 arch/x86/include/asm/syscall.h        |   10 --
 arch/xtensa/kernel/ptrace.c           |    5 -
 include/asm-generic/syscall.h         |    4 -
 include/linux/entry-common.h          |  125 ++++++++++++++++++++--------------
 include/linux/irq-entry-common.h      |    6 -
 include/linux/ptrace.h                |   13 +--
 include/linux/randomize_kstack.h      |   19 +++++
 include/linux/seccomp.h               |   12 +--
 kernel/entry/syscall-common.c         |    7 +
 kernel/seccomp.c                      |   35 ++++-----
 36 files changed, 264 insertions(+), 256 deletions(-)
Quoted 4 lines

_______________________________________________
linux-snps-arc mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-snps-arc

Boot tested this on P11 LPAR and P9 powernv system.

maintainer Acked-by on the v1 series
#133 lore raw
In reply to Thomas Gleixner
Quoted 11 lines

With that all architectures using the generic syscall entry code follow the same scheme, apply stack randomization at the correct and earliest possible place and skip syscall processing depending on the boolean return value of syscall_enter_from_user_mode[_work]().

There should be no functional changes, at least there are none intended.

The resulting text size for the syscall entry code on x8664 is slightly smaller than before these changes.

Quoted 9 lines

Testing syscall heavy workloads and micro benchmarks shows a small performance gain for the general rework, but the last patch, which changes the logic to be more understandable has no measurable impact in either direction.

The series applies on Linus tree and is also available from git:

git://git.kernel.org/pub/scm/linux/kernel/git/tglx/devel.git entry-rework-v1

Hi Thomas,

Thanks for the series.

I have an Alpha GENERIC_ENTRY series posted and planned for the next merge window:

https://lore.kernel.org/linux-alpha/[email protected]/T/#t

Only its final patch intersects with this work.

That patch removes Alpha's architecture-specific syscall_trace_enter() and syscall_trace_leave() implementations, so the Alpha changes in patches 11 and 12 will disappear once the GENERIC_ENTRY conversion is applied.

It also currently uses syscall_enter_from_user_mode(), so I will need to rebase it onto the new entry interface introduced by this series. I expect the integration to be confined to the final GENERIC_ENTRY patch.

The Alpha-specific changes in patches 11 and 12 look correct to me.

maintainer Tested-by on the v1 series
#134 lore raw
In reply to Thomas Gleixner
Quoted 11 lines

With that all architectures using the generic syscall entry code follow the same scheme, apply stack randomization at the correct and earliest possible place and skip syscall processing depending on the boolean return value of syscall_enter_from_user_mode[_work]().

There should be no functional changes, at least there are none intended.

The resulting text size for the syscall entry code on x8664 is slightly smaller than before these changes.

Quoted 9 lines

Testing syscall heavy workloads and micro benchmarks shows a small performance gain for the general rework, but the last patch, which changes the logic to be more understandable has no measurable impact in either direction.

The series applies on Linus tree and is also available from git:

git://git.kernel.org/pub/scm/linux/kernel/git/tglx/devel.git entry-rework-v1

Hi Thomas,

I did another round of testing of this series on Alpha, this time with my Alpha GENERIC_ENTRY conversion rebased on top of this series.

For this test I also manually applied the seccomp fixup discussed earlier in this thread, i.e. fixing the recheck-after-trace logic in __seccomp_filter() along the lines suggested by Jinjie/Oleg.

With that in place, the kernel boots on Alpha and I do not see any regressions in the seccomp_bpf kernel selftest or in the strace testsuite.

One note: the seccomp_bpf selftest run on Alpha uses this not-yet-upstream Alpha selftest enablement patch:

https://lore.kernel.org/linux-alpha/[email protected]/

One Alpha-specific wrinkle I hit while rebasing the GENERIC_ENTRY patch is that Alpha cannot unconditionally pre-seed the normal -ENOSYS return state before calling into the generic entry code: syscall_set_return_value() also updates r19/a3, which is still syscall argument 4 on the normal entry path. Doing that too early broke early userspace mmap() during boot.

The Alpha conversion therefore handles this on the no-dispatch path instead:
after the generic entry helper returns, if the syscall is not to be invoked or the resulting syscall number is invalid, Alpha skips the call, preserves any ptrace/seccomp/BPF-provided return value, and only synthesizes -ENOSYS if the return state was otherwise unchanged. That was needed for the TRACE_syscall.ptrace.syscall_faked and syscall_errno seccomp_bpf cases to pass.

So from the Alpha side, with the seccomp fixup applied:

Are you planning to send a v2 with the seccomp recheck fix and any other review fixups folded in? Is the intention to route this upstream during the next merge window?

Thanks,
Magnus

author maintainer
#135 lore raw

Magnus!

Quoted 5 lines · Magnus Lindholm

One Alpha-specific wrinkle I hit while rebasing the GENERIC_ENTRY patch is that Alpha cannot unconditionally pre-seed the normal -ENOSYS return state before calling into the generic entry code: syscall_set_return_value() also updates r19/a3, which is still syscall argument 4 on the normal entry path. Doing that too early broke early userspace mmap() during boot.

Similar to what Peter and me suggested in the related discussion vs. s390 which has a similar issue, you can just have a dedicated syscall_return member in your pt_regs struct, which is preset to -ENOSYS and operate on that. You have an unused padding entry there which means it won't even change the size.

Quoted 3 lines

Are you planning to send a v2 with the seccomp recheck fix and any other review fixups folded in? Is the intention to route this upstream during the next merge window?

You were on CC for the V2, no?

The whole pile including Jinjie's seccomp bypass fix is in

git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git core/entry

and is targeted for the 7.3 merge window.

If you want to base your stuff on that for 7.3, I can add a tag which makes it immutable so it can be pulled into the alpha tree.

Thanks,

tglx

maintainer
#136 lore raw

Thomas,

Quoted 8 lines · Thomas Gleixner

Similar to what Peter and me suggested in the related discussion vs. s390 which has a similar issue, you can just have a dedicated syscall_return member in your pt_regs struct, which is preset to -ENOSYS and operate on that. You have an unused padding entry there which means it won't even change the size.

Thanks, that makes sense in principle.

One complication is that my Alpha GENERIC_ENTRY branch already reuses that former pt_regs padding slot, while keeping the pt_regs size and stack alignment unchanged. The extra syscall-entry bookkeeping I needed so far lives in thread_info rather than adding more fields to pt_regs.

So the padding slot is not free in my current branch. I can still look at whether a dedicated syscall_return scratch value would be cleaner, but the tested version currently handles this by setting the default -ENOSYS result only on the no-dispatch path, after generic entry processing, and only if ptrace/seccomp/BPF did not already provide a return value.

Quoted 3 lines

You were on CC for the V2, no?

Sorry, I must have missed that.

Quoted 6 lines

The whole pile including Jinjie's seccomp bypass fix is in

git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git core/entry

and is targeted for the 7.3 merge window.

Great!

Quoted 3 lines

If you want to base your stuff on that for 7.3, I can add a tag which makes it immutable so it can be pulled into the alpha tree.

Yes, please. There is still some ongoing testing/review of my Alpha GENERIC_ENTRY series, but assuming it is ready in time for the 7.3 merge window, an immutable tag would be very helpful.

Magnus

author maintainer
#137 lore raw

Magnus!

Quoted 7 lines · Magnus Lindholm
Quoted 2 lines · Thomas Gleixner

If you want to base your stuff on that for 7.3, I can add a tag which makes it immutable so it can be pulled into the alpha tree.

Yes, please. There is still some ongoing testing/review of my Alpha GENERIC_ENTRY series, but assuming it is ready in time for the 7.3 merge window, an immutable tag would be very helpful.

Here you go:

git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git core-entry-for-arch-07-21-26

Thanks,

tglx

#138 lore raw

PATCH 1/1 seccomp: Fix syscall skip logic on ptrace

In reply to Thomas Gleixner

seccomp takes a shortcut here. When the syscall number is re-read after ptrace and the sign bit is set in the syscall number the syscall is skipped right away.

This works fairly well on x86 where the return value of the syscall is preset before seccomp is processed.

However, on some architectures the syscall return value overlaps with the syscall number or syscall arguments, and as a result the return value cannot be preset in advance.

For these architectures seccomp needs to exit without flagging the syscall as skipped. Then processing of invalid syscall number in the architecture code should set the return value to -ENOSYS and skip the syscall.

This introduces a change: If the syscall number has the sign bit set, such as -1, previously the filter re-check would not be done, not applying the filter after trace. Now the re-check is done both for syscall nubers with and without sign bit set. This would only make a difference if the syscall number or the filter was changed by the tracer. Otherwise the filter would be resolved the first time around.

---
 kernel/seccomp.c | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)
kernel/seccomp.c +1 -4
index 066909393c38..9e40a38aaedf 100644
@@ -1318,11 +1318,8 @@ static int __seccomp_filter(int this_syscall, const bool recheck_after_trace)
 		 */
 		if (fatal_signal_pending(current))
 			goto skip;
-		/* Check if the tracer forced the syscall to be skipped. */
-		this_syscall = syscall_get_nr(current, current_pt_regs());
-		if (this_syscall < 0)
-			goto skip;
 
+		this_syscall = syscall_get_nr(current, current_pt_regs());
 		/*
 		 * Recheck the syscall, since it may have changed. This
 		 * intentionally uses a NULL struct seccomp_data to force
Signature · 1 line
2.51.0
#139 lore raw

Re: [PATCH] seccomp: Fix syscall skip logic on ptrace

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Critical] Removing the explicit check for tracer-injected negative syscall numbers breaks ptrace syscall…

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Critical] Removing the explicit check for tracer-injected negative syscall numbers breaks ptrace syscall emulation by erroneously re-evaluating the seccomp BPF filter against a -1 syscall number. --

--- Patch [1]: [PATCH] seccomp: Fix syscall skip logic on ptrace --- commit e1c90f3fd79c2a1c1deae6adb363b4de34006c48
Author: Michal Suchanek <[email protected]>

seccomp: Fix syscall skip logic on ptrace

This commit removes the explicit check for negative syscall numbers after a ptrace stop in the seccomp filter. This allows architectures where the return value overlaps with the syscall number or arguments to exit without flagging the syscall as skipped.

Quoted 5 lines
kernel/seccomp.c +0 -0
index 25f62867a16d9..4d3ad6113b216 100644

kernel/seccomp.c static int __seccomp_filter(int this_syscall, const bool recheck_after_trace) · line 1322

Quoted 9 lines
kernel/seccomp.c +1 -4
@@ -1318,11 +1318,8 @@ static int __seccomp_filter(int this_syscall, const bool recheck_after_trace)
 		 */
 		if (fatal_signal_pending(current))
 			goto skip;
-		/* Check if the tracer forced the syscall to be skipped. */
-		this_syscall = syscall_get_nr(current, current_pt_regs());
-		if (this_syscall < 0)
-			goto skip;
 
+		this_syscall = syscall_get_nr(current, current_pt_regs());

[Severity: Critical]
By removing this check, does this break ptrace syscall emulation?

The standard mechanism for syscall emulation using ptrace and seccomp (used by gVisor, User-Mode Linux, proot, and strace) involves changing the syscall number to -1 to skip the real kernel syscall and setting a custom return value.

Without this check, when the tracee resumes and re-enters __seccomp_filter(), the -1 syscall number will fall through to the BPF evaluation below. Since most seccomp profiles use strict allowlists, won't this cause the -1 syscall to hit the default action (like SECCOMP_RET_KILL_PROCESS or SECCOMP_RET_ERRNO) instead of skipping it?

Could this lead to tracees being unexpectedly killed or having their preset return values overwritten?

Quoted 3 lines
kernel/seccomp.c +0 -0
 		/*
 		 * Recheck the syscall, since it may have changed. This
 		 * intentionally uses a NULL struct seccomp_data to force
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1
maintainer
#140 lore raw

Re: [PATCH] seccomp: Fix syscall skip logic on ptrace

In reply to Michal Suchanek
Quoted 35 lines · Michal Suchanek

seccomp takes a shortcut here. When the syscall number is re-read after ptrace and the sign bit is set in the syscall number the syscall is skipped right away.

This works fairly well on x86 where the return value of the syscall is preset before seccomp is processed.

However, on some architectures the syscall return value overlaps with the syscall number or syscall arguments, and as a result the return value cannot be preset in advance.

For these architectures seccomp needs to exit without flagging the syscall as skipped. Then processing of invalid syscall number in the architecture code should set the return value to -ENOSYS and skip the syscall.

This introduces a change: If the syscall number has the sign bit set, such as -1, previously the filter re-check would not be done, not applying the filter after trace. Now the re-check is done both for syscall nubers with and without sign bit set. This would only make a difference if the syscall number or the filter was changed by the tracer. Otherwise the filter would be resolved the first time around.

---
 kernel/seccomp.c | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)
kernel/seccomp.c +0 -0
index 066909393c38..9e40a38aaedf 100644
@@ -1318,11 +1318,8 @@ static int __seccomp_filter(int this_syscall, const bool recheck_after_trace)
 		 */
 		if (fatal_signal_pending(current))

kernel/seccomp.c static int __seccomp_filter(int this_syscall, const bool recheck_after_trace) · line 1325

Quoted 10 lines
kernel/seccomp.c +1 -4
 			goto skip;
-		/* Check if the tracer forced the syscall to be skipped. */
-		this_syscall = syscall_get_nr(current, current_pt_regs());
-		if (this_syscall < 0)
-			goto skip;
 
+		this_syscall = syscall_get_nr(current, current_pt_regs());
 		/*
 		 * Recheck the syscall, since it may have changed. This
 		 * intentionally uses a NULL struct seccomp_data to force

Does the seccomp selftest still pass with this change? I _think_ it's fine; this just induces more work on a tracer-induced skip path, which, in theory, shouldn't be fast-path: kicking out to the tracer is going to be the slowest part.

Signature · 1 line
Kees Cook
#141 lore raw

Re: [PATCH] seccomp: Fix syscall skip logic on ptrace

Quoted 42 lines · Kees Cook
Quoted 41 lines · Michal Suchanek

seccomp takes a shortcut here. When the syscall number is re-read after ptrace and the sign bit is set in the syscall number the syscall is skipped right away.

This works fairly well on x86 where the return value of the syscall is preset before seccomp is processed.

However, on some architectures the syscall return value overlaps with the syscall number or syscall arguments, and as a result the return value cannot be preset in advance.

For these architectures seccomp needs to exit without flagging the syscall as skipped. Then processing of invalid syscall number in the architecture code should set the return value to -ENOSYS and skip the syscall.

This introduces a change: If the syscall number has the sign bit set, such as -1, previously the filter re-check would not be done, not applying the filter after trace. Now the re-check is done both for syscall nubers with and without sign bit set. This would only make a difference if the syscall number or the filter was changed by the tracer. Otherwise the filter would be resolved the first time around.

---
 kernel/seccomp.c | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)
kernel/seccomp.c +0 -4
index 066909393c38..9e40a38aaedf 100644
@@ -1318,11 +1318,8 @@ static int __seccomp_filter(int this_syscall, const bool recheck_after_trace)
 		 */
 		if (fatal_signal_pending(current))
 			goto skip;
-		/* Check if the tracer forced the syscall to be skipped. */
-		this_syscall = syscall_get_nr(current, current_pt_regs());
-		if (this_syscall < 0)
-			goto skip;
 
Quoted 9 lines

kernel/seccomp.c static int __seccomp_filter(int this_syscall, const bool recheck_after_trace) · line 1325

Quoted 4 lines
kernel/seccomp.c +1 -0
+		this_syscall = syscall_get_nr(current, current_pt_regs());
 		/*
 		 * Recheck the syscall, since it may have changed. This
 		 * intentionally uses a NULL struct seccomp_data to force

Does the seccomp selftest still pass with this change? I _think_ it's fine; this just induces more work on a tracer-induced skip path, which, in theory, shouldn't be fast-path: kicking out to the tracer is going to be the slowest part.

It does not pass without this change, either.

On 7.3-rc6 I get:

./seccomp_bpf
TAP version 13
1..111
# Starting 111 tests from 11 test cases.
# RUN global.kcmp ...
# OK global.kcmp
ok 1 global.kcmp
# RUN global.mode_strict_support ...
# OK global.mode_strict_support
ok 2 global.mode_strict_support
# RUN global.mode_strict_cannot_call_prctl ...
# OK global.mode_strict_cannot_call_prctl
ok 3 global.mode_strict_cannot_call_prctl
# RUN global.no_new_privs_support ...
# OK global.no_new_privs_support
ok 4 global.no_new_privs_support
# RUN global.mode_filter_support ...
# OK global.mode_filter_support
ok 5 global.mode_filter_support
# RUN global.mode_filter_without_nnp ...
# OK global.mode_filter_without_nnp
ok 6 global.mode_filter_without_nnp
# RUN global.filter_size_limits ...
# OK global.filter_size_limits
ok 7 global.filter_size_limits
# RUN global.filter_chain_limits ...
# OK global.filter_chain_limits
ok 8 global.filter_chain_limits
# RUN global.mode_filter_cannot_move_to_strict ...
# OK global.mode_filter_cannot_move_to_strict
ok 9 global.mode_filter_cannot_move_to_strict
# RUN global.mode_filter_get_seccomp ...
# OK global.mode_filter_get_seccomp
ok 10 global.mode_filter_get_seccomp
# RUN global.ALLOW_all ...
# OK global.ALLOW_all
ok 11 global.ALLOW_all
# RUN global.empty_prog ...
# OK global.empty_prog
ok 12 global.empty_prog
# RUN global.log_all ...
# OK global.log_all
ok 13 global.log_all
# RUN global.unknown_ret_is_kill_inside ...
# OK global.unknown_ret_is_kill_inside
ok 14 global.unknown_ret_is_kill_inside
# RUN global.unknown_ret_is_kill_above_allow ...
# OK global.unknown_ret_is_kill_above_allow
ok 15 global.unknown_ret_is_kill_above_allow
# RUN global.KILL_all ...
# OK global.KILL_all
ok 16 global.KILL_all
# RUN global.KILL_one ...
# OK global.KILL_one
ok 17 global.KILL_one
# RUN global.KILL_one_arg_one ...
# OK global.KILL_one_arg_one
ok 18 global.KILL_one_arg_one
# RUN global.KILL_one_arg_six ...
# OK global.KILL_one_arg_six
ok 19 global.KILL_one_arg_six
# RUN global.KILL_thread ...
# OK global.KILL_thread
ok 20 global.KILL_thread
# RUN global.KILL_process ...
# OK global.KILL_process
ok 21 global.KILL_process
# RUN global.KILL_unknown ...
# OK global.KILL_unknown
ok 22 global.KILL_unknown
# RUN global.arg_out_of_range ...
# OK global.arg_out_of_range
ok 23 global.arg_out_of_range
# RUN global.ERRNO_valid ...
# OK global.ERRNO_valid
ok 24 global.ERRNO_valid
# RUN global.ERRNO_zero ...
# OK global.ERRNO_zero
ok 25 global.ERRNO_zero
# RUN global.ERRNO_capped ...
# OK global.ERRNO_capped
ok 26 global.ERRNO_capped
# RUN global.ERRNO_order ...
# OK global.ERRNO_order
ok 27 global.ERRNO_order
# RUN global.negative_ENOSYS ...
# OK global.negative_ENOSYS
ok 28 global.negative_ENOSYS
# RUN global.seccomp_syscall ...
# OK global.seccomp_syscall
ok 29 global.seccomp_syscall
# RUN global.seccomp_syscall_mode_lock ...
# OK global.seccomp_syscall_mode_lock
ok 30 global.seccomp_syscall_mode_lock
# RUN global.detect_seccomp_filter_flags ...
# OK global.detect_seccomp_filter_flags
ok 31 global.detect_seccomp_filter_flags
# RUN global.TSYNC_first ...
# OK global.TSYNC_first
ok 32 global.TSYNC_first
# RUN global.syscall_restart ...
# OK global.syscall_restart
ok 33 global.syscall_restart
# RUN global.filter_flag_log ...
# OK global.filter_flag_log
ok 34 global.filter_flag_log
# RUN global.get_action_avail ...
# OK global.get_action_avail
ok 35 global.get_action_avail
# RUN global.get_metadata ...
# OK global.get_metadata
ok 36 global.get_metadata
# RUN global.user_notification_basic ...
# seccomp_bpf.c:3488:user_notification_basic:Expected 0 (0) == WEXITSTATUS(status) (1) # user_notification_basic: Test failed
# FAIL global.user_notification_basic
not ok 37 global.user_notification_basic
# RUN global.user_notification_with_tsync ...
# OK global.user_notification_with_tsync
ok 38 global.user_notification_with_tsync
# RUN global.user_notification_kill_in_middle ...
# OK global.user_notification_kill_in_middle
ok 39 global.user_notification_kill_in_middle
# RUN global.user_notification_signal ...
# OK global.user_notification_signal
ok 40 global.user_notification_signal
# RUN global.user_notification_closed_listener ...
# OK global.user_notification_closed_listener
ok 41 global.user_notification_closed_listener
# RUN global.user_notification_child_pid_ns ...
# seccomp_bpf.c:3713:user_notification_child_pid_ns:Expected 0 (0) == WEXITSTATUS(status) (1) # user_notification_child_pid_ns: Test failed
# FAIL global.user_notification_child_pid_ns
not ok 42 global.user_notification_child_pid_ns
# RUN global.user_notification_sibling_pid_ns ...
# seccomp_bpf.c:3755:user_notification_sibling_pid_ns:Expected 0 (0) == WEXITSTATUS(status) (1) # seccomp_bpf.c:3791:user_notification_sibling_pid_ns:Expected 0 (0) == WEXITSTATUS(status) (1) # user_notification_sibling_pid_ns: Test failed
# FAIL global.user_notification_sibling_pid_ns
not ok 43 global.user_notification_sibling_pid_ns
# RUN global.user_notification_fault_recv ...
# seccomp_bpf.c:3836:user_notification_fault_recv:Expected 0 (0) == WEXITSTATUS(status) (1) # user_notification_fault_recv: Test failed
# FAIL global.user_notification_fault_recv
not ok 44 global.user_notification_fault_recv
# RUN global.seccomp_get_notif_sizes ...
# OK global.seccomp_get_notif_sizes
ok 45 global.seccomp_get_notif_sizes
# RUN global.user_notification_continue ...
# OK global.user_notification_continue
ok 46 global.user_notification_continue
# RUN global.user_notification_filter_empty ...
# OK global.user_notification_filter_empty
ok 47 global.user_notification_filter_empty
# RUN global.user_ioctl_notification_filter_empty ...
# OK global.user_ioctl_notification_filter_empty
ok 48 global.user_ioctl_notification_filter_empty
# RUN global.user_notification_filter_empty_threaded ...
# OK global.user_notification_filter_empty_threaded
ok 49 global.user_notification_filter_empty_threaded
# RUN global.user_notification_addfd ...
# user_notification_addfd: Test terminated by timeout
# FAIL global.user_notification_addfd
not ok 50 global.user_notification_addfd
# RUN global.user_notification_addfd_rlimit ...
# seccomp_bpf.c:4366:user_notification_addfd_rlimit:Expected 0 (0) == WEXITSTATUS(status) (1) # user_notification_addfd_rlimit: Test failed
# FAIL global.user_notification_addfd_rlimit
not ok 51 global.user_notification_addfd_rlimit
# RUN global.user_notification_sync ...
# seccomp_bpf.c:4404:user_notification_sync:Expected ret (0) == USER_NOTIF_MAGIC (2147483647) # seccomp_bpf.c:4422:user_notification_sync:Expected status (256) == 0 (0)
# user_notification_sync: Test terminated by assertion
# FAIL global.user_notification_sync
not ok 52 global.user_notification_sync
# RUN global.user_notification_fifo ...
# seccomp_bpf.c:4581:user_notification_fifo:Expected 0 (0) == WEXITSTATUS(status) (1) # seccomp_bpf.c:4615:user_notification_fifo:Expected 0 (0) == WEXITSTATUS(status) (1) # seccomp_bpf.c:4615:user_notification_fifo:Expected 0 (0) == WEXITSTATUS(status) (1) # seccomp_bpf.c:4615:user_notification_fifo:Expected 0 (0) == WEXITSTATUS(status) (1) # user_notification_fifo: Test failed
# FAIL global.user_notification_fifo
not ok 53 global.user_notification_fifo
# RUN global.user_notification_wait_killable_pre_notification ...
# OK global.user_notification_wait_killable_pre_notification
ok 54 global.user_notification_wait_killable_pre_notification
# RUN global.user_notification_wait_killable ...
# seccomp_bpf.c:4788:user_notification_wait_killable:Expected 0 (0) == WEXITSTATUS(status) (1) # user_notification_wait_killable: Test failed
# FAIL global.user_notification_wait_killable
not ok 55 global.user_notification_wait_killable
# RUN global.user_notification_wait_killable_fatal ...
# OK global.user_notification_wait_killable_fatal
ok 56 global.user_notification_wait_killable_fatal
# RUN global.user_notification_wait_killable_after_reply ...
# OK global.user_notification_wait_killable_after_reply
ok 57 global.user_notification_wait_killable_after_reply
# RUN global.tsync_vs_dead_thread_leader ...
# OK global.tsync_vs_dead_thread_leader
ok 58 global.tsync_vs_dead_thread_leader
# RUN TRAP.dfl ...
# OK TRAP.dfl
ok 59 TRAP.dfl
# RUN TRAP.ign ...
# OK TRAP.ign
ok 60 TRAP.ign
# RUN TRAP.handler ...
# OK TRAP.handler
ok 61 TRAP.handler
# RUN precedence.allow_ok ...
# OK precedence.allow_ok
ok 62 precedence.allow_ok
# RUN precedence.kill_is_highest ...
# OK precedence.kill_is_highest
ok 63 precedence.kill_is_highest
# RUN precedence.kill_is_highest_in_any_order ...
# OK precedence.kill_is_highest_in_any_order
ok 64 precedence.kill_is_highest_in_any_order
# RUN precedence.trap_is_second ...
# OK precedence.trap_is_second
ok 65 precedence.trap_is_second
# RUN precedence.trap_is_second_in_any_order ...
# OK precedence.trap_is_second_in_any_order
ok 66 precedence.trap_is_second_in_any_order
# RUN precedence.errno_is_third ...
# OK precedence.errno_is_third
ok 67 precedence.errno_is_third
# RUN precedence.errno_is_third_in_any_order ...
# OK precedence.errno_is_third_in_any_order
ok 68 precedence.errno_is_third_in_any_order
# RUN precedence.trace_is_fourth ...
# OK precedence.trace_is_fourth
ok 69 precedence.trace_is_fourth
# RUN precedence.trace_is_fourth_in_any_order ...
# OK precedence.trace_is_fourth_in_any_order
ok 70 precedence.trace_is_fourth_in_any_order
# RUN precedence.log_is_fifth ...
# OK precedence.log_is_fifth
ok 71 precedence.log_is_fifth
# RUN precedence.log_is_fifth_in_any_order ...
# OK precedence.log_is_fifth_in_any_order
ok 72 precedence.log_is_fifth_in_any_order
# RUN TRACE_poke.read_has_side_effects ...
# OK TRACE_poke.read_has_side_effects
ok 73 TRACE_poke.read_has_side_effects
# RUN TRACE_poke.getpid_runs_normally ...
# OK TRACE_poke.getpid_runs_normally
ok 74 TRACE_poke.getpid_runs_normally
# RUN TRACE_syscall.ptrace.negative_ENOSYS ...
# OK TRACE_syscall.ptrace.negative_ENOSYS
ok 75 TRACE_syscall.ptrace.negative_ENOSYS
# RUN TRACE_syscall.ptrace.syscall_allowed ...
# OK TRACE_syscall.ptrace.syscall_allowed
ok 76 TRACE_syscall.ptrace.syscall_allowed
# RUN TRACE_syscall.ptrace.syscall_redirected ...
# OK TRACE_syscall.ptrace.syscall_redirected
ok 77 TRACE_syscall.ptrace.syscall_redirected
# RUN TRACE_syscall.ptrace.syscall_errno ...
# OK TRACE_syscall.ptrace.syscall_errno
ok 78 TRACE_syscall.ptrace.syscall_errno
# RUN TRACE_syscall.ptrace.syscall_faked ...
# OK TRACE_syscall.ptrace.syscall_faked
ok 79 TRACE_syscall.ptrace.syscall_faked
# RUN TRACE_syscall.ptrace.kill_immediate ...
# OK TRACE_syscall.ptrace.kill_immediate
ok 80 TRACE_syscall.ptrace.kill_immediate
# RUN TRACE_syscall.ptrace.skip_after ...
# OK TRACE_syscall.ptrace.skip_after
ok 81 TRACE_syscall.ptrace.skip_after
# RUN TRACE_syscall.ptrace.kill_after ...
# OK TRACE_syscall.ptrace.kill_after
ok 82 TRACE_syscall.ptrace.kill_after
# RUN TRACE_syscall.seccomp.negative_ENOSYS ...
# OK TRACE_syscall.seccomp.negative_ENOSYS
ok 83 TRACE_syscall.seccomp.negative_ENOSYS
# RUN TRACE_syscall.seccomp.syscall_allowed ...
# OK TRACE_syscall.seccomp.syscall_allowed
ok 84 TRACE_syscall.seccomp.syscall_allowed
# RUN TRACE_syscall.seccomp.syscall_redirected ...
# OK TRACE_syscall.seccomp.syscall_redirected
ok 85 TRACE_syscall.seccomp.syscall_redirected
# RUN TRACE_syscall.seccomp.syscall_errno ...
# OK TRACE_syscall.seccomp.syscall_errno
ok 86 TRACE_syscall.seccomp.syscall_errno
# RUN TRACE_syscall.seccomp.syscall_faked ...
# seccomp_bpf.c:2253:syscall_faked:Expected 45000 (45000) == syscall(207) (0)
# syscall_faked: Test failed
# FAIL TRACE_syscall.seccomp.syscall_faked
not ok 87 TRACE_syscall.seccomp.syscall_faked
# RUN TRACE_syscall.seccomp.kill_immediate ...
# OK TRACE_syscall.seccomp.kill_immediate
ok 88 TRACE_syscall.seccomp.kill_immediate
# RUN TRACE_syscall.seccomp.skip_after ...
# OK TRACE_syscall.seccomp.skip_after
ok 89 TRACE_syscall.seccomp.skip_after
# RUN TRACE_syscall.seccomp.kill_after ...
# OK TRACE_syscall.seccomp.kill_after
ok 90 TRACE_syscall.seccomp.kill_after
# RUN TSYNC.siblings_fail_prctl ...
# OK TSYNC.siblings_fail_prctl
ok 91 TSYNC.siblings_fail_prctl
# RUN TSYNC.two_siblings_with_ancestor ...
# OK TSYNC.two_siblings_with_ancestor
ok 92 TSYNC.two_siblings_with_ancestor
# RUN TSYNC.two_sibling_want_nnp ...
# OK TSYNC.two_sibling_want_nnp
ok 93 TSYNC.two_sibling_want_nnp
# RUN TSYNC.two_siblings_with_no_filter ...
# OK TSYNC.two_siblings_with_no_filter
ok 94 TSYNC.two_siblings_with_no_filter
# RUN TSYNC.two_siblings_with_one_divergence ...
# OK TSYNC.two_siblings_with_one_divergence
ok 95 TSYNC.two_siblings_with_one_divergence
# RUN TSYNC.two_siblings_with_one_divergence_no_tid_in_err ...
# OK TSYNC.two_siblings_with_one_divergence_no_tid_in_err
ok 96 TSYNC.two_siblings_with_one_divergence_no_tid_in_err
# RUN TSYNC.two_siblings_not_under_filter ...
# OK TSYNC.two_siblings_not_under_filter
ok 97 TSYNC.two_siblings_not_under_filter
# RUN O_SUSPEND_SECCOMP.setoptions ...
# OK O_SUSPEND_SECCOMP.setoptions
ok 98 O_SUSPEND_SECCOMP.setoptions
# RUN O_SUSPEND_SECCOMP.seize ...
# OK O_SUSPEND_SECCOMP.seize
ok 99 O_SUSPEND_SECCOMP.seize

#  RUN           UPROBE.not_attached.uprobe_default_allow ...
#      SKIP      __NR_uprobe ot __NR_uretprobe syscalls not defined
#            OK  UPROBE.not_attached.uprobe_default_allow
ok 100 UPROBE.not_attached.uprobe_default_allow # SKIP __NR_uprobe ot __NR_uretprobe syscalls not defined
#  RUN           UPROBE.not_attached.uprobe_default_block ...
#      SKIP      __NR_uprobe ot __NR_uretprobe syscalls not defined
#            OK  UPROBE.not_attached.uprobe_default_block
ok 101 UPROBE.not_attached.uprobe_default_block # SKIP __NR_uprobe ot __NR_uretprobe syscalls not defined
#  RUN           UPROBE.not_attached.uprobe_block_syscall ...
#      SKIP      __NR_uprobe ot __NR_uretprobe syscalls not defined
#            OK  UPROBE.not_attached.uprobe_block_syscall
ok 102 UPROBE.not_attached.uprobe_block_syscall # SKIP __NR_uprobe ot __NR_uretprobe syscalls not defined
#  RUN           UPROBE.not_attached.uprobe_default_block_with_syscall ...
#      SKIP      __NR_uprobe ot __NR_uretprobe syscalls not defined
#            OK  UPROBE.not_attached.uprobe_default_block_with_syscall
ok 103 UPROBE.not_attached.uprobe_default_block_with_syscall # SKIP __NR_uprobe ot __NR_uretprobe syscalls not defined
#  RUN           UPROBE.uprobe_attached.uprobe_default_allow ...
#      SKIP      __NR_uprobe ot __NR_uretprobe syscalls not defined
#            OK  UPROBE.uprobe_attached.uprobe_default_allow
ok 104 UPROBE.uprobe_attached.uprobe_default_allow # SKIP __NR_uprobe ot __NR_uretprobe syscalls not defined
#  RUN           UPROBE.uprobe_attached.uprobe_default_block ...
#      SKIP      __NR_uprobe ot __NR_uretprobe syscalls not defined
#            OK  UPROBE.uprobe_attached.uprobe_default_block
ok 105 UPROBE.uprobe_attached.uprobe_default_block # SKIP __NR_uprobe ot __NR_uretprobe syscalls not defined
#  RUN           UPROBE.uprobe_attached.uprobe_block_syscall ...
#      SKIP      __NR_uprobe ot __NR_uretprobe syscalls not defined
#            OK  UPROBE.uprobe_attached.uprobe_block_syscall
ok 106 UPROBE.uprobe_attached.uprobe_block_syscall # SKIP __NR_uprobe ot __NR_uretprobe syscalls not defined
#  RUN           UPROBE.uprobe_attached.uprobe_default_block_with_syscall ...
#      SKIP      __NR_uprobe ot __NR_uretprobe syscalls not defined
#            OK  UPROBE.uprobe_attached.uprobe_default_block_with_syscall
ok 107 UPROBE.uprobe_attached.uprobe_default_block_with_syscall # SKIP __NR_uprobe ot __NR_uretprobe syscalls not defined
#  RUN           UPROBE.uretprobe_attached.uprobe_default_allow ...
#      SKIP      __NR_uprobe ot __NR_uretprobe syscalls not defined
#            OK  UPROBE.uretprobe_attached.uprobe_default_allow
ok 108 UPROBE.uretprobe_attached.uprobe_default_allow # SKIP __NR_uprobe ot __NR_uretprobe syscalls not defined
#  RUN           UPROBE.uretprobe_attached.uprobe_default_block ...
#      SKIP      __NR_uprobe ot __NR_uretprobe syscalls not defined
#            OK  UPROBE.uretprobe_attached.uprobe_default_block
ok 109 UPROBE.uretprobe_attached.uprobe_default_block # SKIP __NR_uprobe ot __NR_uretprobe syscalls not defined
#  RUN           UPROBE.uretprobe_attached.uprobe_block_syscall ...
#      SKIP      __NR_uprobe ot __NR_uretprobe syscalls not defined
#            OK  UPROBE.uretprobe_attached.uprobe_block_syscall
ok 110 UPROBE.uretprobe_attached.uprobe_block_syscall # SKIP __NR_uprobe ot __NR_uretprobe syscalls not defined
#  RUN           UPROBE.uretprobe_attached.uprobe_default_block_with_syscall ...
#      SKIP      __NR_uprobe ot __NR_uretprobe syscalls not defined
#            OK  UPROBE.uretprobe_attached.uprobe_default_block_with_syscall

ok 111 UPROBE.uretprobe_attached.uprobe_default_block_with_syscall # SKIP __NR_uprobe ot __NR_uretprobe syscalls not defined # FAILED: 101 / 111 tests passed.
# 12 skipped test(s) detected. Consider enabling relevant config options to improve coverage.
# Totals: pass:89 fail:10 xfail:0 xpass:0 skip:12 error:0

but it does have an additional failure:

test-patched.log renamed from test-base.log +7 -5
@@ -279,10 +279,12 @@
 #            OK  TRACE_syscall.seccomp.syscall_redirected
 ok 85 TRACE_syscall.seccomp.syscall_redirected
 #  RUN           TRACE_syscall.seccomp.syscall_errno ...
-#            OK  TRACE_syscall.seccomp.syscall_errno
-ok 86 TRACE_syscall.seccomp.syscall_errno
+# seccomp_bpf.c:2247:syscall_errno:Expected -(-3) (3) == errno (38)
+# syscall_errno: Test failed
+#          FAIL  TRACE_syscall.seccomp.syscall_errno
+not ok 86 TRACE_syscall.seccomp.syscall_errno
 #  RUN           TRACE_syscall.seccomp.syscall_faked ...
-# seccomp_bpf.c:2253:syscall_faked:Expected 45000 (45000) == syscall(207) (0)
+# seccomp_bpf.c:2253:syscall_faked:Expected 45000 (45000) == syscall(207) (-1)
 # syscall_faked: Test failed
 #          FAIL  TRACE_syscall.seccomp.syscall_faked
 not ok 87 TRACE_syscall.seccomp.syscall_faked
@@ -370,6 +372,6 @@
 #      SKIP      __NR_uprobe ot __NR_uretprobe syscalls not defined
 #            OK  UPROBE.uretprobe_attached.uprobe_default_block_with_syscall
 ok 111 UPROBE.uretprobe_attached.uprobe_default_block_with_syscall # SKIP __NR_uprobe ot __NR_uretprobe syscalls not defined
-# FAILED: 101 / 111 tests passed.
+# FAILED: 100 / 111 tests passed.
 # 12 skipped test(s) detected. Consider enabling relevant config options to improve coverage.
-# Totals: pass:89 fail:10 xfail:0 xpass:0 skip:12 error:0
+# Totals: pass:88 fail:11 xfail:0 xpass:0 skip:12 error:0

Thanks

Michal