futex: Split out the waiter check from lookup_pi_state()

We want to be a bit more clever in futex_lock_pi_atomic() and separate
the possible states. Split out the waiter verification into a separate
function. No functional change.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Darren Hart <darren@dvhart.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Davidlohr Bueso <davidlohr@hp.com>
Cc: Kees Cook <kees@outflux.net>
Cc: wad@chromium.org
Link: http://lkml.kernel.org/r/20140611204237.180458410@linutronix.de
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
This commit is contained in:
Thomas Gleixner 2014-06-11 20:45:39 +00:00
parent bd1dbcc67c
commit e60cbc5cea
1 changed files with 79 additions and 75 deletions

View File

@ -792,24 +792,19 @@ void exit_pi_state_list(struct task_struct *curr)
* [10] There is no transient state which leaves owner and user space * [10] There is no transient state which leaves owner and user space
* TID out of sync. * TID out of sync.
*/ */
static int
lookup_pi_state(u32 uval, struct futex_hash_bucket *hb, /*
union futex_key *key, struct futex_pi_state **ps) * Validate that the existing waiter has a pi_state and sanity check
* the pi_state against the user space value. If correct, attach to
* it.
*/
static int attach_to_pi_state(u32 uval, struct futex_pi_state *pi_state,
struct futex_pi_state **ps)
{ {
struct futex_q *match = futex_top_waiter(hb, key);
struct futex_pi_state *pi_state = NULL;
struct task_struct *p;
pid_t pid = uval & FUTEX_TID_MASK; pid_t pid = uval & FUTEX_TID_MASK;
if (match) {
/* /*
* Sanity check the waiter before increasing the * Userspace might have messed up non-PI and PI futexes [3]
* refcount and attaching to it.
*/
pi_state = match->pi_state;
/*
* Userspace might have messed up non-PI and PI
* futexes [3]
*/ */
if (unlikely(!pi_state)) if (unlikely(!pi_state))
return -EINVAL; return -EINVAL;
@ -821,61 +816,70 @@ lookup_pi_state(u32 uval, struct futex_hash_bucket *hb,
*/ */
if (uval & FUTEX_OWNER_DIED) { if (uval & FUTEX_OWNER_DIED) {
/* /*
* exit_pi_state_list sets owner to NULL and * exit_pi_state_list sets owner to NULL and wakes the
* wakes the topmost waiter. The task which * topmost waiter. The task which acquires the
* acquires the pi_state->rt_mutex will fixup * pi_state->rt_mutex will fixup owner.
* owner.
*/ */
if (!pi_state->owner) { if (!pi_state->owner) {
/* /*
* No pi state owner, but the user * No pi state owner, but the user space TID
* space TID is not 0. Inconsistent * is not 0. Inconsistent state. [5]
* state. [5]
*/ */
if (pid) if (pid)
return -EINVAL; return -EINVAL;
/* /*
* Take a ref on the state and * Take a ref on the state and return success. [4]
* return. [4]
*/ */
goto out_state; goto out_state;
} }
/* /*
* If TID is 0, then either the dying owner * If TID is 0, then either the dying owner has not
* has not yet executed exit_pi_state_list() * yet executed exit_pi_state_list() or some waiter
* or some waiter acquired the rtmutex in the * acquired the rtmutex in the pi state, but did not
* pi state, but did not yet fixup the TID in * yet fixup the TID in user space.
* user space.
* *
* Take a ref on the state and return. [6] * Take a ref on the state and return success. [6]
*/ */
if (!pid) if (!pid)
goto out_state; goto out_state;
} else { } else {
/* /*
* If the owner died bit is not set, * If the owner died bit is not set, then the pi_state
* then the pi_state must have an * must have an owner. [7]
* owner. [7]
*/ */
if (!pi_state->owner) if (!pi_state->owner)
return -EINVAL; return -EINVAL;
} }
/* /*
* Bail out if user space manipulated the * Bail out if user space manipulated the futex value. If pi
* futex value. If pi state exists then the * state exists then the owner TID must be the same as the
* owner TID must be the same as the user * user space TID. [9/10]
* space TID. [9/10]
*/ */
if (pid != task_pid_vnr(pi_state->owner)) if (pid != task_pid_vnr(pi_state->owner))
return -EINVAL; return -EINVAL;
out_state:
out_state:
atomic_inc(&pi_state->refcount); atomic_inc(&pi_state->refcount);
*ps = pi_state; *ps = pi_state;
return 0; return 0;
} }
static int
lookup_pi_state(u32 uval, struct futex_hash_bucket *hb,
union futex_key *key, struct futex_pi_state **ps)
{
struct futex_q *match = futex_top_waiter(hb, key);
struct futex_pi_state *pi_state = NULL;
struct task_struct *p;
pid_t pid = uval & FUTEX_TID_MASK;
/*
* If there is a waiter on that futex, validate it and
* attach to the pi_state when the validation succeeds.
*/
if (match)
return attach_to_pi_state(uval, match->pi_state, ps);
/* /*
* We are the first waiter - try to look up the real owner and attach * We are the first waiter - try to look up the real owner and attach