Skip to content

Commit 5b51072

Browse files
aagittorvalds
authored andcommitted
userfaultfd: shmem: allocate anonymous memory for MAP_PRIVATE shmem
Userfaultfd did not create private memory when UFFDIO_COPY was invoked on a MAP_PRIVATE shmem mapping. Instead it wrote to the shmem file, even when that had not been opened for writing. Though, fortunately, that could only happen where there was a hole in the file. Fix the shmem-backed implementation of UFFDIO_COPY to create private memory for MAP_PRIVATE mappings. The hugetlbfs-backed implementation was already correct. This change is visible to userland, if userfaultfd has been used in unintended ways: so it introduces a small risk of incompatibility, but is necessary in order to respect file permissions. An app that uses UFFDIO_COPY for anything like postcopy live migration won't notice the difference, and in fact it'll run faster because there will be no copy-on-write and memory waste in the tmpfs pagecache anymore. Userfaults on MAP_PRIVATE shmem keep triggering only on file holes like before. The real zeropage can also be built on a MAP_PRIVATE shmem mapping through UFFDIO_ZEROPAGE and that's safe because the zeropage pte is never dirty, in turn even an mprotect upgrading the vma permission from PROT_READ to PROT_READ|PROT_WRITE won't make the zeropage pte writable. Link: http://lkml.kernel.org/r/20181126173452.26955-3-aarcange@redhat.com Fixes: 4c27fe4 ("userfaultfd: shmem: add shmem_mcopy_atomic_pte for userfaultfd support") Signed-off-by: Andrea Arcangeli <aarcange@redhat.com> Reported-by: Mike Rapoport <rppt@linux.ibm.com> Reviewed-by: Hugh Dickins <hughd@google.com> Cc: <stable@vger.kernel.org> Cc: "Dr. David Alan Gilbert" <dgilbert@redhat.com> Cc: Jann Horn <jannh@google.com> Cc: Mike Kravetz <mike.kravetz@oracle.com> Cc: Peter Xu <peterx@redhat.com> Cc: stable@vger.kernel.org Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
1 parent 9e36825 commit 5b51072

File tree

1 file changed

+13
-2
lines changed

1 file changed

+13
-2
lines changed

mm/userfaultfd.c

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,17 @@ static __always_inline ssize_t mfill_atomic_pte(struct mm_struct *dst_mm,
380380
{
381381
ssize_t err;
382382

383-
if (vma_is_anonymous(dst_vma)) {
383+
/*
384+
* The normal page fault path for a shmem will invoke the
385+
* fault, fill the hole in the file and COW it right away. The
386+
* result generates plain anonymous memory. So when we are
387+
* asked to fill an hole in a MAP_PRIVATE shmem mapping, we'll
388+
* generate anonymous memory directly without actually filling
389+
* the hole. For the MAP_PRIVATE case the robustness check
390+
* only happens in the pagetable (to verify it's still none)
391+
* and not in the radix tree.
392+
*/
393+
if (!(dst_vma->vm_flags & VM_SHARED)) {
384394
if (!zeropage)
385395
err = mcopy_atomic_pte(dst_mm, dst_pmd, dst_vma,
386396
dst_addr, src_addr, page);
@@ -489,7 +499,8 @@ static __always_inline ssize_t __mcopy_atomic(struct mm_struct *dst_mm,
489499
* dst_vma.
490500
*/
491501
err = -ENOMEM;
492-
if (vma_is_anonymous(dst_vma) && unlikely(anon_vma_prepare(dst_vma)))
502+
if (!(dst_vma->vm_flags & VM_SHARED) &&
503+
unlikely(anon_vma_prepare(dst_vma)))
493504
goto out_unlock;
494505

495506
while (src_addr < src_start + len) {

0 commit comments

Comments
 (0)