diff options
| author | Thomas Gleixner <tglx@linutronix.de> | 2014-06-11 20:45:39 +0000 | 
|---|---|---|
| committer | Thomas Gleixner <tglx@linutronix.de> | 2014-06-21 22:26:23 +0200 | 
| commit | e60cbc5ceaa518d630ab8f35a7d05cee1c752648 (patch) | |
| tree | 330a6f56058253e8435867f43734d6101b10b30b /kernel | |
| parent | bd1dbcc67cd2c1181e2c01daac51eabf1b964dd8 (diff) | |
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>
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/futex.c | 138 | 
1 files changed, 71 insertions, 67 deletions
| diff --git a/kernel/futex.c b/kernel/futex.c index fff1ed9b1c43..db0c6863e8a3 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -792,92 +792,96 @@ void exit_pi_state_list(struct task_struct *curr)   * [10] There is no transient state which leaves owner and user space   *	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; -	if (match) { -		/* -		 * Sanity check the waiter before increasing the -		 * 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)) -			return -EINVAL; +	/* +	 * Userspace might have messed up non-PI and PI futexes [3] +	 */ +	if (unlikely(!pi_state)) +		return -EINVAL; -		WARN_ON(!atomic_read(&pi_state->refcount)); +	WARN_ON(!atomic_read(&pi_state->refcount)); +	/* +	 * Handle the owner died case: +	 */ +	if (uval & FUTEX_OWNER_DIED) {  		/* -		 * Handle the owner died case: +		 * 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 (uval & FUTEX_OWNER_DIED) { +		if (!pi_state->owner) {  			/* -			 * 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. +			 * No pi state owner, but the user space TID +			 * is not 0. Inconsistent state. [5]  			 */ -			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 (pid) +				return -EINVAL;  			/* -			 * If the owner died bit is not set, -			 * then the pi_state must have an -			 * owner. [7] +			 * Take a ref on the state and return success. [4]  			 */ -			if (!pi_state->owner) -				return -EINVAL; +			goto out_state;  		}  		/* -		 * 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 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 != task_pid_vnr(pi_state->owner)) +		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; - -	out_state: -		atomic_inc(&pi_state->refcount); -		*ps = pi_state; -		return 0;  	}  	/* +	 * 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 +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  	 * the new pi_state to it, but bail out when TID = 0 [1]  	 */ | 
