diff options
author | akpm@osdl.org <akpm@osdl.org> | 2005-05-01 11:58:35 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-05-01 11:58:35 -0400 |
commit | 119f657c72fc07d6fd28c61de59cfba1566970a9 (patch) | |
tree | 33c8070aa904c4919cf244cdcd7c01e54589bb9e /mm | |
parent | f021e9210185b46e41ec3a0e78ec1621e168eacb (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>
Diffstat (limited to 'mm')
-rw-r--r-- | mm/mmap.c | 24 | ||||
-rw-r--r-- | mm/mremap.c | 6 |
2 files changed, 22 insertions, 8 deletions
@@ -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 | */ | ||
2025 | int 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; |