]> git.proxmox.com Git - mirror_ubuntu-eoan-kernel.git/commitdiff
s390/process: avoid potential reading of freed stack
authorVasily Gorbik <gor@linux.ibm.com>
Tue, 13 Aug 2019 18:11:08 +0000 (20:11 +0200)
committerKhalid Elmously <khalid.elmously@canonical.com>
Fri, 18 Oct 2019 08:26:29 +0000 (04:26 -0400)
BugLink: https://bugs.launchpad.net/bugs/1848039
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>
Signed-off-by: Paolo Pisati <paolo.pisati@canonical.com>
Signed-off-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com>
arch/s390/kernel/process.c

index 63873aa6693fe0881ad3eeb040bb285674025ca4..9f2727bf3cbebadea09c8cca710dc7d1bed9bdc5 100644 (file)
@@ -184,20 +184,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)