Skip to content

Commit

Permalink
userfaultfd: wp: support write protection for userfault vma range
Browse files Browse the repository at this point in the history
Add API to enable/disable writeprotect a vma range.  Unlike mprotect, this
doesn't split/merge vmas.

[[email protected]:
 - use the helper to find VMA;
 - return -ENOENT if not found to match mcopy case;
 - use the new MM_CP_UFFD_WP* flags for change_protection
 - check against mmap_changing for failures
 - replace find_dst_vma with vma_find_uffd]
Signed-off-by: Shaohua Li <[email protected]>
Signed-off-by: Andrea Arcangeli <[email protected]>
Signed-off-by: Peter Xu <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Reviewed-by: Jerome Glisse <[email protected]>
Reviewed-by: Mike Rapoport <[email protected]>
Cc: Andrea Arcangeli <[email protected]>
Cc: Rik van Riel <[email protected]>
Cc: Kirill A. Shutemov <[email protected]>
Cc: Mel Gorman <[email protected]>
Cc: Hugh Dickins <[email protected]>
Cc: Johannes Weiner <[email protected]>
Cc: Bobby Powers <[email protected]>
Cc: Brian Geffon <[email protected]>
Cc: David Hildenbrand <[email protected]>
Cc: Denis Plotnikov <[email protected]>
Cc: "Dr . David Alan Gilbert" <[email protected]>
Cc: Martin Cracauer <[email protected]>
Cc: Marty McFadden <[email protected]>
Cc: Maya Gokhale <[email protected]>
Cc: Mike Kravetz <[email protected]>
Cc: Pavel Emelyanov <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
shligit authored and torvalds committed Apr 7, 2020
1 parent e1e267c commit ffd0579
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 0 deletions.
3 changes: 3 additions & 0 deletions include/linux/userfaultfd_k.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ extern ssize_t mfill_zeropage(struct mm_struct *dst_mm,
unsigned long dst_start,
unsigned long len,
bool *mmap_changing);
extern int mwriteprotect_range(struct mm_struct *dst_mm,
unsigned long start, unsigned long len,
bool enable_wp, bool *mmap_changing);

/* mm helpers */
static inline bool is_mergeable_vm_userfaultfd_ctx(struct vm_area_struct *vma,
Expand Down
54 changes: 54 additions & 0 deletions mm/userfaultfd.c
Original file line number Diff line number Diff line change
Expand Up @@ -638,3 +638,57 @@ ssize_t mfill_zeropage(struct mm_struct *dst_mm, unsigned long start,
{
return __mcopy_atomic(dst_mm, start, 0, len, true, mmap_changing, 0);
}

int mwriteprotect_range(struct mm_struct *dst_mm, unsigned long start,
unsigned long len, bool enable_wp, bool *mmap_changing)
{
struct vm_area_struct *dst_vma;
pgprot_t newprot;
int err;

/*
* Sanitize the command parameters:
*/
BUG_ON(start & ~PAGE_MASK);
BUG_ON(len & ~PAGE_MASK);

/* Does the address range wrap, or is the span zero-sized? */
BUG_ON(start + len <= start);

down_read(&dst_mm->mmap_sem);

/*
* If memory mappings are changing because of non-cooperative
* operation (e.g. mremap) running in parallel, bail out and
* request the user to retry later
*/
err = -EAGAIN;
if (mmap_changing && READ_ONCE(*mmap_changing))
goto out_unlock;

err = -ENOENT;
dst_vma = find_dst_vma(dst_mm, start, len);
/*
* Make sure the vma is not shared, that the dst range is
* both valid and fully within a single existing vma.
*/
if (!dst_vma || (dst_vma->vm_flags & VM_SHARED))
goto out_unlock;
if (!userfaultfd_wp(dst_vma))
goto out_unlock;
if (!vma_is_anonymous(dst_vma))
goto out_unlock;

if (enable_wp)
newprot = vm_get_page_prot(dst_vma->vm_flags & ~(VM_WRITE));
else
newprot = vm_get_page_prot(dst_vma->vm_flags);

change_protection(dst_vma, start, start + len, newprot,
enable_wp ? MM_CP_UFFD_WP : MM_CP_UFFD_WP_RESOLVE);

err = 0;
out_unlock:
up_read(&dst_mm->mmap_sem);
return err;
}

0 comments on commit ffd0579

Please sign in to comment.