All of lore.kernel.org
 help / color / mirror / Atom feed
From: tip-bot for Peter Zijlstra <tipbot@zytor.com>
To: linux-tip-commits@vger.kernel.org
Cc: mingo@kernel.org, torvalds@linux-foundation.org,
	dvyukov@google.com,
	bot+2af19c9e1ffe4d4ee1d16c56ae7580feaee75765@syzkaller.appspotmail.com,
	stable@vger.kernel.org, hpa@zytor.com,
	linux-kernel@vger.kernel.org, tglx@linutronix.de,
	gratian.crisan@ni.com, peterz@infradead.org
Subject: [tip:core/urgent] futex: Fix more put_pi_state() vs. exit_pi_state_list() races
Date: Wed, 1 Nov 2017 01:09:55 -0700	[thread overview]
Message-ID: <tip-153fbd1226fb30b8630802aa5047b8af5ef53c9f@git.kernel.org> (raw)
In-Reply-To: <20171031101853.xpfh72y643kdfhjs@hirez.programming.kicks-ass.net>

Commit-ID:  153fbd1226fb30b8630802aa5047b8af5ef53c9f
Gitweb:     https://git.kernel.org/tip/153fbd1226fb30b8630802aa5047b8af5ef53c9f
Author:     Peter Zijlstra <peterz@infradead.org>
AuthorDate: Tue, 31 Oct 2017 11:18:53 +0100
Committer:  Ingo Molnar <mingo@kernel.org>
CommitDate: Wed, 1 Nov 2017 09:05:00 +0100

futex: Fix more put_pi_state() vs. exit_pi_state_list() races

Dmitry (through syzbot) reported being able to trigger the WARN in
get_pi_state() and a use-after-free on:

	raw_spin_lock_irq(&pi_state->pi_mutex.wait_lock);

Both are due to this race:

  exit_pi_state_list()				put_pi_state()

  lock(&curr->pi_lock)
  while() {
	pi_state = list_first_entry(head);
	hb = hash_futex(&pi_state->key);
	unlock(&curr->pi_lock);

						dec_and_test(&pi_state->refcount);

	lock(&hb->lock)
	lock(&pi_state->pi_mutex.wait_lock)	// uaf if pi_state free'd
	lock(&curr->pi_lock);

	....

	unlock(&curr->pi_lock);
	get_pi_state();				// WARN; refcount==0

The problem is we take the reference count too late, and don't allow it
being 0. Fix it by using inc_not_zero() and simply retrying the loop
when we fail to get a refcount. In that case put_pi_state() should
remove the entry from the list.

Reported-by: Dmitry Vyukov <dvyukov@google.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Gratian Crisan <gratian.crisan@ni.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: dvhart@infradead.org
Cc: syzbot <bot+2af19c9e1ffe4d4ee1d16c56ae7580feaee75765@syzkaller.appspotmail.com>
Cc: syzkaller-bugs@googlegroups.com
Cc: <stable@vger.kernel.org>
Fixes: c74aef2d06a9 ("futex: Fix pi_state->owner serialization")
Link: http://lkml.kernel.org/r/20171031101853.xpfh72y643kdfhjs@hirez.programming.kicks-ass.net
Signed-off-by: Ingo Molnar <mingo@kernel.org>
---
 kernel/futex.c | 23 ++++++++++++++++++++---
 1 file changed, 20 insertions(+), 3 deletions(-)

diff --git a/kernel/futex.c b/kernel/futex.c
index 0518a0b..ca5bb9c 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -903,11 +903,27 @@ void exit_pi_state_list(struct task_struct *curr)
 	 */
 	raw_spin_lock_irq(&curr->pi_lock);
 	while (!list_empty(head)) {
-
 		next = head->next;
 		pi_state = list_entry(next, struct futex_pi_state, list);
 		key = pi_state->key;
 		hb = hash_futex(&key);
+
+		/*
+		 * We can race against put_pi_state() removing itself from the
+		 * list (a waiter going away). put_pi_state() will first
+		 * decrement the reference count and then modify the list, so
+		 * its possible to see the list entry but fail this reference
+		 * acquire.
+		 *
+		 * In that case; drop the locks to let put_pi_state() make
+		 * progress and retry the loop.
+		 */
+		if (!atomic_inc_not_zero(&pi_state->refcount)) {
+			raw_spin_unlock_irq(&curr->pi_lock);
+			cpu_relax();
+			raw_spin_lock_irq(&curr->pi_lock);
+			continue;
+		}
 		raw_spin_unlock_irq(&curr->pi_lock);
 
 		spin_lock(&hb->lock);
@@ -918,8 +934,10 @@ void exit_pi_state_list(struct task_struct *curr)
 		 * task still owns the PI-state:
 		 */
 		if (head->next != next) {
+			/* retain curr->pi_lock for the loop invariant */
 			raw_spin_unlock(&pi_state->pi_mutex.wait_lock);
 			spin_unlock(&hb->lock);
+			put_pi_state(pi_state);
 			continue;
 		}
 
@@ -927,9 +945,8 @@ void exit_pi_state_list(struct task_struct *curr)
 		WARN_ON(list_empty(&pi_state->list));
 		list_del_init(&pi_state->list);
 		pi_state->owner = NULL;
-		raw_spin_unlock(&curr->pi_lock);
 
-		get_pi_state(pi_state);
+		raw_spin_unlock(&curr->pi_lock);
 		raw_spin_unlock_irq(&pi_state->pi_mutex.wait_lock);
 		spin_unlock(&hb->lock);
 

  parent reply	other threads:[~2017-11-01  8:15 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-10-30 19:44 WARNING in get_pi_state syzbot
2017-10-30 19:53 ` Dmitry Vyukov
2017-10-31  8:36 ` Peter Zijlstra
2017-10-31 10:18   ` Peter Zijlstra
2017-10-31 10:31     ` Peter Zijlstra
2017-10-31 10:38       ` Peter Zijlstra
2017-11-01  8:45         ` Peter Zijlstra
2017-11-07 16:16         ` Dmitry Vyukov
2017-10-31 12:06     ` [tip:core/urgent] futex: Fix more put_pi_state() vs. exit_pi_state_list() races tip-bot for Peter Zijlstra
2017-10-31 22:11       ` Thomas Gleixner
2017-11-01  8:05         ` Ingo Molnar
2017-11-01  8:09     ` tip-bot for Peter Zijlstra [this message]
2017-10-31  9:16 ` WARNING in get_pi_state Peter Zijlstra
2017-10-31  9:29   ` Dmitry Vyukov
2017-10-31 10:08     ` Peter Zijlstra
2017-10-31 10:21       ` Dmitry Vyukov
2017-10-31 10:23         ` Dmitry Vyukov
2017-10-31 10:36           ` Peter Zijlstra
2017-11-07 14:50       ` Dmitry Vyukov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=tip-153fbd1226fb30b8630802aa5047b8af5ef53c9f@git.kernel.org \
    --to=tipbot@zytor.com \
    --cc=bot+2af19c9e1ffe4d4ee1d16c56ae7580feaee75765@syzkaller.appspotmail.com \
    --cc=dvyukov@google.com \
    --cc=gratian.crisan@ni.com \
    --cc=hpa@zytor.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-tip-commits@vger.kernel.org \
    --cc=mingo@kernel.org \
    --cc=peterz@infradead.org \
    --cc=stable@vger.kernel.org \
    --cc=tglx@linutronix.de \
    --cc=torvalds@linux-foundation.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.