unsigned long populate = 0;
        unsigned long ret = -EINVAL;
        struct file *file;
+       vm_flags_t vm_flags;
 
        pr_warn_once("%s (%d) uses deprecated remap_file_pages() syscall. See Documentation/mm/remap_file_pages.rst.\n",
                     current->comm, current->pid);
        if (pgoff + (size >> PAGE_SHIFT) < pgoff)
                return ret;
 
-       if (mmap_write_lock_killable(mm))
+       if (mmap_read_lock_killable(mm))
                return -EINTR;
 
+       /*
+        * Look up VMA under read lock first so we can perform the security
+        * without holding locks (which can be problematic). We reacquire a
+        * write lock later and check nothing changed underneath us.
+        */
        vma = vma_lookup(mm, start);
 
-       if (!vma || !(vma->vm_flags & VM_SHARED))
+       if (!vma || !(vma->vm_flags & VM_SHARED)) {
+               mmap_read_unlock(mm);
+               return -EINVAL;
+       }
+
+       prot |= vma->vm_flags & VM_READ ? PROT_READ : 0;
+       prot |= vma->vm_flags & VM_WRITE ? PROT_WRITE : 0;
+       prot |= vma->vm_flags & VM_EXEC ? PROT_EXEC : 0;
+
+       flags &= MAP_NONBLOCK;
+       flags |= MAP_SHARED | MAP_FIXED | MAP_POPULATE;
+       if (vma->vm_flags & VM_LOCKED)
+               flags |= MAP_LOCKED;
+
+       /* Save vm_flags used to calculate prot and flags, and recheck later. */
+       vm_flags = vma->vm_flags;
+       file = get_file(vma->vm_file);
+
+       mmap_read_unlock(mm);
+
+       /* Call outside mmap_lock to be consistent with other callers. */
+       ret = security_mmap_file(file, prot, flags);
+       if (ret) {
+               fput(file);
+               return ret;
+       }
+
+       ret = -EINVAL;
+
+       /* OK security check passed, take write lock + let it rip. */
+       if (mmap_write_lock_killable(mm)) {
+               fput(file);
+               return -EINTR;
+       }
+
+       vma = vma_lookup(mm, start);
+
+       if (!vma)
+               goto out;
+
+       /* Make sure things didn't change under us. */
+       if (vma->vm_flags != vm_flags)
+               goto out;
+       if (vma->vm_file != file)
                goto out;
 
        if (start + size > vma->vm_end) {
                        goto out;
        }
 
-       prot |= vma->vm_flags & VM_READ ? PROT_READ : 0;
-       prot |= vma->vm_flags & VM_WRITE ? PROT_WRITE : 0;
-       prot |= vma->vm_flags & VM_EXEC ? PROT_EXEC : 0;
-
-       flags &= MAP_NONBLOCK;
-       flags |= MAP_SHARED | MAP_FIXED | MAP_POPULATE;
-       if (vma->vm_flags & VM_LOCKED)
-               flags |= MAP_LOCKED;
-
-       file = get_file(vma->vm_file);
-       ret = security_mmap_file(vma->vm_file, prot, flags);
-       if (ret)
-               goto out_fput;
        ret = do_mmap(vma->vm_file, start, size,
                        prot, flags, 0, pgoff, &populate, NULL);
-out_fput:
-       fput(file);
 out:
        mmap_write_unlock(mm);
+       fput(file);
        if (populate)
                mm_populate(ret, populate);
        if (!IS_ERR_VALUE(ret))