提交 57839a67 编写于 作者: T Thomas Gleixner 提交者: Yu Changchun

futex: Ensure the correct return value from futex_lock_pi()

stable inclusion
from linux-4.19.172
commit 72f38fffa4758b878f819f8a47761b3f03443f36
category: bugfix
bugzilla: NA
CVE: CVE-2021-3347

--------------------------------

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: c1e2f0ea ("futex: Avoid violating the 10th rule of futex")
Signed-off-by: NThomas Gleixner <tglx@linutronix.de>
Acked-by: NPeter Zijlstra (Intel) <peterz@infradead.org>
Cc: stable@vger.kernel.org
Signed-off-by: NGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: NYang Yingliang <yangyingliang@huawei.com>
Signed-off-by: NYu Changchun <yuchangchun1@huawei.com>
上级 33c42b89
...@@ -2412,8 +2412,8 @@ static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q, ...@@ -2412,8 +2412,8 @@ static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q,
} }
if (__rt_mutex_futex_trylock(&pi_state->pi_mutex)) { 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. */
ret = 0; ret = 1;
goto out_unlock; goto out_unlock;
} }
...@@ -2429,7 +2429,7 @@ static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q, ...@@ -2429,7 +2429,7 @@ static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q,
* We raced against a concurrent self; things are * We raced against a concurrent self; things are
* already fixed up. Nothing to do. * already fixed up. Nothing to do.
*/ */
ret = 0; ret = 1;
goto out_unlock; goto out_unlock;
} }
newowner = argowner; newowner = argowner;
...@@ -2475,7 +2475,7 @@ static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q, ...@@ -2475,7 +2475,7 @@ static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q,
raw_spin_unlock(&newowner->pi_lock); raw_spin_unlock(&newowner->pi_lock);
raw_spin_unlock_irq(&pi_state->pi_mutex.wait_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 * In order to reschedule or handle a page fault, we need to drop the
...@@ -2517,7 +2517,7 @@ static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q, ...@@ -2517,7 +2517,7 @@ static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q,
* Check if someone else fixed it for us: * Check if someone else fixed it for us:
*/ */
if (pi_state->owner != oldowner) { if (pi_state->owner != oldowner) {
ret = 0; ret = argowner == current;
goto out_unlock; goto out_unlock;
} }
...@@ -2550,8 +2550,6 @@ static long futex_wait_restart(struct restart_block *restart); ...@@ -2550,8 +2550,6 @@ static long futex_wait_restart(struct restart_block *restart);
*/ */
static int fixup_owner(u32 __user *uaddr, struct futex_q *q, int locked) static int fixup_owner(u32 __user *uaddr, struct futex_q *q, int locked)
{ {
int ret = 0;
if (locked) { if (locked) {
/* /*
* Got the lock. We might not be the anticipated owner if we * Got the lock. We might not be the anticipated owner if we
...@@ -2562,8 +2560,8 @@ static int fixup_owner(u32 __user *uaddr, struct futex_q *q, int locked) ...@@ -2562,8 +2560,8 @@ static int fixup_owner(u32 __user *uaddr, struct futex_q *q, int locked)
* stable state, anything else needs more attention. * stable state, anything else needs more attention.
*/ */
if (q->pi_state->owner != current) if (q->pi_state->owner != current)
ret = fixup_pi_state_owner(uaddr, q, current); return fixup_pi_state_owner(uaddr, q, current);
goto out; return 1;
} }
/* /*
...@@ -2574,10 +2572,8 @@ static int fixup_owner(u32 __user *uaddr, struct futex_q *q, int locked) ...@@ -2574,10 +2572,8 @@ static int fixup_owner(u32 __user *uaddr, struct futex_q *q, int locked)
* Another speculative read; pi_state->owner == current is unstable * Another speculative read; pi_state->owner == current is unstable
* but needs our attention. * but needs our attention.
*/ */
if (q->pi_state->owner == current) { if (q->pi_state->owner == current)
ret = fixup_pi_state_owner(uaddr, q, NULL); return fixup_pi_state_owner(uaddr, q, NULL);
goto out;
}
/* /*
* Paranoia check. If we did not take the lock, then we should not be * Paranoia check. If we did not take the lock, then we should not be
...@@ -2590,8 +2586,7 @@ static int fixup_owner(u32 __user *uaddr, struct futex_q *q, int locked) ...@@ -2590,8 +2586,7 @@ static int fixup_owner(u32 __user *uaddr, struct futex_q *q, int locked)
q->pi_state->owner); q->pi_state->owner);
} }
out: return 0;
return ret ? ret : locked;
} }
/** /**
...@@ -3313,7 +3308,7 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags, ...@@ -3313,7 +3308,7 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
if (q.pi_state && (q.pi_state->owner != current)) { if (q.pi_state && (q.pi_state->owner != current)) {
spin_lock(q.lock_ptr); spin_lock(q.lock_ptr);
ret = fixup_pi_state_owner(uaddr2, &q, current); 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; pi_state = q.pi_state;
get_pi_state(pi_state); get_pi_state(pi_state);
} }
...@@ -3323,6 +3318,11 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags, ...@@ -3323,6 +3318,11 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
*/ */
put_pi_state(q.pi_state); put_pi_state(q.pi_state);
spin_unlock(q.lock_ptr); 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 { } else {
struct rt_mutex *pi_mutex; struct rt_mutex *pi_mutex;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册