|
@@ -745,7 +745,8 @@ void exit_pi_state_list(struct task_struct *curr)
|
|
|
|
|
|
static int
|
|
|
lookup_pi_state(u32 uval, struct futex_hash_bucket *hb,
|
|
|
- union futex_key *key, struct futex_pi_state **ps)
|
|
|
+ union futex_key *key, struct futex_pi_state **ps,
|
|
|
+ struct task_struct *task)
|
|
|
{
|
|
|
struct futex_pi_state *pi_state = NULL;
|
|
|
struct futex_q *this, *next;
|
|
@@ -786,6 +787,16 @@ lookup_pi_state(u32 uval, struct futex_hash_bucket *hb,
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
|
+ /*
|
|
|
+ * Protect against a corrupted uval. If uval
|
|
|
+ * is 0x80000000 then pid is 0 and the waiter
|
|
|
+ * bit is set. So the deadlock check in the
|
|
|
+ * calling code has failed and we did not fall
|
|
|
+ * into the check above due to !pid.
|
|
|
+ */
|
|
|
+ if (task && pi_state->owner == task)
|
|
|
+ return -EDEADLK;
|
|
|
+
|
|
|
atomic_inc(&pi_state->refcount);
|
|
|
*ps = pi_state;
|
|
|
|
|
@@ -935,7 +946,7 @@ retry:
|
|
|
* We dont have the lock. Look up the PI state (or create it if
|
|
|
* we are the first waiter):
|
|
|
*/
|
|
|
- ret = lookup_pi_state(uval, hb, key, ps);
|
|
|
+ ret = lookup_pi_state(uval, hb, key, ps, task);
|
|
|
|
|
|
if (unlikely(ret)) {
|
|
|
switch (ret) {
|
|
@@ -1347,7 +1358,7 @@ void requeue_pi_wake_futex(struct futex_q *q, union futex_key *key,
|
|
|
*
|
|
|
* Return:
|
|
|
* 0 - failed to acquire the lock atomically;
|
|
|
- * 1 - acquired the lock;
|
|
|
+ * >0 - acquired the lock, return value is vpid of the top_waiter
|
|
|
* <0 - error
|
|
|
*/
|
|
|
static int futex_proxy_trylock_atomic(u32 __user *pifutex,
|
|
@@ -1358,7 +1369,7 @@ static int futex_proxy_trylock_atomic(u32 __user *pifutex,
|
|
|
{
|
|
|
struct futex_q *top_waiter = NULL;
|
|
|
u32 curval;
|
|
|
- int ret;
|
|
|
+ int ret, vpid;
|
|
|
|
|
|
if (get_futex_value_locked(&curval, pifutex))
|
|
|
return -EFAULT;
|
|
@@ -1386,11 +1397,13 @@ static int futex_proxy_trylock_atomic(u32 __user *pifutex,
|
|
|
* the contended case or if set_waiters is 1. The pi_state is returned
|
|
|
* in ps in contended cases.
|
|
|
*/
|
|
|
+ vpid = task_pid_vnr(top_waiter->task);
|
|
|
ret = futex_lock_pi_atomic(pifutex, hb2, key2, ps, top_waiter->task,
|
|
|
set_waiters);
|
|
|
- if (ret == 1)
|
|
|
+ if (ret == 1) {
|
|
|
requeue_pi_wake_futex(top_waiter, key2, hb2);
|
|
|
-
|
|
|
+ return vpid;
|
|
|
+ }
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
@@ -1421,7 +1434,6 @@ static int futex_requeue(u32 __user *uaddr1, unsigned int flags,
|
|
|
struct futex_pi_state *pi_state = NULL;
|
|
|
struct futex_hash_bucket *hb1, *hb2;
|
|
|
struct futex_q *this, *next;
|
|
|
- u32 curval2;
|
|
|
|
|
|
if (requeue_pi) {
|
|
|
/*
|
|
@@ -1509,16 +1521,25 @@ retry_private:
|
|
|
* At this point the top_waiter has either taken uaddr2 or is
|
|
|
* waiting on it. If the former, then the pi_state will not
|
|
|
* exist yet, look it up one more time to ensure we have a
|
|
|
- * reference to it.
|
|
|
+ * reference to it. If the lock was taken, ret contains the
|
|
|
+ * vpid of the top waiter task.
|
|
|
*/
|
|
|
- if (ret == 1) {
|
|
|
+ if (ret > 0) {
|
|
|
WARN_ON(pi_state);
|
|
|
drop_count++;
|
|
|
task_count++;
|
|
|
- ret = get_futex_value_locked(&curval2, uaddr2);
|
|
|
- if (!ret)
|
|
|
- ret = lookup_pi_state(curval2, hb2, &key2,
|
|
|
- &pi_state);
|
|
|
+ /*
|
|
|
+ * If we acquired the lock, then the user
|
|
|
+ * space value of uaddr2 should be vpid. It
|
|
|
+ * cannot be changed by the top waiter as it
|
|
|
+ * is blocked on hb2 lock if it tries to do
|
|
|
+ * so. If something fiddled with it behind our
|
|
|
+ * back the pi state lookup might unearth
|
|
|
+ * it. So we rather use the known value than
|
|
|
+ * rereading and handing potential crap to
|
|
|
+ * lookup_pi_state.
|
|
|
+ */
|
|
|
+ ret = lookup_pi_state(ret, hb2, &key2, &pi_state, NULL);
|
|
|
}
|
|
|
|
|
|
switch (ret) {
|