Add a sanity check to ensure the stack only grows down, and print a
warning if the check fails.

Use printk_deferred_once() because the unwinder can be called with the
console lock by lockdep via save_stack_trace().

Signed-off-by: Josh Poimboeuf <[email protected]>
---
 arch/x86/kernel/unwind_frame.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/arch/x86/kernel/unwind_frame.c b/arch/x86/kernel/unwind_frame.c
index f943413..a29c342 100644
--- a/arch/x86/kernel/unwind_frame.c
+++ b/arch/x86/kernel/unwind_frame.c
@@ -107,6 +107,7 @@ bool unwind_next_frame(struct unwind_state *state)
 {
        struct pt_regs *regs;
        unsigned long *next_bp;
+       enum stack_type prev_type = state->stack_info.type;
 
        state->regs = NULL;
 
@@ -186,6 +187,15 @@ bool unwind_next_frame(struct unwind_state *state)
                return false;
        }
 
+       /* make sure the stack only unwinds up */
+       if (state->stack_info.type == prev_type && next_bp <= state->bp) {
+               printk_deferred_once(KERN_WARNING "WARNING: kernel stack frame 
pointer at %p in %s:%d points the wrong way (%p)\n",
+                                    state->bp, state->task->comm,
+                                    state->task->pid, next_bp);
+               state->stack_info.type = STACK_TYPE_UNKNOWN;
+               return false;
+       }
+
        /* move to the next frame */
        state->bp = next_bp;
        return true;
-- 
2.7.4

Reply via email to