diff options
author | Joe Lawrence <joe.lawrence@redhat.com> | 2019-01-22 10:57:22 -0500 |
---|---|---|
committer | Michael Ellerman <mpe@ellerman.id.au> | 2019-01-31 00:43:38 -0500 |
commit | 18be37603de81674e41a0b0282326a0debc1696e (patch) | |
tree | cc3e5a0d4b83b5bc0517b5c2b6dcda029931d797 | |
parent | a50d3250d7ae34c561177a1f9cfb79816fcbcff1 (diff) |
powerpc/livepatch: relax reliable stack tracer checks for first-frame
The bottom-most stack frame (the first to be unwound) may be largely
uninitialized, for the "Power Architecture 64-Bit ELF V2 ABI" only
requires its backchain pointer to be set.
The reliable stack tracer should be careful when verifying this frame:
skip checks on STACK_FRAME_LR_SAVE and STACK_FRAME_MARKER offsets that
may contain uninitialized residual data.
Fixes: df78d3f61480 ("powerpc/livepatch: Implement reliable stack tracing for the consistency model")
Signed-off-by: Joe Lawrence <joe.lawrence@redhat.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
-rw-r--r-- | arch/powerpc/kernel/stacktrace.c | 32 |
1 files changed, 24 insertions, 8 deletions
diff --git a/arch/powerpc/kernel/stacktrace.c b/arch/powerpc/kernel/stacktrace.c index e2c50b55138f..06688f4d557b 100644 --- a/arch/powerpc/kernel/stacktrace.c +++ b/arch/powerpc/kernel/stacktrace.c | |||
@@ -84,6 +84,12 @@ save_stack_trace_regs(struct pt_regs *regs, struct stack_trace *trace) | |||
84 | EXPORT_SYMBOL_GPL(save_stack_trace_regs); | 84 | EXPORT_SYMBOL_GPL(save_stack_trace_regs); |
85 | 85 | ||
86 | #ifdef CONFIG_HAVE_RELIABLE_STACKTRACE | 86 | #ifdef CONFIG_HAVE_RELIABLE_STACKTRACE |
87 | /* | ||
88 | * This function returns an error if it detects any unreliable features of the | ||
89 | * stack. Otherwise it guarantees that the stack trace is reliable. | ||
90 | * | ||
91 | * If the task is not 'current', the caller *must* ensure the task is inactive. | ||
92 | */ | ||
87 | int | 93 | int |
88 | save_stack_trace_tsk_reliable(struct task_struct *tsk, | 94 | save_stack_trace_tsk_reliable(struct task_struct *tsk, |
89 | struct stack_trace *trace) | 95 | struct stack_trace *trace) |
@@ -142,12 +148,6 @@ save_stack_trace_tsk_reliable(struct task_struct *tsk, | |||
142 | if (sp & 0xF) | 148 | if (sp & 0xF) |
143 | return 1; | 149 | return 1; |
144 | 150 | ||
145 | /* Mark stacktraces with exception frames as unreliable. */ | ||
146 | if (sp <= stack_end - STACK_INT_FRAME_SIZE && | ||
147 | stack[STACK_FRAME_MARKER] == STACK_FRAME_REGS_MARKER) { | ||
148 | return 1; | ||
149 | } | ||
150 | |||
151 | newsp = stack[0]; | 151 | newsp = stack[0]; |
152 | /* Stack grows downwards; unwinder may only go up. */ | 152 | /* Stack grows downwards; unwinder may only go up. */ |
153 | if (newsp <= sp) | 153 | if (newsp <= sp) |
@@ -158,11 +158,26 @@ save_stack_trace_tsk_reliable(struct task_struct *tsk, | |||
158 | return 1; /* invalid backlink, too far up. */ | 158 | return 1; /* invalid backlink, too far up. */ |
159 | } | 159 | } |
160 | 160 | ||
161 | /* | ||
162 | * We can only trust the bottom frame's backlink, the | ||
163 | * rest of the frame may be uninitialized, continue to | ||
164 | * the next. | ||
165 | */ | ||
166 | if (firstframe) { | ||
167 | firstframe = 0; | ||
168 | goto next; | ||
169 | } | ||
170 | |||
171 | /* Mark stacktraces with exception frames as unreliable. */ | ||
172 | if (sp <= stack_end - STACK_INT_FRAME_SIZE && | ||
173 | stack[STACK_FRAME_MARKER] == STACK_FRAME_REGS_MARKER) { | ||
174 | return 1; | ||
175 | } | ||
176 | |||
161 | /* Examine the saved LR: it must point into kernel code. */ | 177 | /* Examine the saved LR: it must point into kernel code. */ |
162 | ip = stack[STACK_FRAME_LR_SAVE]; | 178 | ip = stack[STACK_FRAME_LR_SAVE]; |
163 | if (!firstframe && !__kernel_text_address(ip)) | 179 | if (!__kernel_text_address(ip)) |
164 | return 1; | 180 | return 1; |
165 | firstframe = 0; | ||
166 | 181 | ||
167 | /* | 182 | /* |
168 | * FIXME: IMHO these tests do not belong in | 183 | * FIXME: IMHO these tests do not belong in |
@@ -183,6 +198,7 @@ save_stack_trace_tsk_reliable(struct task_struct *tsk, | |||
183 | else | 198 | else |
184 | trace->skip--; | 199 | trace->skip--; |
185 | 200 | ||
201 | next: | ||
186 | if (newsp == stack_end) | 202 | if (newsp == stack_end) |
187 | break; | 203 | break; |
188 | 204 | ||