aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorakpm@osdl.org <akpm@osdl.org>2005-05-01 11:58:35 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-05-01 11:58:35 -0400
commit119f657c72fc07d6fd28c61de59cfba1566970a9 (patch)
tree33c8070aa904c4919cf244cdcd7c01e54589bb9e
parentf021e9210185b46e41ec3a0e78ec1621e168eacb (diff)
[PATCH] RLIMIT_AS checking fix
Address bug #4508: there's potential for wraparound in the various places where we perform RLIMIT_AS checking. (I'm a bit worried about acct_stack_growth(). Are we sure that vma->vm_mm is always equal to current->mm? If not, then we're comparing some other process's total_vm with the calling process's rlimits). Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--include/linux/mm.h1
-rw-r--r--mm/mmap.c24
-rw-r--r--mm/mremap.c6
3 files changed, 23 insertions, 8 deletions
diff --git a/include/linux/mm.h b/include/linux/mm.h
index c74a74ca401d..8b007ad2d450 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -726,6 +726,7 @@ extern void __vma_link_rb(struct mm_struct *, struct vm_area_struct *,
726extern struct vm_area_struct *copy_vma(struct vm_area_struct **, 726extern struct vm_area_struct *copy_vma(struct vm_area_struct **,
727 unsigned long addr, unsigned long len, pgoff_t pgoff); 727 unsigned long addr, unsigned long len, pgoff_t pgoff);
728extern void exit_mmap(struct mm_struct *); 728extern void exit_mmap(struct mm_struct *);
729extern int may_expand_vm(struct mm_struct *mm, unsigned long npages);
729 730
730extern unsigned long get_unmapped_area(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); 731extern unsigned long get_unmapped_area(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
731 732
diff --git a/mm/mmap.c b/mm/mmap.c
index 6ea204cc751e..1ec0f6e9c0d8 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -1009,8 +1009,7 @@ munmap_back:
1009 } 1009 }
1010 1010
1011 /* Check against address space limit. */ 1011 /* Check against address space limit. */
1012 if ((mm->total_vm << PAGE_SHIFT) + len 1012 if (!may_expand_vm(mm, len >> PAGE_SHIFT))
1013 > current->signal->rlim[RLIMIT_AS].rlim_cur)
1014 return -ENOMEM; 1013 return -ENOMEM;
1015 1014
1016 if (accountable && (!(flags & MAP_NORESERVE) || 1015 if (accountable && (!(flags & MAP_NORESERVE) ||
@@ -1421,7 +1420,7 @@ static int acct_stack_growth(struct vm_area_struct * vma, unsigned long size, un
1421 struct rlimit *rlim = current->signal->rlim; 1420 struct rlimit *rlim = current->signal->rlim;
1422 1421
1423 /* address space limit tests */ 1422 /* address space limit tests */
1424 if (mm->total_vm + grow > rlim[RLIMIT_AS].rlim_cur >> PAGE_SHIFT) 1423 if (!may_expand_vm(mm, grow))
1425 return -ENOMEM; 1424 return -ENOMEM;
1426 1425
1427 /* Stack limit test */ 1426 /* Stack limit test */
@@ -1848,8 +1847,7 @@ unsigned long do_brk(unsigned long addr, unsigned long len)
1848 } 1847 }
1849 1848
1850 /* Check against address space limits *after* clearing old maps... */ 1849 /* Check against address space limits *after* clearing old maps... */
1851 if ((mm->total_vm << PAGE_SHIFT) + len 1850 if (!may_expand_vm(mm, len >> PAGE_SHIFT))
1852 > current->signal->rlim[RLIMIT_AS].rlim_cur)
1853 return -ENOMEM; 1851 return -ENOMEM;
1854 1852
1855 if (mm->map_count > sysctl_max_map_count) 1853 if (mm->map_count > sysctl_max_map_count)
@@ -2019,3 +2017,19 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap,
2019 } 2017 }
2020 return new_vma; 2018 return new_vma;
2021} 2019}
2020
2021/*
2022 * Return true if the calling process may expand its vm space by the passed
2023 * number of pages
2024 */
2025int may_expand_vm(struct mm_struct *mm, unsigned long npages)
2026{
2027 unsigned long cur = mm->total_vm; /* pages */
2028 unsigned long lim;
2029
2030 lim = current->signal->rlim[RLIMIT_AS].rlim_cur >> PAGE_SHIFT;
2031
2032 if (cur + npages > lim)
2033 return 0;
2034 return 1;
2035}
diff --git a/mm/mremap.c b/mm/mremap.c
index 0d1c1b9c7a0a..0dd7ace94e51 100644
--- a/mm/mremap.c
+++ b/mm/mremap.c
@@ -347,10 +347,10 @@ unsigned long do_mremap(unsigned long addr,
347 if (locked > lock_limit && !capable(CAP_IPC_LOCK)) 347 if (locked > lock_limit && !capable(CAP_IPC_LOCK))
348 goto out; 348 goto out;
349 } 349 }
350 ret = -ENOMEM; 350 if (!may_expand_vm(current->mm, (new_len - old_len) >> PAGE_SHIFT)) {
351 if ((current->mm->total_vm << PAGE_SHIFT) + (new_len - old_len) 351 ret = -ENOMEM;
352 > current->signal->rlim[RLIMIT_AS].rlim_cur)
353 goto out; 352 goto out;
353 }
354 354
355 if (vma->vm_flags & VM_ACCOUNT) { 355 if (vma->vm_flags & VM_ACCOUNT) {
356 charged = (new_len - old_len) >> PAGE_SHIFT; 356 charged = (new_len - old_len) >> PAGE_SHIFT;