| From c6c314a613cd7d03fb97713e0d642b493de42e69 Mon Sep 17 00:00:00 2001 |
| From: Andy Lutomirski <luto@kernel.org> |
| Date: Thu, 15 Sep 2016 22:45:43 -0700 |
| Subject: [PATCH] sched/core: Add try_get_task_stack() and put_task_stack() |
| |
| commit c6c314a613cd7d03fb97713e0d642b493de42e69 upstream. |
| |
| There are a few places in the kernel that access stack memory |
| belonging to a different task. Before we can start freeing task |
| stacks before the task_struct is freed, we need a way for those code |
| paths to pin the stack. |
| |
| 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/17a434f50ad3d77000104f21666575e10a9c1fbd.1474003868.git.luto@kernel.org |
| Signed-off-by: Ingo Molnar <mingo@kernel.org> |
| |
| diff --git a/include/linux/sched.h b/include/linux/sched.h |
| index a287e8b13549..a95867267e9f 100644 |
| --- a/include/linux/sched.h |
| +++ b/include/linux/sched.h |
| @@ -3094,11 +3094,19 @@ static inline struct thread_info *task_thread_info(struct task_struct *task) |
| { |
| return &task->thread_info; |
| } |
| + |
| +/* |
| + * When accessing the stack of a non-current task that might exit, use |
| + * try_get_task_stack() instead. task_stack_page will return a pointer |
| + * that could get freed out from under you. |
| + */ |
| static inline void *task_stack_page(const struct task_struct *task) |
| { |
| return task->stack; |
| } |
| + |
| #define setup_thread_stack(new,old) do { } while(0) |
| + |
| static inline unsigned long *end_of_stack(const struct task_struct *task) |
| { |
| return task->stack; |
| @@ -3134,6 +3142,14 @@ static inline unsigned long *end_of_stack(struct task_struct *p) |
| } |
| |
| #endif |
| + |
| +static inline void *try_get_task_stack(struct task_struct *tsk) |
| +{ |
| + return task_stack_page(tsk); |
| +} |
| + |
| +static inline void put_task_stack(struct task_struct *tsk) {} |
| + |
| #define task_stack_end_corrupted(task) \ |
| (*(end_of_stack(task)) != STACK_END_MAGIC) |
| |
| diff --git a/init/Kconfig b/init/Kconfig |
| index ec8d43894b02..3b9a47fe843b 100644 |
| --- a/init/Kconfig |
| +++ b/init/Kconfig |
| @@ -33,6 +33,9 @@ config THREAD_INFO_IN_TASK |
| make this work, an arch will need to remove all thread_info fields |
| except flags and fix any runtime bugs. |
| |
| + One subtle change that will be needed is to use try_get_task_stack() |
| + and put_task_stack() in save_thread_stack_tsk() and get_wchan(). |
| + |
| menu "General setup" |
| |
| config BROKEN |
| -- |
| 2.15.0 |
| |