| [2557] | 1 | From 9ad5dabd87e8dd5506529e12e4e8c7b25fb88d7a Mon Sep 17 00:00:00 2001 | 
|---|
 | 2 | From: Thomas Gleixner <tglx@linutronix.de> | 
|---|
 | 3 | Date: Tue, 3 Jun 2014 12:27:07 +0000 | 
|---|
 | 4 | Subject: [PATCH 3/4] futex: Always cleanup owner tid in unlock_pi | 
|---|
 | 5 |  | 
|---|
 | 6 | commit 13fbca4c6ecd96ec1a1cfa2e4f2ce191fe928a5e upstream. | 
|---|
 | 7 |  | 
|---|
 | 8 | If the owner died bit is set at futex_unlock_pi, we currently do not | 
|---|
 | 9 | cleanup the user space futex.  So the owner TID of the current owner | 
|---|
 | 10 | (the unlocker) persists.  That's observable inconsistant state, | 
|---|
 | 11 | especially when the ownership of the pi state got transferred. | 
|---|
 | 12 |  | 
|---|
 | 13 | Clean it up unconditionally. | 
|---|
 | 14 |  | 
|---|
 | 15 | Signed-off-by: Thomas Gleixner <tglx@linutronix.de> | 
|---|
 | 16 | Cc: Kees Cook <keescook@chromium.org> | 
|---|
 | 17 | Cc: Will Drewry <wad@chromium.org> | 
|---|
 | 18 | Cc: Darren Hart <dvhart@linux.intel.com> | 
|---|
 | 19 | Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> | 
|---|
 | 20 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 
|---|
 | 21 | --- | 
|---|
 | 22 |  kernel/futex.c |   40 ++++++++++++++++++---------------------- | 
|---|
 | 23 |  1 file changed, 18 insertions(+), 22 deletions(-) | 
|---|
 | 24 |  | 
|---|
 | 25 | diff --git a/kernel/futex.c b/kernel/futex.c | 
|---|
 | 26 | index 8c1e6d0..9720c42 100644 | 
|---|
 | 27 | --- a/kernel/futex.c | 
|---|
 | 28 | +++ b/kernel/futex.c | 
|---|
 | 29 | @@ -903,6 +903,7 @@ static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_q *this) | 
|---|
 | 30 |         struct task_struct *new_owner; | 
|---|
 | 31 |         struct futex_pi_state *pi_state = this->pi_state; | 
|---|
 | 32 |         u32 uninitialized_var(curval), newval; | 
|---|
 | 33 | +       int ret = 0; | 
|---|
 | 34 |   | 
|---|
 | 35 |         if (!pi_state) | 
|---|
 | 36 |                 return -EINVAL; | 
|---|
 | 37 | @@ -926,23 +927,19 @@ static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_q *this) | 
|---|
 | 38 |                 new_owner = this->task; | 
|---|
 | 39 |   | 
|---|
 | 40 |         /* | 
|---|
 | 41 | -        * We pass it to the next owner. (The WAITERS bit is always | 
|---|
 | 42 | -        * kept enabled while there is PI state around. We must also | 
|---|
 | 43 | -        * preserve the owner died bit.) | 
|---|
 | 44 | +        * We pass it to the next owner. The WAITERS bit is always | 
|---|
 | 45 | +        * kept enabled while there is PI state around. We cleanup the | 
|---|
 | 46 | +        * owner died bit, because we are the owner. | 
|---|
 | 47 |          */ | 
|---|
 | 48 | -       if (!(uval & FUTEX_OWNER_DIED)) { | 
|---|
 | 49 | -               int ret = 0; | 
|---|
 | 50 | - | 
|---|
 | 51 | -               newval = FUTEX_WAITERS | task_pid_vnr(new_owner); | 
|---|
 | 52 | +       newval = FUTEX_WAITERS | task_pid_vnr(new_owner); | 
|---|
 | 53 |   | 
|---|
 | 54 | -               if (cmpxchg_futex_value_locked(&curval, uaddr, uval, newval)) | 
|---|
 | 55 | -                       ret = -EFAULT; | 
|---|
 | 56 | -               else if (curval != uval) | 
|---|
 | 57 | -                       ret = -EINVAL; | 
|---|
 | 58 | -               if (ret) { | 
|---|
 | 59 | -                       raw_spin_unlock(&pi_state->pi_mutex.wait_lock); | 
|---|
 | 60 | -                       return ret; | 
|---|
 | 61 | -               } | 
|---|
 | 62 | +       if (cmpxchg_futex_value_locked(&curval, uaddr, uval, newval)) | 
|---|
 | 63 | +               ret = -EFAULT; | 
|---|
 | 64 | +       else if (curval != uval) | 
|---|
 | 65 | +               ret = -EINVAL; | 
|---|
 | 66 | +       if (ret) { | 
|---|
 | 67 | +               raw_spin_unlock(&pi_state->pi_mutex.wait_lock); | 
|---|
 | 68 | +               return ret; | 
|---|
 | 69 |         } | 
|---|
 | 70 |   | 
|---|
 | 71 |         raw_spin_lock_irq(&pi_state->owner->pi_lock); | 
|---|
 | 72 | @@ -2187,9 +2184,10 @@ retry: | 
|---|
 | 73 |         /* | 
|---|
 | 74 |          * To avoid races, try to do the TID -> 0 atomic transition | 
|---|
 | 75 |          * again. If it succeeds then we can return without waking | 
|---|
 | 76 | -        * anyone else up: | 
|---|
 | 77 | +        * anyone else up. We only try this if neither the waiters nor | 
|---|
 | 78 | +        * the owner died bit are set. | 
|---|
 | 79 |          */ | 
|---|
 | 80 | -       if (!(uval & FUTEX_OWNER_DIED) && | 
|---|
 | 81 | +       if (!(uval & ~FUTEX_TID_MASK) && | 
|---|
 | 82 |             cmpxchg_futex_value_locked(&uval, uaddr, vpid, 0)) | 
|---|
 | 83 |                 goto pi_faulted; | 
|---|
 | 84 |         /* | 
|---|
 | 85 | @@ -2221,11 +2219,9 @@ retry: | 
|---|
 | 86 |         /* | 
|---|
 | 87 |          * No waiters - kernel unlocks the futex: | 
|---|
 | 88 |          */ | 
|---|
 | 89 | -       if (!(uval & FUTEX_OWNER_DIED)) { | 
|---|
 | 90 | -               ret = unlock_futex_pi(uaddr, uval); | 
|---|
 | 91 | -               if (ret == -EFAULT) | 
|---|
 | 92 | -                       goto pi_faulted; | 
|---|
 | 93 | -       } | 
|---|
 | 94 | +       ret = unlock_futex_pi(uaddr, uval); | 
|---|
 | 95 | +       if (ret == -EFAULT) | 
|---|
 | 96 | +               goto pi_faulted; | 
|---|
 | 97 |   | 
|---|
 | 98 |  out_unlock: | 
|---|
 | 99 |         spin_unlock(&hb->lock); | 
|---|
 | 100 | --  | 
|---|
 | 101 | 1.7.10.4 | 
|---|
 | 102 |  | 
|---|