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

Commit ad8fdbab authored by Thomas Gleixner's avatar Thomas Gleixner Committed by Greg Kroah-Hartman
Browse files

futex: Ensure the correct return value from futex_lock_pi()



commit 12bb3f7f1b03d5913b3f9d4236a488aa7774dfe9 upstream

In case that futex_lock_pi() was aborted by a signal or a timeout and the
task returned without acquiring the rtmutex, but is the designated owner of
the futex due to a concurrent futex_unlock_pi() fixup_owner() is invoked to
establish consistent state. In that case it invokes fixup_pi_state_owner()
which in turn tries to acquire the rtmutex again. If that succeeds then it
does not propagate this success to fixup_owner() and futex_lock_pi()
returns -EINTR or -ETIMEOUT despite having the futex locked.

Return success from fixup_pi_state_owner() in all cases where the current
task owns the rtmutex and therefore the futex and propagate it correctly
through fixup_owner(). Fixup the other callsite which does not expect a
positive return value.

Fixes: c1e2f0eaf015 ("futex: Avoid violating the 10th rule of futex")
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
Acked-by: default avatarPeter Zijlstra (Intel) <peterz@infradead.org>
Cc: stable@vger.kernel.org
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
[Lee: Back-ported in support of a previous futex attempt]
Signed-off-by: default avatarLee Jones <lee.jones@linaro.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent aff82146
Loading
Loading
Loading
Loading
+12 −12
Original line number Diff line number Diff line
@@ -2322,7 +2322,7 @@ static int __fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q,
		}

		if (__rt_mutex_futex_trylock(&pi_state->pi_mutex)) {
			/* We got the lock after all, nothing to fix. */
			/* We got the lock. pi_state is correct. Tell caller. */
			return 1;
		}

@@ -2364,7 +2364,7 @@ static int __fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q,
	 */
	pi_state_update_owner(pi_state, newowner);

	return 0;
	return argowner == current;

	/*
	 * To handle the page fault we need to drop the hash bucket
@@ -2447,8 +2447,6 @@ static long futex_wait_restart(struct restart_block *restart);
 */
static int fixup_owner(u32 __user *uaddr, struct futex_q *q, int locked)
{
	int ret = 0;

	if (locked) {
		/*
		 * Got the lock. We might not be the anticipated owner if we
@@ -2459,8 +2457,8 @@ static int fixup_owner(u32 __user *uaddr, struct futex_q *q, int locked)
		 * stable state, anything else needs more attention.
		 */
		if (q->pi_state->owner != current)
			ret = fixup_pi_state_owner(uaddr, q, current);
		goto out;
			return fixup_pi_state_owner(uaddr, q, current);
		return 1;
	}

	/*
@@ -2471,10 +2469,8 @@ static int fixup_owner(u32 __user *uaddr, struct futex_q *q, int locked)
	 * Another speculative read; pi_state->owner == current is unstable
	 * but needs our attention.
	 */
	if (q->pi_state->owner == current) {
		ret = fixup_pi_state_owner(uaddr, q, NULL);
		goto out;
	}
	if (q->pi_state->owner == current)
		return fixup_pi_state_owner(uaddr, q, NULL);

	/*
	 * Paranoia check. If we did not take the lock, then we should not be
@@ -2483,8 +2479,7 @@ static int fixup_owner(u32 __user *uaddr, struct futex_q *q, int locked)
	if (WARN_ON_ONCE(rt_mutex_owner(&q->pi_state->pi_mutex) == current))
		return fixup_pi_state_owner(uaddr, q, current);

out:
	return ret ? ret : locked;
	return 0;
}

/**
@@ -3106,6 +3101,11 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
			 */
			put_pi_state(q.pi_state);
			spin_unlock(q.lock_ptr);
			/*
			 * Adjust the return value. It's either -EFAULT or
			 * success (1) but the caller expects 0 for success.
			 */
			ret = ret < 0 ? ret : 0;
		}
	} else {
		struct rt_mutex *pi_mutex;