Skip to content

Commit

Permalink
futex: Ensure the correct return value from futex_lock_pi()
Browse files Browse the repository at this point in the history
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: c1e2f0e ("futex: Avoid violating the 10th rule of futex")
Signed-off-by: Thomas Gleixner <[email protected]>
Acked-by: Peter Zijlstra (Intel) <[email protected]>
Cc: [email protected]
  • Loading branch information
KAGA-KOKO committed Jan 26, 2021
1 parent 13391c6 commit 12bb3f7
Showing 1 changed file with 16 additions and 15 deletions.
31 changes: 16 additions & 15 deletions kernel/futex.c
Original file line number Diff line number Diff line change
Expand Up @@ -2373,8 +2373,8 @@ 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. */
ret = 0;
/* We got the lock. pi_state is correct. Tell caller. */
ret = 1;
goto out_unlock;
}

Expand Down Expand Up @@ -2402,7 +2402,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 = 0;
ret = 1;
goto out_unlock;
}
newowner = argowner;
Expand Down Expand Up @@ -2448,7 +2448,7 @@ static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q,
raw_spin_unlock(&newowner->pi_lock);
raw_spin_unlock_irq(&pi_state->pi_mutex.wait_lock);

return 0;
return argowner == current;

/*
* In order to reschedule or handle a page fault, we need to drop the
Expand Down Expand Up @@ -2490,7 +2490,7 @@ 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 = 0;
ret = argowner == current;
goto out_unlock;
}

Expand Down Expand Up @@ -2523,8 +2523,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
Expand All @@ -2535,8 +2533,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);
return ret ? ret : locked;
return fixup_pi_state_owner(uaddr, q, current);
return 1;
}

/*
Expand All @@ -2547,10 +2545,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);
return ret;
}
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
Expand All @@ -2563,7 +2559,7 @@ static int fixup_owner(u32 __user *uaddr, struct futex_q *q, int locked)
q->pi_state->owner);
}

return ret;
return 0;
}

/**
Expand Down Expand Up @@ -3261,7 +3257,7 @@ 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 && rt_mutex_owner(&q.pi_state->pi_mutex) == current) {
if (ret < 0 && rt_mutex_owner(&q.pi_state->pi_mutex) == current) {
pi_state = q.pi_state;
get_pi_state(pi_state);
}
Expand All @@ -3271,6 +3267,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;
Expand Down

0 comments on commit 12bb3f7

Please sign in to comment.