Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e60cbc5c authored by Thomas Gleixner's avatar Thomas Gleixner
Browse files

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: default avatarThomas Gleixner <tglx@linutronix.de>
Reviewed-by: default avatarDarren 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: default avatarThomas Gleixner <tglx@linutronix.de>
parent bd1dbcc6
Loading
Loading
Loading
Loading
+71 −67
Original line number Diff line number Diff line
@@ -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
 *	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)
{
	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.
 * 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.
 */
		pi_state = match->pi_state;
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]
	 * Userspace might have messed up non-PI and PI futexes [3]
	 */
	if (unlikely(!pi_state))
		return -EINVAL;
@@ -821,62 +816,71 @@ lookup_pi_state(u32 uval, struct futex_hash_bucket *hb,
	 */
	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.
		 * 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]
			 * 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]
			 * 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.
		 * 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]
		 * 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 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]
	 * 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]