Commit 119f657c authored by akpm@osdl.org's avatar akpm@osdl.org Committed by Linus Torvalds

[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: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent f021e921
...@@ -726,6 +726,7 @@ extern void __vma_link_rb(struct mm_struct *, struct vm_area_struct *, ...@@ -726,6 +726,7 @@ extern void __vma_link_rb(struct mm_struct *, struct vm_area_struct *,
extern struct vm_area_struct *copy_vma(struct vm_area_struct **, extern struct vm_area_struct *copy_vma(struct vm_area_struct **,
unsigned long addr, unsigned long len, pgoff_t pgoff); unsigned long addr, unsigned long len, pgoff_t pgoff);
extern void exit_mmap(struct mm_struct *); extern void exit_mmap(struct mm_struct *);
extern int may_expand_vm(struct mm_struct *mm, unsigned long npages);
extern unsigned long get_unmapped_area(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); extern unsigned long get_unmapped_area(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
......
...@@ -1009,8 +1009,7 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr, ...@@ -1009,8 +1009,7 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr,
} }
/* Check against address space limit. */ /* Check against address space limit. */
if ((mm->total_vm << PAGE_SHIFT) + len if (!may_expand_vm(mm, len >> PAGE_SHIFT))
> current->signal->rlim[RLIMIT_AS].rlim_cur)
return -ENOMEM; return -ENOMEM;
if (accountable && (!(flags & MAP_NORESERVE) || if (accountable && (!(flags & MAP_NORESERVE) ||
...@@ -1421,7 +1420,7 @@ static int acct_stack_growth(struct vm_area_struct * vma, unsigned long size, un ...@@ -1421,7 +1420,7 @@ static int acct_stack_growth(struct vm_area_struct * vma, unsigned long size, un
struct rlimit *rlim = current->signal->rlim; struct rlimit *rlim = current->signal->rlim;
/* address space limit tests */ /* address space limit tests */
if (mm->total_vm + grow > rlim[RLIMIT_AS].rlim_cur >> PAGE_SHIFT) if (!may_expand_vm(mm, grow))
return -ENOMEM; return -ENOMEM;
/* Stack limit test */ /* Stack limit test */
...@@ -1848,8 +1847,7 @@ unsigned long do_brk(unsigned long addr, unsigned long len) ...@@ -1848,8 +1847,7 @@ unsigned long do_brk(unsigned long addr, unsigned long len)
} }
/* Check against address space limits *after* clearing old maps... */ /* Check against address space limits *after* clearing old maps... */
if ((mm->total_vm << PAGE_SHIFT) + len if (!may_expand_vm(mm, len >> PAGE_SHIFT))
> current->signal->rlim[RLIMIT_AS].rlim_cur)
return -ENOMEM; return -ENOMEM;
if (mm->map_count > sysctl_max_map_count) if (mm->map_count > sysctl_max_map_count)
...@@ -2019,3 +2017,19 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap, ...@@ -2019,3 +2017,19 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap,
} }
return new_vma; return new_vma;
} }
/*
* Return true if the calling process may expand its vm space by the passed
* number of pages
*/
int may_expand_vm(struct mm_struct *mm, unsigned long npages)
{
unsigned long cur = mm->total_vm; /* pages */
unsigned long lim;
lim = current->signal->rlim[RLIMIT_AS].rlim_cur >> PAGE_SHIFT;
if (cur + npages > lim)
return 0;
return 1;
}
...@@ -347,10 +347,10 @@ unsigned long do_mremap(unsigned long addr, ...@@ -347,10 +347,10 @@ unsigned long do_mremap(unsigned long addr,
if (locked > lock_limit && !capable(CAP_IPC_LOCK)) if (locked > lock_limit && !capable(CAP_IPC_LOCK))
goto out; goto out;
} }
if (!may_expand_vm(current->mm, (new_len - old_len) >> PAGE_SHIFT)) {
ret = -ENOMEM; ret = -ENOMEM;
if ((current->mm->total_vm << PAGE_SHIFT) + (new_len - old_len)
> current->signal->rlim[RLIMIT_AS].rlim_cur)
goto out; goto out;
}
if (vma->vm_flags & VM_ACCOUNT) { if (vma->vm_flags & VM_ACCOUNT) {
charged = (new_len - old_len) >> PAGE_SHIFT; charged = (new_len - old_len) >> PAGE_SHIFT;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment