From: Peter Zijlstra <peterz@infradead.org>
To: x86@kernel.org
Cc: linux-kernel@vger.kernel.org, peterz@infradead.org,
jpoimboe@kernel.org, leitao@debian.org, keescook@chromium.org,
hpa@zytor.com
Subject: [PATCH 4/6] x86_64/entry: Mark all syscalls __noendbr
Date: Mon, 02 Nov 2026 12:25:53 +0100 [thread overview]
Message-ID: <20261102114000.771366690@infradead.org> (raw)
In-Reply-To: <20261102112549.714541309@infradead.org>
Since system call dispatch is now strictly through direct calls, there is no
reason for the syscalls to be called indirectly. Mark them all __noendbr.
Notably, the sys_call_table[] is purely a lookup for tracing and the like,
nobody actually (should) dispatch anything through it, and with this we make
sure nobody *can*.
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
---
arch/x86/entry/syscall_32.c | 5 +++--
arch/x86/entry/syscall_64.c | 7 ++++---
arch/x86/include/asm/syscall_wrapper.h | 23 ++++++++++++-----------
tools/objtool/check.c | 9 ++++++++-
4 files changed, 27 insertions(+), 17 deletions(-)
--- a/arch/x86/entry/syscall_32.c
+++ b/arch/x86/entry/syscall_32.c
@@ -12,6 +12,7 @@
#include <asm/traps.h>
#include <asm/cpufeature.h>
#include <asm/syscall.h>
+#include <asm/ibt.h>
#ifdef CONFIG_IA32_EMULATION
#define __SYSCALL_WITH_COMPAT(nr, native, compat) __SYSCALL(nr, compat)
@@ -19,8 +20,8 @@
#define __SYSCALL_WITH_COMPAT(nr, native, compat) __SYSCALL(nr, native)
#endif
-#define __SYSCALL(nr, sym) extern long __ia32_##sym(const struct pt_regs *);
-#define __SYSCALL_NORETURN(nr, sym) extern long __noreturn __ia32_##sym(const struct pt_regs *);
+#define __SYSCALL(nr, sym) extern __noendbr long __ia32_##sym(const struct pt_regs *);
+#define __SYSCALL_NORETURN(nr, sym) extern __noendbr long __noreturn __ia32_##sym(const struct pt_regs *);
#include <asm/syscalls_32.h>
#undef __SYSCALL
--- a/arch/x86/entry/syscall_64.c
+++ b/arch/x86/entry/syscall_64.c
@@ -8,9 +8,10 @@
#include <linux/entry-common.h>
#include <linux/nospec.h>
#include <asm/syscall.h>
+#include <asm/ibt.h>
-#define __SYSCALL(nr, sym) extern long __x64_##sym(const struct pt_regs *);
-#define __SYSCALL_NORETURN(nr, sym) extern long __noreturn __x64_##sym(const struct pt_regs *);
+#define __SYSCALL(nr, sym) extern __noendbr long __x64_##sym(const struct pt_regs *);
+#define __SYSCALL_NORETURN(nr, sym) extern __noendbr long __noreturn __x64_##sym(const struct pt_regs *);
#include <asm/syscalls_64.h>
#ifdef CONFIG_X86_X32_ABI
#include <asm/syscalls_x32.h>
@@ -25,7 +26,7 @@
* kernel/trace/trace_syscalls.c still wants to know the system
* call address.
*/
-#define __SYSCALL(nr, sym) __x64_##sym,
+#define __SYSCALL(nr, sym) (void *)&__x64_##sym,
const sys_call_ptr_t sys_call_table[] = {
#include <asm/syscalls_64.h>
};
--- a/arch/x86/include/asm/syscall_wrapper.h
+++ b/arch/x86/include/asm/syscall_wrapper.h
@@ -7,9 +7,10 @@
#define _ASM_X86_SYSCALL_WRAPPER_H
#include <asm/ptrace.h>
+#include <asm/ibt.h>
-extern long __x64_sys_ni_syscall(const struct pt_regs *regs);
-extern long __ia32_sys_ni_syscall(const struct pt_regs *regs);
+extern __noendbr long __x64_sys_ni_syscall(const struct pt_regs *regs);
+extern __noendbr long __ia32_sys_ni_syscall(const struct pt_regs *regs);
/*
* Instead of the generic __SYSCALL_DEFINEx() definition, the x86 version takes
@@ -83,22 +84,22 @@ extern long __ia32_sys_ni_syscall(const
__MAP(x, __SC_TYPE, __VA_ARGS__)) \
#define __SYS_STUB0(abi, name) \
- long __##abi##_##name(const struct pt_regs *regs); \
+ long __noendbr __##abi##_##name(const struct pt_regs *regs); \
ALLOW_ERROR_INJECTION(__##abi##_##name, ERRNO); \
- long __##abi##_##name(const struct pt_regs *regs) \
+ long __noendbr __##abi##_##name(const struct pt_regs *regs) \
__alias(__do_##name);
#define __SYS_STUBx(abi, name, ...) \
- long __##abi##_##name(const struct pt_regs *regs); \
+ long __noendbr __##abi##_##name(const struct pt_regs *regs); \
ALLOW_ERROR_INJECTION(__##abi##_##name, ERRNO); \
- long __##abi##_##name(const struct pt_regs *regs) \
+ long __noendbr __##abi##_##name(const struct pt_regs *regs) \
{ \
return __se_##name(__VA_ARGS__); \
}
#define __COND_SYSCALL(abi, name) \
- __weak long __##abi##_##name(const struct pt_regs *__unused); \
- __weak long __##abi##_##name(const struct pt_regs *__unused) \
+ __weak long __noendbr __##abi##_##name(const struct pt_regs *__unused); \
+ __weak long __noendbr __##abi##_##name(const struct pt_regs *__unused) \
{ \
return sys_ni_syscall(); \
}
@@ -257,8 +258,8 @@ extern long __ia32_sys_ni_syscall(const
* For VSYSCALLS, we need to declare these three syscalls with the new
* pt_regs-based calling convention for in-kernel use.
*/
-long __x64_sys_getcpu(const struct pt_regs *regs);
-long __x64_sys_gettimeofday(const struct pt_regs *regs);
-long __x64_sys_time(const struct pt_regs *regs);
+long __noendbr __x64_sys_getcpu(const struct pt_regs *regs);
+long __noendbr __x64_sys_gettimeofday(const struct pt_regs *regs);
+long __noendbr __x64_sys_time(const struct pt_regs *regs);
#endif /* _ASM_X86_SYSCALL_WRAPPER_H */
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -4672,8 +4672,15 @@ static int validate_ibt(struct objtool_f
!strcmp(sec->name, "__patchable_function_entries"))
continue;
- for_each_reloc(sec->rsec, reloc)
+ for_each_reloc(sec->rsec, reloc) {
+ struct symbol *sym = find_symbol_containing(reloc->sec->base,
+ reloc_offset(reloc));
+
+ if (sym && !strcmp(sym->name, "sys_call_table"))
+ continue;
+
warnings += validate_ibt_data_reloc(file, reloc);
+ }
}
return warnings;
next prev parent reply other threads:[~2026-11-02 11:40 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-02 11:25 [PATCH 0/6] x86: Harden syscall dispatch Peter Zijlstra
2026-11-02 11:25 ` [PATCH 1/6] x86_64/entry: Unconditionally use -fno-jump-table Peter Zijlstra
2026-11-02 14:28 ` Breno Leitao
2026-11-02 11:25 ` [PATCH 2/6] objtool: Add instrumentation_weak() Peter Zijlstra
2026-11-02 11:25 ` [PATCH 3/6] x86_64/entry: Make syscall dispatch noinstr Peter Zijlstra
2026-11-02 11:25 ` Peter Zijlstra [this message]
2026-11-02 11:25 ` [PATCH 5/6] objtool: Allow EXPORT_SYMBOL() of __noendbr functions Peter Zijlstra
2026-11-02 11:25 ` [PATCH 6/6] x86_64/entry: Mark C noinstr __noendbr Peter Zijlstra
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261102114000.771366690@infradead.org \
--to=peterz@infradead.org \
--cc=hpa@zytor.com \
--cc=jpoimboe@kernel.org \
--cc=keescook@chromium.org \
--cc=leitao@debian.org \
--cc=linux-kernel@vger.kernel.org \
--cc=x86@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®