1942 lines · 50.6 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-only/* *  mm/userfaultfd.c * *  Copyright (C) 2015  Red Hat, Inc. */ #include <linux/mm.h>#include <linux/sched/signal.h>#include <linux/pagemap.h>#include <linux/rmap.h>#include <linux/swap.h>#include <linux/swapops.h>#include <linux/userfaultfd_k.h>#include <linux/mmu_notifier.h>#include <linux/hugetlb.h>#include <linux/shmem_fs.h>#include <asm/tlbflush.h>#include <asm/tlb.h>#include "internal.h" static __always_inlinebool validate_dst_vma(struct vm_area_struct *dst_vma, unsigned long dst_end){	/* Make sure that the dst range is fully within dst_vma. */	if (dst_end > dst_vma->vm_end)		return false; 	/*	 * Check the vma is registered in uffd, this is required to	 * enforce the VM_MAYWRITE check done at uffd registration	 * time.	 */	if (!dst_vma->vm_userfaultfd_ctx.ctx)		return false; 	return true;} static __always_inlinestruct vm_area_struct *find_vma_and_prepare_anon(struct mm_struct *mm,						 unsigned long addr){	struct vm_area_struct *vma; 	mmap_assert_locked(mm);	vma = vma_lookup(mm, addr);	if (!vma)		vma = ERR_PTR(-ENOENT);	else if (!(vma->vm_flags & VM_SHARED) &&		 unlikely(anon_vma_prepare(vma)))		vma = ERR_PTR(-ENOMEM); 	return vma;} #ifdef CONFIG_PER_VMA_LOCK/* * uffd_lock_vma() - Lookup and lock vma corresponding to @address. * @mm: mm to search vma in. * @address: address that the vma should contain. * * Should be called without holding mmap_lock. * * Return: A locked vma containing @address, -ENOENT if no vma is found, or * -ENOMEM if anon_vma couldn't be allocated. */static struct vm_area_struct *uffd_lock_vma(struct mm_struct *mm,				       unsigned long address){	struct vm_area_struct *vma; 	vma = lock_vma_under_rcu(mm, address);	if (vma) {		/*		 * We know we're going to need to use anon_vma, so check		 * that early.		 */		if (!(vma->vm_flags & VM_SHARED) && unlikely(!vma->anon_vma))			vma_end_read(vma);		else			return vma;	} 	mmap_read_lock(mm);	vma = find_vma_and_prepare_anon(mm, address);	if (!IS_ERR(vma)) {		/*		 * We cannot use vma_start_read() as it may fail due to		 * false locked (see comment in vma_start_read()). We		 * can avoid that by directly locking vm_lock under		 * mmap_lock, which guarantees that nobody can lock the		 * vma for write (vma_start_write()) under us.		 */		down_read(&vma->vm_lock->lock);	} 	mmap_read_unlock(mm);	return vma;} static struct vm_area_struct *uffd_mfill_lock(struct mm_struct *dst_mm,					      unsigned long dst_start,					      unsigned long len){	struct vm_area_struct *dst_vma; 	dst_vma = uffd_lock_vma(dst_mm, dst_start);	if (IS_ERR(dst_vma) || validate_dst_vma(dst_vma, dst_start + len))		return dst_vma; 	vma_end_read(dst_vma);	return ERR_PTR(-ENOENT);} static void uffd_mfill_unlock(struct vm_area_struct *vma){	vma_end_read(vma);} #else static struct vm_area_struct *uffd_mfill_lock(struct mm_struct *dst_mm,					      unsigned long dst_start,					      unsigned long len){	struct vm_area_struct *dst_vma; 	mmap_read_lock(dst_mm);	dst_vma = find_vma_and_prepare_anon(dst_mm, dst_start);	if (IS_ERR(dst_vma))		goto out_unlock; 	if (validate_dst_vma(dst_vma, dst_start + len))		return dst_vma; 	dst_vma = ERR_PTR(-ENOENT);out_unlock:	mmap_read_unlock(dst_mm);	return dst_vma;} static void uffd_mfill_unlock(struct vm_area_struct *vma){	mmap_read_unlock(vma->vm_mm);}#endif /* Check if dst_addr is outside of file's size. Must be called with ptl held. */static bool mfill_file_over_size(struct vm_area_struct *dst_vma,				 unsigned long dst_addr){	struct inode *inode;	pgoff_t offset, max_off; 	if (!dst_vma->vm_file)		return false; 	inode = dst_vma->vm_file->f_inode;	offset = linear_page_index(dst_vma, dst_addr);	max_off = DIV_ROUND_UP(i_size_read(inode), PAGE_SIZE);	return offset >= max_off;} /* * Install PTEs, to map dst_addr (within dst_vma) to page. * * This function handles both MCOPY_ATOMIC_NORMAL and _CONTINUE for both shmem * and anon, and for both shared and private VMAs. */int mfill_atomic_install_pte(pmd_t *dst_pmd,			     struct vm_area_struct *dst_vma,			     unsigned long dst_addr, struct page *page,			     bool newly_allocated, uffd_flags_t flags){	int ret;	struct mm_struct *dst_mm = dst_vma->vm_mm;	pte_t _dst_pte, *dst_pte;	bool writable = dst_vma->vm_flags & VM_WRITE;	bool vm_shared = dst_vma->vm_flags & VM_SHARED;	spinlock_t *ptl;	struct folio *folio = page_folio(page);	bool page_in_cache = folio_mapping(folio); 	_dst_pte = mk_pte(page, dst_vma->vm_page_prot);	_dst_pte = pte_mkdirty(_dst_pte);	if (page_in_cache && !vm_shared)		writable = false;	if (writable)		_dst_pte = pte_mkwrite(_dst_pte, dst_vma);	if (flags & MFILL_ATOMIC_WP)		_dst_pte = pte_mkuffd_wp(_dst_pte); 	ret = -EAGAIN;	dst_pte = pte_offset_map_lock(dst_mm, dst_pmd, dst_addr, &ptl);	if (!dst_pte)		goto out; 	if (mfill_file_over_size(dst_vma, dst_addr)) {		ret = -EFAULT;		goto out_unlock;	} 	ret = -EEXIST;	/*	 * We allow to overwrite a pte marker: consider when both MISSING|WP	 * registered, we firstly wr-protect a none pte which has no page cache	 * page backing it, then access the page.	 */	if (!pte_none_mostly(ptep_get(dst_pte)))		goto out_unlock; 	if (page_in_cache) {		/* Usually, cache pages are already added to LRU */		if (newly_allocated)			folio_add_lru(folio);		folio_add_file_rmap_pte(folio, page, dst_vma);	} else {		folio_add_new_anon_rmap(folio, dst_vma, dst_addr, RMAP_EXCLUSIVE);		folio_add_lru_vma(folio, dst_vma);	} 	/*	 * Must happen after rmap, as mm_counter() checks mapping (via	 * PageAnon()), which is set by __page_set_anon_rmap().	 */	inc_mm_counter(dst_mm, mm_counter(folio)); 	set_pte_at(dst_mm, dst_addr, dst_pte, _dst_pte); 	/* No need to invalidate - it was non-present before */	update_mmu_cache(dst_vma, dst_addr, dst_pte);	ret = 0;out_unlock:	pte_unmap_unlock(dst_pte, ptl);out:	return ret;} static int mfill_atomic_pte_copy(pmd_t *dst_pmd,				 struct vm_area_struct *dst_vma,				 unsigned long dst_addr,				 unsigned long src_addr,				 uffd_flags_t flags,				 struct folio **foliop){	void *kaddr;	int ret;	struct folio *folio; 	if (!*foliop) {		ret = -ENOMEM;		folio = vma_alloc_folio(GFP_HIGHUSER_MOVABLE, 0, dst_vma,					dst_addr);		if (!folio)			goto out; 		kaddr = kmap_local_folio(folio, 0);		/*		 * The read mmap_lock is held here.  Despite the		 * mmap_lock being read recursive a deadlock is still		 * possible if a writer has taken a lock.  For example:		 *		 * process A thread 1 takes read lock on own mmap_lock		 * process A thread 2 calls mmap, blocks taking write lock		 * process B thread 1 takes page fault, read lock on own mmap lock		 * process B thread 2 calls mmap, blocks taking write lock		 * process A thread 1 blocks taking read lock on process B		 * process B thread 1 blocks taking read lock on process A		 *		 * Disable page faults to prevent potential deadlock		 * and retry the copy outside the mmap_lock.		 */		pagefault_disable();		ret = copy_from_user(kaddr, (const void __user *) src_addr,				     PAGE_SIZE);		pagefault_enable();		kunmap_local(kaddr); 		/* fallback to copy_from_user outside mmap_lock */		if (unlikely(ret)) {			ret = -ENOENT;			*foliop = folio;			/* don't free the page */			goto out;		} 		flush_dcache_folio(folio);	} else {		folio = *foliop;		*foliop = NULL;	} 	/*	 * The memory barrier inside __folio_mark_uptodate makes sure that	 * preceding stores to the page contents become visible before	 * the set_pte_at() write.	 */	__folio_mark_uptodate(folio); 	ret = -ENOMEM;	if (mem_cgroup_charge(folio, dst_vma->vm_mm, GFP_KERNEL))		goto out_release; 	ret = mfill_atomic_install_pte(dst_pmd, dst_vma, dst_addr,				       &folio->page, true, flags);	if (ret)		goto out_release;out:	return ret;out_release:	folio_put(folio);	goto out;} static int mfill_atomic_pte_zeroed_folio(pmd_t *dst_pmd,					 struct vm_area_struct *dst_vma,					 unsigned long dst_addr){	struct folio *folio;	int ret = -ENOMEM; 	folio = vma_alloc_zeroed_movable_folio(dst_vma, dst_addr);	if (!folio)		return ret; 	if (mem_cgroup_charge(folio, dst_vma->vm_mm, GFP_KERNEL))		goto out_put; 	/*	 * The memory barrier inside __folio_mark_uptodate makes sure that	 * zeroing out the folio become visible before mapping the page	 * using set_pte_at(). See do_anonymous_page().	 */	__folio_mark_uptodate(folio); 	ret = mfill_atomic_install_pte(dst_pmd, dst_vma, dst_addr,				       &folio->page, true, 0);	if (ret)		goto out_put; 	return 0;out_put:	folio_put(folio);	return ret;} static int mfill_atomic_pte_zeropage(pmd_t *dst_pmd,				     struct vm_area_struct *dst_vma,				     unsigned long dst_addr){	pte_t _dst_pte, *dst_pte;	spinlock_t *ptl;	int ret; 	if (mm_forbids_zeropage(dst_vma->vm_mm))		return mfill_atomic_pte_zeroed_folio(dst_pmd, dst_vma, dst_addr); 	_dst_pte = pte_mkspecial(pfn_pte(my_zero_pfn(dst_addr),					 dst_vma->vm_page_prot));	ret = -EAGAIN;	dst_pte = pte_offset_map_lock(dst_vma->vm_mm, dst_pmd, dst_addr, &ptl);	if (!dst_pte)		goto out;	if (mfill_file_over_size(dst_vma, dst_addr)) {		ret = -EFAULT;		goto out_unlock;	}	ret = -EEXIST;	if (!pte_none(ptep_get(dst_pte)))		goto out_unlock;	set_pte_at(dst_vma->vm_mm, dst_addr, dst_pte, _dst_pte);	/* No need to invalidate - it was non-present before */	update_mmu_cache(dst_vma, dst_addr, dst_pte);	ret = 0;out_unlock:	pte_unmap_unlock(dst_pte, ptl);out:	return ret;} /* Handles UFFDIO_CONTINUE for all shmem VMAs (shared or private). */static int mfill_atomic_pte_continue(pmd_t *dst_pmd,				     struct vm_area_struct *dst_vma,				     unsigned long dst_addr,				     uffd_flags_t flags){	struct inode *inode = file_inode(dst_vma->vm_file);	pgoff_t pgoff = linear_page_index(dst_vma, dst_addr);	struct folio *folio;	struct page *page;	int ret; 	ret = shmem_get_folio(inode, pgoff, 0, &folio, SGP_NOALLOC);	/* Our caller expects us to return -EFAULT if we failed to find folio */	if (ret == -ENOENT)		ret = -EFAULT;	if (ret)		goto out;	if (!folio) {		ret = -EFAULT;		goto out;	} 	page = folio_file_page(folio, pgoff);	if (PageHWPoison(page)) {		ret = -EIO;		goto out_release;	} 	ret = mfill_atomic_install_pte(dst_pmd, dst_vma, dst_addr,				       page, false, flags);	if (ret)		goto out_release; 	folio_unlock(folio);	ret = 0;out:	return ret;out_release:	folio_unlock(folio);	folio_put(folio);	goto out;} /* Handles UFFDIO_POISON for all non-hugetlb VMAs. */static int mfill_atomic_pte_poison(pmd_t *dst_pmd,				   struct vm_area_struct *dst_vma,				   unsigned long dst_addr,				   uffd_flags_t flags){	int ret;	struct mm_struct *dst_mm = dst_vma->vm_mm;	pte_t _dst_pte, *dst_pte;	spinlock_t *ptl; 	_dst_pte = make_pte_marker(PTE_MARKER_POISONED);	ret = -EAGAIN;	dst_pte = pte_offset_map_lock(dst_mm, dst_pmd, dst_addr, &ptl);	if (!dst_pte)		goto out; 	if (mfill_file_over_size(dst_vma, dst_addr)) {		ret = -EFAULT;		goto out_unlock;	} 	ret = -EEXIST;	/* Refuse to overwrite any PTE, even a PTE marker (e.g. UFFD WP). */	if (!pte_none(ptep_get(dst_pte)))		goto out_unlock; 	set_pte_at(dst_mm, dst_addr, dst_pte, _dst_pte); 	/* No need to invalidate - it was non-present before */	update_mmu_cache(dst_vma, dst_addr, dst_pte);	ret = 0;out_unlock:	pte_unmap_unlock(dst_pte, ptl);out:	return ret;} static pmd_t *mm_alloc_pmd(struct mm_struct *mm, unsigned long address){	pgd_t *pgd;	p4d_t *p4d;	pud_t *pud; 	pgd = pgd_offset(mm, address);	p4d = p4d_alloc(mm, pgd, address);	if (!p4d)		return NULL;	pud = pud_alloc(mm, p4d, address);	if (!pud)		return NULL;	/*	 * Note that we didn't run this because the pmd was	 * missing, the *pmd may be already established and in	 * turn it may also be a trans_huge_pmd.	 */	return pmd_alloc(mm, pud, address);} #ifdef CONFIG_HUGETLB_PAGE/* * mfill_atomic processing for HUGETLB vmas.  Note that this routine is * called with either vma-lock or mmap_lock held, it will release the lock * before returning. */static __always_inline ssize_t mfill_atomic_hugetlb(					      struct userfaultfd_ctx *ctx,					      struct vm_area_struct *dst_vma,					      unsigned long dst_start,					      unsigned long src_start,					      unsigned long len,					      uffd_flags_t flags){	struct mm_struct *dst_mm = dst_vma->vm_mm;	ssize_t err;

Lines 1–500 of 1942.