aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosh Poimboeuf <jpoimboe@redhat.com>2017-03-14 00:27:47 -0400
committerThomas Gleixner <tglx@linutronix.de>2017-03-14 16:51:57 -0400
commit87a6b2975f0d340c75b7488d22d61d2f98fb8abf (patch)
tree560b56ad4a1fa1b0bb7749e419226b68f015db7d
parentd434936e4cbb10181463622962f30b989d3e9e19 (diff)
x86/unwind: Fix last frame check for aligned function stacks
Pavel Machek reported the following warning on x86-32: WARNING: kernel stack frame pointer at f50cdf98 in swapper/2:0 has bad value (null) The warning is caused by the unwinder not realizing that it reached the end of the stack, due to an unusual prologue which gcc sometimes generates for aligned stacks. The prologue is based on a gcc feature called the Dynamic Realign Argument Pointer (DRAP). It's almost always enabled for aligned stacks when -maccumulate-outgoing-args isn't set. This issue is similar to the one fixed by the following commit: 8023e0e2a48d ("x86/unwind: Adjust last frame check for aligned function stacks") ... but that fix was specific to x86-64. Make the fix more generic to cover x86-32 as well, and also ensure that the return address referred to by the frame pointer is a copy of the original return address. Fixes: acb4608ad186 ("x86/unwind: Create stack frames for saved syscall registers") Reported-by: Pavel Machek <pavel@ucw.cz> Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com> Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/50d4924db716c264b14f1633037385ec80bf89d2.1489465609.git.jpoimboe@redhat.com Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r--arch/x86/kernel/unwind_frame.c36
1 files changed, 30 insertions, 6 deletions
diff --git a/arch/x86/kernel/unwind_frame.c b/arch/x86/kernel/unwind_frame.c
index 478d15dbaee4..08339262b666 100644
--- a/arch/x86/kernel/unwind_frame.c
+++ b/arch/x86/kernel/unwind_frame.c
@@ -82,19 +82,43 @@ static size_t regs_size(struct pt_regs *regs)
82 return sizeof(*regs); 82 return sizeof(*regs);
83} 83}
84 84
85#ifdef CONFIG_X86_32
86#define GCC_REALIGN_WORDS 3
87#else
88#define GCC_REALIGN_WORDS 1
89#endif
90
85static bool is_last_task_frame(struct unwind_state *state) 91static bool is_last_task_frame(struct unwind_state *state)
86{ 92{
87 unsigned long bp = (unsigned long)state->bp; 93 unsigned long *last_bp = (unsigned long *)task_pt_regs(state->task) - 2;
88 unsigned long regs = (unsigned long)task_pt_regs(state->task); 94 unsigned long *aligned_bp = last_bp - GCC_REALIGN_WORDS;
89 95
90 /* 96 /*
91 * We have to check for the last task frame at two different locations 97 * We have to check for the last task frame at two different locations
92 * because gcc can occasionally decide to realign the stack pointer and 98 * because gcc can occasionally decide to realign the stack pointer and
93 * change the offset of the stack frame by a word in the prologue of a 99 * change the offset of the stack frame in the prologue of a function
94 * function called by head/entry code. 100 * called by head/entry code. Examples:
101 *
102 * <start_secondary>:
103 * push %edi
104 * lea 0x8(%esp),%edi
105 * and $0xfffffff8,%esp
106 * pushl -0x4(%edi)
107 * push %ebp
108 * mov %esp,%ebp
109 *
110 * <x86_64_start_kernel>:
111 * lea 0x8(%rsp),%r10
112 * and $0xfffffffffffffff0,%rsp
113 * pushq -0x8(%r10)
114 * push %rbp
115 * mov %rsp,%rbp
116 *
117 * Note that after aligning the stack, it pushes a duplicate copy of
118 * the return address before pushing the frame pointer.
95 */ 119 */
96 return bp == regs - FRAME_HEADER_SIZE || 120 return (state->bp == last_bp ||
97 bp == regs - FRAME_HEADER_SIZE - sizeof(long); 121 (state->bp == aligned_bp && *(aligned_bp+1) == *(last_bp+1)));
98} 122}
99 123
100/* 124/*