Vulnerability: The futex_wait_requeue_pi function in kernel/futex.c in the Linux kernel before 3.5.1 does not ensure that calls have two different futex addresses, which allows local users to cause a denial of service (NULL pointer dereference and system crash) or possibly have unspecified other impact via a crafted FUTEX_WAIT_REQUEUE_PI command.
Vulnerability ID: CVE-2012-6647
CWE: CWE-20
Severity score: 6.9
Project: https://github.com/torvalds/linux
Published: 2014-05-26
File: kernel/futex.c
Commit message: futex: Forbid uaddr == uaddr2 in futex_wait_requeue_pi()

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,
as the trinity test suite manages to do, we miss early wakeups as
q.key is equal to key2 (because they are the same uaddr). We will then
attempt to dereference the pi_mutex (which would exist had the futex_q
been properly requeued to a pi futex) and trigger a NULL pointer
dereference.

Signed-off-by: Darren Hart <dvhart@linux.intel.com>
Cc: Dave Jones <davej@redhat.com>
Cc: stable@vger.kernel.org
Link: http://lkml.kernel.org/r/ad82bfe7f7d130247fbe2b5b4275654807774227.1342809673.git.dvhart@linux.intel.com
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Commit author: Darren Hart

Vulnerable version (before fix):
 int handle_early_requeue_pi_wakeup(struct futex_hash_bucket *hb,  * @uaddr2:	the pi futex we will take prior to returning to user-space  *  * The caller will wait on uaddr and will be requeued by futex_requeue() to  * uaddr2 which must be PI aware.  Normal wakeup will wake on uaddr2 and  * complete the acquisition of the rt_mutex prior to returning to userspace.  * This ensures the rt_mutex maintains an owner when it has waiters; without  * one, the pi logic wouldn't know which task to boost/deboost, if there was a  * need to.  *  * We call schedule in futex_wait_queue_me() when we enqueue and return there  * via the following: static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags, 	struct futex_q q = futex_q_init; 	int res, ret;  	if (!bitset) 		return -EINVAL; 

Fixed version (after fix):
 int handle_early_requeue_pi_wakeup(struct futex_hash_bucket *hb,  * @uaddr2:	the pi futex we will take prior to returning to user-space  *  * The caller will wait on uaddr and will be requeued by futex_requeue() to  * uaddr2 which must be PI aware and unique from uaddr.  Normal wakeup will wake  * on uaddr2 and complete the acquisition of the rt_mutex prior to returning to  * userspace.  This ensures the rt_mutex maintains an owner when it has waiters;  * without one, the pi logic would not know which task to boost/deboost, if  * there was a need to.  *  * We call schedule in futex_wait_queue_me() when we enqueue and return there  * via the following: static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags, 	struct futex_q q = futex_q_init; 	int res, ret;  	if (uaddr == uaddr2) 		return -EINVAL;  	if (!bitset) 		return -EINVAL; 

Patch:
patch: @@ -2231,11 +2231,11 @@ int handle_early_requeue_pi_wakeup(struct futex_hash_bucket *hb,
  * @uaddr2:	the pi futex we will take prior to returning to user-space
  *
  * The caller will wait on uaddr and will be requeued by futex_requeue() to
- * uaddr2 which must be PI aware.  Normal wakeup will wake on uaddr2 and
- * complete the acquisition of the rt_mutex prior to returning to userspace.
- * This ensures the rt_mutex maintains an owner when it has waiters; without
- * one, the pi logic wouldn't know which task to boost/deboost, if there was a
- * need to.
+ * uaddr2 which must be PI aware and unique from uaddr.  Normal wakeup will wake
+ * on uaddr2 and complete the acquisition of the rt_mutex prior to returning to
+ * userspace.  This ensures the rt_mutex maintains an owner when it has waiters;
+ * without one, the pi logic would not know which task to boost/deboost, if
+ * there was a need to.
  *
  * We call schedule in futex_wait_queue_me() when we enqueue and return there
  * via the following:
@@ -2272,6 +2272,9 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
 	struct futex_q q = futex_q_init;
 	int res, ret;
 
+	if (uaddr == uaddr2)
+		return -EINVAL;
+
 	if (!bitset)
 		return -EINVAL;
path: kernel/futex.c