| From 8a567429ebb70da56eb63f05deee51d9328c5c00 Mon Sep 17 00:00:00 2001 |
| From: Andy Lutomirski <luto@kernel.org> |
| Date: Thu, 15 Sep 2016 22:45:45 -0700 |
| Subject: [PATCH] x86/dumpstack: Pin the target stack when dumping it |
| |
| commit 1959a60182f48879635812a03a99c02231ea8677 upstream. |
| |
| Specifically, pin the stack in save_stack_trace_tsk() and |
| show_trace_log_lvl(). |
| |
| This will prevent a crash if the target task dies before or while |
| dumping its stack once we start freeing task stacks early. |
| |
| Signed-off-by: Andy Lutomirski <luto@kernel.org> |
| Cc: Borislav Petkov <bp@alien8.de> |
| Cc: Brian Gerst <brgerst@gmail.com> |
| Cc: Denys Vlasenko <dvlasenk@redhat.com> |
| Cc: H. Peter Anvin <hpa@zytor.com> |
| Cc: Jann Horn <jann@thejh.net> |
| Cc: Josh Poimboeuf <jpoimboe@redhat.com> |
| Cc: Linus Torvalds <torvalds@linux-foundation.org> |
| Cc: Peter Zijlstra <peterz@infradead.org> |
| Cc: Thomas Gleixner <tglx@linutronix.de> |
| Link: http://lkml.kernel.org/r/cf0082cde65d1941a996d026f2b2cdbfaca17bfa.1474003868.git.luto@kernel.org |
| Signed-off-by: Ingo Molnar <mingo@kernel.org> |
| |
| diff --git a/arch/x86/kernel/dumpstack_32.c b/arch/x86/kernel/dumpstack_32.c |
| index 09675712eba8..8ad32dc94e8d 100644 |
| --- a/arch/x86/kernel/dumpstack_32.c |
| +++ b/arch/x86/kernel/dumpstack_32.c |
| @@ -95,6 +95,9 @@ show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs, |
| unsigned long *stack; |
| int i; |
| |
| + if (!try_get_task_stack(task)) |
| + return; |
| + |
| if (sp == NULL) { |
| if (regs) |
| sp = (unsigned long *)regs->sp; |
| @@ -118,6 +121,8 @@ show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs, |
| } |
| pr_cont("\n"); |
| show_trace_log_lvl(task, regs, sp, bp, log_lvl); |
| + |
| + put_task_stack(task); |
| } |
| |
| |
| diff --git a/arch/x86/kernel/dumpstack_64.c b/arch/x86/kernel/dumpstack_64.c |
| index 9ee4520ce83c..1bcdb164afd9 100644 |
| --- a/arch/x86/kernel/dumpstack_64.c |
| +++ b/arch/x86/kernel/dumpstack_64.c |
| @@ -253,6 +253,9 @@ show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs, |
| int cpu; |
| int i; |
| |
| + if (!try_get_task_stack(task)) |
| + return; |
| + |
| preempt_disable(); |
| cpu = smp_processor_id(); |
| |
| @@ -303,6 +306,8 @@ show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs, |
| |
| pr_cont("\n"); |
| show_trace_log_lvl(task, regs, sp, bp, log_lvl); |
| + |
| + put_task_stack(task); |
| } |
| |
| void show_regs(struct pt_regs *regs) |
| diff --git a/arch/x86/kernel/stacktrace.c b/arch/x86/kernel/stacktrace.c |
| index 4738f5e0f2ab..b3f32fbe3ba4 100644 |
| --- a/arch/x86/kernel/stacktrace.c |
| +++ b/arch/x86/kernel/stacktrace.c |
| @@ -79,9 +79,14 @@ void save_stack_trace_regs(struct pt_regs *regs, struct stack_trace *trace) |
| |
| void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) |
| { |
| + if (!try_get_task_stack(tsk)) |
| + return; |
| + |
| dump_trace(tsk, NULL, NULL, 0, &save_stack_ops_nosched, trace); |
| if (trace->nr_entries < trace->max_entries) |
| trace->entries[trace->nr_entries++] = ULONG_MAX; |
| + |
| + put_task_stack(tsk); |
| } |
| EXPORT_SYMBOL_GPL(save_stack_trace_tsk); |
| |
| -- |
| 2.15.0 |
| |