Sign Up for Your FREE Weekly SecurityTracker E-mail Alert Summary
|
|
|
|
|
|
|
Put SecurityTracker Vulnerability Alerts on Your Web Site -- It's Free!
|
|
|
|
Become a Partner and License Our Database or Notification Service
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Linux Kernel Deadlock Error in futex Functions Let Local Users Deny Service
|
|
SecurityTracker Alert ID: 1013616
|
|
SecurityTracker URL: http://securitytracker.com/id?1013616
|
|
CVE Reference: CAN-2005-0937
(Links to External Site)
|
Date: Mar 31 2005
|
Impact: Denial of service via local system
|
Fix Available: Yes
Vendor Confirmed: Yes
|
Version(s): 2.6
|
Description: A vulnerability was reported in the LInux kernel futex functions. A local user can cause the kernel to crash.
Some kernel futex functions invoke get_user() calls while holding mmap_sem for reading. If a get_user() function fails while another
thread is in mmap, then the do_page_fault() function will deadlock.
Another similar deadlock condition may occur.
A local
user can exploit this to cause denial of service conditions on the target system.
The flaw resides in 'kernel/futex.c'.
Olof
Johansson reported this vulnerability.
|
Impact: A local user can cause the target system to crash.
|
Solution: A development patch (and changeset) is available, as described at:
http://lkml.org/lkml/2005/2/22/185
|
Vendor URL: www.kernel.org/ (Links to External Site)
|
Cause: State error
|
Underlying OS: Linux (Caldera/SCO), Linux (Conectiva), Linux (Debian), Linux (EnGarde), Linux (Gentoo), Linux (HP Secure OS), Linux (Immunix), Linux (Mandrake), Linux (Progeny Debian), Linux (Red Hat Enterprise), Linux (Red Hat Fedora), Linux (Red Hat Linux), Linux (SGI), Linux (Slackware), Linux (Sun), Linux (SuSE), Linux (Trustix), Linux (Turbo Linux), Linux (Ubuntu), Linux (Xandros)
|
Reported By: Olof Johansson <user@domain.name>
|
Message History:
None.
|
Source Message Contents
|
Date: Tue, 22 Feb 2005 16:42:56 -0600
From: Olof Johansson <user@domain.name>
Subject: Re: [PATCH/RFC] Futex mmap_sem deadlock
|
On Tue, Feb 22, 2005 at 10:34:57PM +0000, Jamie Lokier wrote:
> There is one small but important error: the "return ret" mustn't just
> return. It must call unqueue_me(&q) just like the code at out_unqueue,
> _including_ the conditional "ret = 0", but _excluding_ the up_read().
Not only that, but someone might already have dequeued us, right? It's
probably a pathological case though, i.e. someone did a wake on the same
(bad) address.
How's this patch? It's closer to Linus' pseudo-code than Andrew's, to
avoid the extra get_user() at function entry and keep the common case
path short.
It also includes the feedback from Andrew on the sys_get_mempolicy(),
making the patch even simpler there.
----
Some futex functions do get_user calls while holding mmap_sem for
reading. If get_user() faults, and another thread happens to be in mmap
(or somewhere else holding waiting on down_write for the same semaphore),
then do_page_fault will deadlock. Most architectures seem to be exposed
to this.
To avoid it, make sure the page is available. If not, release the
semaphore, fault it in and retry.
I also found another exposure by inspection, moving some of the code
around avoids the possible deadlock there.
Signed-off-by: Olof Johansson <olof@austin.ibm.com>
Index: linux-2.5/kernel/futex.c
===================================================================
--- linux-2.5.orig/kernel/futex.c 2005-02-21 16:09:38.000000000 -0600
+++ linux-2.5/kernel/futex.c 2005-02-22 16:38:24.000000000 -0600
@@ -329,6 +329,7 @@
int ret, drop_count = 0;
unsigned int nqueued;
+ retry:
down_read(¤t->mm->mmap_sem);
ret = get_futex_key(uaddr1, &key1);
@@ -355,9 +356,19 @@
before *uaddr1. */
smp_mb();
- if (get_user(curval, (int __user *)uaddr1) != 0) {
- ret = -EFAULT;
- goto out;
+ inc_preempt_count();
+ ret = get_user(curval, (int __user *)uaddr1);
+ dec_preempt_count();
+
+ if (unlikely(ret)) {
+ up_read(¤t->mm->mmap_sem);
+ /* Re-do the access outside the lock */
+ ret = get_user(curval, (int __user *)uaddr1);
+
+ if (!ret)
+ goto retry;
+
+ return ret;
}
if (curval != *valp) {
ret = -EAGAIN;
@@ -480,6 +491,7 @@
int ret, curval;
struct futex_q q;
+ retry:
down_read(¤t->mm->mmap_sem);
ret = get_futex_key(uaddr, &q.key);
@@ -508,9 +520,21 @@
* We hold the mmap semaphore, so the mapping cannot have changed
* since we looked it up in get_futex_key.
*/
- if (get_user(curval, (int __user *)uaddr) != 0) {
- ret = -EFAULT;
- goto out_unqueue;
+ inc_preempt_count();
+ ret = get_user(curval, (int __user *)uaddr);
+ dec_preempt_count();
+ if (unlikely(ret)) {
+ up_read(¤t->mm->mmap_sem);
+
+ if (!unqueue_me(&q)) /* There's a chance we got woken already */
+ return 0;
+
+ /* Re-do the access outside the lock */
+ ret = get_user(curval, (int __user *)uaddr);
+
+ if (!ret)
+ goto retry;
+ return ret;
}
if (curval != val) {
ret = -EWOULDBLOCK;
Index: linux-2.5/mm/mempolicy.c
===================================================================
--- linux-2.5.orig/mm/mempolicy.c 2005-02-04 00:27:40.000000000 -0600
+++ linux-2.5/mm/mempolicy.c 2005-02-22 14:34:19.000000000 -0600
@@ -524,9 +524,13 @@
} else
pval = pol->policy;
- err = -EFAULT;
+ if (vma) {
+ up_read(¤t->mm->mmap_sem);
+ vma = NULL;
+ }
+
if (policy && put_user(pval, policy))
- goto out;
+ return -EFAULT;
err = 0;
if (nmask) {
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
|
|
Go to the Top of This SecurityTracker Archive Page
|