Skip to content

Commit

Permalink
x86/entry: Assert that syscalls are on the right stack
Browse files Browse the repository at this point in the history
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
  • Loading branch information
amluto authored and KAGA-KOKO committed Jul 1, 2020
1 parent 009bce1 commit c9c2615
Showing 1 changed file with 15 additions and 3 deletions.
18 changes: 15 additions & 3 deletions arch/x86/entry/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,15 @@
#define CREATE_TRACE_POINTS
#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
/**
* enter_from_user_mode - Establish state when coming from user mode
Expand Down Expand Up @@ -127,9 +136,6 @@ static long syscall_trace_enter(struct pt_regs *regs)
unsigned long ret = 0;
u32 work;

if (IS_ENABLED(CONFIG_DEBUG_ENTRY))
BUG_ON(regs != task_pt_regs(current));

work = READ_ONCE(ti->flags);

if (work & (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_EMU)) {
Expand Down Expand Up @@ -346,6 +352,8 @@ __visible noinstr void do_syscall_64(unsigned long nr, struct pt_regs *regs)
{
struct thread_info *ti;

check_user_regs(regs);

enter_from_user_mode();
instrumentation_begin();

Expand Down Expand Up @@ -409,6 +417,8 @@ static void do_syscall_32_irqs_on(struct pt_regs *regs)
/* Handles int $0x80 */
__visible noinstr void do_int80_syscall_32(struct pt_regs *regs)
{
check_user_regs(regs);

enter_from_user_mode();
instrumentation_begin();

Expand Down Expand Up @@ -460,6 +470,8 @@ __visible noinstr long do_fast_syscall_32(struct pt_regs *regs)
vdso_image_32.sym_int80_landing_pad;
bool success;

check_user_regs(regs);

/*
* SYSENTER loses EIP, and even SYSCALL32 needs us to skip forward
* so that 'regs->ip -= 2' lands back on an int $0x80 instruction.
Expand Down

0 comments on commit c9c2615

Please sign in to comment.