Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1636478

[PATCH] kthread: fix use-after-free if kthread fork fails

From Vegard Nossum <vegard.nossum@oracle.com>
Newsgroups linux.kernel
Subject [PATCH] kthread: fix use-after-free if kthread fork fails
Date 2017-05-05 18:30 +0200
Message-ID <tDOhc-46o-3@gated-at.bofh.it> (permalink)
Organization linux.* mail to news gateway

Show all headers | View raw


If a kthread forks (e.g. usermodehelper since commit 1da5c46fa965) but
fails in copy_process() between calling dup_task_struct() and setting
p->set_child_tid, then the value of p->set_child_tid will be inherited
from the parent and get prematurely freed by free_kthread_struct().

    kthread()
     - worker_thread()
        - process_one_work()
        |  - call_usermodehelper_exec_work()
        |     - kernel_thread()
        |        - _do_fork()
        |           - copy_process()
        |              - dup_task_struct()
        |                 - arch_dup_task_struct()
        |                    - tsk->set_child_tid = current->set_child_tid // implied
        |              - ...
        |              - goto bad_fork_*
        |              - ...
        |              - free_task(tsk)
        |                 - free_kthread_struct(tsk)
        |                    - kfree(tsk->set_child_tid)
        - ...
        - schedule()
           - __schedule()
              - wq_worker_sleeping()
                 - kthread_data(task)->flags // UAF

The problem started showing up with commit 1da5c46fa965 since it reused
->set_child_tid for the kthread worker data.

A better long-term solution might be to get rid of the ->set_child_tid
abuse. The comment in set_kthread_struct() also looks slightly wrong.

Fixes: 1da5c46fa965ff90f5ffc080b6ab3fae5e227bc3 ("kthread: Make struct kthread kmalloc'ed")
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Andy Lutomirski <luto@kernel.org>
Debugged-by: Jamie Iles <jamie.iles@oracle.com>
Signed-off-by: Vegard Nossum <vegard.nossum@oracle.com>
---
 kernel/fork.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/kernel/fork.c b/kernel/fork.c
index dd5a371c392a..fbdc29365b83 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -518,6 +518,13 @@ static struct task_struct *dup_task_struct(struct task_struct *orig, int node)
 	atomic_set(&tsk->stack_refcount, 1);
 #endif
 
+	/*
+	 * Forking kthreads (e.g. usermodehelper) should not inherit this
+	 * field since it's a pointer to a 'struct kthread' which is not
+	 * reference counted.
+	 */
+	tsk->set_child_tid = NULL;
+
 	if (err)
 		goto free_stack;
 
-- 
2.12.0.rc0

Back to linux.kernel | Previous | NextNext in thread | Find similar | Unroll thread


Thread

[PATCH] kthread: fix use-after-free if kthread fork fails Vegard Nossum <vegard.nossum@oracle.com> - 2017-05-05 18:30 +0200
  Re: [PATCH] kthread: fix use-after-free if kthread fork fails Oleg Nesterov <oleg@redhat.com> - 2017-05-05 18:50 +0200
    Re: [PATCH] kthread: fix use-after-free if kthread fork fails Vegard Nossum <vegard.nossum@oracle.com> - 2017-05-05 19:20 +0200
      Re: [PATCH] kthread: fix use-after-free if kthread fork fails Oleg Nesterov <oleg@redhat.com> - 2017-05-06 22:00 +0200

csiph-web