All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2] kthread: fix use-after-free if kthread fork fails
@ 2017-05-09  7:39 Vegard Nossum
  2017-05-10 14:02 ` Oleg Nesterov
  2017-05-22 20:24 ` [tip:core/urgent] kthread: Fix " tip-bot for Vegard Nossum
  0 siblings, 2 replies; 3+ messages in thread
From: Vegard Nossum @ 2017-05-09  7:39 UTC (permalink / raw)
  To: Oleg Nesterov, linux-kernel
  Cc: Greg Kroah-Hartman, Frederic Weisbecker, Jamie Iles,
	Vegard Nossum, Peter Zijlstra, Thomas Gleixner, Andy Lutomirski

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 | 17 ++++++++++++-----
 1 file changed, 12 insertions(+), 5 deletions(-)

diff --git a/kernel/fork.c b/kernel/fork.c
index dd5a371c392a..03b2f9606a54 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1554,6 +1554,18 @@ static __latent_entropy struct task_struct *copy_process(
 	if (!p)
 		goto fork_out;
 
+	/*
+	 * This _must_ happen before we call free_task(), i.e. before we jump
+	 * to any of the bad_fork_* labels. This is to avoid freeing
+	 * p->set_child_tid which is (ab)used as a kthread's data pointer for
+	 * kernel threads (PF_KTHREAD).
+	 */
+	p->set_child_tid = (clone_flags & CLONE_CHILD_SETTID) ? child_tidptr : NULL;
+	/*
+	 * Clear TID on mm_release()?
+	 */
+	p->clear_child_tid = (clone_flags & CLONE_CHILD_CLEARTID) ? child_tidptr : NULL;
+
 	ftrace_graph_init_task(p);
 
 	rt_mutex_init_task(p);
@@ -1720,11 +1732,6 @@ static __latent_entropy struct task_struct *copy_process(
 		}
 	}
 
-	p->set_child_tid = (clone_flags & CLONE_CHILD_SETTID) ? child_tidptr : NULL;
-	/*
-	 * Clear TID on mm_release()?
-	 */
-	p->clear_child_tid = (clone_flags & CLONE_CHILD_CLEARTID) ? child_tidptr : NULL;
 #ifdef CONFIG_BLOCK
 	p->plug = NULL;
 #endif
-- 
2.12.0.rc0

^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH v2] kthread: fix use-after-free if kthread fork fails
  2017-05-09  7:39 [PATCH v2] kthread: fix use-after-free if kthread fork fails Vegard Nossum
@ 2017-05-10 14:02 ` Oleg Nesterov
  2017-05-22 20:24 ` [tip:core/urgent] kthread: Fix " tip-bot for Vegard Nossum
  1 sibling, 0 replies; 3+ messages in thread
From: Oleg Nesterov @ 2017-05-10 14:02 UTC (permalink / raw)
  To: Vegard Nossum
  Cc: linux-kernel, Greg Kroah-Hartman, Frederic Weisbecker,
	Jamie Iles, Peter Zijlstra, Thomas Gleixner, Andy Lutomirski

On 05/09, Vegard Nossum wrote:
>
> 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().

Thanks,

Acked-by: Oleg Nesterov <oleg@redhat.com>

^ permalink raw reply	[flat|nested] 3+ messages in thread

* [tip:core/urgent] kthread: Fix use-after-free if kthread fork fails
  2017-05-09  7:39 [PATCH v2] kthread: fix use-after-free if kthread fork fails Vegard Nossum
  2017-05-10 14:02 ` Oleg Nesterov
@ 2017-05-22 20:24 ` tip-bot for Vegard Nossum
  1 sibling, 0 replies; 3+ messages in thread
From: tip-bot for Vegard Nossum @ 2017-05-22 20:24 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: linux-kernel, hpa, fweisbec, tglx, peterz, mingo, jamie.iles,
	gregkh, luto, vegard.nossum, oleg

Commit-ID:  4d6501dce079c1eb6bf0b1d8f528a5e81770109e
Gitweb:     http://git.kernel.org/tip/4d6501dce079c1eb6bf0b1d8f528a5e81770109e
Author:     Vegard Nossum <vegard.nossum@oracle.com>
AuthorDate: Tue, 9 May 2017 09:39:59 +0200
Committer:  Thomas Gleixner <tglx@linutronix.de>
CommitDate: Mon, 22 May 2017 22:21:16 +0200

kthread: Fix use-after-free if kthread fork fails

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.

Debugged-by: Jamie Iles <jamie.iles@oracle.com>
Fixes: 1da5c46fa965 ("kthread: Make struct kthread kmalloc'ed")
Signed-off-by: Vegard Nossum <vegard.nossum@oracle.com>
Acked-by: Oleg Nesterov <oleg@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jamie Iles <jamie.iles@oracle.com>
Cc: stable@vger.kernel.org
Link: http://lkml.kernel.org/r/20170509073959.17858-1-vegard.nossum@oracle.com
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>

---
 kernel/fork.c | 17 ++++++++++++-----
 1 file changed, 12 insertions(+), 5 deletions(-)

diff --git a/kernel/fork.c b/kernel/fork.c
index d681f8f..b7cdea1 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1553,6 +1553,18 @@ static __latent_entropy struct task_struct *copy_process(
 	if (!p)
 		goto fork_out;
 
+	/*
+	 * This _must_ happen before we call free_task(), i.e. before we jump
+	 * to any of the bad_fork_* labels. This is to avoid freeing
+	 * p->set_child_tid which is (ab)used as a kthread's data pointer for
+	 * kernel threads (PF_KTHREAD).
+	 */
+	p->set_child_tid = (clone_flags & CLONE_CHILD_SETTID) ? child_tidptr : NULL;
+	/*
+	 * Clear TID on mm_release()?
+	 */
+	p->clear_child_tid = (clone_flags & CLONE_CHILD_CLEARTID) ? child_tidptr : NULL;
+
 	ftrace_graph_init_task(p);
 
 	rt_mutex_init_task(p);
@@ -1716,11 +1728,6 @@ static __latent_entropy struct task_struct *copy_process(
 		}
 	}
 
-	p->set_child_tid = (clone_flags & CLONE_CHILD_SETTID) ? child_tidptr : NULL;
-	/*
-	 * Clear TID on mm_release()?
-	 */
-	p->clear_child_tid = (clone_flags & CLONE_CHILD_CLEARTID) ? child_tidptr : NULL;
 #ifdef CONFIG_BLOCK
 	p->plug = NULL;
 #endif

^ permalink raw reply related	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2017-05-22 20:29 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-05-09  7:39 [PATCH v2] kthread: fix use-after-free if kthread fork fails Vegard Nossum
2017-05-10 14:02 ` Oleg Nesterov
2017-05-22 20:24 ` [tip:core/urgent] kthread: Fix " tip-bot for Vegard Nossum

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.