aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/kernel/unwind_frame.c16
1 files changed, 15 insertions, 1 deletions
diff --git a/arch/x86/kernel/unwind_frame.c b/arch/x86/kernel/unwind_frame.c
index d145a0b1f529..d05637726c10 100644
--- a/arch/x86/kernel/unwind_frame.c
+++ b/arch/x86/kernel/unwind_frame.c
@@ -184,6 +184,12 @@ static struct pt_regs *decode_frame_pointer(unsigned long *bp)
184 return (struct pt_regs *)(regs & ~0x1); 184 return (struct pt_regs *)(regs & ~0x1);
185} 185}
186 186
187#ifdef CONFIG_X86_32
188#define KERNEL_REGS_SIZE (sizeof(struct pt_regs) - 2*sizeof(long))
189#else
190#define KERNEL_REGS_SIZE (sizeof(struct pt_regs))
191#endif
192
187static bool update_stack_state(struct unwind_state *state, 193static bool update_stack_state(struct unwind_state *state,
188 unsigned long *next_bp) 194 unsigned long *next_bp)
189{ 195{
@@ -202,7 +208,7 @@ static bool update_stack_state(struct unwind_state *state,
202 regs = decode_frame_pointer(next_bp); 208 regs = decode_frame_pointer(next_bp);
203 if (regs) { 209 if (regs) {
204 frame = (unsigned long *)regs; 210 frame = (unsigned long *)regs;
205 len = regs_size(regs); 211 len = KERNEL_REGS_SIZE;
206 state->got_irq = true; 212 state->got_irq = true;
207 } else { 213 } else {
208 frame = next_bp; 214 frame = next_bp;
@@ -226,6 +232,14 @@ static bool update_stack_state(struct unwind_state *state,
226 frame < prev_frame_end) 232 frame < prev_frame_end)
227 return false; 233 return false;
228 234
235 /*
236 * On 32-bit with user mode regs, make sure the last two regs are safe
237 * to access:
238 */
239 if (IS_ENABLED(CONFIG_X86_32) && regs && user_mode(regs) &&
240 !on_stack(info, frame, len + 2*sizeof(long)))
241 return false;
242
229 /* Move state to the next frame: */ 243 /* Move state to the next frame: */
230 if (regs) { 244 if (regs) {
231 state->regs = regs; 245 state->regs = regs;