diff options
-rw-r--r-- | kernel/futex.c | 134 |
1 files changed, 106 insertions, 28 deletions
diff --git a/kernel/futex.c b/kernel/futex.c index e1cb1baa23fb..de938d20df19 100644 --- a/kernel/futex.c +++ b/kernel/futex.c | |||
@@ -743,10 +743,58 @@ void exit_pi_state_list(struct task_struct *curr) | |||
743 | raw_spin_unlock_irq(&curr->pi_lock); | 743 | raw_spin_unlock_irq(&curr->pi_lock); |
744 | } | 744 | } |
745 | 745 | ||
746 | /* | ||
747 | * We need to check the following states: | ||
748 | * | ||
749 | * Waiter | pi_state | pi->owner | uTID | uODIED | ? | ||
750 | * | ||
751 | * [1] NULL | --- | --- | 0 | 0/1 | Valid | ||
752 | * [2] NULL | --- | --- | >0 | 0/1 | Valid | ||
753 | * | ||
754 | * [3] Found | NULL | -- | Any | 0/1 | Invalid | ||
755 | * | ||
756 | * [4] Found | Found | NULL | 0 | 1 | Valid | ||
757 | * [5] Found | Found | NULL | >0 | 1 | Invalid | ||
758 | * | ||
759 | * [6] Found | Found | task | 0 | 1 | Valid | ||
760 | * | ||
761 | * [7] Found | Found | NULL | Any | 0 | Invalid | ||
762 | * | ||
763 | * [8] Found | Found | task | ==taskTID | 0/1 | Valid | ||
764 | * [9] Found | Found | task | 0 | 0 | Invalid | ||
765 | * [10] Found | Found | task | !=taskTID | 0/1 | Invalid | ||
766 | * | ||
767 | * [1] Indicates that the kernel can acquire the futex atomically. We | ||
768 | * came came here due to a stale FUTEX_WAITERS/FUTEX_OWNER_DIED bit. | ||
769 | * | ||
770 | * [2] Valid, if TID does not belong to a kernel thread. If no matching | ||
771 | * thread is found then it indicates that the owner TID has died. | ||
772 | * | ||
773 | * [3] Invalid. The waiter is queued on a non PI futex | ||
774 | * | ||
775 | * [4] Valid state after exit_robust_list(), which sets the user space | ||
776 | * value to FUTEX_WAITERS | FUTEX_OWNER_DIED. | ||
777 | * | ||
778 | * [5] The user space value got manipulated between exit_robust_list() | ||
779 | * and exit_pi_state_list() | ||
780 | * | ||
781 | * [6] Valid state after exit_pi_state_list() which sets the new owner in | ||
782 | * the pi_state but cannot access the user space value. | ||
783 | * | ||
784 | * [7] pi_state->owner can only be NULL when the OWNER_DIED bit is set. | ||
785 | * | ||
786 | * [8] Owner and user space value match | ||
787 | * | ||
788 | * [9] There is no transient state which sets the user space TID to 0 | ||
789 | * except exit_robust_list(), but this is indicated by the | ||
790 | * FUTEX_OWNER_DIED bit. See [4] | ||
791 | * | ||
792 | * [10] There is no transient state which leaves owner and user space | ||
793 | * TID out of sync. | ||
794 | */ | ||
746 | static int | 795 | static int |
747 | lookup_pi_state(u32 uval, struct futex_hash_bucket *hb, | 796 | lookup_pi_state(u32 uval, struct futex_hash_bucket *hb, |
748 | union futex_key *key, struct futex_pi_state **ps, | 797 | union futex_key *key, struct futex_pi_state **ps) |
749 | struct task_struct *task) | ||
750 | { | 798 | { |
751 | struct futex_pi_state *pi_state = NULL; | 799 | struct futex_pi_state *pi_state = NULL; |
752 | struct futex_q *this, *next; | 800 | struct futex_q *this, *next; |
@@ -756,12 +804,13 @@ lookup_pi_state(u32 uval, struct futex_hash_bucket *hb, | |||
756 | plist_for_each_entry_safe(this, next, &hb->chain, list) { | 804 | plist_for_each_entry_safe(this, next, &hb->chain, list) { |
757 | if (match_futex(&this->key, key)) { | 805 | if (match_futex(&this->key, key)) { |
758 | /* | 806 | /* |
759 | * Another waiter already exists - bump up | 807 | * Sanity check the waiter before increasing |
760 | * the refcount and return its pi_state: | 808 | * the refcount and attaching to it. |
761 | */ | 809 | */ |
762 | pi_state = this->pi_state; | 810 | pi_state = this->pi_state; |
763 | /* | 811 | /* |
764 | * Userspace might have messed up non-PI and PI futexes | 812 | * Userspace might have messed up non-PI and |
813 | * PI futexes [3] | ||
765 | */ | 814 | */ |
766 | if (unlikely(!pi_state)) | 815 | if (unlikely(!pi_state)) |
767 | return -EINVAL; | 816 | return -EINVAL; |
@@ -769,44 +818,70 @@ lookup_pi_state(u32 uval, struct futex_hash_bucket *hb, | |||
769 | WARN_ON(!atomic_read(&pi_state->refcount)); | 818 | WARN_ON(!atomic_read(&pi_state->refcount)); |
770 | 819 | ||
771 | /* | 820 | /* |
772 | * When pi_state->owner is NULL then the owner died | 821 | * Handle the owner died case: |
773 | * and another waiter is on the fly. pi_state->owner | ||
774 | * is fixed up by the task which acquires | ||
775 | * pi_state->rt_mutex. | ||
776 | * | ||
777 | * We do not check for pid == 0 which can happen when | ||
778 | * the owner died and robust_list_exit() cleared the | ||
779 | * TID. | ||
780 | */ | 822 | */ |
781 | if (pid && pi_state->owner) { | 823 | if (uval & FUTEX_OWNER_DIED) { |
782 | /* | 824 | /* |
783 | * Bail out if user space manipulated the | 825 | * exit_pi_state_list sets owner to NULL and |
784 | * futex value. | 826 | * wakes the topmost waiter. The task which |
827 | * acquires the pi_state->rt_mutex will fixup | ||
828 | * owner. | ||
785 | */ | 829 | */ |
786 | if (pid != task_pid_vnr(pi_state->owner)) | 830 | if (!pi_state->owner) { |
831 | /* | ||
832 | * No pi state owner, but the user | ||
833 | * space TID is not 0. Inconsistent | ||
834 | * state. [5] | ||
835 | */ | ||
836 | if (pid) | ||
837 | return -EINVAL; | ||
838 | /* | ||
839 | * Take a ref on the state and | ||
840 | * return. [4] | ||
841 | */ | ||
842 | goto out_state; | ||
843 | } | ||
844 | |||
845 | /* | ||
846 | * If TID is 0, then either the dying owner | ||
847 | * has not yet executed exit_pi_state_list() | ||
848 | * or some waiter acquired the rtmutex in the | ||
849 | * pi state, but did not yet fixup the TID in | ||
850 | * user space. | ||
851 | * | ||
852 | * Take a ref on the state and return. [6] | ||
853 | */ | ||
854 | if (!pid) | ||
855 | goto out_state; | ||
856 | } else { | ||
857 | /* | ||
858 | * If the owner died bit is not set, | ||
859 | * then the pi_state must have an | ||
860 | * owner. [7] | ||
861 | */ | ||
862 | if (!pi_state->owner) | ||
787 | return -EINVAL; | 863 | return -EINVAL; |
788 | } | 864 | } |
789 | 865 | ||
790 | /* | 866 | /* |
791 | * Protect against a corrupted uval. If uval | 867 | * Bail out if user space manipulated the |
792 | * is 0x80000000 then pid is 0 and the waiter | 868 | * futex value. If pi state exists then the |
793 | * bit is set. So the deadlock check in the | 869 | * owner TID must be the same as the user |
794 | * calling code has failed and we did not fall | 870 | * space TID. [9/10] |
795 | * into the check above due to !pid. | ||
796 | */ | 871 | */ |
797 | if (task && pi_state->owner == task) | 872 | if (pid != task_pid_vnr(pi_state->owner)) |
798 | return -EDEADLK; | 873 | return -EINVAL; |
799 | 874 | ||
875 | out_state: | ||
800 | atomic_inc(&pi_state->refcount); | 876 | atomic_inc(&pi_state->refcount); |
801 | *ps = pi_state; | 877 | *ps = pi_state; |
802 | |||
803 | return 0; | 878 | return 0; |
804 | } | 879 | } |
805 | } | 880 | } |
806 | 881 | ||
807 | /* | 882 | /* |
808 | * We are the first waiter - try to look up the real owner and attach | 883 | * We are the first waiter - try to look up the real owner and attach |
809 | * the new pi_state to it, but bail out when TID = 0 | 884 | * the new pi_state to it, but bail out when TID = 0 [1] |
810 | */ | 885 | */ |
811 | if (!pid) | 886 | if (!pid) |
812 | return -ESRCH; | 887 | return -ESRCH; |
@@ -839,6 +914,9 @@ lookup_pi_state(u32 uval, struct futex_hash_bucket *hb, | |||
839 | return ret; | 914 | return ret; |
840 | } | 915 | } |
841 | 916 | ||
917 | /* | ||
918 | * No existing pi state. First waiter. [2] | ||
919 | */ | ||
842 | pi_state = alloc_pi_state(); | 920 | pi_state = alloc_pi_state(); |
843 | 921 | ||
844 | /* | 922 | /* |
@@ -959,7 +1037,7 @@ retry: | |||
959 | * We dont have the lock. Look up the PI state (or create it if | 1037 | * We dont have the lock. Look up the PI state (or create it if |
960 | * we are the first waiter): | 1038 | * we are the first waiter): |
961 | */ | 1039 | */ |
962 | ret = lookup_pi_state(uval, hb, key, ps, task); | 1040 | ret = lookup_pi_state(uval, hb, key, ps); |
963 | 1041 | ||
964 | if (unlikely(ret)) { | 1042 | if (unlikely(ret)) { |
965 | switch (ret) { | 1043 | switch (ret) { |
@@ -1565,7 +1643,7 @@ retry_private: | |||
1565 | * rereading and handing potential crap to | 1643 | * rereading and handing potential crap to |
1566 | * lookup_pi_state. | 1644 | * lookup_pi_state. |
1567 | */ | 1645 | */ |
1568 | ret = lookup_pi_state(ret, hb2, &key2, &pi_state, NULL); | 1646 | ret = lookup_pi_state(ret, hb2, &key2, &pi_state); |
1569 | } | 1647 | } |
1570 | 1648 | ||
1571 | switch (ret) { | 1649 | switch (ret) { |