aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosh Poimboeuf <jpoimboe@redhat.com>2017-04-17 09:44:00 -0400
committerIngo Molnar <mingo@kernel.org>2017-04-18 04:30:23 -0400
commite335bb51cc15e80ac180701a0d335ef1c050828e (patch)
tree2e4543538bfc26e5b1867c0bc82b92f5f10cc0fd
parentf26dee15103f4040bfe21c910131db0cfe6624fc (diff)
x86/unwind: Ensure stack pointer is aligned
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: 7c7900f89770 ("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>
-rw-r--r--arch/x86/kernel/dumpstack.c2
-rw-r--r--arch/x86/kernel/unwind_guess.c4
2 files changed, 3 insertions, 3 deletions
diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c
index 924f45ea4382..dbce3cca94cb 100644
--- a/arch/x86/kernel/dumpstack.c
+++ b/arch/x86/kernel/dumpstack.c
@@ -77,7 +77,7 @@ void show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
77 * - softirq stack 77 * - softirq stack
78 * - hardirq stack 78 * - hardirq stack
79 */ 79 */
80 for (regs = NULL; stack; stack = stack_info.next_sp) { 80 for (regs = NULL; stack; stack = PTR_ALIGN(stack_info.next_sp, sizeof(long))) {
81 const char *stack_name; 81 const char *stack_name;
82 82
83 /* 83 /*
diff --git a/arch/x86/kernel/unwind_guess.c b/arch/x86/kernel/unwind_guess.c
index 22881ddcbb9f..039f36738e49 100644
--- a/arch/x86/kernel/unwind_guess.c
+++ b/arch/x86/kernel/unwind_guess.c
@@ -34,7 +34,7 @@ bool unwind_next_frame(struct unwind_state *state)
34 return true; 34 return true;
35 } 35 }
36 36
37 state->sp = info->next_sp; 37 state->sp = PTR_ALIGN(info->next_sp, sizeof(long));
38 38
39 } while (!get_stack_info(state->sp, state->task, info, 39 } while (!get_stack_info(state->sp, state->task, info,
40 &state->stack_mask)); 40 &state->stack_mask));
@@ -49,7 +49,7 @@ void __unwind_start(struct unwind_state *state, struct task_struct *task,
49 memset(state, 0, sizeof(*state)); 49 memset(state, 0, sizeof(*state));
50 50
51 state->task = task; 51 state->task = task;
52 state->sp = first_frame; 52 state->sp = PTR_ALIGN(first_frame, sizeof(long));
53 53
54 get_stack_info(first_frame, state->task, &state->stack_info, 54 get_stack_info(first_frame, state->task, &state->stack_info,
55 &state->stack_mask); 55 &state->stack_mask);