During a syscall, the kernel is entered and it switches the stack to the PTI stack which is mapped both in the kernel and in the user page-table. When executing the syscall function, switch to the kernel stack (which is mapped only in the kernel page-table) so that no kernel data leak to the userland through the stack.
Signed-off-by: Alexandre Chartre <alexandre.char...@oracle.com> --- arch/x86/entry/common.c | 11 ++++++++++- arch/x86/entry/entry_64.S | 1 + arch/x86/include/asm/irq_stack.h | 3 +++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/arch/x86/entry/common.c b/arch/x86/entry/common.c index 7ee15a12c115..1aba02ecb806 100644 --- a/arch/x86/entry/common.c +++ b/arch/x86/entry/common.c @@ -56,10 +56,19 @@ __visible noinstr void return_from_fork(struct pt_regs *regs, static __always_inline void run_syscall(sys_call_ptr_t sysfunc, struct pt_regs *regs) { + unsigned long stack; + if (!sysfunc) return; - regs->ax = sysfunc(regs); + if (!pti_enabled()) { + regs->ax = sysfunc(regs); + return; + } + + stack = (unsigned long)task_top_of_kernel_stack(current); + regs->ax = asm_call_syscall_on_stack((void *)(stack - 8), + sysfunc, regs); } #ifdef CONFIG_X86_64 diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S index 29beab46bedd..6b88a0eb8975 100644 --- a/arch/x86/entry/entry_64.S +++ b/arch/x86/entry/entry_64.S @@ -771,6 +771,7 @@ SYM_FUNC_START(asm_call_on_stack_2) SYM_FUNC_START(asm_call_on_stack_3) SYM_INNER_LABEL(asm_call_sysvec_on_stack, SYM_L_GLOBAL) SYM_INNER_LABEL(asm_call_irq_on_stack, SYM_L_GLOBAL) +SYM_INNER_LABEL(asm_call_syscall_on_stack, SYM_L_GLOBAL) /* * Save the frame pointer unconditionally. This allows the ORC * unwinder to handle the stack switch. diff --git a/arch/x86/include/asm/irq_stack.h b/arch/x86/include/asm/irq_stack.h index 359427216336..108d9da7c01c 100644 --- a/arch/x86/include/asm/irq_stack.h +++ b/arch/x86/include/asm/irq_stack.h @@ -5,6 +5,7 @@ #include <linux/ptrace.h> #include <asm/processor.h> +#include <asm/syscall.h> #ifdef CONFIG_X86_64 static __always_inline bool irqstack_active(void) @@ -25,6 +26,8 @@ void asm_call_sysvec_on_stack(void *sp, void (*func)(struct pt_regs *regs), struct pt_regs *regs); void asm_call_irq_on_stack(void *sp, void (*func)(struct irq_desc *desc), struct irq_desc *desc); +long asm_call_syscall_on_stack(void *sp, sys_call_ptr_t func, + struct pt_regs *regs); static __always_inline void __run_on_irqstack(void (*func)(void)) { -- 2.18.4