[kernel] r8034 - in dists/sid/linux-2.6/debian: . patches/bugfix patches/series

Dann Frazier dannf at alioth.debian.org
Thu Dec 21 21:36:48 UTC 2006


Author: dannf
Date: Thu Dec 21 22:36:48 2006
New Revision: 8034

Added:
   dists/sid/linux-2.6/debian/patches/bugfix/mincore-error-value-cases.patch
   dists/sid/linux-2.6/debian/patches/bugfix/mincore-hang.patch
   dists/sid/linux-2.6/debian/patches/bugfix/mincore-typo.patch
Modified:
   dists/sid/linux-2.6/debian/changelog
   dists/sid/linux-2.6/debian/patches/series/9
Log:
* Fix mincore hang (CVE-2006-4814)

Modified: dists/sid/linux-2.6/debian/changelog
==============================================================================
--- dists/sid/linux-2.6/debian/changelog	(original)
+++ dists/sid/linux-2.6/debian/changelog	Thu Dec 21 22:36:48 2006
@@ -30,6 +30,7 @@
     - Revert change that replaed XFER_READ/XFER_WRITE macros with
       h->cciss_read/h->cciss_write that caused command timeouts on older
       controllers on ia32 (closes: #402787)
+  * Fix mincore hang (CVE-2006-4814)
 
   [ Norbert Tretkowski ]
   * libata: handle 0xff status properly. (closes: #391867)
@@ -40,7 +41,7 @@
   * m68k/atari: enable keyboard, mouse and fb drivers
   * m68k/atari: fixes for ethernec and video driver by Michael Schmitz
 
- -- Norbert Tretkowski <nobse at debian.org>  Thu, 21 Dec 2006 21:40:38 +0100
+ -- dann frazier <dannf at debian.org>  Thu, 21 Dec 2006 14:34:01 -0700
 
 linux-2.6 (2.6.18-8) unstable; urgency=low
 

Added: dists/sid/linux-2.6/debian/patches/bugfix/mincore-error-value-cases.patch
==============================================================================
--- (empty file)
+++ dists/sid/linux-2.6/debian/patches/bugfix/mincore-error-value-cases.patch	Thu Dec 21 22:36:48 2006
@@ -0,0 +1,75 @@
+From: Linus Torvalds <torvalds at woody.osdl.org>
+Date: Sun, 17 Dec 2006 00:01:50 +0000 (-0800)
+Subject: Fix up mm/mincore.c error value cases
+X-Git-Url: http://www.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=4fb23e439ce09157d64b89a21061b9fc08f2b495
+
+Fix up mm/mincore.c error value cases
+
+Hugh Dickins correctly points out that mincore() is actually _supposed_
+to fail on an unmapped hole in the user address space, rather than
+return valid ("empty") information about the hole.  This just simplifies
+the problem further (I had been misled by our previous confusing and
+complicated way of doing mincore()).
+
+Also, in the unlikely situation that we can't allocate a temporary
+kernel buffer, we should actually return EAGAIN, not ENOMEM, to keep the
+"unmapped hole" and "allocation failure" error cases separate.
+
+Finally, add a comment about our stupid historical lack of support for
+anonymous mappings.  I'll fix that if somebody reminds me after 2.6.20
+is out.
+
+Acked-by: Hugh Dickins <hugh at veritas.com>
+Signed-off-by: Linus Torvalds <torvalds at osdl.org>
+---
+
+--- a/mm/mincore.c
++++ b/mm/mincore.c
+@@ -49,29 +49,20 @@ static long do_mincore(unsigned long add
+ 	struct vm_area_struct *vma = find_vma(current->mm, addr);
+ 
+ 	/*
+-	 * find_vma() didn't find anything: the address
+-	 * is above everything we have mapped.
++	 * find_vma() didn't find anything above us, or we're
++	 * in an unmapped hole in the address space: ENOMEM.
+ 	 */
+-	if (!vma) {
+-		memset(vec, 0, pages);
+-		return pages;
+-	}
+-
+-	/*
+-	 * find_vma() found something, but we might be
+-	 * below it: check for that.
+-	 */
+-	if (addr < vma->vm_start) {
+-		unsigned long gap = (vma->vm_start - addr) >> PAGE_SHIFT;
+-		if (gap > pages)
+-			gap = pages;
+-		memset(vec, 0, gap);
+-		return gap;
+-	}
++	if (!vma || addr < vma->vm_start)
++		return -ENOMEM;
+ 
+ 	/*
+ 	 * Ok, got it. But check whether it's a segment we support
+ 	 * mincore() on. Right now, we don't do any anonymous mappings.
++	 *
++	 * FIXME: This is just stupid. And returning ENOMEM is 
++	 * stupid too. We should just look at the page tables. But
++	 * this is what we've traditionally done, so we'll just
++	 * continue doing it.
+ 	 */
+ 	if (!vma->vm_file)
+ 		return -ENOMEM;
+@@ -142,7 +133,7 @@ asmlinkage long sys_mincore(unsigned lon
+ 
+ 	tmp = (void *) __get_free_page(GFP_USER);
+ 	if (!tmp)
+-		return -ENOMEM;
++		return -EAGAIN;
+ 
+ 	retval = 0;
+ 	while (pages) {

Added: dists/sid/linux-2.6/debian/patches/bugfix/mincore-hang.patch
==============================================================================
--- (empty file)
+++ dists/sid/linux-2.6/debian/patches/bugfix/mincore-hang.patch	Thu Dec 21 22:36:48 2006
@@ -0,0 +1,249 @@
+From: Linus Torvalds <torvalds at woody.osdl.org>
+Date: Sat, 16 Dec 2006 17:44:32 +0000 (-0800)
+Subject: Fix incorrect user space access locking in mincore()
+X-Git-Url: http://www.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=2f77d107050abc14bc393b34bdb7b91cf670c250
+
+Fix incorrect user space access locking in mincore()
+
+Doug Chapman noticed that mincore() will doa "copy_to_user()" of the
+result while holding the mmap semaphore for reading, which is a big
+no-no.  While a recursive read-lock on a semaphore in the case of a page
+fault happens to work, we don't actually allow them due to deadlock
+schenarios with writers due to fairness issues.
+
+Doug and Marcel sent in a patch to fix it, but I decided to just rewrite
+the mess instead - not just fixing the locking problem, but making the
+code smaller and (imho) much easier to understand.
+
+Cc: Doug Chapman <dchapman at redhat.com>
+Cc: Marcel Holtmann <holtmann at redhat.com>
+Cc: Hugh Dickins <hugh at veritas.com>
+Cc: Andrew Morton <akpm at osdl.org>
+Signed-off-by: Linus Torvalds <torvalds at osdl.org>
+---
+
+--- a/mm/mincore.c
++++ b/mm/mincore.c
+@@ -1,7 +1,7 @@
+ /*
+  *	linux/mm/mincore.c
+  *
+- * Copyright (C) 1994-1999  Linus Torvalds
++ * Copyright (C) 1994-2006  Linus Torvalds
+  */
+ 
+ /*
+@@ -38,46 +38,60 @@ static unsigned char mincore_page(struct
+ 	return present;
+ }
+ 
+-static long mincore_vma(struct vm_area_struct * vma,
+-	unsigned long start, unsigned long end, unsigned char __user * vec)
++/*
++ * Do a chunk of "sys_mincore()". We've already checked
++ * all the arguments, we hold the mmap semaphore: we should
++ * just return the amount of info we're asked for.
++ */
++static long do_mincore(unsigned long addr, unsigned char *vec, unsigned long pages)
+ {
+-	long error, i, remaining;
+-	unsigned char * tmp;
+-
+-	error = -ENOMEM;
+-	if (!vma->vm_file)
+-		return error;
+-
+-	start = ((start - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
+-	if (end > vma->vm_end)
+-		end = vma->vm_end;
+-	end = ((end - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
++	unsigned long i, nr, pgoff;
++	struct vm_area_struct *vma = find_vma(current->mm, addr);
+ 
+-	error = -EAGAIN;
+-	tmp = (unsigned char *) __get_free_page(GFP_KERNEL);
+-	if (!tmp)
+-		return error;
+-
+-	/* (end - start) is # of pages, and also # of bytes in "vec */
+-	remaining = (end - start),
++	/*
++	 * find_vma() didn't find anything: the address
++	 * is above everything we have mapped.
++	 */
++	if (!vma) {
++		memset(vec, 0, pages);
++		return pages;
++	}
+ 
+-	error = 0;
+-	for (i = 0; remaining > 0; remaining -= PAGE_SIZE, i++) {
+-		int j = 0;
+-		long thispiece = (remaining < PAGE_SIZE) ?
+-						remaining : PAGE_SIZE;
++	/*
++	 * find_vma() found something, but we might be
++	 * below it: check for that.
++	 */
++	if (addr < vma->vm_start) {
++		unsigned long gap = (vma->vm_start - addr) >> PAGE_SHIFT;
++		if (gap > pages)
++			gap = pages;
++		memset(vec, 0, gap);
++		return gap;
++	}
+ 
+-		while (j < thispiece)
+-			tmp[j++] = mincore_page(vma, start++);
++	/*
++	 * Ok, got it. But check whether it's a segment we support
++	 * mincore() on. Right now, we don't do any anonymous mappings.
++	 */
++	if (!vma->vm_file)
++		return -ENOMEM;
+ 
+-		if (copy_to_user(vec + PAGE_SIZE * i, tmp, thispiece)) {
+-			error = -EFAULT;
+-			break;
+-		}
+-	}
++	/*
++	 * Calculate how many pages there are left in the vma, and
++	 * what the pgoff is for our address.
++	 */
++	nr = (vma->vm_end - addr) >> PAGE_SHIFT;
++	if (nr > pages)
++		nr = pages;
++
++	pgoff = (addr - vma->vm_start) >> PAGE_SHIFT;
++	pgoff += vma->vm_pgoff;
++
++	/* And then we just fill the sucker in.. */
++	for (i = 0 ; i < nr; i++, pgoff++)
++		vec[i] = mincore_page(vma, pgoff);
+ 
+-	free_page((unsigned long) tmp);
+-	return error;
++	return nr;
+ }
+ 
+ /*
+@@ -107,82 +121,50 @@ static long mincore_vma(struct vm_area_s
+ asmlinkage long sys_mincore(unsigned long start, size_t len,
+ 	unsigned char __user * vec)
+ {
+-	int index = 0;
+-	unsigned long end, limit;
+-	struct vm_area_struct * vma;
+-	size_t max;
+-	int unmapped_error = 0;
+-	long error;
++	long retval;
++	unsigned long pages;
++	unsigned char *tmp;
+ 
+-	/* check the arguments */
++	/* Check the start address: needs to be page-aligned.. */
+  	if (start & ~PAGE_CACHE_MASK)
+-		goto einval;
+-
+-	limit = TASK_SIZE;
+-	if (start >= limit)
+-		goto enomem;
++		return -EINVAL;
+ 
+-	if (!len)
+-		return 0;
++	/* ..and we need to be passed a valid user-space range */
++	if (!access_ok(VERIFY_READ, (void __user *) start, len))
++		return -ENOMEM;
+ 
+-	max = limit - start;
+-	len = PAGE_CACHE_ALIGN(len);
+-	if (len > max || !len)
+-		goto enomem;
++	/* This also avoids any overflows on PAGE_CACHE_ALIGN */
++	pages = len >> PAGE_SHIFT;
++	pages += (len & ~PAGE_MASK) != 0;
+ 
+-	end = start + len;
++	if (!access_ok(VERIFY_WRITE, vec, pages))
++		return -EFAULT;
+ 
+-	/* check the output buffer whilst holding the lock */
+-	error = -EFAULT;
+-	down_read(&current->mm->mmap_sem);
+-
+-	if (!access_ok(VERIFY_WRITE, vec, len >> PAGE_SHIFT))
+-		goto out;
+-
+-	/*
+-	 * If the interval [start,end) covers some unmapped address
+-	 * ranges, just ignore them, but return -ENOMEM at the end.
+-	 */
+-	error = 0;
++	tmp = (void *) __get_free_page(GFP_USER);
++	if (!tmp)
++		return -ENOMEM;
+ 
+-	vma = find_vma(current->mm, start);
+-	while (vma) {
+-		/* Here start < vma->vm_end. */
+-		if (start < vma->vm_start) {
+-			unmapped_error = -ENOMEM;
+-			start = vma->vm_start;
+-		}
++	retval = 0;
++	while (pages) {
++		/*
++		 * Do at most PAGE_SIZE entries per iteration, due to
++		 * the temporary buffer size.
++		 */
++		down_read(&current->mm->mmap_sem);
++		retval = do_mincore(start, tmp, max(pages, PAGE_SIZE));
++		up_read(&current->mm->mmap_sem);
+ 
+-		/* Here vma->vm_start <= start < vma->vm_end. */
+-		if (end <= vma->vm_end) {
+-			if (start < end) {
+-				error = mincore_vma(vma, start, end,
+-							&vec[index]);
+-				if (error)
+-					goto out;
+-			}
+-			error = unmapped_error;
+-			goto out;
++		if (retval <= 0)
++			break;
++		if (copy_to_user(vec, tmp, retval)) {
++			retval = -EFAULT;
++			break;
+ 		}
+-
+-		/* Here vma->vm_start <= start < vma->vm_end < end. */
+-		error = mincore_vma(vma, start, vma->vm_end, &vec[index]);
+-		if (error)
+-			goto out;
+-		index += (vma->vm_end - start) >> PAGE_CACHE_SHIFT;
+-		start = vma->vm_end;
+-		vma = vma->vm_next;
++		pages -= retval;
++		vec += retval;
++		start += retval << PAGE_SHIFT;
++		retval = 0;
+ 	}
+-
+-	/* we found a hole in the area queried if we arrive here */
+-	error = -ENOMEM;
+-
+-out:
+-	up_read(&current->mm->mmap_sem);
+-	return error;
+-
+-einval:
+-	return -EINVAL;
+-enomem:
+-	return -ENOMEM;
++	free_page((unsigned long) tmp);
++	return retval;
+ }

Added: dists/sid/linux-2.6/debian/patches/bugfix/mincore-typo.patch
==============================================================================
--- (empty file)
+++ dists/sid/linux-2.6/debian/patches/bugfix/mincore-typo.patch	Thu Dec 21 22:36:48 2006
@@ -0,0 +1,24 @@
+From: Oleg Nesterov <oleg at tv-sign.ru>
+Date: Sun, 17 Dec 2006 15:52:47 +0000 (+0300)
+Subject: [PATCH] sys_mincore: s/max/min/
+X-Git-Url: http://www.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=825020c3866e7312947e17a0caa9dd1a5622bafc
+
+[PATCH] sys_mincore: s/max/min/
+
+fix a typo, sys_mincore() needs min().
+
+Signed-off-by: Oleg Nesterov <oleg at tv-sign.ru>
+Signed-off-by: Linus "I'm a moron" Torvalds <torvalds at osdl.org>
+---
+
+--- a/mm/mincore.c
++++ b/mm/mincore.c
+@@ -142,7 +142,7 @@ asmlinkage long sys_mincore(unsigned lon
+ 		 * the temporary buffer size.
+ 		 */
+ 		down_read(&current->mm->mmap_sem);
+-		retval = do_mincore(start, tmp, max(pages, PAGE_SIZE));
++		retval = do_mincore(start, tmp, min(pages, PAGE_SIZE));
+ 		up_read(&current->mm->mmap_sem);
+ 
+ 		if (retval <= 0)

Modified: dists/sid/linux-2.6/debian/patches/series/9
==============================================================================
--- dists/sid/linux-2.6/debian/patches/series/9	(original)
+++ dists/sid/linux-2.6/debian/patches/series/9	Thu Dec 21 22:36:48 2006
@@ -13,3 +13,6 @@
 + bugfix/cciss-set-default-raid-level.patch
 + bugfix/cciss-XFER_READ-WRITE.patch
 + bugfix/i2c-elektor-works-on-smp.patch
++ bugfix/mincore-hang.patch
++ bugfix/mincore-error-value-cases.patch
++ bugfix/mincore-typo.patch



More information about the Kernel-svn-changes mailing list