[PATCH v4 35/57] x86/dumpstack: add recursion checking for all stacks

From: Josh Poimboeuf
Date: Thu Aug 18 2016 - 09:23:47 EST


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 <jpoimboe@xxxxxxxxxx>
---
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 ca49102..c233f93 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 65a77bf..7a4029d 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