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.

Signed-off-by: Thomas Gleixner <tglx@kernel.org>
Tested-by: Mukesh Kumar Chaurasiya (IBM) <mkchauras@gmail.com>
Link: https://patch.msgid.link/20260707190254.545214398@kernel.org
This commit is contained in:
Thomas Gleixner
2026-07-12 12:38:02 +02:00
parent 1b1f3b3e1b
commit fb419d53f2
3 changed files with 25 additions and 37 deletions
+11 -15
View File
@@ -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);
+13 -21
View File
@@ -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);
+1 -1
View File
@@ -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 */