Commit fcd709ef authored by Josh Poimboeuf's avatar Josh Poimboeuf Committed by Ingo Molnar

x86/dumpstack: Add recursion checking for all stacks

in_exception_stack() has some recursion checking which makes sure the
stack trace code never traverses a given exception stack more than once.
This prevents an infinite loop if corruption somehow causes a stack's
"next stack" pointer to point to itself (directly or indirectly).

The recursion checking can be useful for other stacks in addition to the
exception stack, so extend it to work for all stacks.
Signed-off-by: default avatarJosh Poimboeuf <jpoimboe@redhat.com>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Byungchul Park <byungchul.park@lge.com>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Nilay Vaish <nilayvaish@gmail.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/95de5db4cfe111754845a5cef04e20630d01423f.1473905218.git.jpoimboe@redhat.comSigned-off-by: default avatarIngo Molnar <mingo@kernel.org>
parent 5fe599e0
...@@ -89,16 +89,32 @@ int get_stack_info(unsigned long *stack, struct task_struct *task, ...@@ -89,16 +89,32 @@ int get_stack_info(unsigned long *stack, struct task_struct *task,
task = task ? : current; task = task ? : current;
if (in_task_stack(stack, task, info)) if (in_task_stack(stack, task, info))
return 0; goto recursion_check;
if (task != current) if (task != current)
goto unknown; goto unknown;
if (in_hardirq_stack(stack, info)) if (in_hardirq_stack(stack, info))
return 0; goto recursion_check;
if (in_softirq_stack(stack, info)) 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: unknown:
info->type = STACK_TYPE_UNKNOWN; info->type = STACK_TYPE_UNKNOWN;
......
...@@ -47,8 +47,7 @@ void stack_type_str(enum stack_type type, const char **begin, const char **end) ...@@ -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, static bool in_exception_stack(unsigned long *stack, struct stack_info *info)
unsigned long *visit_mask)
{ {
unsigned long *begin, *end; unsigned long *begin, *end;
struct pt_regs *regs; struct pt_regs *regs;
...@@ -64,16 +63,6 @@ static bool in_exception_stack(unsigned long *stack, struct stack_info *info, ...@@ -64,16 +63,6 @@ static bool in_exception_stack(unsigned long *stack, struct stack_info *info,
if (stack < begin || stack >= end) if (stack < begin || stack >= end)
continue; continue;
/*
* Make sure we don't iterate through an exception 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 & (1U << k))
break;
*visit_mask |= 1U << k;
info->type = STACK_TYPE_EXCEPTION + k; info->type = STACK_TYPE_EXCEPTION + k;
info->begin = begin; info->begin = begin;
info->end = end; info->end = end;
...@@ -119,16 +108,30 @@ int get_stack_info(unsigned long *stack, struct task_struct *task, ...@@ -119,16 +108,30 @@ int get_stack_info(unsigned long *stack, struct task_struct *task,
task = task ? : current; task = task ? : current;
if (in_task_stack(stack, task, info)) if (in_task_stack(stack, task, info))
return 0; goto recursion_check;
if (task != current) if (task != current)
goto unknown; goto unknown;
if (in_exception_stack(stack, info, visit_mask)) if (in_exception_stack(stack, info))
return 0; goto recursion_check;
if (in_irq_stack(stack, info)) 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; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment