On Wed, Apr 6, 2011 at 7:47 AM, Hugh Dickins <hughd@xxxxxxxxxx> wrote: >> >> I dunno. But that odd negative pg_off thing makes me think there is >> some overflow issue (ie HEAP_INDEX being pg_off + size ends up >> fluctuating between really big and really small). So I'd suspect THAT >> as the main reason. > > Yes, one of the vmas is such that the end offset (pgoff of next page > after) would be 0, and for the other it would be 16. There's sure to > be places, inside the prio_tree code and outside it, where we rely > upon pgoff not wrapping around - wrap should be prevented by original > validation of arguments. Well, we _do_ validate them in do_mmap_pgoff(), which is the main routine for all the mmap() system calls, and the main way to get a new mapping. There are other ways, like do_brk(), but afaik that always sets vm_pgoff to the virtual address (shifted), so again the new mapping should be fine. So when a new mapping is created, it should all be ok. But I think mremap() may end up expanding it without doing the same overflow check. Do you see any other way to get this situation? Does the vma dump give you any hint about where it came from? Robert - here's a (UNTESTED!) patch to make mremap() be a bit more careful about vm_pgoff when growing a mapping. Does it make any difference? Linus
mm/mremap.c | 11 +++++++++-- 1 files changed, 9 insertions(+), 2 deletions(-) diff --git a/mm/mremap.c b/mm/mremap.c index 1de98d492ddc..a7c1f9f9b941 100644 --- a/mm/mremap.c +++ b/mm/mremap.c @@ -277,9 +277,16 @@ static struct vm_area_struct *vma_to_resize(unsigned long addr, 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) {