source:
trunk/server/common/patches/cve-2014-3153-4.patch
@
2590
Last change on this file since 2590 was 2557, checked in by achernya, 10 years ago | |
---|---|
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) 592 592 raw_spin_unlock_irq(&curr->pi_lock); 593 593 } 594 594 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 */ 595 644 static int 596 645 lookup_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) 599 647 { 600 648 struct futex_pi_state *pi_state = NULL; 601 649 struct futex_q *this, *next; … … lookup_pi_state(u32 uval, struct futex_hash_bucket *hb, 608 656 plist_for_each_entry_safe(this, next, head, list) { 609 657 if (match_futex(&this->key, key)) { 610 658 /* 611 * Another waiter already exists - bump up612 * the refcount and return its pi_state:659 * Sanity check the waiter before increasing 660 * the refcount and attaching to it. 613 661 */ 614 662 pi_state = this->pi_state; 615 663 /* 616 * Userspace might have messed up non-PI and PI futexes 664 * Userspace might have messed up non-PI and 665 * PI futexes [3] 617 666 */ 618 667 if (unlikely(!pi_state)) 619 668 return -EINVAL; … … lookup_pi_state(u32 uval, struct futex_hash_bucket *hb, 621 670 WARN_ON(!atomic_read(&pi_state->refcount)); 622 671 623 672 /* 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: 632 674 */ 633 if ( pid && pi_state->owner) {675 if (uval & FUTEX_OWNER_DIED) { 634 676 /* 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. 637 681 */ 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) 639 715 return -EINVAL; 640 716 } 641 717 642 718 /* 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] 648 723 */ 649 if ( task && pi_state->owner == task)650 return -E DEADLK;724 if (pid != task_pid_vnr(pi_state->owner)) 725 return -EINVAL; 651 726 727 out_state: 652 728 atomic_inc(&pi_state->refcount); 653 729 *ps = pi_state; 654 655 730 return 0; 656 731 } 657 732 } 658 733 659 734 /* 660 735 * 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] 662 737 */ 663 738 if (!pid) 664 739 return -ESRCH; … … lookup_pi_state(u32 uval, struct futex_hash_bucket *hb, 691 766 return ret; 692 767 } 693 768 769 /* 770 * No existing pi state. First waiter. [2] 771 */ 694 772 pi_state = alloc_pi_state(); 695 773 696 774 /* … … retry: 811 889 * We dont have the lock. Look up the PI state (or create it if 812 890 * we are the first waiter): 813 891 */ 814 ret = lookup_pi_state(uval, hb, key, ps , task);892 ret = lookup_pi_state(uval, hb, key, ps); 815 893 816 894 if (unlikely(ret)) { 817 895 switch (ret) { … … retry_private: 1414 1492 * rereading and handing potential crap to 1415 1493 * lookup_pi_state. 1416 1494 */ 1417 ret = lookup_pi_state(ret, hb2, &key2, &pi_state , NULL);1495 ret = lookup_pi_state(ret, hb2, &key2, &pi_state); 1418 1496 } 1419 1497 1420 1498 switch (ret) {
Note: See TracBrowser
for help on using the repository browser.