Skip to content

Commit 1dfb0f4

Browse files
committed
Merge tag 'x86-entry-2021-06-29' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 entry code related updates from Thomas Gleixner: - Consolidate the macros for .byte ... opcode sequences - Deduplicate register offset defines in include files - Simplify the ia32,x32 compat handling of the related syscall tables to get rid of #ifdeffery. - Clear all EFLAGS which are not required for syscall handling - Consolidate the syscall tables and switch the generation over to the generic shell script and remove the CFLAGS tweaks which are not longer required. - Use 'int' type for system call numbers to match the generic code. - Add more selftests for syscalls * tag 'x86-entry-2021-06-29' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86/syscalls: Don't adjust CFLAGS for syscall tables x86/syscalls: Remove -Wno-override-init for syscall tables x86/uml/syscalls: Remove array index from syscall initializers x86/syscalls: Clear 'offset' and 'prefix' in case they are set in env x86/entry: Use int everywhere for system call numbers x86/entry: Treat out of range and gap system calls the same x86/entry/64: Sign-extend system calls on entry to int selftests/x86/syscall: Add tests under ptrace to syscall_numbering_64 selftests/x86/syscall: Simplify message reporting in syscall_numbering selftests/x86/syscall: Update and extend syscall_numbering_64 x86/syscalls: Switch to generic syscallhdr.sh x86/syscalls: Use __NR_syscalls instead of __NR_syscall_max x86/unistd: Define X32_NR_syscalls only for 64-bit kernel x86/syscalls: Stop filling syscall arrays with *_sys_ni_syscall x86/syscalls: Switch to generic syscalltbl.sh x86/entry/x32: Rename __x32_compat_sys_* to __x64_compat_sys_*
2 parents a22c3f6 + 48f7eee commit 1dfb0f4

File tree

17 files changed

+568
-266
lines changed

17 files changed

+568
-266
lines changed

arch/um/kernel/skas/syscall.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ void handle_syscall(struct uml_pt_regs *r)
4141
goto out;
4242

4343
syscall = UPT_SYSCALL_NR(r);
44-
if (syscall >= 0 && syscall <= __NR_syscall_max)
44+
if (syscall >= 0 && syscall < __NR_syscalls)
4545
PT_REGS_SET_SYSCALL_RETURN(regs,
4646
EXECUTE_SYSCALL(syscall, regs));
4747

arch/x86/entry/Makefile

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,8 @@ UBSAN_SANITIZE := n
88
KCOV_INSTRUMENT := n
99

1010
CFLAGS_REMOVE_common.o = $(CC_FLAGS_FTRACE)
11-
CFLAGS_REMOVE_syscall_64.o = $(CC_FLAGS_FTRACE)
12-
CFLAGS_REMOVE_syscall_32.o = $(CC_FLAGS_FTRACE)
13-
CFLAGS_REMOVE_syscall_x32.o = $(CC_FLAGS_FTRACE)
1411

1512
CFLAGS_common.o += -fno-stack-protector
16-
CFLAGS_syscall_64.o += -fno-stack-protector
17-
CFLAGS_syscall_32.o += -fno-stack-protector
18-
CFLAGS_syscall_x32.o += -fno-stack-protector
19-
20-
CFLAGS_syscall_64.o += $(call cc-option,-Wno-override-init,)
21-
CFLAGS_syscall_32.o += $(call cc-option,-Wno-override-init,)
22-
CFLAGS_syscall_x32.o += $(call cc-option,-Wno-override-init,)
2313

2414
obj-y := entry_$(BITS).o thunk_$(BITS).o syscall_$(BITS).o
2515
obj-y += common.o

arch/x86/entry/common.c

Lines changed: 61 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -36,61 +36,97 @@
3636
#include <asm/irq_stack.h>
3737

3838
#ifdef CONFIG_X86_64
39-
__visible noinstr void do_syscall_64(struct pt_regs *regs, unsigned long nr)
39+
40+
static __always_inline bool do_syscall_x64(struct pt_regs *regs, int nr)
41+
{
42+
/*
43+
* Convert negative numbers to very high and thus out of range
44+
* numbers for comparisons.
45+
*/
46+
unsigned int unr = nr;
47+
48+
if (likely(unr < NR_syscalls)) {
49+
unr = array_index_nospec(unr, NR_syscalls);
50+
regs->ax = sys_call_table[unr](regs);
51+
return true;
52+
}
53+
return false;
54+
}
55+
56+
static __always_inline bool do_syscall_x32(struct pt_regs *regs, int nr)
57+
{
58+
/*
59+
* Adjust the starting offset of the table, and convert numbers
60+
* < __X32_SYSCALL_BIT to very high and thus out of range
61+
* numbers for comparisons.
62+
*/
63+
unsigned int xnr = nr - __X32_SYSCALL_BIT;
64+
65+
if (IS_ENABLED(CONFIG_X86_X32_ABI) && likely(xnr < X32_NR_syscalls)) {
66+
xnr = array_index_nospec(xnr, X32_NR_syscalls);
67+
regs->ax = x32_sys_call_table[xnr](regs);
68+
return true;
69+
}
70+
return false;
71+
}
72+
73+
__visible noinstr void do_syscall_64(struct pt_regs *regs, int nr)
4074
{
4175
add_random_kstack_offset();
4276
nr = syscall_enter_from_user_mode(regs, nr);
4377

4478
instrumentation_begin();
45-
if (likely(nr < NR_syscalls)) {
46-
nr = array_index_nospec(nr, NR_syscalls);
47-
regs->ax = sys_call_table[nr](regs);
48-
#ifdef CONFIG_X86_X32_ABI
49-
} else if (likely((nr & __X32_SYSCALL_BIT) &&
50-
(nr & ~__X32_SYSCALL_BIT) < X32_NR_syscalls)) {
51-
nr = array_index_nospec(nr & ~__X32_SYSCALL_BIT,
52-
X32_NR_syscalls);
53-
regs->ax = x32_sys_call_table[nr](regs);
54-
#endif
79+
80+
if (!do_syscall_x64(regs, nr) && !do_syscall_x32(regs, nr) && nr != -1) {
81+
/* Invalid system call, but still a system call. */
82+
regs->ax = __x64_sys_ni_syscall(regs);
5583
}
84+
5685
instrumentation_end();
5786
syscall_exit_to_user_mode(regs);
5887
}
5988
#endif
6089

6190
#if defined(CONFIG_X86_32) || defined(CONFIG_IA32_EMULATION)
62-
static __always_inline unsigned int syscall_32_enter(struct pt_regs *regs)
91+
static __always_inline int syscall_32_enter(struct pt_regs *regs)
6392
{
6493
if (IS_ENABLED(CONFIG_IA32_EMULATION))
6594
current_thread_info()->status |= TS_COMPAT;
6695

67-
return (unsigned int)regs->orig_ax;
96+
return (int)regs->orig_ax;
6897
}
6998

7099
/*
71100
* Invoke a 32-bit syscall. Called with IRQs on in CONTEXT_KERNEL.
72101
*/
73-
static __always_inline void do_syscall_32_irqs_on(struct pt_regs *regs,
74-
unsigned int nr)
102+
static __always_inline void do_syscall_32_irqs_on(struct pt_regs *regs, int nr)
75103
{
76-
if (likely(nr < IA32_NR_syscalls)) {
77-
nr = array_index_nospec(nr, IA32_NR_syscalls);
78-
regs->ax = ia32_sys_call_table[nr](regs);
104+
/*
105+
* Convert negative numbers to very high and thus out of range
106+
* numbers for comparisons.
107+
*/
108+
unsigned int unr = nr;
109+
110+
if (likely(unr < IA32_NR_syscalls)) {
111+
unr = array_index_nospec(unr, IA32_NR_syscalls);
112+
regs->ax = ia32_sys_call_table[unr](regs);
113+
} else if (nr != -1) {
114+
regs->ax = __ia32_sys_ni_syscall(regs);
79115
}
80116
}
81117

82118
/* Handles int $0x80 */
83119
__visible noinstr void do_int80_syscall_32(struct pt_regs *regs)
84120
{
85-
unsigned int nr = syscall_32_enter(regs);
121+
int nr = syscall_32_enter(regs);
86122

87123
add_random_kstack_offset();
88124
/*
89-
* Subtlety here: if ptrace pokes something larger than 2^32-1 into
90-
* orig_ax, the unsigned int return value truncates it. This may
91-
* or may not be necessary, but it matches the old asm behavior.
125+
* Subtlety here: if ptrace pokes something larger than 2^31-1 into
126+
* orig_ax, the int return value truncates it. This matches
127+
* the semantics of syscall_get_nr().
92128
*/
93-
nr = (unsigned int)syscall_enter_from_user_mode(regs, nr);
129+
nr = syscall_enter_from_user_mode(regs, nr);
94130
instrumentation_begin();
95131

96132
do_syscall_32_irqs_on(regs, nr);
@@ -101,7 +137,7 @@ __visible noinstr void do_int80_syscall_32(struct pt_regs *regs)
101137

102138
static noinstr bool __do_fast_syscall_32(struct pt_regs *regs)
103139
{
104-
unsigned int nr = syscall_32_enter(regs);
140+
int nr = syscall_32_enter(regs);
105141
int res;
106142

107143
add_random_kstack_offset();
@@ -136,8 +172,7 @@ static noinstr bool __do_fast_syscall_32(struct pt_regs *regs)
136172
return false;
137173
}
138174

139-
/* The case truncates any ptrace induced syscall nr > 2^32 -1 */
140-
nr = (unsigned int)syscall_enter_from_user_mode_work(regs, nr);
175+
nr = syscall_enter_from_user_mode_work(regs, nr);
141176

142177
/* Now this is just like a normal syscall. */
143178
do_syscall_32_irqs_on(regs, nr);

arch/x86/entry/entry_64.S

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,8 @@ SYM_INNER_LABEL(entry_SYSCALL_64_after_hwframe, SYM_L_GLOBAL)
108108

109109
/* IRQs are off. */
110110
movq %rsp, %rdi
111-
movq %rax, %rsi
111+
/* Sign extend the lower 32bit as syscall numbers are treated as int */
112+
movslq %eax, %rsi
112113
call do_syscall_64 /* returns with IRQs disabled */
113114

114115
/*

arch/x86/entry/syscall_32.c

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,21 @@
55
#include <linux/sys.h>
66
#include <linux/cache.h>
77
#include <linux/syscalls.h>
8-
#include <asm/unistd.h>
98
#include <asm/syscall.h>
109

11-
#define __SYSCALL_I386(nr, sym) extern long __ia32_##sym(const struct pt_regs *);
10+
#ifdef CONFIG_IA32_EMULATION
11+
#define __SYSCALL_WITH_COMPAT(nr, native, compat) __SYSCALL(nr, compat)
12+
#else
13+
#define __SYSCALL_WITH_COMPAT(nr, native, compat) __SYSCALL(nr, native)
14+
#endif
15+
16+
#define __SYSCALL(nr, sym) extern long __ia32_##sym(const struct pt_regs *);
1217

1318
#include <asm/syscalls_32.h>
14-
#undef __SYSCALL_I386
19+
#undef __SYSCALL
1520

16-
#define __SYSCALL_I386(nr, sym) [nr] = __ia32_##sym,
21+
#define __SYSCALL(nr, sym) __ia32_##sym,
1722

18-
__visible const sys_call_ptr_t ia32_sys_call_table[__NR_ia32_syscall_max+1] = {
19-
/*
20-
* Smells like a compiler bug -- it doesn't work
21-
* when the & below is removed.
22-
*/
23-
[0 ... __NR_ia32_syscall_max] = &__ia32_sys_ni_syscall,
23+
__visible const sys_call_ptr_t ia32_sys_call_table[] = {
2424
#include <asm/syscalls_32.h>
2525
};

arch/x86/entry/syscall_64.c

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,14 @@
55
#include <linux/sys.h>
66
#include <linux/cache.h>
77
#include <linux/syscalls.h>
8-
#include <asm/unistd.h>
98
#include <asm/syscall.h>
109

11-
#define __SYSCALL_X32(nr, sym)
12-
#define __SYSCALL_COMMON(nr, sym) __SYSCALL_64(nr, sym)
13-
14-
#define __SYSCALL_64(nr, sym) extern long __x64_##sym(const struct pt_regs *);
10+
#define __SYSCALL(nr, sym) extern long __x64_##sym(const struct pt_regs *);
1511
#include <asm/syscalls_64.h>
16-
#undef __SYSCALL_64
12+
#undef __SYSCALL
1713

18-
#define __SYSCALL_64(nr, sym) [nr] = __x64_##sym,
14+
#define __SYSCALL(nr, sym) __x64_##sym,
1915

20-
asmlinkage const sys_call_ptr_t sys_call_table[__NR_syscall_max+1] = {
21-
/*
22-
* Smells like a compiler bug -- it doesn't work
23-
* when the & below is removed.
24-
*/
25-
[0 ... __NR_syscall_max] = &__x64_sys_ni_syscall,
16+
asmlinkage const sys_call_ptr_t sys_call_table[] = {
2617
#include <asm/syscalls_64.h>
2718
};

arch/x86/entry/syscall_x32.c

Lines changed: 6 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -5,37 +5,14 @@
55
#include <linux/sys.h>
66
#include <linux/cache.h>
77
#include <linux/syscalls.h>
8-
#include <asm/unistd.h>
98
#include <asm/syscall.h>
109

11-
/*
12-
* Reuse the 64-bit entry points for the x32 versions that occupy different
13-
* slots in the syscall table.
14-
*/
15-
#define __x32_sys_readv __x64_sys_readv
16-
#define __x32_sys_writev __x64_sys_writev
17-
#define __x32_sys_getsockopt __x64_sys_getsockopt
18-
#define __x32_sys_setsockopt __x64_sys_setsockopt
19-
#define __x32_sys_vmsplice __x64_sys_vmsplice
20-
#define __x32_sys_process_vm_readv __x64_sys_process_vm_readv
21-
#define __x32_sys_process_vm_writev __x64_sys_process_vm_writev
10+
#define __SYSCALL(nr, sym) extern long __x64_##sym(const struct pt_regs *);
11+
#include <asm/syscalls_x32.h>
12+
#undef __SYSCALL
2213

23-
#define __SYSCALL_64(nr, sym)
14+
#define __SYSCALL(nr, sym) __x64_##sym,
2415

25-
#define __SYSCALL_X32(nr, sym) extern long __x32_##sym(const struct pt_regs *);
26-
#define __SYSCALL_COMMON(nr, sym) extern long __x64_##sym(const struct pt_regs *);
27-
#include <asm/syscalls_64.h>
28-
#undef __SYSCALL_X32
29-
#undef __SYSCALL_COMMON
30-
31-
#define __SYSCALL_X32(nr, sym) [nr] = __x32_##sym,
32-
#define __SYSCALL_COMMON(nr, sym) [nr] = __x64_##sym,
33-
34-
asmlinkage const sys_call_ptr_t x32_sys_call_table[__NR_x32_syscall_max+1] = {
35-
/*
36-
* Smells like a compiler bug -- it doesn't work
37-
* when the & below is removed.
38-
*/
39-
[0 ... __NR_x32_syscall_max] = &__x64_sys_ni_syscall,
40-
#include <asm/syscalls_64.h>
16+
asmlinkage const sys_call_ptr_t x32_sys_call_table[] = {
17+
#include <asm/syscalls_x32.h>
4118
};

arch/x86/entry/syscalls/Makefile

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,47 +9,54 @@ _dummy := $(shell [ -d '$(out)' ] || mkdir -p '$(out)') \
99
syscall32 := $(src)/syscall_32.tbl
1010
syscall64 := $(src)/syscall_64.tbl
1111

12-
syshdr := $(srctree)/$(src)/syscallhdr.sh
13-
systbl := $(srctree)/$(src)/syscalltbl.sh
12+
syshdr := $(srctree)/scripts/syscallhdr.sh
13+
systbl := $(srctree)/scripts/syscalltbl.sh
14+
offset :=
15+
prefix :=
1416

1517
quiet_cmd_syshdr = SYSHDR $@
16-
cmd_syshdr = $(CONFIG_SHELL) '$(syshdr)' '$<' '$@' \
17-
'$(syshdr_abi_$(basetarget))' \
18-
'$(syshdr_pfx_$(basetarget))' \
19-
'$(syshdr_offset_$(basetarget))'
18+
cmd_syshdr = $(CONFIG_SHELL) $(syshdr) --abis $(abis) --emit-nr \
19+
$(if $(offset),--offset $(offset)) \
20+
$(if $(prefix),--prefix $(prefix)) \
21+
$< $@
2022
quiet_cmd_systbl = SYSTBL $@
21-
cmd_systbl = $(CONFIG_SHELL) '$(systbl)' $< $@
23+
cmd_systbl = $(CONFIG_SHELL) $(systbl) --abis $(abis) $< $@
2224

2325
quiet_cmd_hypercalls = HYPERCALLS $@
2426
cmd_hypercalls = $(CONFIG_SHELL) '$<' $@ $(filter-out $<, $(real-prereqs))
2527

26-
syshdr_abi_unistd_32 := i386
28+
$(uapi)/unistd_32.h: abis := i386
2729
$(uapi)/unistd_32.h: $(syscall32) $(syshdr) FORCE
2830
$(call if_changed,syshdr)
2931

30-
syshdr_abi_unistd_32_ia32 := i386
31-
syshdr_pfx_unistd_32_ia32 := ia32_
32+
$(out)/unistd_32_ia32.h: abis := i386
33+
$(out)/unistd_32_ia32.h: prefix := ia32_
3234
$(out)/unistd_32_ia32.h: $(syscall32) $(syshdr) FORCE
3335
$(call if_changed,syshdr)
3436

35-
syshdr_abi_unistd_x32 := common,x32
36-
syshdr_offset_unistd_x32 := __X32_SYSCALL_BIT
37+
$(uapi)/unistd_x32.h: abis := common,x32
38+
$(uapi)/unistd_x32.h: offset := __X32_SYSCALL_BIT
3739
$(uapi)/unistd_x32.h: $(syscall64) $(syshdr) FORCE
3840
$(call if_changed,syshdr)
3941

40-
syshdr_abi_unistd_64 := common,64
42+
$(uapi)/unistd_64.h: abis := common,64
4143
$(uapi)/unistd_64.h: $(syscall64) $(syshdr) FORCE
4244
$(call if_changed,syshdr)
4345

44-
syshdr_abi_unistd_64_x32 := x32
45-
syshdr_pfx_unistd_64_x32 := x32_
46+
$(out)/unistd_64_x32.h: abis := x32
47+
$(out)/unistd_64_x32.h: prefix := x32_
4648
$(out)/unistd_64_x32.h: $(syscall64) $(syshdr) FORCE
4749
$(call if_changed,syshdr)
4850

51+
$(out)/syscalls_32.h: abis := i386
4952
$(out)/syscalls_32.h: $(syscall32) $(systbl) FORCE
5053
$(call if_changed,systbl)
54+
$(out)/syscalls_64.h: abis := common,64
5155
$(out)/syscalls_64.h: $(syscall64) $(systbl) FORCE
5256
$(call if_changed,systbl)
57+
$(out)/syscalls_x32.h: abis := common,x32
58+
$(out)/syscalls_x32.h: $(syscall64) $(systbl) FORCE
59+
$(call if_changed,systbl)
5360

5461
$(out)/xen-hypercalls.h: $(srctree)/scripts/xen-hypercalls.sh FORCE
5562
$(call if_changed,hypercalls)
@@ -60,6 +67,7 @@ uapisyshdr-y += unistd_32.h unistd_64.h unistd_x32.h
6067
syshdr-y += syscalls_32.h
6168
syshdr-$(CONFIG_X86_64) += unistd_32_ia32.h unistd_64_x32.h
6269
syshdr-$(CONFIG_X86_64) += syscalls_64.h
70+
syshdr-$(CONFIG_X86_X32) += syscalls_x32.h
6371
syshdr-$(CONFIG_XEN) += xen-hypercalls.h
6472

6573
uapisyshdr-y := $(addprefix $(uapi)/, $(uapisyshdr-y))

arch/x86/entry/syscalls/syscallhdr.sh

Lines changed: 0 additions & 35 deletions
This file was deleted.

0 commit comments

Comments
 (0)