Skip to contentSkip to conversation

futex: Fix issues found with trinity and static analysis

PATCH In review Darren Hart 1 participant 7 messages Jul 20, 2012 – Jul 24, 2012

lore
Share & tools
lore
#0 lore raw

cover futex: Fix issues found with trinity and static analysis

Dave Jones and Dan Carpenter reported issues uncovered via trinity and static analysis respectively.

The following changes since commit 85efc72a0218335324d358ac479a04c16316fd4d:

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/sage/ceph-client (2012-07-19 16:11:28 -0700)

are available in the git repository at:

git://git.infradead.org/users/dvhart/linux-2.6.git futex

Darren Hart (3):
futex: Test for pi_mutex on fault in futex_wait_requeue_pi
futex: Fix bug in WARN_ON for NULL q.pi_state
futex: Forbid uaddr == uaddr2 in futex_wait_requeue_pi()

 kernel/futex.c |   17 ++++++++++-------
 1 file changed, 10 insertions(+), 7 deletions(-)
Signature · 1 line
1.7.10.4
#1 lore raw

PATCH 1/3 futex: Test for pi_mutex on fault in futex_wait_requeue_pi

If fixup_pi_state_owner() faults, pi_mutex may be NULL. Test for pi_mutex != NULL before testing the owner against current and possibly unlocking it.

CC Dave Jones <[email protected]>
CC Dan Carpenter <[email protected]>
CC Thomas Gleixner <[email protected]>
---
 kernel/futex.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/futex.c +1 -1
index e2b0fb9..05018bf 100644
@@ -2370,7 +2370,7 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
 	 * fault, unlock the rt_mutex and return the fault to userspace.
 	 */
 	if (ret == -EFAULT) {
-		if (rt_mutex_owner(pi_mutex) == current)
+		if (pi_mutex && rt_mutex_owner(pi_mutex) == current)
 			rt_mutex_unlock(pi_mutex);
 	} else if (ret == -EINTR) {
 		/*
Signature · 1 line
1.7.10.4
#2 lore raw

[tip:core/urgent] futex: Test for pi_mutex on fault in futex_wait_requeue_pi()

Commit-ID:  b6070a8d9853eda010a549fa9a09eb8d7269b929
Gitweb:     http://git.kernel.org/tip/b6070a8d9853eda010a549fa9a09eb8d7269b929
Author:     Darren Hart <[email protected]>
AuthorDate: Fri, 20 Jul 2012 11:53:29 -0700
Committer:  Thomas Gleixner <[email protected]>
CommitDate: Tue, 24 Jul 2012 16:02:56 +0200

futex: Test for pi_mutex on fault in futex_wait_requeue_pi()

If fixup_pi_state_owner() faults, pi_mutex may be NULL. Test for pi_mutex != NULL before testing the owner against current and possibly unlocking it.

---
 kernel/futex.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
kernel/futex.c +1 -1
index e2b0fb9..05018bf 100644
@@ -2370,7 +2370,7 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
 	 * fault, unlock the rt_mutex and return the fault to userspace.
 	 */
 	if (ret == -EFAULT) {
-		if (rt_mutex_owner(pi_mutex) == current)
+		if (pi_mutex && rt_mutex_owner(pi_mutex) == current)
 			rt_mutex_unlock(pi_mutex);
 	} else if (ret == -EINTR) {
 		/*
#3 lore raw

PATCH 2/3 futex: Fix bug in WARN_ON for NULL q.pi_state

In reply to Darren Hart

The WARN_ON in futex_wait_requeue_pi() for a NULL q.pi_state was testing the address (&q.pi_state) of the pointer instead of the value (q.pi_state) of the pointer. Correct it accordingly.

CC Dave Jones <[email protected]>
CC Thomas Gleixner <[email protected]>
---
 kernel/futex.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/futex.c +1 -1
index 05018bf..5551ada 100644
@@ -2343,7 +2343,7 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
 		 * signal.  futex_unlock_pi() will not destroy the lock_ptr nor
 		 * the pi_state.
 		 */
-		WARN_ON(!&q.pi_state);
+		WARN_ON(!q.pi_state);
 		pi_mutex = &q.pi_state->pi_mutex;
 		ret = rt_mutex_finish_proxy_lock(pi_mutex, to, &rt_waiter, 1);
 		debug_rt_mutex_free_waiter(&rt_waiter);
Signature · 1 line
1.7.10.4
#4 lore raw

[tip:core/urgent] futex: Fix bug in WARN_ON for NULL q.pi_state

Commit-ID:  f27071cb7fe3e1d37a9dbe6c0dfc5395cd40fa43
Gitweb:     http://git.kernel.org/tip/f27071cb7fe3e1d37a9dbe6c0dfc5395cd40fa43
Author:     Darren Hart <[email protected]>
AuthorDate: Fri, 20 Jul 2012 11:53:30 -0700
Committer:  Thomas Gleixner <[email protected]>
CommitDate: Tue, 24 Jul 2012 16:02:57 +0200

futex: Fix bug in WARN_ON for NULL q.pi_state

The WARN_ON in futex_wait_requeue_pi() for a NULL q.pi_state was testing the address (&q.pi_state) of the pointer instead of the value (q.pi_state) of the pointer. Correct it accordingly.

---
 kernel/futex.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
kernel/futex.c +1 -1
index 05018bf..5551ada 100644
@@ -2343,7 +2343,7 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
 		 * signal.  futex_unlock_pi() will not destroy the lock_ptr nor
 		 * the pi_state.
 		 */
-		WARN_ON(!&q.pi_state);
+		WARN_ON(!q.pi_state);
 		pi_mutex = &q.pi_state->pi_mutex;
 		ret = rt_mutex_finish_proxy_lock(pi_mutex, to, &rt_waiter, 1);
 		debug_rt_mutex_free_waiter(&rt_waiter);
#5 lore raw

PATCH 3/3 futex: Forbid uaddr == uaddr2 in futex_wait_requeue_pi()

In reply to Darren Hart

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.

CC Dave Jones <[email protected]>
CC Thomas Gleixner <[email protected]>
---
 kernel/futex.c |   13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)
kernel/futex.c +8 -5
index 5551ada..3717e7b 100644
@@ -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;
 
Signature · 1 line
1.7.10.4
#6 lore raw

[tip:core/urgent] futex: Forbid uaddr == uaddr2 in futex_wait_requeue_pi()

Commit-ID:  6f7b0a2a5c0fb03be7c25bd1745baa50582348ef
Gitweb:     http://git.kernel.org/tip/6f7b0a2a5c0fb03be7c25bd1745baa50582348ef
Author:     Darren Hart <[email protected]>
AuthorDate: Fri, 20 Jul 2012 11:53:31 -0700
Committer:  Thomas Gleixner <[email protected]>
CommitDate: Tue, 24 Jul 2012 16:02:57 +0200

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.

---
 kernel/futex.c |   13 ++++++++-----
 1 files changed, 8 insertions(+), 5 deletions(-)
kernel/futex.c +8 -5
index 5551ada..3717e7b 100644
@@ -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;