| From 982134ba62618c2d69fbbbd166d0a11ee3b7e3d8 Mon Sep 17 00:00:00 2001 |
| From: Linus Torvalds <torvalds@linux-foundation.org> |
| Date: Thu, 7 Apr 2011 07:35:50 -0700 |
| Subject: mm: avoid wrapping vm_pgoff in mremap() |
| |
| From: Linus Torvalds <torvalds@linux-foundation.org> |
| |
| commit 982134ba62618c2d69fbbbd166d0a11ee3b7e3d8 upstream. |
| |
| The normal mmap paths all avoid creating a mapping where the pgoff |
| inside the mapping could wrap around due to overflow. However, an |
| expanding mremap() can take such a non-wrapping mapping and make it |
| bigger and cause a wrapping condition. |
| |
| Noticed by Robert Swiecki when running a system call fuzzer, where it |
| caused a BUG_ON() due to terminally confusing the vma_prio_tree code. A |
| vma dumping patch by Hugh then pinpointed the crazy wrapped case. |
| |
| Reported-and-tested-by: Robert Swiecki <robert@swiecki.net> |
| Acked-by: Hugh Dickins <hughd@google.com> |
| Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| |
| --- |
| mm/mremap.c | 11 +++++++++-- |
| 1 file changed, 9 insertions(+), 2 deletions(-) |
| |
| --- a/mm/mremap.c |
| +++ b/mm/mremap.c |
| @@ -275,9 +275,16 @@ static struct vm_area_struct *vma_to_res |
| if (old_len > vma->vm_end - addr) |
| goto Efault; |
| |
| - if (vma->vm_flags & (VM_DONTEXPAND | VM_PFNMAP)) { |
| - if (new_len > old_len) |
| + /* Need to be careful about a growing mapping */ |
| + if (new_len > old_len) { |
| + unsigned long pgoff; |
| + |
| + if (vma->vm_flags & (VM_DONTEXPAND | VM_PFNMAP)) |
| goto Efault; |
| + pgoff = (addr - vma->vm_start) >> PAGE_SHIFT; |
| + pgoff += vma->vm_pgoff; |
| + if (pgoff + (new_len >> PAGE_SHIFT) < pgoff) |
| + goto Einval; |
| } |
| |
| if (vma->vm_flags & VM_LOCKED) { |