futex: Split out the waiter check from lookup_pi_state()
upstream commit: e60cbc5cea
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>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
This commit is contained in:
parent
9e62263a76
commit
16268bd779
154
kernel/futex.c
154
kernel/futex.c
|
@ -782,6 +782,79 @@ 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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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)
|
||||||
|
{
|
||||||
|
pid_t pid = uval & FUTEX_TID_MASK;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Userspace might have messed up non-PI and PI futexes [3]
|
||||||
|
*/
|
||||||
|
if (unlikely(!pi_state))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
WARN_ON(!atomic_read(&pi_state->refcount));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Handle the owner died case:
|
||||||
|
*/
|
||||||
|
if (uval & FUTEX_OWNER_DIED) {
|
||||||
|
/*
|
||||||
|
* exit_pi_state_list sets owner to NULL and wakes the
|
||||||
|
* topmost waiter. The task which acquires the
|
||||||
|
* pi_state->rt_mutex will fixup owner.
|
||||||
|
*/
|
||||||
|
if (!pi_state->owner) {
|
||||||
|
/*
|
||||||
|
* No pi state owner, but the user space TID
|
||||||
|
* is not 0. Inconsistent state. [5]
|
||||||
|
*/
|
||||||
|
if (pid)
|
||||||
|
return -EINVAL;
|
||||||
|
/*
|
||||||
|
* Take a ref on the state and return success. [4]
|
||||||
|
*/
|
||||||
|
goto out_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If TID is 0, then either the dying owner has not
|
||||||
|
* yet executed exit_pi_state_list() or some waiter
|
||||||
|
* acquired the rtmutex in the pi state, but did not
|
||||||
|
* yet fixup the TID in user space.
|
||||||
|
*
|
||||||
|
* Take a ref on the state and return success. [6]
|
||||||
|
*/
|
||||||
|
if (!pid)
|
||||||
|
goto out_state;
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* If the owner died bit is not set, then the pi_state
|
||||||
|
* must have an owner. [7]
|
||||||
|
*/
|
||||||
|
if (!pi_state->owner)
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Bail out if user space manipulated the futex value. If pi
|
||||||
|
* state exists then the owner TID must be the same as the
|
||||||
|
* user space TID. [9/10]
|
||||||
|
*/
|
||||||
|
if (pid != task_pid_vnr(pi_state->owner))
|
||||||
|
return -EINVAL;
|
||||||
|
out_state:
|
||||||
|
atomic_inc(&pi_state->refcount);
|
||||||
|
*ps = pi_state;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
lookup_pi_state(u32 uval, struct futex_hash_bucket *hb,
|
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)
|
||||||
|
@ -791,81 +864,12 @@ lookup_pi_state(u32 uval, struct futex_hash_bucket *hb,
|
||||||
struct task_struct *p;
|
struct task_struct *p;
|
||||||
pid_t pid = uval & FUTEX_TID_MASK;
|
pid_t pid = uval & FUTEX_TID_MASK;
|
||||||
|
|
||||||
if (match) {
|
/*
|
||||||
/*
|
* If there is a waiter on that futex, validate it and
|
||||||
* Sanity check the waiter before increasing the
|
* attach to the pi_state when the validation succeeds.
|
||||||
* refcount and attaching to it.
|
*/
|
||||||
*/
|
if (match)
|
||||||
pi_state = match->pi_state;
|
return attach_to_pi_state(uval, match->pi_state, ps);
|
||||||
/*
|
|
||||||
* Userspace might have messed up non-PI and PI
|
|
||||||
* futexes [3]
|
|
||||||
*/
|
|
||||||
if (unlikely(!pi_state))
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
WARN_ON(!atomic_read(&pi_state->refcount));
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Handle the owner died case:
|
|
||||||
*/
|
|
||||||
if (uval & FUTEX_OWNER_DIED) {
|
|
||||||
/*
|
|
||||||
* exit_pi_state_list sets owner to NULL and
|
|
||||||
* wakes the topmost waiter. The task which
|
|
||||||
* acquires the pi_state->rt_mutex will fixup
|
|
||||||
* owner.
|
|
||||||
*/
|
|
||||||
if (!pi_state->owner) {
|
|
||||||
/*
|
|
||||||
* No pi state owner, but the user
|
|
||||||
* space TID is not 0. Inconsistent
|
|
||||||
* state. [5]
|
|
||||||
*/
|
|
||||||
if (pid)
|
|
||||||
return -EINVAL;
|
|
||||||
/*
|
|
||||||
* Take a ref on the state and
|
|
||||||
* return. [4]
|
|
||||||
*/
|
|
||||||
goto out_state;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If TID is 0, then either the dying owner
|
|
||||||
* has not yet executed exit_pi_state_list()
|
|
||||||
* or some waiter acquired the rtmutex in the
|
|
||||||
* pi state, but did not yet fixup the TID in
|
|
||||||
* user space.
|
|
||||||
*
|
|
||||||
* Take a ref on the state and return. [6]
|
|
||||||
*/
|
|
||||||
if (!pid)
|
|
||||||
goto out_state;
|
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
* If the owner died bit is not set,
|
|
||||||
* then the pi_state must have an
|
|
||||||
* owner. [7]
|
|
||||||
*/
|
|
||||||
if (!pi_state->owner)
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Bail out if user space manipulated the
|
|
||||||
* futex value. If pi state exists then the
|
|
||||||
* owner TID must be the same as the user
|
|
||||||
* space TID. [9/10]
|
|
||||||
*/
|
|
||||||
if (pid != task_pid_vnr(pi_state->owner))
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
out_state:
|
|
||||||
atomic_inc(&pi_state->refcount);
|
|
||||||
*ps = pi_state;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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
|
||||||
|
|
Loading…
Reference in New Issue