source: trunk/server/common/patches/cve-2014-3153-4.patch @ 2561

Last change on this file since 2561 was 2557, checked in by achernya, 10 years ago
Kernel patches against cve-2014-3153 (old, uncommitted changes)
File size: 9.2 KB
  • kernel/futex.c

    From efccdcdb63a7f7cc7cc1816f0d5e2524eb084c72 Mon Sep 17 00:00:00 2001
    From: Thomas Gleixner <tglx@linutronix.de>
    Date: Tue, 3 Jun 2014 12:27:08 +0000
    Subject: [PATCH 4/4] futex: Make lookup_pi_state more robust
    
    commit 54a217887a7b658e2650c3feff22756ab80c7339 upstream.
    
    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.
    
    Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
    Cc: Kees Cook <keescook@chromium.org>
    Cc: Will Drewry <wad@chromium.org>
    Cc: Darren Hart <dvhart@linux.intel.com>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    ---
     kernel/futex.c |  134 ++++++++++++++++++++++++++++++++++++++++++++------------
     1 file changed, 106 insertions(+), 28 deletions(-)
    
    diff --git a/kernel/futex.c b/kernel/futex.c
    index 9720c42..625a4e6 100644
    a b void exit_pi_state_list(struct task_struct *curr) 
    592592        raw_spin_unlock_irq(&curr->pi_lock);
    593593}
    594594
     595/*
     596 * We need to check the following states:
     597 *
     598 *      Waiter | pi_state | pi->owner | uTID      | uODIED | ?
     599 *
     600 * [1]  NULL   | ---      | ---       | 0         | 0/1    | Valid
     601 * [2]  NULL   | ---      | ---       | >0        | 0/1    | Valid
     602 *
     603 * [3]  Found  | NULL     | --        | Any       | 0/1    | Invalid
     604 *
     605 * [4]  Found  | Found    | NULL      | 0         | 1      | Valid
     606 * [5]  Found  | Found    | NULL      | >0        | 1      | Invalid
     607 *
     608 * [6]  Found  | Found    | task      | 0         | 1      | Valid
     609 *
     610 * [7]  Found  | Found    | NULL      | Any       | 0      | Invalid
     611 *
     612 * [8]  Found  | Found    | task      | ==taskTID | 0/1    | Valid
     613 * [9]  Found  | Found    | task      | 0         | 0      | Invalid
     614 * [10] Found  | Found    | task      | !=taskTID | 0/1    | Invalid
     615 *
     616 * [1]  Indicates that the kernel can acquire the futex atomically. We
     617 *      came came here due to a stale FUTEX_WAITERS/FUTEX_OWNER_DIED bit.
     618 *
     619 * [2]  Valid, if TID does not belong to a kernel thread. If no matching
     620 *      thread is found then it indicates that the owner TID has died.
     621 *
     622 * [3]  Invalid. The waiter is queued on a non PI futex
     623 *
     624 * [4]  Valid state after exit_robust_list(), which sets the user space
     625 *      value to FUTEX_WAITERS | FUTEX_OWNER_DIED.
     626 *
     627 * [5]  The user space value got manipulated between exit_robust_list()
     628 *      and exit_pi_state_list()
     629 *
     630 * [6]  Valid state after exit_pi_state_list() which sets the new owner in
     631 *      the pi_state but cannot access the user space value.
     632 *
     633 * [7]  pi_state->owner can only be NULL when the OWNER_DIED bit is set.
     634 *
     635 * [8]  Owner and user space value match
     636 *
     637 * [9]  There is no transient state which sets the user space TID to 0
     638 *      except exit_robust_list(), but this is indicated by the
     639 *      FUTEX_OWNER_DIED bit. See [4]
     640 *
     641 * [10] There is no transient state which leaves owner and user space
     642 *      TID out of sync.
     643 */
    595644static int
    596645lookup_pi_state(u32 uval, struct futex_hash_bucket *hb,
    597                 union futex_key *key, struct futex_pi_state **ps,
    598                 struct task_struct *task)
     646                union futex_key *key, struct futex_pi_state **ps)
    599647{
    600648        struct futex_pi_state *pi_state = NULL;
    601649        struct futex_q *this, *next;
    lookup_pi_state(u32 uval, struct futex_hash_bucket *hb, 
    608656        plist_for_each_entry_safe(this, next, head, list) {
    609657                if (match_futex(&this->key, key)) {
    610658                        /*
    611                          * Another waiter already exists - bump up
    612                          * the refcount and return its pi_state:
     659                         * Sanity check the waiter before increasing
     660                         * the refcount and attaching to it.
    613661                         */
    614662                        pi_state = this->pi_state;
    615663                        /*
    616                          * Userspace might have messed up non-PI and PI futexes
     664                         * Userspace might have messed up non-PI and
     665                         * PI futexes [3]
    617666                         */
    618667                        if (unlikely(!pi_state))
    619668                                return -EINVAL;
    lookup_pi_state(u32 uval, struct futex_hash_bucket *hb, 
    621670                        WARN_ON(!atomic_read(&pi_state->refcount));
    622671
    623672                        /*
    624                          * When pi_state->owner is NULL then the owner died
    625                          * and another waiter is on the fly. pi_state->owner
    626                          * is fixed up by the task which acquires
    627                          * pi_state->rt_mutex.
    628                          *
    629                          * We do not check for pid == 0 which can happen when
    630                          * the owner died and robust_list_exit() cleared the
    631                          * TID.
     673                         * Handle the owner died case:
    632674                         */
    633                         if (pid && pi_state->owner) {
     675                        if (uval & FUTEX_OWNER_DIED) {
    634676                                /*
    635                                  * Bail out if user space manipulated the
    636                                  * futex value.
     677                                 * exit_pi_state_list sets owner to NULL and
     678                                 * wakes the topmost waiter. The task which
     679                                 * acquires the pi_state->rt_mutex will fixup
     680                                 * owner.
    637681                                 */
    638                                 if (pid != task_pid_vnr(pi_state->owner))
     682                                if (!pi_state->owner) {
     683                                        /*
     684                                         * No pi state owner, but the user
     685                                         * space TID is not 0. Inconsistent
     686                                         * state. [5]
     687                                         */
     688                                        if (pid)
     689                                                return -EINVAL;
     690                                        /*
     691                                         * Take a ref on the state and
     692                                         * return. [4]
     693                                         */
     694                                        goto out_state;
     695                                }
     696
     697                                /*
     698                                 * If TID is 0, then either the dying owner
     699                                 * has not yet executed exit_pi_state_list()
     700                                 * or some waiter acquired the rtmutex in the
     701                                 * pi state, but did not yet fixup the TID in
     702                                 * user space.
     703                                 *
     704                                 * Take a ref on the state and return. [6]
     705                                 */
     706                                if (!pid)
     707                                        goto out_state;
     708                        } else {
     709                                /*
     710                                 * If the owner died bit is not set,
     711                                 * then the pi_state must have an
     712                                 * owner. [7]
     713                                 */
     714                                if (!pi_state->owner)
    639715                                        return -EINVAL;
    640716                        }
    641717
    642718                        /*
    643                          * Protect against a corrupted uval. If uval
    644                          * is 0x80000000 then pid is 0 and the waiter
    645                          * bit is set. So the deadlock check in the
    646                          * calling code has failed and we did not fall
    647                          * into the check above due to !pid.
     719                         * Bail out if user space manipulated the
     720                         * futex value. If pi state exists then the
     721                         * owner TID must be the same as the user
     722                         * space TID. [9/10]
    648723                         */
    649                         if (task && pi_state->owner == task)
    650                                 return -EDEADLK;
     724                        if (pid != task_pid_vnr(pi_state->owner))
     725                                return -EINVAL;
    651726
     727                out_state:
    652728                        atomic_inc(&pi_state->refcount);
    653729                        *ps = pi_state;
    654 
    655730                        return 0;
    656731                }
    657732        }
    658733
    659734        /*
    660735         * We are the first waiter - try to look up the real owner and attach
    661          * the new pi_state to it, but bail out when TID = 0
     736         * the new pi_state to it, but bail out when TID = 0 [1]
    662737         */
    663738        if (!pid)
    664739                return -ESRCH;
    lookup_pi_state(u32 uval, struct futex_hash_bucket *hb, 
    691766                return ret;
    692767        }
    693768
     769        /*
     770         * No existing pi state. First waiter. [2]
     771         */
    694772        pi_state = alloc_pi_state();
    695773
    696774        /*
    retry: 
    811889         * We dont have the lock. Look up the PI state (or create it if
    812890         * we are the first waiter):
    813891         */
    814         ret = lookup_pi_state(uval, hb, key, ps, task);
     892        ret = lookup_pi_state(uval, hb, key, ps);
    815893
    816894        if (unlikely(ret)) {
    817895                switch (ret) {
    retry_private: 
    14141492                         * rereading and handing potential crap to
    14151493                         * lookup_pi_state.
    14161494                         */
    1417                         ret = lookup_pi_state(ret, hb2, &key2, &pi_state, NULL);
     1495                        ret = lookup_pi_state(ret, hb2, &key2, &pi_state);
    14181496                }
    14191497
    14201498                switch (ret) {
Note: See TracBrowser for help on using the repository browser.