diff --git a/mm/mremap.c b/mm/mremap.c index 65c7f29b6116..9ce20c238ffd 100644 --- a/mm/mremap.c +++ b/mm/mremap.c @@ -1413,14 +1413,6 @@ static unsigned long mremap_to(struct vma_remap_struct *vrm) struct mm_struct *mm = current->mm; unsigned long err; - /* Is the new length or address silly? */ - if (vrm->new_len > TASK_SIZE || - vrm->new_addr > TASK_SIZE - vrm->new_len) - return -EINVAL; - - if (vrm_overlaps(vrm)) - return -EINVAL; - if (vrm->flags & MREMAP_FIXED) { /* * In mremap_to(). @@ -1525,7 +1517,12 @@ static unsigned long check_mremap_params(struct vma_remap_struct *vrm) * for DOS-emu "duplicate shm area" thing. But * a zero new-len is nonsensical. */ - if (!PAGE_ALIGN(vrm->new_len)) + if (!vrm->new_len) + return -EINVAL; + + /* Is the new length or address silly? */ + if (vrm->new_len > TASK_SIZE || + vrm->new_addr > TASK_SIZE - vrm->new_len) return -EINVAL; /* Remainder of checks are for cases with specific new_addr. */ @@ -1544,6 +1541,10 @@ static unsigned long check_mremap_params(struct vma_remap_struct *vrm) if (flags & MREMAP_DONTUNMAP && vrm->old_len != vrm->new_len) return -EINVAL; + /* Target VMA must not overlap source VMA. */ + if (vrm_overlaps(vrm)) + return -EINVAL; + /* * move_vma() need us to stay 4 maps below the threshold, otherwise * it will bail out at the very beginning. @@ -1620,8 +1621,6 @@ static bool align_hugetlb(struct vma_remap_struct *vrm) if (vrm->new_len > vrm->old_len) return false; - vrm_set_delta(vrm); - return true; } @@ -1721,14 +1720,13 @@ static unsigned long do_mremap(struct vma_remap_struct *vrm) struct vm_area_struct *vma; unsigned long res; + vrm->old_len = PAGE_ALIGN(vrm->old_len); + vrm->new_len = PAGE_ALIGN(vrm->new_len); + res = check_mremap_params(vrm); if (res) return res; - vrm->old_len = PAGE_ALIGN(vrm->old_len); - vrm->new_len = PAGE_ALIGN(vrm->new_len); - vrm_set_delta(vrm); - if (mmap_write_lock_killable(mm)) return -EINTR; vrm->mmap_locked = true; @@ -1751,6 +1749,7 @@ static unsigned long do_mremap(struct vma_remap_struct *vrm) goto out; } + vrm_set_delta(vrm); vrm->remap_type = vrm_remap_type(vrm); /* Actually execute mremap. */