diff options
author | Vasily Gorbik <gor@linux.ibm.com> | 2019-08-13 20:11:08 +0200 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2019-10-11 18:18:27 +0200 |
commit | 219faf28d9c054a9ba0da4983253b08a0650be82 (patch) | |
tree | 8a3c6c0939c2ac509a90f4bd63850cde08c5042c /arch | |
parent | 42327896f194f256e5a361e0069985bc8d209b42 (diff) | |
download | linux-stable-219faf28d9c054a9ba0da4983253b08a0650be82.tar.gz linux-stable-219faf28d9c054a9ba0da4983253b08a0650be82.tar.bz2 linux-stable-219faf28d9c054a9ba0da4983253b08a0650be82.zip |
s390/process: avoid potential reading of freed stack
commit 8769f610fe6d473e5e8e221709c3ac402037da6c upstream.
With THREAD_INFO_IN_TASK (which is selected on s390) task's stack usage
is refcounted and should always be protected by get/put when touching
other task's stack to avoid race conditions with task's destruction code.
Fixes: d5c352cdd022 ("s390: move thread_info into task_struct")
Cc: stable@vger.kernel.org # v4.10+
Acked-by: Ilya Leoshkevich <iii@linux.ibm.com>
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/s390/kernel/process.c | 22 |
1 files changed, 16 insertions, 6 deletions
diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c index 7d4c5500c6c2..1bb7ea6afcf9 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c @@ -185,20 +185,30 @@ unsigned long get_wchan(struct task_struct *p) if (!p || p == current || p->state == TASK_RUNNING || !task_stack_page(p)) return 0; + + if (!try_get_task_stack(p)) + return 0; + low = task_stack_page(p); high = (struct stack_frame *) task_pt_regs(p); sf = (struct stack_frame *) p->thread.ksp; - if (sf <= low || sf > high) - return 0; + if (sf <= low || sf > high) { + return_address = 0; + goto out; + } for (count = 0; count < 16; count++) { sf = (struct stack_frame *) sf->back_chain; - if (sf <= low || sf > high) - return 0; + if (sf <= low || sf > high) { + return_address = 0; + goto out; + } return_address = sf->gprs[8]; if (!in_sched_functions(return_address)) - return return_address; + goto out; } - return 0; +out: + put_task_stack(p); + return return_address; } unsigned long arch_align_stack(unsigned long sp) |