• Thomas Gleixner's avatar
    futex: Make lookup_pi_state more robust · 8b7b2d6b
    Thomas Gleixner authored
    
    
    The current implementation of lookup_pi_state has ambigous handling of
    the TID value 0 in the user space futex. We can get into the kernel
    even if the TID value is 0, because either there is a stale waiters
    bit or the owner died bit is set or we are called from the requeue_pi
    path or from user space just for fun.
    
    The current code avoids an explicit sanity check for pid = 0 in case
    that kernel internal state (waiters) are found for the user space
    address. This can lead to state leakage and worse under some
    circumstances.
    
    Handle the cases explicit:
    
         Waiter | pi_state | pi->owner | uTID      | uODIED | ?
    
    [1]  NULL   | ---      | ---       | 0         | 0/1    | Valid
    [2]  NULL   | ---      | ---       | >0        | 0/1    | Valid
    
    [3]  Found  | NULL     | --        | Any       | 0/1    | Invalid
    
    [4]  Found  | Found    | NULL      | 0         | 1      | Valid
    [5]  Found  | Found    | NULL      | >0        | 1      | Invalid
    
    [6]  Found  | Found    | task      | 0         | 1      | Valid
    
    [7]  Found  | Found    | NULL      | Any       | 0      | Invalid
    
    [8]  Found  | Found    | task      | ==taskTID | 0/1    | Valid
    [9]  Found  | Found    | task      | 0         | 0      | Invalid
    [10] Found  | Found    | task      | !=taskTID | 0/1    | Invalid
    
    [1]  Indicates that the kernel can acquire the futex atomically. We
         came came here due to a stale FUTEX_WAITERS/FUTEX_OWNER_DIED bit.
    
    [2]  Valid, if TID does not belong to a kernel thread. If no matching
         thread is found then it indicates that the owner TID has died.
    
    [3]  Invalid. The waiter is queued on a non PI futex
    
    [4]  Valid state after exit_robust_list(), which sets the user space
         value to FUTEX_WAITERS | FUTEX_OWNER_DIED.
    
    [5]  The user space value got manipulated between exit_robust_list()
         and exit_pi_state_list()
    
    [6]  Valid state after exit_pi_state_list() which sets the new owner in
         the pi_state but cannot access the user space value.
    
    [7]  pi_state->owner can only be NULL when the OWNER_DIED bit is set.
    
    [8]  Owner and user space value match
    
    [9]  There is no transient state which sets the user space TID to 0
         except exit_robust_list(), but this is indicated by the
         FUTEX_OWNER_DIED bit. See [4]
    
    [10] There is no transient state which leaves owner and user space
         TID out of sync.
    
    Backport to 3.13
      conflicts: kernel/futex.c
    Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
    Signed-off-by: default avatarJohn Johansen <john.johansen@canonical.com>
    Cc: Kees Cook <keescook@chromium.org>
    Cc: Will Drewry <wad@chromium.org>
    Cc: Darren Hart <dvhart@linux.intel.com>
    Cc: stable@vger.kernel.org
    (cherry picked from commit e66d93c97bf3e02215409deccf31555873d51ce8)
    
    Change-Id: Ieaa328d9498c5e30abd5c7ec5c473508bc593e0c
    8b7b2d6b