mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Michal Hocko <mhocko@suse.cz>
To: Ingo Molnar <mingo@elte.hu>
Cc: Darren Hart <dvhltc@us.ibm.com>,
	Thomas Gleixner <tglx@linutronix.de>,
	LKML <linux-kernel@vger.kernel.org>,
	Nick Piggin <npiggin@suse.de>,
	Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>,
	Linus Torvalds <torvalds@linux-foundation.org>,
	Peter Zijlstra <peterz@infradead.org>
Subject: [PATCH] futex: futex_find_get_task make credentials check conditional
Date: Tue, 29 Jun 2010 10:42:30 +0200	[thread overview]
Message-ID: <20100629084230.GE6215@tiehlicka.suse.cz> (raw)
In-Reply-To: <1277743748.3561.139.camel@laptop>

On Mon 28-06-10 18:49:08, Peter Zijlstra wrote:
> On Mon, 2010-06-28 at 18:39 +0200, Michal Hocko wrote:
> > Would something like the following be acceptable (just a compile
> > tested without comments). It simply makes caller of lookup_pi_state to
> > decide whether credentials should be checked.
> 
> So it was Ingo, who in c87e2837be8 (pi-futex:
> futex_lock_pi/futex_unlock_pi support) introduced the euid checks:
> 
> +futex_find_get_task():
> +       if ((current->euid != p->euid) && (current->euid != p->uid)) {
> +               p = NULL;
> +               goto out_unlock;
> +       }
> 
> Ingo, do you remember the rationale behind that? It seems to be causing
> grief when two different users contend on the same (shared) futex.
> 
> See the below proposed solution.

Here is the patch with comments and rationale:
(reference to the original discussion: http://lkml.org/lkml/2010/6/23/52)

--
>From f477a6d989dfde11c5bb5f28d5ce21d0682f4e25 Mon Sep 17 00:00:00 2001
From: Michal Hocko <mhocko@suse.cz>
Date: Tue, 29 Jun 2010 10:02:58 +0200
Subject: [PATCH] futex: futex_find_get_task make credentials check conditional

futex_find_get_task is currently used (through lookup_pi_state) from two
contexts, futex_requeue and futex_lock_pi_atomic. While credentials check
makes sense in the first code path, the second one is more problematic
because this check requires that the PI lock holder (pid parameter) has
the same uid and euid as the process's euid which is trying to lock the
same futex (current).

This results in glibc assert failure or process hang (if glibc is
compiled without assert support) for shared robust pthread mutex with
priority inheritance if a process tries to lock already held lock owned
by a process with a different euid:

pthread_mutex_lock.c:312: __pthread_mutex_lock_full: Assertion `(-(e)) != 3 || !robust' failed.

The problem is that futex_lock_pi_atomic which is called when we try to
lock already held lock checks the current holder (tid is stored in the
futex value) to get the PI state. It uses lookup_pi_state which in turn
gets task struct from futex_find_get_task. ESRCH is returned either when
the task is not found or if credentials check fails.
futex_lock_pi_atomic simply returns if it gets ESRCH. glibc code,
however,  doesn't expect that robust lock returns with ESRCH because it
should get either success or owner died.

Let's make credentials check conditional (as a new parameter) in
futex_find_get_task. Then we can prevent from check in the pi lock path
and still preserve it in the futex_requeue path.

Signed-off-by: Michal Hocko <mhocko@suse.cz>
---
 kernel/futex.c |   24 +++++++++++++++---------
 1 files changed, 15 insertions(+), 9 deletions(-)

diff --git a/kernel/futex.c b/kernel/futex.c
index e7a35f1..79b69e5 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -425,8 +425,9 @@ static void free_pi_state(struct futex_pi_state *pi_state)
 /*
  * Look up the task based on what TID userspace gave us.
  * We dont trust it.
+ * Check the credentials if required by check_cred
  */
-static struct task_struct * futex_find_get_task(pid_t pid)
+static struct task_struct * futex_find_get_task(pid_t pid, bool check_cred)
 {
 	struct task_struct *p;
 	const struct cred *cred = current_cred(), *pcred;
@@ -436,10 +437,12 @@ static struct task_struct * futex_find_get_task(pid_t pid)
 	if (!p) {
 		p = ERR_PTR(-ESRCH);
 	} else {
-		pcred = __task_cred(p);
-		if (cred->euid != pcred->euid &&
-		    cred->euid != pcred->uid)
-			p = ERR_PTR(-ESRCH);
+		if (check_cred) {
+			pcred = __task_cred(p);
+			if (cred->euid != pcred->euid &&
+			    cred->euid != pcred->uid)
+				p = ERR_PTR(-ESRCH);
+		}
 		else
 			get_task_struct(p);
 	}
@@ -504,9 +507,10 @@ void exit_pi_state_list(struct task_struct *curr)
 	raw_spin_unlock_irq(&curr->pi_lock);
 }
 
+/* check_cred is just passed through to futex_find_get_task */
 static int
 lookup_pi_state(u32 uval, struct futex_hash_bucket *hb,
-		union futex_key *key, struct futex_pi_state **ps)
+		union futex_key *key, struct futex_pi_state **ps, bool check_cred)
 {
 	struct futex_pi_state *pi_state = NULL;
 	struct futex_q *this, *next;
@@ -563,7 +567,7 @@ lookup_pi_state(u32 uval, struct futex_hash_bucket *hb,
 	 */
 	if (!pid)
 		return -ESRCH;
-	p = futex_find_get_task(pid);
+	p = futex_find_get_task(pid, check_cred);
 	if (IS_ERR(p))
 		return PTR_ERR(p);
 
@@ -704,8 +708,10 @@ retry:
 	/*
 	 * We dont have the lock. Look up the PI state (or create it if
 	 * we are the first waiter):
+	 * Do not ask for credentials check because we want to share the
+	 * lock between processes with different (e)uids
 	 */
-	ret = lookup_pi_state(uval, hb, key, ps);
+	ret = lookup_pi_state(uval, hb, key, ps, false);
 
 	if (unlikely(ret)) {
 		switch (ret) {
@@ -1258,7 +1264,7 @@ retry_private:
 			ret = get_futex_value_locked(&curval2, uaddr2);
 			if (!ret)
 				ret = lookup_pi_state(curval2, hb2, &key2,
-						      &pi_state);
+						      &pi_state, true);
 		}
 
 		switch (ret) {
-- 
1.7.1


-- 
Michal Hocko
L3 team 
SUSE LINUX s.r.o.
Lihovarska 1060/12
190 00 Praha 9    
Czech Republic

  reply	other threads:[~2010-06-29  8:42 UTC|newest]

Thread overview: 28+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-06-23  9:13 futex: race in lock and unlock&exit for robust futex with PI? Michal Hocko
2010-06-25  2:42 ` Darren Hart
2010-06-25  8:27   ` Michal Hocko
2010-06-25 17:53     ` Darren Hart
2010-06-25 23:35       ` Darren Hart
2010-06-28 14:42         ` Michal Hocko
2010-06-28 14:56           ` Darren Hart
2010-06-28 15:32           ` Michal Hocko
2010-06-28 15:40             ` Michal Hocko
2010-06-28 15:58             ` Michal Hocko
2010-06-28 16:39               ` Michal Hocko
2010-06-28 16:45                 ` Peter Zijlstra
2010-06-28 16:56                   ` Michal Hocko
2010-06-28 16:49                 ` Peter Zijlstra
2010-06-29  8:42                   ` Michal Hocko [this message]
2010-06-29 14:56                     ` [PATCH] futex: futex_find_get_task make credentials check conditional Darren Hart
2010-06-29 15:24                       ` Michal Hocko
2010-06-29 16:41                     ` Linus Torvalds
2010-06-29 16:58                       ` Darren Hart
2010-06-29 18:03                         ` Thomas Gleixner
2010-06-30  7:01                       ` Michal Hocko
2010-06-30  9:55                         ` [PATCH] futex: futex_find_get_task remove credentails check Michal Hocko
2010-06-30 16:43                           ` Darren Hart
2010-07-08  9:28                             ` Michal Hocko
2010-07-08  9:32                               ` Ingo Molnar
2010-07-08  9:39                                 ` Michal Hocko
2010-07-08  9:43                                   ` Peter Zijlstra
2010-07-08  9:50                                     ` Michal Hocko

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=20100629084230.GE6215@tiehlicka.suse.cz \
    --to=mhocko@suse.cz \
    --cc=dvhltc@us.ibm.com \
    --cc=kuznet@ms2.inr.ac.ru \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mingo@elte.hu \
    --cc=npiggin@suse.de \
    --cc=peterz@infradead.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®