On 07/17/2017 10:34 AM, Mike Rapoport wrote: > When mremap is called with MREMAP_FIXED it unmaps memory at the destination > address without notifying userfaultfd monitor. If the destination were > registered with userfaultfd, the monitor has no way to distinguish between > the old and new ranges and to properly relate the page faults that would > occur in the destination region. > > Cc: stable@xxxxxxxxxxxxxxx > Fixes: 897ab3e0c49e ("userfaultfd: non-cooperative: add event for memory > unmaps") > > Signed-off-by: Mike Rapoport <rppt@xxxxxxxxxxxxxxxxxx> Acked-by: Pavel Emelyanov <xemul@xxxxxxxxxxxxx> > --- > > v2: make sure userfault callbacks are called with mmap_sem released > > mm/mremap.c | 7 +++++-- > 1 file changed, 5 insertions(+), 2 deletions(-) > > diff --git a/mm/mremap.c b/mm/mremap.c > index cd8a1b199ef9..8d6fc5f104d1 100644 > --- a/mm/mremap.c > +++ b/mm/mremap.c > @@ -428,6 +428,7 @@ static struct vm_area_struct *vma_to_resize(unsigned long addr, > static unsigned long mremap_to(unsigned long addr, unsigned long old_len, > unsigned long new_addr, unsigned long new_len, bool *locked, > struct vm_userfaultfd_ctx *uf, > + struct list_head *uf_unmap_early, > struct list_head *uf_unmap) > { > struct mm_struct *mm = current->mm; > @@ -446,7 +447,7 @@ static unsigned long mremap_to(unsigned long addr, unsigned long old_len, > if (addr + old_len > new_addr && new_addr + new_len > addr) > goto out; > > - ret = do_munmap(mm, new_addr, new_len, NULL); > + ret = do_munmap(mm, new_addr, new_len, uf_unmap_early); > if (ret) > goto out; > > @@ -514,6 +515,7 @@ SYSCALL_DEFINE5(mremap, unsigned long, addr, unsigned long, old_len, > unsigned long charged = 0; > bool locked = false; > struct vm_userfaultfd_ctx uf = NULL_VM_UFFD_CTX; > + LIST_HEAD(uf_unmap_early); > LIST_HEAD(uf_unmap); > > if (flags & ~(MREMAP_FIXED | MREMAP_MAYMOVE)) > @@ -541,7 +543,7 @@ SYSCALL_DEFINE5(mremap, unsigned long, addr, unsigned long, old_len, > > if (flags & MREMAP_FIXED) { > ret = mremap_to(addr, old_len, new_addr, new_len, > - &locked, &uf, &uf_unmap); > + &locked, &uf, &uf_unmap_early, &uf_unmap); > goto out; > } > > @@ -621,6 +623,7 @@ SYSCALL_DEFINE5(mremap, unsigned long, addr, unsigned long, old_len, > up_write(¤t->mm->mmap_sem); > if (locked && new_len > old_len) > mm_populate(new_addr + old_len, new_len - old_len); > + userfaultfd_unmap_complete(mm, &uf_unmap_early); > mremap_userfaultfd_complete(&uf, addr, new_addr, old_len); > userfaultfd_unmap_complete(mm, &uf_unmap); > return ret; >