forked from Minki/linux
x86/entry: Assert that syscalls are on the right stack
Now that the entry stack is a full page, it's too easy to regress the system call entry code and end up on the wrong stack without noticing. Assert that all system calls (SYSCALL64, SYSCALL32, SYSENTER, and INT80) are on the right stack and have pt_regs in the right place. Signed-off-by: Andy Lutomirski <luto@kernel.org> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Link: https://lkml.kernel.org/r/52059e42bb0ab8551153d012d68f7be18d72ff8e.1593191971.git.luto@kernel.org
This commit is contained in:
parent
009bce1df0
commit
c9c26150e6
@ -45,6 +45,15 @@
|
|||||||
#define CREATE_TRACE_POINTS
|
#define CREATE_TRACE_POINTS
|
||||||
#include <trace/events/syscalls.h>
|
#include <trace/events/syscalls.h>
|
||||||
|
|
||||||
|
/* Check that the stack and regs on entry from user mode are sane. */
|
||||||
|
static void check_user_regs(struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
if (IS_ENABLED(CONFIG_DEBUG_ENTRY)) {
|
||||||
|
WARN_ON_ONCE(!on_thread_stack());
|
||||||
|
WARN_ON_ONCE(regs != task_pt_regs(current));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_CONTEXT_TRACKING
|
#ifdef CONFIG_CONTEXT_TRACKING
|
||||||
/**
|
/**
|
||||||
* enter_from_user_mode - Establish state when coming from user mode
|
* enter_from_user_mode - Establish state when coming from user mode
|
||||||
@ -127,9 +136,6 @@ static long syscall_trace_enter(struct pt_regs *regs)
|
|||||||
unsigned long ret = 0;
|
unsigned long ret = 0;
|
||||||
u32 work;
|
u32 work;
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_DEBUG_ENTRY))
|
|
||||||
BUG_ON(regs != task_pt_regs(current));
|
|
||||||
|
|
||||||
work = READ_ONCE(ti->flags);
|
work = READ_ONCE(ti->flags);
|
||||||
|
|
||||||
if (work & (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_EMU)) {
|
if (work & (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_EMU)) {
|
||||||
@ -346,6 +352,8 @@ __visible noinstr void do_syscall_64(unsigned long nr, struct pt_regs *regs)
|
|||||||
{
|
{
|
||||||
struct thread_info *ti;
|
struct thread_info *ti;
|
||||||
|
|
||||||
|
check_user_regs(regs);
|
||||||
|
|
||||||
enter_from_user_mode();
|
enter_from_user_mode();
|
||||||
instrumentation_begin();
|
instrumentation_begin();
|
||||||
|
|
||||||
@ -409,6 +417,8 @@ static void do_syscall_32_irqs_on(struct pt_regs *regs)
|
|||||||
/* Handles int $0x80 */
|
/* Handles int $0x80 */
|
||||||
__visible noinstr void do_int80_syscall_32(struct pt_regs *regs)
|
__visible noinstr void do_int80_syscall_32(struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
|
check_user_regs(regs);
|
||||||
|
|
||||||
enter_from_user_mode();
|
enter_from_user_mode();
|
||||||
instrumentation_begin();
|
instrumentation_begin();
|
||||||
|
|
||||||
@ -460,6 +470,8 @@ __visible noinstr long do_fast_syscall_32(struct pt_regs *regs)
|
|||||||
vdso_image_32.sym_int80_landing_pad;
|
vdso_image_32.sym_int80_landing_pad;
|
||||||
bool success;
|
bool success;
|
||||||
|
|
||||||
|
check_user_regs(regs);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SYSENTER loses EIP, and even SYSCALL32 needs us to skip forward
|
* SYSENTER loses EIP, and even SYSCALL32 needs us to skip forward
|
||||||
* so that 'regs->ip -= 2' lands back on an int $0x80 instruction.
|
* so that 'regs->ip -= 2' lands back on an int $0x80 instruction.
|
||||||
|
Loading…
Reference in New Issue
Block a user