Skip to content

Commit

Permalink
x86/unwind: Ensure stack pointer is aligned
Browse files Browse the repository at this point in the history
With frame pointers disabled, on some older versions of GCC (like
4.8.3), it's possible for the stack pointer to get aligned at a
half-word boundary:

  00000000000004d0 <fib_table_lookup>:
       4d0:       41 57                   push   %r15
       4d2:       41 56                   push   %r14
       4d4:       41 55                   push   %r13
       4d6:       41 54                   push   %r12
       4d8:       55                      push   %rbp
       4d9:       53                      push   %rbx
       4da:       48 83 ec 24             sub    $0x24,%rsp

In such a case, the unwinder ends up reading the entire stack at the
wrong alignment.  Then the last read goes past the end of the stack,
hitting the stack guard page:

  BUG: stack guard page was hit at ffffc900217c4000 (stack is ffffc900217c0000..ffffc900217c3fff)
  kernel stack overflow (page fault): 0000 [#1] SMP
  ...

Fix it by ensuring the stack pointer is properly aligned before
unwinding.

Reported-by: Jirka Hladky <jhladky@redhat.com>
Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
Acked-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Fixes: 7c7900f ("x86/unwind: Add new unwind interface and implementations")
Link: http://lkml.kernel.org/r/cff33847cc9b02fa548625aa23268ac574460d8d.1492436590.git.jpoimboe@redhat.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
  • Loading branch information
Josh Poimboeuf authored and Ingo Molnar committed Apr 18, 2017
1 parent f26dee1 commit e335bb5
Show file tree
Hide file tree
Showing 2 changed files with 3 additions and 3 deletions.
2 changes: 1 addition & 1 deletion arch/x86/kernel/dumpstack.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ void show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
* - softirq stack
* - hardirq stack
*/
for (regs = NULL; stack; stack = stack_info.next_sp) {
for (regs = NULL; stack; stack = PTR_ALIGN(stack_info.next_sp, sizeof(long))) {
const char *stack_name;

/*
Expand Down
4 changes: 2 additions & 2 deletions arch/x86/kernel/unwind_guess.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ bool unwind_next_frame(struct unwind_state *state)
return true;
}

state->sp = info->next_sp;
state->sp = PTR_ALIGN(info->next_sp, sizeof(long));

} while (!get_stack_info(state->sp, state->task, info,
&state->stack_mask));
Expand All @@ -49,7 +49,7 @@ void __unwind_start(struct unwind_state *state, struct task_struct *task,
memset(state, 0, sizeof(*state));

state->task = task;
state->sp = first_frame;
state->sp = PTR_ALIGN(first_frame, sizeof(long));

get_stack_info(first_frame, state->task, &state->stack_info,
&state->stack_mask);
Expand Down

0 comments on commit e335bb5

Please sign in to comment.