in_exception_stack() has some recursion checking which makes sure the
stack trace code never traverses a given exception stack more than once.
Otherwise corruption could cause a stack to point to itself (directly or
indirectly), resulting in an infinite loop.

Extend the recursion checking to all stacks.

Signed-off-by: Josh Poimboeuf <jpoim...@redhat.com>
---
 arch/x86/kernel/dumpstack_32.c | 22 +++++++++++++++++++---
 arch/x86/kernel/dumpstack_64.c | 34 +++++++++++++++++++---------------
 2 files changed, 38 insertions(+), 18 deletions(-)

diff --git a/arch/x86/kernel/dumpstack_32.c b/arch/x86/kernel/dumpstack_32.c
index 51a113b..37d9c30 100644
--- a/arch/x86/kernel/dumpstack_32.c
+++ b/arch/x86/kernel/dumpstack_32.c
@@ -81,16 +81,32 @@ int get_stack_info(unsigned long *stack, struct task_struct 
*task,
        task = task ? : current;
 
        if (in_task_stack(stack, task, info))
-               return 0;
+               goto recursion_check;
 
        if (task != current)
                goto unknown;
 
        if (in_hardirq_stack(stack, info))
-               return 0;
+               goto recursion_check;
 
        if (in_softirq_stack(stack, info))
-               return 0;
+               goto recursion_check;
+
+       goto unknown;
+
+recursion_check:
+       /*
+        * Make sure we don't iterate through any given stack more than once.
+        * If it comes up a second time then there's something wrong going on:
+        * just break out and report an unknown stack type.
+        */
+       if (visit_mask) {
+               if (*visit_mask & (1UL << info->type))
+                       goto unknown;
+               *visit_mask |= 1UL << info->type;
+       }
+
+       return 0;
 
 unknown:
        info->type = STACK_TYPE_UNKNOWN;
diff --git a/arch/x86/kernel/dumpstack_64.c b/arch/x86/kernel/dumpstack_64.c
index 2e8c750..2292292 100644
--- a/arch/x86/kernel/dumpstack_64.c
+++ b/arch/x86/kernel/dumpstack_64.c
@@ -47,8 +47,7 @@ void stack_type_str(enum stack_type type, const char **begin, 
const char **end)
        }
 }
 
-static bool in_exception_stack(unsigned long *stack, struct stack_info *info,
-                              unsigned long *visit_mask)
+static bool in_exception_stack(unsigned long *stack, struct stack_info *info)
 {
        unsigned long *begin, *end;
        struct pt_regs *regs;
@@ -64,15 +63,6 @@ static bool in_exception_stack(unsigned long *stack, struct 
stack_info *info,
                if (stack < begin || stack >= end)
                        continue;
 
-               /*
-                * Make sure we only iterate through an exception stack once.
-                * If it comes up for the second time then there's something
-                * wrong going on - just break and return NULL:
-                */
-               if (*visit_mask & (1U << k))
-                       break;
-               *visit_mask |= 1U << k;
-
                info->type      = STACK_TYPE_EXCEPTION + k;
                info->begin     = begin;
                info->end       = end;
@@ -114,16 +104,30 @@ int get_stack_info(unsigned long *stack, struct 
task_struct *task,
        task = task ? : current;
 
        if (in_task_stack(stack, task, info))
-               return 0;
+               goto recursion_check;
 
        if (task != current)
                goto unknown;
 
-       if (in_exception_stack(stack, info, visit_mask))
-               return 0;
+       if (in_exception_stack(stack, info))
+               goto recursion_check;
 
        if (in_irq_stack(stack, info))
-               return 0;
+               goto recursion_check;
+
+       goto unknown;
+
+recursion_check:
+       /*
+        * Make sure we don't iterate through any given stack more than once.
+        * If it comes up a second time then there's something wrong going on:
+        * just break out and report an unknown stack type.
+        */
+       if (visit_mask) {
+               if (*visit_mask & (1UL << info->type))
+                       goto unknown;
+               *visit_mask |= 1UL << info->type;
+       }
 
        return 0;
 
-- 
2.7.4

Reply via email to