浏览代码

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>
Vasily Gorbik 6 年之前
父节点
当前提交
8b41a30f91
共有 1 个文件被更改,包括 16 次插入6 次删除
  1. 16 6
      arch/s390/kernel/process.c

+ 16 - 6
arch/s390/kernel/process.c

@@ -183,20 +183,30 @@ unsigned long get_wchan(struct task_struct *p)
 
 
 	if (!p || p == current || p->state == TASK_RUNNING || !task_stack_page(p))
 	if (!p || p == current || p->state == TASK_RUNNING || !task_stack_page(p))
 		return 0;
 		return 0;
+
+	if (!try_get_task_stack(p))
+		return 0;
+
 	low = task_stack_page(p);
 	low = task_stack_page(p);
 	high = (struct stack_frame *) task_pt_regs(p);
 	high = (struct stack_frame *) task_pt_regs(p);
 	sf = (struct stack_frame *) p->thread.ksp;
 	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++) {
 	for (count = 0; count < 16; count++) {
 		sf = (struct stack_frame *) sf->back_chain;
 		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];
 		return_address = sf->gprs[8];
 		if (!in_sched_functions(return_address))
 		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)
 unsigned long arch_align_stack(unsigned long sp)