# This is a BitKeeper generated diff -Nru style patch. # # ChangeSet # 2004/12/17 21:45:58-02:00 chrisw@osdl.org # [PATCH] Backport of 2.6 fix to insert_vm_struct to make it return an error rather than BUG(). # # Backport of 2.6 fix to insert_vm_struct to make it return an error # rather than BUG(). This eliminates a user triggerable BUG() when user # created a large vma that overlapped with arg pages during exec (could be # triggered with a.out on i386 and x86_64 and elf on ia64). # # Signed-off-by: Chris Wright # # ===== arch/ia64/ia32/binfmt_elf32.c 1.13 vs edited ===== # # arch/ia64/ia32/binfmt_elf32.c # 2004/12/17 17:22:06-02:00 chrisw@osdl.org +16 -4 # Backport of 2.6 fix to insert_vm_struct to make it return an error rather than BUG(). # # arch/ia64/mm/init.c # 2004/12/17 15:25:47-02:00 chrisw@osdl.org +14 -2 # Backport of 2.6 fix to insert_vm_struct to make it return an error rather than BUG(). # # arch/s390x/kernel/exec32.c # 2004/12/17 15:32:42-02:00 chrisw@osdl.org +6 -2 # Backport of 2.6 fix to insert_vm_struct to make it return an error rather than BUG(). This eliminates a user triggerable BUG() when user # # arch/x86_64/ia32/ia32_binfmt.c # 2004/12/17 15:34:21-02:00 chrisw@osdl.org +6 -2 # Backport of 2.6 fix to insert_vm_struct to make it return an error rather than BUG(). This eliminates a user triggerable BUG() when user # # fs/exec.c # 2004/12/17 15:54:18-02:00 chrisw@osdl.org +6 -2 # Backport of 2.6 fix to insert_vm_struct to make it return an error rather than BUG(). # # include/linux/mm.h # 2004/12/16 20:38:37-02:00 chrisw@osdl.org +1 -1 # Backport of 2.6 fix to insert_vm_struct to make it return an error rather than BUG(). This eliminates a user triggerable BUG() when user # # mm/mmap.c # 2004/12/16 20:43:15-02:00 chrisw@osdl.org +3 -2 # Backport of 2.6 fix to insert_vm_struct to make it return an error rather than BUG(). # diff -Nru a/arch/ia64/ia32/binfmt_elf32.c b/arch/ia64/ia32/binfmt_elf32.c --- a/arch/ia64/ia32/binfmt_elf32.c 2004-12-19 07:39:49 -08:00 +++ b/arch/ia64/ia32/binfmt_elf32.c 2004-12-19 07:39:49 -08:00 @@ -95,7 +95,11 @@ vma->vm_private_data = NULL; down_write(¤t->mm->mmap_sem); { - insert_vm_struct(current->mm, vma); + if (insert_vm_struct(current->mm, vma)) { + kmem_cache_free(vm_area_cachep, vma); + up_write(¤t->mm->mmap_sem); + return; + } } up_write(¤t->mm->mmap_sem); } @@ -117,7 +121,11 @@ vma->vm_private_data = NULL; down_write(¤t->mm->mmap_sem); { - insert_vm_struct(current->mm, vma); + if (insert_vm_struct(current->mm, vma)) { + kmem_cache_free(vm_area_cachep, vma); + up_write(¤t->mm->mmap_sem); + return; + } } up_write(¤t->mm->mmap_sem); } @@ -164,7 +172,7 @@ { unsigned long stack_base; struct vm_area_struct *mpnt; - int i; + int i, ret; stack_base = IA32_STACK_TOP - MAX_ARG_PAGES*PAGE_SIZE; @@ -188,7 +196,11 @@ mpnt->vm_pgoff = 0; mpnt->vm_file = NULL; mpnt->vm_private_data = 0; - insert_vm_struct(current->mm, mpnt); + if ((ret = insert_vm_struct(current->mm, mpnt))) { + up_write(¤t->mm->mmap_sem); + kmem_cache_free(vm_area_cachep, mpnt); + return ret; + } current->mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT; } diff -Nru a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c --- a/arch/ia64/mm/init.c 2004-12-19 07:39:49 -08:00 +++ b/arch/ia64/mm/init.c 2004-12-19 07:39:49 -08:00 @@ -105,7 +105,13 @@ vma->vm_pgoff = 0; vma->vm_file = NULL; vma->vm_private_data = NULL; - insert_vm_struct(current->mm, vma); + down_write(¤t->mm->mmap_sem); + if (insert_vm_struct(current->mm, vma)) { + up_write(¤t->mm->mmap_sem); + kmem_cache_free(vm_area_cachep, vma); + return; + } + up_write(¤t->mm->mmap_sem); } /* map NaT-page at address zero to speed up speculative dereferencing of NULL: */ @@ -117,7 +123,13 @@ vma->vm_end = PAGE_SIZE; vma->vm_page_prot = __pgprot(pgprot_val(PAGE_READONLY) | _PAGE_MA_NAT); vma->vm_flags = VM_READ | VM_MAYREAD | VM_IO | VM_RESERVED; - insert_vm_struct(current->mm, vma); + down_write(¤t->mm->mmap_sem); + if (insert_vm_struct(current->mm, vma)) { + up_write(¤t->mm->mmap_sem); + kmem_cache_free(vm_area_cachep, vma); + return; + } + up_write(¤t->mm->mmap_sem); } } } diff -Nru a/arch/s390x/kernel/exec32.c b/arch/s390x/kernel/exec32.c --- a/arch/s390x/kernel/exec32.c 2004-12-19 07:39:49 -08:00 +++ b/arch/s390x/kernel/exec32.c 2004-12-19 07:39:49 -08:00 @@ -41,7 +41,7 @@ { unsigned long stack_base; struct vm_area_struct *mpnt; - int i; + int i, ret; stack_base = STACK_TOP - MAX_ARG_PAGES*PAGE_SIZE; @@ -65,7 +65,11 @@ mpnt->vm_pgoff = 0; mpnt->vm_file = NULL; mpnt->vm_private_data = (void *) 0; - insert_vm_struct(current->mm, mpnt); + if ((ret = insert_vm_struct(current->mm, mpnt))) { + up_write(¤t->mm->mmap_sem); + kmem_cache_free(vm_area_cachep, mpnt); + return ret; + } current->mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT; } diff -Nru a/arch/x86_64/ia32/ia32_binfmt.c b/arch/x86_64/ia32/ia32_binfmt.c --- a/arch/x86_64/ia32/ia32_binfmt.c 2004-12-19 07:39:49 -08:00 +++ b/arch/x86_64/ia32/ia32_binfmt.c 2004-12-19 07:39:49 -08:00 @@ -225,7 +225,7 @@ { unsigned long stack_base; struct vm_area_struct *mpnt; - int i; + int i, ret; stack_base = IA32_STACK_TOP - MAX_ARG_PAGES*PAGE_SIZE; @@ -250,7 +250,11 @@ mpnt->vm_pgoff = 0; mpnt->vm_file = NULL; mpnt->vm_private_data = (void *) 0; - insert_vm_struct(current->mm, mpnt); + if ((ret = insert_vm_struct(current->mm, mpnt))) { + up_write(¤t->mm->mmap_sem); + kmem_cache_free(vm_area_cachep, mpnt); + return ret; + } current->mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT; } diff -Nru a/fs/exec.c b/fs/exec.c --- a/fs/exec.c 2004-12-19 07:39:49 -08:00 +++ b/fs/exec.c 2004-12-19 07:39:49 -08:00 @@ -327,7 +327,7 @@ { unsigned long stack_base; struct vm_area_struct *mpnt; - int i; + int i, ret; stack_base = STACK_TOP - MAX_ARG_PAGES*PAGE_SIZE; @@ -387,7 +387,6 @@ down_write(¤t->mm->mmap_sem); { - struct vm_area_struct *vma; mpnt->vm_mm = current->mm; mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p; mpnt->vm_end = STACK_TOP; @@ -402,13 +401,11 @@ mpnt->vm_pgoff = 0; mpnt->vm_file = NULL; mpnt->vm_private_data = (void *) 0; - vma = find_vma(current->mm, mpnt->vm_start); - if (vma) { + if ((ret = insert_vm_struct(current->mm, mpnt))) { up_write(¤t->mm->mmap_sem); kmem_cache_free(vm_area_cachep, mpnt); - return -ENOMEM; + return ret; } - insert_vm_struct(current->mm, mpnt); current->mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT; } diff -Nru a/include/linux/mm.h b/include/linux/mm.h --- a/include/linux/mm.h 2004-12-19 07:39:49 -08:00 +++ b/include/linux/mm.h 2004-12-19 07:39:49 -08:00 @@ -548,7 +548,7 @@ /* mmap.c */ extern void lock_vma_mappings(struct vm_area_struct *); extern void unlock_vma_mappings(struct vm_area_struct *); -extern void insert_vm_struct(struct mm_struct *, struct vm_area_struct *); +extern int insert_vm_struct(struct mm_struct *, struct vm_area_struct *); extern void __insert_vm_struct(struct mm_struct *, struct vm_area_struct *); extern void build_mmap_rb(struct mm_struct *); extern void exit_mmap(struct mm_struct *); diff -Nru a/mm/mmap.c b/mm/mmap.c --- a/mm/mmap.c 2004-12-19 07:39:49 -08:00 +++ b/mm/mmap.c 2004-12-19 07:39:49 -08:00 @@ -1193,14 +1193,15 @@ validate_mm(mm); } -void insert_vm_struct(struct mm_struct * mm, struct vm_area_struct * vma) +int insert_vm_struct(struct mm_struct * mm, struct vm_area_struct * vma) { struct vm_area_struct * __vma, * prev; rb_node_t ** rb_link, * rb_parent; __vma = find_vma_prepare(mm, vma->vm_start, &prev, &rb_link, &rb_parent); if (__vma && __vma->vm_start < vma->vm_end) - BUG(); + return -ENOMEM; vma_link(mm, vma, prev, rb_link, rb_parent); validate_mm(mm); + return 0; }