aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosh Poimboeuf <jpoimboe@redhat.com>2016-09-14 22:07:44 -0400
committerIngo Molnar <mingo@kernel.org>2016-09-15 02:13:15 -0400
commitfcd709ef20a9d83bdb7524d27cd6719dac8690a0 (patch)
tree10a1653fa1da45343b11311c0c4336f77c4f4180
parent5fe599e02e41550c59831613a11c8ae057897c29 (diff)
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: Josh 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.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--arch/x86/kernel/dumpstack_32.c22
-rw-r--r--arch/x86/kernel/dumpstack_64.c35
2 files changed, 38 insertions, 19 deletions
diff --git a/arch/x86/kernel/dumpstack_32.c b/arch/x86/kernel/dumpstack_32.c
index 50076d4366c4..2d65cfa5e0b4 100644
--- a/arch/x86/kernel/dumpstack_32.c
+++ b/arch/x86/kernel/dumpstack_32.c
@@ -89,16 +89,32 @@ int get_stack_info(unsigned long *stack, struct task_struct *task,
89 task = task ? : current; 89 task = task ? : current;
90 90
91 if (in_task_stack(stack, task, info)) 91 if (in_task_stack(stack, task, info))
92 return 0; 92 goto recursion_check;
93 93
94 if (task != current) 94 if (task != current)
95 goto unknown; 95 goto unknown;
96 96
97 if (in_hardirq_stack(stack, info)) 97 if (in_hardirq_stack(stack, info))
98 return 0; 98 goto recursion_check;
99 99
100 if (in_softirq_stack(stack, info)) 100 if (in_softirq_stack(stack, info))
101 return 0; 101 goto recursion_check;
102
103 goto unknown;
104
105recursion_check:
106 /*
107 * Make sure we don't iterate through any given stack more than once.
108 * If it comes up a second time then there's something wrong going on:
109 * just break out and report an unknown stack type.
110 */
111 if (visit_mask) {
112 if (*visit_mask & (1UL << info->type))
113 goto unknown;
114 *visit_mask |= 1UL << info->type;
115 }
116
117 return 0;
102 118
103unknown: 119unknown:
104 info->type = STACK_TYPE_UNKNOWN; 120 info->type = STACK_TYPE_UNKNOWN;
diff --git a/arch/x86/kernel/dumpstack_64.c b/arch/x86/kernel/dumpstack_64.c
index 2e708afe146d..8cb6004a4dfd 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)
47 } 47 }
48} 48}
49 49
50static bool in_exception_stack(unsigned long *stack, struct stack_info *info, 50static bool in_exception_stack(unsigned long *stack, struct stack_info *info)
51 unsigned long *visit_mask)
52{ 51{
53 unsigned long *begin, *end; 52 unsigned long *begin, *end;
54 struct pt_regs *regs; 53 struct pt_regs *regs;
@@ -64,16 +63,6 @@ static bool in_exception_stack(unsigned long *stack, struct stack_info *info,
64 if (stack < begin || stack >= end) 63 if (stack < begin || stack >= end)
65 continue; 64 continue;
66 65
67 /*
68 * Make sure we don't iterate through an exception stack more
69 * than once. If it comes up a second time then there's
70 * something wrong going on - just break out and report an
71 * unknown stack type.
72 */
73 if (*visit_mask & (1U << k))
74 break;
75 *visit_mask |= 1U << k;
76
77 info->type = STACK_TYPE_EXCEPTION + k; 66 info->type = STACK_TYPE_EXCEPTION + k;
78 info->begin = begin; 67 info->begin = begin;
79 info->end = end; 68 info->end = end;
@@ -119,16 +108,30 @@ int get_stack_info(unsigned long *stack, struct task_struct *task,
119 task = task ? : current; 108 task = task ? : current;
120 109
121 if (in_task_stack(stack, task, info)) 110 if (in_task_stack(stack, task, info))
122 return 0; 111 goto recursion_check;
123 112
124 if (task != current) 113 if (task != current)
125 goto unknown; 114 goto unknown;
126 115
127 if (in_exception_stack(stack, info, visit_mask)) 116 if (in_exception_stack(stack, info))
128 return 0; 117 goto recursion_check;
129 118
130 if (in_irq_stack(stack, info)) 119 if (in_irq_stack(stack, info))
131 return 0; 120 goto recursion_check;
121
122 goto unknown;
123
124recursion_check:
125 /*
126 * Make sure we don't iterate through any given stack more than once.
127 * If it comes up a second time then there's something wrong going on:
128 * just break out and report an unknown stack type.
129 */
130 if (visit_mask) {
131 if (*visit_mask & (1UL << info->type))
132 goto unknown;
133 *visit_mask |= 1UL << info->type;
134 }
132 135
133 return 0; 136 return 0;
134 137