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

Commit 9511b8a1 authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "futex: Handle faults correctly for PI futexes"

parents 0942efb2 7c077255
Loading
Loading
Loading
Loading
+46 −63
Original line number Diff line number Diff line
@@ -1032,7 +1032,8 @@ void exit_pi_state_list(struct task_struct *curr)
 *	FUTEX_OWNER_DIED bit. See [4]
 *
 * [10] There is no transient state which leaves owner and user space
 *	TID out of sync.
 *	TID out of sync. Except one error case where the kernel is denied
 *	write access to the user address, see fixup_pi_state_owner().
 *
 *
 * Serialization and lifetime rules:
@@ -2373,18 +2374,13 @@ static void unqueue_me_pi(struct futex_q *q)
	spin_unlock(q->lock_ptr);
}

static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q,
static int __fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q,
				  struct task_struct *argowner)
{
	u32 uval, uninitialized_var(curval), newval, newtid;
	struct futex_pi_state *pi_state = q->pi_state;
	u32 uval, uninitialized_var(curval), newval;
	struct task_struct *oldowner, *newowner;
	u32 newtid;
	int ret, err = 0;

	lockdep_assert_held(q->lock_ptr);

	raw_spin_lock_irq(&pi_state->pi_mutex.wait_lock);
	int err = 0;

	oldowner = pi_state->owner;

@@ -2418,14 +2414,12 @@ static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q,
			 * We raced against a concurrent self; things are
			 * already fixed up. Nothing to do.
			 */
			ret = 0;
			goto out_unlock;
			return 0;
		}

		if (__rt_mutex_futex_trylock(&pi_state->pi_mutex)) {
			/* We got the lock. pi_state is correct. Tell caller. */
			ret = 1;
			goto out_unlock;
			return 1;
		}

		/*
@@ -2452,8 +2446,7 @@ static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q,
			 * We raced against a concurrent self; things are
			 * already fixed up. Nothing to do.
			 */
			ret = 1;
			goto out_unlock;
			return 1;
		}
		newowner = argowner;
	}
@@ -2484,7 +2477,6 @@ static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q,
	 * itself.
	 */
	pi_state_update_owner(pi_state, newowner);
	raw_spin_unlock_irq(&pi_state->pi_mutex.wait_lock);

	return argowner == current;

@@ -2507,17 +2499,16 @@ static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q,

	switch (err) {
	case -EFAULT:
		ret = fault_in_user_writeable(uaddr);
		err = fault_in_user_writeable(uaddr);
		break;

	case -EAGAIN:
		cond_resched();
		ret = 0;
		err = 0;
		break;

	default:
		WARN_ON_ONCE(1);
		ret = err;
		break;
	}

@@ -2527,17 +2518,44 @@ static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q,
	/*
	 * Check if someone else fixed it for us:
	 */
	if (pi_state->owner != oldowner) {
		ret = argowner == current;
		goto out_unlock;
	if (pi_state->owner != oldowner)
		return argowner == current;

	/* Retry if err was -EAGAIN or the fault in succeeded */
	if (!err)
		goto retry;

	/*
	 * fault_in_user_writeable() failed so user state is immutable. At
	 * best we can make the kernel state consistent but user state will
	 * be most likely hosed and any subsequent unlock operation will be
	 * rejected due to PI futex rule [10].
	 *
	 * Ensure that the rtmutex owner is also the pi_state owner despite
	 * the user space value claiming something different. There is no
	 * point in unlocking the rtmutex if current is the owner as it
	 * would need to wait until the next waiter has taken the rtmutex
	 * to guarantee consistent state. Keep it simple. Userspace asked
	 * for this wreckaged state.
	 *
	 * The rtmutex has an owner - either current or some other
	 * task. See the EAGAIN loop above.
	 */
	pi_state_update_owner(pi_state, rt_mutex_owner(&pi_state->pi_mutex));

	return err;
}

	if (ret)
		goto out_unlock;
static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q,
				struct task_struct *argowner)
{
	struct futex_pi_state *pi_state = q->pi_state;
	int ret;

	goto retry;
	lockdep_assert_held(q->lock_ptr);

out_unlock:
	raw_spin_lock_irq(&pi_state->pi_mutex.wait_lock);
	ret = __fixup_pi_state_owner(uaddr, q, argowner);
	raw_spin_unlock_irq(&pi_state->pi_mutex.wait_lock);
	return ret;
}
@@ -2814,7 +2832,6 @@ static int futex_lock_pi(u32 __user *uaddr, unsigned int flags,
			 ktime_t *time, int trylock)
{
	struct hrtimer_sleeper timeout, *to = NULL;
	struct futex_pi_state *pi_state = NULL;
	struct rt_mutex_waiter rt_waiter;
	struct futex_hash_bucket *hb;
	struct futex_q q = futex_q_init;
@@ -2948,23 +2965,9 @@ static int futex_lock_pi(u32 __user *uaddr, unsigned int flags,
	if (res)
		ret = (res < 0) ? res : 0;

	/*
	 * If fixup_owner() faulted and was unable to handle the fault, unlock
	 * it and return the fault to userspace.
	 */
	if (ret && (rt_mutex_owner(&q.pi_state->pi_mutex) == current)) {
		pi_state = q.pi_state;
		get_pi_state(pi_state);
	}

	/* Unqueue and drop the lock */
	unqueue_me_pi(&q);

	if (pi_state) {
		rt_mutex_futex_unlock(&pi_state->pi_mutex);
		put_pi_state(pi_state);
	}

	goto out_put_key;

out_unlock_put_key:
@@ -3230,7 +3233,6 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
				 u32 __user *uaddr2)
{
	struct hrtimer_sleeper timeout, *to = NULL;
	struct futex_pi_state *pi_state = NULL;
	struct rt_mutex_waiter rt_waiter;
	struct futex_hash_bucket *hb;
	union futex_key key2 = FUTEX_KEY_INIT;
@@ -3315,10 +3317,6 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
		if (q.pi_state && (q.pi_state->owner != current)) {
			spin_lock(q.lock_ptr);
			ret = fixup_pi_state_owner(uaddr2, &q, current);
			if (ret < 0 && rt_mutex_owner(&q.pi_state->pi_mutex) == current) {
				pi_state = q.pi_state;
				get_pi_state(pi_state);
			}
			/*
			 * Drop the reference to the pi state which
			 * the requeue_pi() code acquired for us.
@@ -3360,25 +3358,10 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
		if (res)
			ret = (res < 0) ? res : 0;

		/*
		 * If fixup_pi_state_owner() faulted and was unable to handle
		 * the fault, unlock the rt_mutex and return the fault to
		 * userspace.
		 */
		if (ret && rt_mutex_owner(&q.pi_state->pi_mutex) == current) {
			pi_state = q.pi_state;
			get_pi_state(pi_state);
		}

		/* Unqueue and drop the lock. */
		unqueue_me_pi(&q);
	}

	if (pi_state) {
		rt_mutex_futex_unlock(&pi_state->pi_mutex);
		put_pi_state(pi_state);
	}

	if (ret == -EINTR) {
		/*
		 * We've already been requeued, but cannot restart by calling