All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] Fix the mincore() syscall
@ 2005-02-11 18:52 David Howells
  0 siblings, 0 replies; only message in thread
From: David Howells @ 2005-02-11 18:52 UTC (permalink / raw)
  To: akpm, torvalds; +Cc: linuxppc64-dev, linux-kernel


The attached patch fixes the mincore syscall in three ways:

 (1) It moves as much argument checking outside of the semaphore-holding
     region as possible.

 (2) It checks the region parameters against TASK_SIZE so that a 32-bit binary
     on a 64-bit platform will get the right error when calling this syscall
     on a region that overlaps the end of the 32-bit address space.

 (3) It tidies up the VMA checking loop a little.

Signed-Off-By: David Howells <dhowells@redhat.com>
---
warthog>diffstat mincore-2611rc3bk8.diff 
 mincore.c |   50 ++++++++++++++++++++++++++++++++------------------
 1 files changed, 32 insertions(+), 18 deletions(-)

diff -uNrp linux-2.6.11-rc3-bk8/mm/mincore.c linux-2.6.11-rc3-bk8-mincore/mm/mincore.c
--- linux-2.6.11-rc3-bk8/mm/mincore.c	2005-01-04 11:13:57.000000000 +0000
+++ linux-2.6.11-rc3-bk8-mincore/mm/mincore.c	2005-02-11 18:44:25.563625998 +0000
@@ -109,39 +109,45 @@ asmlinkage long sys_mincore(unsigned lon
 	unsigned char __user * vec)
 {
 	int index = 0;
-	unsigned long end;
+	unsigned long end, limit;
 	struct vm_area_struct * vma;
+	size_t max;
 	int unmapped_error = 0;
-	long error = -EINVAL;
+	long error;
 
-	down_read(&current->mm->mmap_sem);
+	/* check the arguments */
+ 	if (start & ~PAGE_CACHE_MASK)
+		goto einval;
+
+	if (start < FIRST_USER_PGD_NR * PGDIR_SIZE)
+		goto enomem;
+
+	limit = TASK_SIZE;
+	if (start >= limit)
+		goto enomem;
+
+	max = limit - start;
+	len = PAGE_CACHE_ALIGN(len);
+	if (len > max)
+		goto einval;
 
-	if (start & ~PAGE_CACHE_MASK)
-		goto out;
-	len = (len + ~PAGE_CACHE_MASK) & PAGE_CACHE_MASK;
 	end = start + len;
-	if (end < start)
-		goto out;
 
+	/* check the output buffer whilst holding the lock */
 	error = -EFAULT;
-	if (!access_ok(VERIFY_WRITE, vec, len >> PAGE_SHIFT))
-		goto out;
+	down_read(&current->mm->mmap_sem);
 
-	error = 0;
-	if (end == start)
+	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.
 	 */
-	vma = find_vma(current->mm, start);
-	for (;;) {
-		/* Still start < end. */
-		error = -ENOMEM;
-		if (!vma)
-			goto out;
+	error = 0;
 
+	vma = find_vma(current->mm, start);
+	while (vma) {
 		/* Here start < vma->vm_end. */
 		if (start < vma->vm_start) {
 			unmapped_error = -ENOMEM;
@@ -169,7 +175,15 @@ asmlinkage long sys_mincore(unsigned lon
 		vma = vma->vm_next;
 	}
 
+	/* 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;
 }

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2005-02-11 18:54 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-02-11 18:52 [PATCH] Fix the mincore() syscall David Howells

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.