[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: 2.2 Kernel Fix



> 2.2 series of kernels, sincee they're apparently vulnerable too?
 You can find the patch on bugtraq/isec/etc, attached is a peek at it

-- 
Dariush Pietrzak,
Key fingerprint = 40D0 9FFB 9939 7320 8294  05E0 BCC7 02C4 75CC 50D9
--- linux/mm/mremap.c.security	Sun Mar 25 20:31:03 2001
+++ linux/mm/mremap.c	Thu Feb 19 05:10:34 2004
@@ -9,6 +9,7 @@
 #include <linux/shm.h>
 #include <linux/mman.h>
 #include <linux/swap.h>
+#include <linux/file.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -25,7 +26,7 @@
 	if (pgd_none(*pgd))
 		goto end;
 	if (pgd_bad(*pgd)) {
-		printk("move_one_page: bad source pgd (%08lx)\n", pgd_val(*pgd));
+		printk("copy_one_page: bad source pgd (%08lx)\n", pgd_val(*pgd));
 		pgd_clear(pgd);
 		goto end;
 	}
@@ -34,7 +35,7 @@
 	if (pmd_none(*pmd))
 		goto end;
 	if (pmd_bad(*pmd)) {
-		printk("move_one_page: bad source pmd (%08lx)\n", pmd_val(*pmd));
+		printk("copy_one_page: bad source pmd (%08lx)\n", pmd_val(*pmd));
 		pmd_clear(pmd);
 		goto end;
 	}
@@ -57,34 +58,22 @@
 	return pte;
 }
 
-static inline int copy_one_pte(pte_t * src, pte_t * dst)
+static int copy_one_page(struct mm_struct *mm, unsigned long old_addr, unsigned long new_addr)
 {
-	int error = 0;
-	pte_t pte = *src;
+	pte_t * src, * dst;
 
-	if (!pte_none(pte)) {
-		error++;
-		if (dst) {
-			pte_clear(src);
-			set_pte(dst, pte);
-			error--;
+	src = get_one_pte(mm, old_addr);
+	if (src && !pte_none(*src)) {
+		if ((dst = alloc_one_pte(mm, new_addr))) {
+			set_pte(dst, *src);
+			return 0;
 		}
+		return 1;
 	}
-	return error;
-}
-
-static int move_one_page(struct mm_struct *mm, unsigned long old_addr, unsigned long new_addr)
-{
-	int error = 0;
-	pte_t * src;
-
-	src = get_one_pte(mm, old_addr);
-	if (src)
-		error = copy_one_pte(src, alloc_one_pte(mm, new_addr));
-	return error;
+	return 0;
 }
 
-static int move_page_tables(struct mm_struct * mm,
+static int copy_page_tables(struct mm_struct * mm,
 	unsigned long new_addr, unsigned long old_addr, unsigned long len)
 {
 	unsigned long offset = len;
@@ -99,7 +88,7 @@
 	 */
 	while (offset) {
 		offset -= PAGE_SIZE;
-		if (move_one_page(mm, old_addr + offset, new_addr + offset))
+		if (copy_one_page(mm, old_addr + offset, new_addr + offset))
 			goto oops_we_failed;
 	}
 	return 0;
@@ -113,8 +102,6 @@
 	 */
 oops_we_failed:
 	flush_cache_range(mm, new_addr, new_addr + len);
-	while ((offset += PAGE_SIZE) < len)
-		move_one_page(mm, new_addr + offset, old_addr + offset);
 	zap_page_range(mm, new_addr, len);
 	flush_tlb_range(mm, new_addr, new_addr + len);
 	return -1;
@@ -129,7 +116,9 @@
 	if (new_vma) {
 		unsigned long new_addr = get_unmapped_area(addr, new_len);
 
-		if (new_addr && !move_page_tables(current->mm, new_addr, addr, old_len)) {
+		if (new_addr && !copy_page_tables(current->mm, new_addr, addr, old_len)) {
+			unsigned long ret;
+
 			*new_vma = *vma;
 			new_vma->vm_start = new_addr;
 			new_vma->vm_end = new_addr+new_len;
@@ -138,9 +127,19 @@
 				new_vma->vm_file->f_count++;
 			if (new_vma->vm_ops && new_vma->vm_ops->open)
 				new_vma->vm_ops->open(new_vma);
+			if ((ret = do_munmap(addr, old_len))) {
+				if (new_vma->vm_ops && new_vma->vm_ops->close)
+					new_vma->vm_ops->close(new_vma);
+				if (new_vma->vm_file)
+					fput(new_vma->vm_file);
+				flush_cache_range(current->mm, new_addr, new_addr + old_len);
+				zap_page_range(current->mm, new_addr, old_len);
+				flush_tlb_range(current->mm, new_addr, new_addr + old_len);
+				kmem_cache_free(vm_area_cachep, new_vma);
+				return ret;
+			}
 			insert_vm_struct(current->mm, new_vma);
 			merge_segments(current->mm, new_vma->vm_start, new_vma->vm_end);
-			do_munmap(addr, old_len);
 			current->mm->total_vm += new_len >> PAGE_SHIFT;
 			if (new_vma->vm_flags & VM_LOCKED) {
 				current->mm->locked_vm += new_len >> PAGE_SHIFT;
@@ -176,9 +175,9 @@
 	 * Always allow a shrinking remap: that just unmaps
 	 * the unnecessary pages..
 	 */
-	ret = addr;
 	if (old_len >= new_len) {
-		do_munmap(addr+new_len, old_len - new_len);
+		if (!(ret = do_munmap(addr+new_len, old_len - new_len)))
+			ret = addr;
 		goto out;
 	}
 

Reply to: