diff options
author | Josh Poimboeuf <jpoimboe@redhat.com> | 2017-04-12 14:47:10 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2017-04-14 04:19:49 -0400 |
commit | 5ed8d8bb38c5dcd78de540182cedb0fb19399aab (patch) | |
tree | 8a8fa0f779e57d4e7b35f918062268d2c6c893a1 | |
parent | b5effd3815ccbe3df1a015a6d67d8a24a27813d5 (diff) |
x86/unwind: Move common code into update_stack_state()
The __unwind_start() and unwind_next_frame() functions have some
duplicated functionality. They both call decode_frame_pointer() and set
state->regs and state->bp accordingly. Move that functionality to a
common place in update_stack_state().
Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
Acked-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: Dave Jones <davej@codemonkey.org.uk>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/a2ee4801113f6d2300d58f08f6b69f85edf4eb43.1492020577.git.jpoimboe@redhat.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r-- | arch/x86/kernel/unwind_frame.c | 119 |
1 files changed, 55 insertions, 64 deletions
diff --git a/arch/x86/kernel/unwind_frame.c b/arch/x86/kernel/unwind_frame.c index 08339262b666..9098ef1da8f8 100644 --- a/arch/x86/kernel/unwind_frame.c +++ b/arch/x86/kernel/unwind_frame.c | |||
@@ -135,26 +135,59 @@ static struct pt_regs *decode_frame_pointer(unsigned long *bp) | |||
135 | return (struct pt_regs *)(regs & ~0x1); | 135 | return (struct pt_regs *)(regs & ~0x1); |
136 | } | 136 | } |
137 | 137 | ||
138 | static bool update_stack_state(struct unwind_state *state, void *addr, | 138 | static bool update_stack_state(struct unwind_state *state, |
139 | size_t len) | 139 | unsigned long *next_bp) |
140 | { | 140 | { |
141 | struct stack_info *info = &state->stack_info; | 141 | struct stack_info *info = &state->stack_info; |
142 | enum stack_type orig_type = info->type; | 142 | enum stack_type prev_type = info->type; |
143 | struct pt_regs *regs; | ||
144 | unsigned long *frame, *prev_frame_end; | ||
145 | size_t len; | ||
146 | |||
147 | if (state->regs) | ||
148 | prev_frame_end = (void *)state->regs + regs_size(state->regs); | ||
149 | else | ||
150 | prev_frame_end = (void *)state->bp + FRAME_HEADER_SIZE; | ||
151 | |||
152 | /* Is the next frame pointer an encoded pointer to pt_regs? */ | ||
153 | regs = decode_frame_pointer(next_bp); | ||
154 | if (regs) { | ||
155 | frame = (unsigned long *)regs; | ||
156 | len = regs_size(regs); | ||
157 | } else { | ||
158 | frame = next_bp; | ||
159 | len = FRAME_HEADER_SIZE; | ||
160 | } | ||
143 | 161 | ||
144 | /* | 162 | /* |
145 | * If addr isn't on the current stack, switch to the next one. | 163 | * If the next bp isn't on the current stack, switch to the next one. |
146 | * | 164 | * |
147 | * We may have to traverse multiple stacks to deal with the possibility | 165 | * We may have to traverse multiple stacks to deal with the possibility |
148 | * that 'info->next_sp' could point to an empty stack and 'addr' could | 166 | * that info->next_sp could point to an empty stack and the next bp |
149 | * be on a subsequent stack. | 167 | * could be on a subsequent stack. |
150 | */ | 168 | */ |
151 | while (!on_stack(info, addr, len)) | 169 | while (!on_stack(info, frame, len)) |
152 | if (get_stack_info(info->next_sp, state->task, info, | 170 | if (get_stack_info(info->next_sp, state->task, info, |
153 | &state->stack_mask)) | 171 | &state->stack_mask)) |
154 | return false; | 172 | return false; |
155 | 173 | ||
156 | if (!state->orig_sp || info->type != orig_type) | 174 | /* Make sure it only unwinds up and doesn't overlap the prev frame: */ |
157 | state->orig_sp = addr; | 175 | if (state->orig_sp && state->stack_info.type == prev_type && |
176 | frame < prev_frame_end) | ||
177 | return false; | ||
178 | |||
179 | /* Move state to the next frame: */ | ||
180 | if (regs) { | ||
181 | state->regs = regs; | ||
182 | state->bp = NULL; | ||
183 | } else { | ||
184 | state->bp = next_bp; | ||
185 | state->regs = NULL; | ||
186 | } | ||
187 | |||
188 | /* Save the original stack pointer for unwind_dump(): */ | ||
189 | if (!state->orig_sp || info->type != prev_type) | ||
190 | state->orig_sp = frame; | ||
158 | 191 | ||
159 | return true; | 192 | return true; |
160 | } | 193 | } |
@@ -162,14 +195,12 @@ static bool update_stack_state(struct unwind_state *state, void *addr, | |||
162 | bool unwind_next_frame(struct unwind_state *state) | 195 | bool unwind_next_frame(struct unwind_state *state) |
163 | { | 196 | { |
164 | struct pt_regs *regs; | 197 | struct pt_regs *regs; |
165 | unsigned long *next_bp, *next_frame; | 198 | unsigned long *next_bp; |
166 | size_t next_len; | ||
167 | enum stack_type prev_type = state->stack_info.type; | ||
168 | 199 | ||
169 | if (unwind_done(state)) | 200 | if (unwind_done(state)) |
170 | return false; | 201 | return false; |
171 | 202 | ||
172 | /* have we reached the end? */ | 203 | /* Have we reached the end? */ |
173 | if (state->regs && user_mode(state->regs)) | 204 | if (state->regs && user_mode(state->regs)) |
174 | goto the_end; | 205 | goto the_end; |
175 | 206 | ||
@@ -200,24 +231,14 @@ bool unwind_next_frame(struct unwind_state *state) | |||
200 | return true; | 231 | return true; |
201 | } | 232 | } |
202 | 233 | ||
203 | /* get the next frame pointer */ | 234 | /* Get the next frame pointer: */ |
204 | if (state->regs) | 235 | if (state->regs) |
205 | next_bp = (unsigned long *)state->regs->bp; | 236 | next_bp = (unsigned long *)state->regs->bp; |
206 | else | 237 | else |
207 | next_bp = (unsigned long *)READ_ONCE_TASK_STACK(state->task,*state->bp); | 238 | next_bp = (unsigned long *)READ_ONCE_TASK_STACK(state->task, *state->bp); |
208 | 239 | ||
209 | /* is the next frame pointer an encoded pointer to pt_regs? */ | 240 | /* Move to the next frame if it's safe: */ |
210 | regs = decode_frame_pointer(next_bp); | 241 | if (!update_stack_state(state, next_bp)) { |
211 | if (regs) { | ||
212 | next_frame = (unsigned long *)regs; | ||
213 | next_len = sizeof(*regs); | ||
214 | } else { | ||
215 | next_frame = next_bp; | ||
216 | next_len = FRAME_HEADER_SIZE; | ||
217 | } | ||
218 | |||
219 | /* make sure the next frame's data is accessible */ | ||
220 | if (!update_stack_state(state, next_frame, next_len)) { | ||
221 | /* | 242 | /* |
222 | * Don't warn on bad regs->bp. An interrupt in entry code | 243 | * Don't warn on bad regs->bp. An interrupt in entry code |
223 | * might cause a false positive warning. | 244 | * might cause a false positive warning. |
@@ -228,24 +249,6 @@ bool unwind_next_frame(struct unwind_state *state) | |||
228 | goto bad_address; | 249 | goto bad_address; |
229 | } | 250 | } |
230 | 251 | ||
231 | /* Make sure it only unwinds up and doesn't overlap the last frame: */ | ||
232 | if (state->stack_info.type == prev_type) { | ||
233 | if (state->regs && (void *)next_frame < (void *)state->regs + regs_size(state->regs)) | ||
234 | goto bad_address; | ||
235 | |||
236 | if (state->bp && (void *)next_frame < (void *)state->bp + FRAME_HEADER_SIZE) | ||
237 | goto bad_address; | ||
238 | } | ||
239 | |||
240 | /* move to the next frame */ | ||
241 | if (regs) { | ||
242 | state->regs = regs; | ||
243 | state->bp = NULL; | ||
244 | } else { | ||
245 | state->bp = next_bp; | ||
246 | state->regs = NULL; | ||
247 | } | ||
248 | |||
249 | return true; | 252 | return true; |
250 | 253 | ||
251 | bad_address: | 254 | bad_address: |
@@ -263,13 +266,13 @@ bad_address: | |||
263 | printk_deferred_once(KERN_WARNING | 266 | printk_deferred_once(KERN_WARNING |
264 | "WARNING: kernel stack regs at %p in %s:%d has bad 'bp' value %p\n", | 267 | "WARNING: kernel stack regs at %p in %s:%d has bad 'bp' value %p\n", |
265 | state->regs, state->task->comm, | 268 | state->regs, state->task->comm, |
266 | state->task->pid, next_frame); | 269 | state->task->pid, next_bp); |
267 | unwind_dump(state, (unsigned long *)state->regs); | 270 | unwind_dump(state, (unsigned long *)state->regs); |
268 | } else { | 271 | } else { |
269 | printk_deferred_once(KERN_WARNING | 272 | printk_deferred_once(KERN_WARNING |
270 | "WARNING: kernel stack frame pointer at %p in %s:%d has bad value %p\n", | 273 | "WARNING: kernel stack frame pointer at %p in %s:%d has bad value %p\n", |
271 | state->bp, state->task->comm, | 274 | state->bp, state->task->comm, |
272 | state->task->pid, next_frame); | 275 | state->task->pid, next_bp); |
273 | unwind_dump(state, state->bp); | 276 | unwind_dump(state, state->bp); |
274 | } | 277 | } |
275 | the_end: | 278 | the_end: |
@@ -281,35 +284,23 @@ EXPORT_SYMBOL_GPL(unwind_next_frame); | |||
281 | void __unwind_start(struct unwind_state *state, struct task_struct *task, | 284 | void __unwind_start(struct unwind_state *state, struct task_struct *task, |
282 | struct pt_regs *regs, unsigned long *first_frame) | 285 | struct pt_regs *regs, unsigned long *first_frame) |
283 | { | 286 | { |
284 | unsigned long *bp, *frame; | 287 | unsigned long *bp; |
285 | size_t len; | ||
286 | 288 | ||
287 | memset(state, 0, sizeof(*state)); | 289 | memset(state, 0, sizeof(*state)); |
288 | state->task = task; | 290 | state->task = task; |
289 | 291 | ||
290 | /* don't even attempt to start from user mode regs */ | 292 | /* Don't even attempt to start from user mode regs: */ |
291 | if (regs && user_mode(regs)) { | 293 | if (regs && user_mode(regs)) { |
292 | state->stack_info.type = STACK_TYPE_UNKNOWN; | 294 | state->stack_info.type = STACK_TYPE_UNKNOWN; |
293 | return; | 295 | return; |
294 | } | 296 | } |
295 | 297 | ||
296 | /* set up the starting stack frame */ | ||
297 | bp = get_frame_pointer(task, regs); | 298 | bp = get_frame_pointer(task, regs); |
298 | regs = decode_frame_pointer(bp); | ||
299 | if (regs) { | ||
300 | state->regs = regs; | ||
301 | frame = (unsigned long *)regs; | ||
302 | len = sizeof(*regs); | ||
303 | } else { | ||
304 | state->bp = bp; | ||
305 | frame = bp; | ||
306 | len = FRAME_HEADER_SIZE; | ||
307 | } | ||
308 | 299 | ||
309 | /* initialize stack info and make sure the frame data is accessible */ | 300 | /* Initialize stack info and make sure the frame data is accessible: */ |
310 | get_stack_info(frame, state->task, &state->stack_info, | 301 | get_stack_info(bp, state->task, &state->stack_info, |
311 | &state->stack_mask); | 302 | &state->stack_mask); |
312 | update_stack_state(state, frame, len); | 303 | update_stack_state(state, bp); |
313 | 304 | ||
314 | /* | 305 | /* |
315 | * The caller can provide the address of the first frame directly | 306 | * The caller can provide the address of the first frame directly |