From: Greg Kroah-Hartman Date: Thu, 5 Jun 2014 23:11:00 +0000 (-0700) Subject: 3.10-stable patches X-Git-Tag: v3.14.6~3 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=4e4f2282e6f31d8149c8f1a9c28ba0a88a75d2a5;p=thirdparty%2Fkernel%2Fstable-queue.git 3.10-stable patches added patches: futex-always-cleanup-owner-tid-in-unlock_pi.patch futex-make-lookup_pi_state-more-robust.patch futex-prevent-requeue-pi-on-same-futex.patch-futex-forbid-uaddr-uaddr2-in-futex_requeue-...-requeue_pi-1.patch futex-validate-atomic-acquisition-in-futex_lock_pi_atomic.patch --- diff --git a/queue-3.10/futex-always-cleanup-owner-tid-in-unlock_pi.patch b/queue-3.10/futex-always-cleanup-owner-tid-in-unlock_pi.patch new file mode 100644 index 00000000000..1a414d8cc0f --- /dev/null +++ b/queue-3.10/futex-always-cleanup-owner-tid-in-unlock_pi.patch @@ -0,0 +1,102 @@ +From 13fbca4c6ecd96ec1a1cfa2e4f2ce191fe928a5e Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Tue, 3 Jun 2014 12:27:07 +0000 +Subject: futex: Always cleanup owner tid in unlock_pi + +From: Thomas Gleixner + +commit 13fbca4c6ecd96ec1a1cfa2e4f2ce191fe928a5e upstream. + +If the owner died bit is set at futex_unlock_pi, we currently do not +cleanup the user space futex. So the owner TID of the current owner +(the unlocker) persists. That's observable inconsistant state, +especially when the ownership of the pi state got transferred. + +Clean it up unconditionally. + +Signed-off-by: Thomas Gleixner +Cc: Kees Cook +Cc: Will Drewry +Cc: Darren Hart +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + kernel/futex.c | 44 ++++++++++++++++++++------------------------ + 1 file changed, 20 insertions(+), 24 deletions(-) + +--- a/kernel/futex.c ++++ b/kernel/futex.c +@@ -903,6 +903,7 @@ static int wake_futex_pi(u32 __user *uad + struct task_struct *new_owner; + struct futex_pi_state *pi_state = this->pi_state; + u32 uninitialized_var(curval), newval; ++ int ret = 0; + + if (!pi_state) + return -EINVAL; +@@ -926,23 +927,19 @@ static int wake_futex_pi(u32 __user *uad + new_owner = this->task; + + /* +- * We pass it to the next owner. (The WAITERS bit is always +- * kept enabled while there is PI state around. We must also +- * preserve the owner died bit.) +- */ +- if (!(uval & FUTEX_OWNER_DIED)) { +- int ret = 0; +- +- newval = FUTEX_WAITERS | task_pid_vnr(new_owner); +- +- if (cmpxchg_futex_value_locked(&curval, uaddr, uval, newval)) +- ret = -EFAULT; +- else if (curval != uval) +- ret = -EINVAL; +- if (ret) { +- raw_spin_unlock(&pi_state->pi_mutex.wait_lock); +- return ret; +- } ++ * We pass it to the next owner. The WAITERS bit is always ++ * kept enabled while there is PI state around. We cleanup the ++ * owner died bit, because we are the owner. ++ */ ++ newval = FUTEX_WAITERS | task_pid_vnr(new_owner); ++ ++ if (cmpxchg_futex_value_locked(&curval, uaddr, uval, newval)) ++ ret = -EFAULT; ++ else if (curval != uval) ++ ret = -EINVAL; ++ if (ret) { ++ raw_spin_unlock(&pi_state->pi_mutex.wait_lock); ++ return ret; + } + + raw_spin_lock_irq(&pi_state->owner->pi_lock); +@@ -2187,9 +2184,10 @@ retry: + /* + * To avoid races, try to do the TID -> 0 atomic transition + * again. If it succeeds then we can return without waking +- * anyone else up: ++ * anyone else up. We only try this if neither the waiters nor ++ * the owner died bit are set. + */ +- if (!(uval & FUTEX_OWNER_DIED) && ++ if (!(uval & ~FUTEX_TID_MASK) && + cmpxchg_futex_value_locked(&uval, uaddr, vpid, 0)) + goto pi_faulted; + /* +@@ -2221,11 +2219,9 @@ retry: + /* + * No waiters - kernel unlocks the futex: + */ +- if (!(uval & FUTEX_OWNER_DIED)) { +- ret = unlock_futex_pi(uaddr, uval); +- if (ret == -EFAULT) +- goto pi_faulted; +- } ++ ret = unlock_futex_pi(uaddr, uval); ++ if (ret == -EFAULT) ++ goto pi_faulted; + + out_unlock: + spin_unlock(&hb->lock); diff --git a/queue-3.10/futex-make-lookup_pi_state-more-robust.patch b/queue-3.10/futex-make-lookup_pi_state-more-robust.patch new file mode 100644 index 00000000000..4a0f7f37080 --- /dev/null +++ b/queue-3.10/futex-make-lookup_pi_state-more-robust.patch @@ -0,0 +1,279 @@ +From 54a217887a7b658e2650c3feff22756ab80c7339 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Tue, 3 Jun 2014 12:27:08 +0000 +Subject: futex: Make lookup_pi_state more robust + +From: Thomas Gleixner + +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 +Cc: Kees Cook +Cc: Will Drewry +Cc: Darren Hart +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + kernel/futex.c | 134 +++++++++++++++++++++++++++++++++++++++++++++------------ + 1 file changed, 106 insertions(+), 28 deletions(-) + +--- a/kernel/futex.c ++++ b/kernel/futex.c +@@ -592,10 +592,58 @@ void exit_pi_state_list(struct task_stru + raw_spin_unlock_irq(&curr->pi_lock); + } + ++/* ++ * We need to check the following states: ++ * ++ * 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. ++ */ + static int + lookup_pi_state(u32 uval, struct futex_hash_bucket *hb, +- union futex_key *key, struct futex_pi_state **ps, +- struct task_struct *task) ++ union futex_key *key, struct futex_pi_state **ps) + { + struct futex_pi_state *pi_state = NULL; + struct futex_q *this, *next; +@@ -608,12 +656,13 @@ lookup_pi_state(u32 uval, struct futex_h + plist_for_each_entry_safe(this, next, head, list) { + if (match_futex(&this->key, key)) { + /* +- * Another waiter already exists - bump up +- * the refcount and return its pi_state: ++ * Sanity check the waiter before increasing ++ * the refcount and attaching to it. + */ + pi_state = this->pi_state; + /* +- * Userspace might have messed up non-PI and PI futexes ++ * Userspace might have messed up non-PI and ++ * PI futexes [3] + */ + if (unlikely(!pi_state)) + return -EINVAL; +@@ -621,44 +670,70 @@ lookup_pi_state(u32 uval, struct futex_h + WARN_ON(!atomic_read(&pi_state->refcount)); + + /* +- * When pi_state->owner is NULL then the owner died +- * and another waiter is on the fly. pi_state->owner +- * is fixed up by the task which acquires +- * pi_state->rt_mutex. +- * +- * We do not check for pid == 0 which can happen when +- * the owner died and robust_list_exit() cleared the +- * TID. ++ * Handle the owner died case: + */ +- if (pid && pi_state->owner) { ++ if (uval & FUTEX_OWNER_DIED) { + /* +- * Bail out if user space manipulated the +- * futex value. ++ * exit_pi_state_list sets owner to NULL and ++ * wakes the topmost waiter. The task which ++ * acquires the pi_state->rt_mutex will fixup ++ * owner. + */ +- if (pid != task_pid_vnr(pi_state->owner)) ++ if (!pi_state->owner) { ++ /* ++ * No pi state owner, but the user ++ * space TID is not 0. Inconsistent ++ * state. [5] ++ */ ++ if (pid) ++ return -EINVAL; ++ /* ++ * Take a ref on the state and ++ * return. [4] ++ */ ++ goto out_state; ++ } ++ ++ /* ++ * If TID is 0, then either the dying owner ++ * has not yet executed exit_pi_state_list() ++ * or some waiter acquired the rtmutex in the ++ * pi state, but did not yet fixup the TID in ++ * user space. ++ * ++ * Take a ref on the state and return. [6] ++ */ ++ if (!pid) ++ goto out_state; ++ } else { ++ /* ++ * If the owner died bit is not set, ++ * then the pi_state must have an ++ * owner. [7] ++ */ ++ if (!pi_state->owner) + return -EINVAL; + } + + /* +- * Protect against a corrupted uval. If uval +- * is 0x80000000 then pid is 0 and the waiter +- * bit is set. So the deadlock check in the +- * calling code has failed and we did not fall +- * into the check above due to !pid. ++ * Bail out if user space manipulated the ++ * futex value. If pi state exists then the ++ * owner TID must be the same as the user ++ * space TID. [9/10] + */ +- if (task && pi_state->owner == task) +- return -EDEADLK; ++ if (pid != task_pid_vnr(pi_state->owner)) ++ return -EINVAL; + ++ out_state: + atomic_inc(&pi_state->refcount); + *ps = pi_state; +- + return 0; + } + } + + /* + * We are the first waiter - try to look up the real owner and attach +- * the new pi_state to it, but bail out when TID = 0 ++ * the new pi_state to it, but bail out when TID = 0 [1] + */ + if (!pid) + return -ESRCH; +@@ -691,6 +766,9 @@ lookup_pi_state(u32 uval, struct futex_h + return ret; + } + ++ /* ++ * No existing pi state. First waiter. [2] ++ */ + pi_state = alloc_pi_state(); + + /* +@@ -811,7 +889,7 @@ retry: + * We dont have the lock. Look up the PI state (or create it if + * we are the first waiter): + */ +- ret = lookup_pi_state(uval, hb, key, ps, task); ++ ret = lookup_pi_state(uval, hb, key, ps); + + if (unlikely(ret)) { + switch (ret) { +@@ -1414,7 +1492,7 @@ retry_private: + * rereading and handing potential crap to + * lookup_pi_state. + */ +- ret = lookup_pi_state(ret, hb2, &key2, &pi_state, NULL); ++ ret = lookup_pi_state(ret, hb2, &key2, &pi_state); + } + + switch (ret) { diff --git a/queue-3.10/futex-prevent-requeue-pi-on-same-futex.patch-futex-forbid-uaddr-uaddr2-in-futex_requeue-...-requeue_pi-1.patch b/queue-3.10/futex-prevent-requeue-pi-on-same-futex.patch-futex-forbid-uaddr-uaddr2-in-futex_requeue-...-requeue_pi-1.patch new file mode 100644 index 00000000000..28e53a22fb1 --- /dev/null +++ b/queue-3.10/futex-prevent-requeue-pi-on-same-futex.patch-futex-forbid-uaddr-uaddr2-in-futex_requeue-...-requeue_pi-1.patch @@ -0,0 +1,83 @@ +From e9c243a5a6de0be8e584c604d353412584b592f8 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Tue, 3 Jun 2014 12:27:06 +0000 +Subject: futex-prevent-requeue-pi-on-same-futex.patch futex: Forbid uaddr == uaddr2 in futex_requeue(..., requeue_pi=1) + +From: Thomas Gleixner + +commit e9c243a5a6de0be8e584c604d353412584b592f8 upstream. + +If uaddr == uaddr2, then we have broken the rule of only requeueing from +a non-pi futex to a pi futex with this call. If we attempt this, then +dangling pointers may be left for rt_waiter resulting in an exploitable +condition. + +This change brings futex_requeue() in line with futex_wait_requeue_pi() +which performs the same check as per commit 6f7b0a2a5c0f ("futex: Forbid +uaddr == uaddr2 in futex_wait_requeue_pi()") + +[ tglx: Compare the resulting keys as well, as uaddrs might be + different depending on the mapping ] + +Fixes CVE-2014-3153. + +Reported-by: Pinkie Pie +Signed-off-by: Will Drewry +Signed-off-by: Kees Cook +Signed-off-by: Thomas Gleixner +Reviewed-by: Darren Hart +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + kernel/futex.c | 25 +++++++++++++++++++++++++ + 1 file changed, 25 insertions(+) + +--- a/kernel/futex.c ++++ b/kernel/futex.c +@@ -1293,6 +1293,13 @@ static int futex_requeue(u32 __user *uad + + if (requeue_pi) { + /* ++ * Requeue PI only works on two distinct uaddrs. This ++ * check is only valid for private futexes. See below. ++ */ ++ if (uaddr1 == uaddr2) ++ return -EINVAL; ++ ++ /* + * requeue_pi requires a pi_state, try to allocate it now + * without any locks in case it fails. + */ +@@ -1330,6 +1337,15 @@ retry: + if (unlikely(ret != 0)) + goto out_put_key1; + ++ /* ++ * The check above which compares uaddrs is not sufficient for ++ * shared futexes. We need to compare the keys: ++ */ ++ if (requeue_pi && match_futex(&key1, &key2)) { ++ ret = -EINVAL; ++ goto out_put_keys; ++ } ++ + hb1 = hash_futex(&key1); + hb2 = hash_futex(&key2); + +@@ -2360,6 +2376,15 @@ static int futex_wait_requeue_pi(u32 __u + if (ret) + goto out_key2; + ++ /* ++ * The check above which compares uaddrs is not sufficient for ++ * shared futexes. We need to compare the keys: ++ */ ++ if (match_futex(&q.key, &key2)) { ++ ret = -EINVAL; ++ goto out_put_keys; ++ } ++ + /* Queue the futex_q, drop the hb lock, wait for wakeup. */ + futex_wait_queue_me(hb, &q, to); + diff --git a/queue-3.10/futex-validate-atomic-acquisition-in-futex_lock_pi_atomic.patch b/queue-3.10/futex-validate-atomic-acquisition-in-futex_lock_pi_atomic.patch new file mode 100644 index 00000000000..3b3b08e4c48 --- /dev/null +++ b/queue-3.10/futex-validate-atomic-acquisition-in-futex_lock_pi_atomic.patch @@ -0,0 +1,56 @@ +From b3eaa9fc5cd0a4d74b18f6b8dc617aeaf1873270 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Tue, 3 Jun 2014 12:27:06 +0000 +Subject: futex: Validate atomic acquisition in futex_lock_pi_atomic() + +From: Thomas Gleixner + +commit b3eaa9fc5cd0a4d74b18f6b8dc617aeaf1873270 upstream. + +We need to protect the atomic acquisition in the kernel against rogue +user space which sets the user space futex to 0, so the kernel side +acquisition succeeds while there is existing state in the kernel +associated to the real owner. + +Verify whether the futex has waiters associated with kernel state. If +it has, return -EINVAL. The state is corrupted already, so no point in +cleaning it up. Subsequent calls will fail as well. Not our problem. + +[ tglx: Use futex_top_waiter() and explain why we do not need to try + restoring the already corrupted user space state. ] + +Signed-off-by: Darren Hart +Cc: Kees Cook +Cc: Will Drewry +Signed-off-by: Thomas Gleixner +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + kernel/futex.c | 14 +++++++++++--- + 1 file changed, 11 insertions(+), 3 deletions(-) + +--- a/kernel/futex.c ++++ b/kernel/futex.c +@@ -762,10 +762,18 @@ retry: + return -EDEADLK; + + /* +- * Surprise - we got the lock. Just return to userspace: ++ * Surprise - we got the lock, but we do not trust user space at all. + */ +- if (unlikely(!curval)) +- return 1; ++ if (unlikely(!curval)) { ++ /* ++ * We verify whether there is kernel state for this ++ * futex. If not, we can safely assume, that the 0 -> ++ * TID transition is correct. If state exists, we do ++ * not bother to fixup the user space state as it was ++ * corrupted already. ++ */ ++ return futex_top_waiter(hb, key) ? -EINVAL : 1; ++ } + + uval = curval; + diff --git a/queue-3.10/series b/queue-3.10/series index 15aebb904af..4aa9977c0aa 100644 --- a/queue-3.10/series +++ b/queue-3.10/series @@ -102,3 +102,7 @@ media-fc2580-fix-tuning-failure-on-32-bit-arch.patch media-v4l2-ov7670-fix-a-wrong-index-potentially-oopsing-the-kernel-from-user-space.patch media-v4l2-fix-vidioc_create_bufs-in-64-32-bit-compatibility-mode.patch ath9k-protect-tid-sched-check.patch +futex-prevent-requeue-pi-on-same-futex.patch-futex-forbid-uaddr-uaddr2-in-futex_requeue-...-requeue_pi-1.patch +futex-validate-atomic-acquisition-in-futex_lock_pi_atomic.patch +futex-always-cleanup-owner-tid-in-unlock_pi.patch +futex-make-lookup_pi_state-more-robust.patch