| From bb1473ad47c809331691da42a23b884130e7922d Mon Sep 17 00:00:00 2001 |
| From: Josh Poimboeuf <jpoimboe@redhat.com> |
| Date: Thu, 14 May 2020 15:31:10 -0500 |
| Subject: [PATCH] x86/unwind/orc: Fix error handling in __unwind_start() |
| |
| commit 71c95825289f585014fe9741b051d32a7a916680 upstream. |
| |
| The unwind_state 'error' field is used to inform the reliable unwinding |
| code that the stack trace can't be trusted. Set this field for all |
| errors in __unwind_start(). |
| |
| Also, move the zeroing out of the unwind_state struct to before the ORC |
| table initialization check, to prevent the caller from reading |
| uninitialized data if the ORC table is corrupted. |
| |
| Fixes: af085d9084b4 ("stacktrace/x86: add function for detecting reliable stack traces") |
| Fixes: d3a09104018c ("x86/unwinder/orc: Dont bail on stack overflow") |
| Fixes: 98d0c8ebf77e ("x86/unwind/orc: Prevent unwinding before ORC initialization") |
| Reported-by: Pavel Machek <pavel@denx.de> |
| Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com> |
| Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> |
| Link: https://lkml.kernel.org/r/d6ac7215a84ca92b895fdd2e1aa546729417e6e6.1589487277.git.jpoimboe@redhat.com |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/arch/x86/kernel/unwind_orc.c b/arch/x86/kernel/unwind_orc.c |
| index fb37221a1532..647e6af0883d 100644 |
| --- a/arch/x86/kernel/unwind_orc.c |
| +++ b/arch/x86/kernel/unwind_orc.c |
| @@ -608,23 +608,23 @@ EXPORT_SYMBOL_GPL(unwind_next_frame); |
| void __unwind_start(struct unwind_state *state, struct task_struct *task, |
| struct pt_regs *regs, unsigned long *first_frame) |
| { |
| - if (!orc_init) |
| - goto done; |
| - |
| memset(state, 0, sizeof(*state)); |
| state->task = task; |
| |
| + if (!orc_init) |
| + goto err; |
| + |
| /* |
| * Refuse to unwind the stack of a task while it's executing on another |
| * CPU. This check is racy, but that's ok: the unwinder has other |
| * checks to prevent it from going off the rails. |
| */ |
| if (task_on_another_cpu(task)) |
| - goto done; |
| + goto err; |
| |
| if (regs) { |
| if (user_mode(regs)) |
| - goto done; |
| + goto the_end; |
| |
| state->ip = regs->ip; |
| state->sp = regs->sp; |
| @@ -657,6 +657,7 @@ void __unwind_start(struct unwind_state *state, struct task_struct *task, |
| * generate some kind of backtrace if this happens. |
| */ |
| void *next_page = (void *)PAGE_ALIGN((unsigned long)state->sp); |
| + state->error = true; |
| if (get_stack_info(next_page, state->task, &state->stack_info, |
| &state->stack_mask)) |
| return; |
| @@ -682,8 +683,9 @@ void __unwind_start(struct unwind_state *state, struct task_struct *task, |
| |
| return; |
| |
| -done: |
| +err: |
| + state->error = true; |
| +the_end: |
| state->stack_info.type = STACK_TYPE_UNKNOWN; |
| - return; |
| } |
| EXPORT_SYMBOL_GPL(__unwind_start); |
| -- |
| 2.7.4 |
| |