1971 lines · 50.4 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-only#include <linux/export.h>#include <linux/bvec.h>#include <linux/fault-inject-usercopy.h>#include <linux/uio.h>#include <linux/pagemap.h>#include <linux/highmem.h>#include <linux/slab.h>#include <linux/vmalloc.h>#include <linux/splice.h>#include <linux/compat.h>#include <linux/scatterlist.h>#include <linux/instrumented.h>#include <linux/iov_iter.h> static __always_inlinesize_t copy_to_user_iter(void __user *iter_to, size_t progress,			 size_t len, void *from, void *priv2){	if (should_fail_usercopy())		return len;	if (access_ok(iter_to, len)) {		from += progress;		instrument_copy_to_user(iter_to, from, len);		len = raw_copy_to_user(iter_to, from, len);	}	return len;} static __always_inlinesize_t copy_to_user_iter_nofault(void __user *iter_to, size_t progress,				 size_t len, void *from, void *priv2){	ssize_t res; 	if (should_fail_usercopy())		return len; 	from += progress;	res = copy_to_user_nofault(iter_to, from, len);	return res < 0 ? len : res;} static __always_inlinesize_t copy_from_user_iter(void __user *iter_from, size_t progress,			   size_t len, void *to, void *priv2){	size_t res = len; 	if (should_fail_usercopy())		return len;	if (can_do_masked_user_access()) {		iter_from = mask_user_address(iter_from);	} else {		if (!access_ok(iter_from, len))			return res; 		/*		 * Ensure that bad access_ok() speculation will not		 * lead to nasty side effects *after* the copy is		 * finished:		 */		barrier_nospec();	}	to += progress;	instrument_copy_from_user_before(to, iter_from, len);	res = raw_copy_from_user(to, iter_from, len);	instrument_copy_from_user_after(to, iter_from, len, res); 	return res;} static __always_inlinesize_t memcpy_to_iter(void *iter_to, size_t progress,		      size_t len, void *from, void *priv2){	memcpy(iter_to, from + progress, len);	return 0;} static __always_inlinesize_t memcpy_from_iter(void *iter_from, size_t progress,			size_t len, void *to, void *priv2){	memcpy(to + progress, iter_from, len);	return 0;} /* * fault_in_iov_iter_readable - fault in iov iterator for reading * @i: iterator * @size: maximum length * * Fault in one or more iovecs of the given iov_iter, to a maximum length of * @size.  For each iovec, fault in each page that constitutes the iovec. * * Returns the number of bytes not faulted in (like copy_to_user() and * copy_from_user()). * * Always returns 0 for non-userspace iterators. */size_t fault_in_iov_iter_readable(const struct iov_iter *i, size_t size){	if (iter_is_ubuf(i)) {		size_t n = min(size, iov_iter_count(i));		n -= fault_in_readable(i->ubuf + i->iov_offset, n);		return size - n;	} else if (iter_is_iovec(i)) {		size_t count = min(size, iov_iter_count(i));		const struct iovec *p;		size_t skip; 		size -= count;		for (p = iter_iov(i), skip = i->iov_offset; count; p++, skip = 0) {			size_t len = min(count, p->iov_len - skip);			size_t ret; 			if (unlikely(!len))				continue;			ret = fault_in_readable(p->iov_base + skip, len);			count -= len - ret;			if (ret)				break;		}		return count + size;	}	return 0;}EXPORT_SYMBOL(fault_in_iov_iter_readable); /* * fault_in_iov_iter_writeable - fault in iov iterator for writing * @i: iterator * @size: maximum length * * Faults in the iterator using get_user_pages(), i.e., without triggering * hardware page faults.  This is primarily useful when we already know that * some or all of the pages in @i aren't in memory. * * Returns the number of bytes not faulted in, like copy_to_user() and * copy_from_user(). * * Always returns 0 for non-user-space iterators. */size_t fault_in_iov_iter_writeable(const struct iov_iter *i, size_t size){	if (iter_is_ubuf(i)) {		size_t n = min(size, iov_iter_count(i));		n -= fault_in_safe_writeable(i->ubuf + i->iov_offset, n);		return size - n;	} else if (iter_is_iovec(i)) {		size_t count = min(size, iov_iter_count(i));		const struct iovec *p;		size_t skip; 		size -= count;		for (p = iter_iov(i), skip = i->iov_offset; count; p++, skip = 0) {			size_t len = min(count, p->iov_len - skip);			size_t ret; 			if (unlikely(!len))				continue;			ret = fault_in_safe_writeable(p->iov_base + skip, len);			count -= len - ret;			if (ret)				break;		}		return count + size;	}	return 0;}EXPORT_SYMBOL(fault_in_iov_iter_writeable); void iov_iter_init(struct iov_iter *i, unsigned int direction,			const struct iovec *iov, unsigned long nr_segs,			size_t count){	WARN_ON(direction & ~(READ | WRITE));	*i = (struct iov_iter) {		.iter_type = ITER_IOVEC,		.nofault = false,		.data_source = direction,		.__iov = iov,		.nr_segs = nr_segs,		.iov_offset = 0,		.count = count	};}EXPORT_SYMBOL(iov_iter_init); size_t _copy_to_iter(const void *addr, size_t bytes, struct iov_iter *i){	if (WARN_ON_ONCE(i->data_source))		return 0;	if (user_backed_iter(i))		might_fault();	return iterate_and_advance(i, bytes, (void *)addr,				   copy_to_user_iter, memcpy_to_iter);}EXPORT_SYMBOL(_copy_to_iter); #ifdef CONFIG_ARCH_HAS_COPY_MCstatic __always_inlinesize_t copy_to_user_iter_mc(void __user *iter_to, size_t progress,			    size_t len, void *from, void *priv2){	if (access_ok(iter_to, len)) {		from += progress;		instrument_copy_to_user(iter_to, from, len);		len = copy_mc_to_user(iter_to, from, len);	}	return len;} static __always_inlinesize_t memcpy_to_iter_mc(void *iter_to, size_t progress,			 size_t len, void *from, void *priv2){	return copy_mc_to_kernel(iter_to, from + progress, len);} /** * _copy_mc_to_iter - copy to iter with source memory error exception handling * @addr: source kernel address * @bytes: total transfer length * @i: destination iterator * * The pmem driver deploys this for the dax operation * (dax_copy_to_iter()) for dax reads (bypass page-cache and the * block-layer). Upon #MC read(2) aborts and returns EIO or the bytes * successfully copied. * * The main differences between this and typical _copy_to_iter(). * * * Typical tail/residue handling after a fault retries the copy *   byte-by-byte until the fault happens again. Re-triggering machine *   checks is potentially fatal so the implementation uses source *   alignment and poison alignment assumptions to avoid re-triggering *   hardware exceptions. * * * ITER_KVEC and ITER_BVEC can return short copies.  Compare to *   copy_to_iter() where only ITER_IOVEC attempts might return a short copy. * * Return: number of bytes copied (may be %0) */size_t _copy_mc_to_iter(const void *addr, size_t bytes, struct iov_iter *i){	if (WARN_ON_ONCE(i->data_source))		return 0;	if (user_backed_iter(i))		might_fault();	return iterate_and_advance(i, bytes, (void *)addr,				   copy_to_user_iter_mc, memcpy_to_iter_mc);}EXPORT_SYMBOL_GPL(_copy_mc_to_iter);#endif /* CONFIG_ARCH_HAS_COPY_MC */ static __always_inlinesize_t __copy_from_iter(void *addr, size_t bytes, struct iov_iter *i){	return iterate_and_advance(i, bytes, addr,				   copy_from_user_iter, memcpy_from_iter);} size_t _copy_from_iter(void *addr, size_t bytes, struct iov_iter *i){	if (WARN_ON_ONCE(!i->data_source))		return 0; 	if (user_backed_iter(i))		might_fault();	return __copy_from_iter(addr, bytes, i);}EXPORT_SYMBOL(_copy_from_iter); static __always_inlinesize_t copy_from_user_iter_nocache(void __user *iter_from, size_t progress,				   size_t len, void *to, void *priv2){	return copy_from_user_inatomic_nontemporal(to + progress, iter_from, len);} size_t _copy_from_iter_nocache(void *addr, size_t bytes, struct iov_iter *i){	if (WARN_ON_ONCE(!i->data_source))		return 0; 	return iterate_and_advance(i, bytes, addr,				   copy_from_user_iter_nocache,				   memcpy_from_iter);}EXPORT_SYMBOL(_copy_from_iter_nocache); #ifdef CONFIG_ARCH_HAS_UACCESS_FLUSHCACHEstatic __always_inlinesize_t copy_from_user_iter_flushcache(void __user *iter_from, size_t progress,				      size_t len, void *to, void *priv2){	return copy_from_user_flushcache(to + progress, iter_from, len);} static __always_inlinesize_t memcpy_from_iter_flushcache(void *iter_from, size_t progress,				   size_t len, void *to, void *priv2){	memcpy_flushcache(to + progress, iter_from, len);	return 0;} /** * _copy_from_iter_flushcache - write destination through cpu cache * @addr: destination kernel address * @bytes: total transfer length * @i: source iterator * * The pmem driver arranges for filesystem-dax to use this facility via * dax_copy_from_iter() for ensuring that writes to persistent memory * are flushed through the CPU cache. It is differentiated from * _copy_from_iter_nocache() in that guarantees all data is flushed for * all iterator types. The _copy_from_iter_nocache() only attempts to * bypass the cache for the ITER_IOVEC case, and on some archs may use * instructions that strand dirty-data in the cache. * * Return: number of bytes copied (may be %0) */size_t _copy_from_iter_flushcache(void *addr, size_t bytes, struct iov_iter *i){	if (WARN_ON_ONCE(!i->data_source))		return 0; 	return iterate_and_advance(i, bytes, addr,				   copy_from_user_iter_flushcache,				   memcpy_from_iter_flushcache);}EXPORT_SYMBOL_GPL(_copy_from_iter_flushcache);#endif static inline bool page_copy_sane(struct page *page, size_t offset, size_t n){	struct page *head;	size_t v = n + offset; 	/*	 * The general case needs to access the page order in order	 * to compute the page size.	 * However, we mostly deal with order-0 pages and thus can	 * avoid a possible cache line miss for requests that fit all	 * page orders.	 */	if (n <= v && v <= PAGE_SIZE)		return true; 	head = compound_head(page);	v += (page - head) << PAGE_SHIFT; 	if (WARN_ON(n > v || v > page_size(head)))		return false;	return true;} size_t copy_page_to_iter(struct page *page, size_t offset, size_t bytes,			 struct iov_iter *i){	size_t res = 0;	if (!page_copy_sane(page, offset, bytes))		return 0;	if (WARN_ON_ONCE(i->data_source))		return 0;	page += offset / PAGE_SIZE; // first subpage	offset %= PAGE_SIZE;	while (1) {		void *kaddr = kmap_local_page(page);		size_t n = min(bytes, (size_t)PAGE_SIZE - offset);		n = _copy_to_iter(kaddr + offset, n, i);		kunmap_local(kaddr);		res += n;		bytes -= n;		if (!bytes || !n)			break;		offset += n;		if (offset == PAGE_SIZE) {			page++;			offset = 0;		}	}	return res;}EXPORT_SYMBOL(copy_page_to_iter); size_t copy_page_to_iter_nofault(struct page *page, unsigned offset, size_t bytes,				 struct iov_iter *i){	size_t res = 0; 	if (!page_copy_sane(page, offset, bytes))		return 0;	if (WARN_ON_ONCE(i->data_source))		return 0;	page += offset / PAGE_SIZE; // first subpage	offset %= PAGE_SIZE;	while (1) {		void *kaddr = kmap_local_page(page);		size_t n = min(bytes, (size_t)PAGE_SIZE - offset); 		n = iterate_and_advance(i, n, kaddr + offset,					copy_to_user_iter_nofault,					memcpy_to_iter);		kunmap_local(kaddr);		res += n;		bytes -= n;		if (!bytes || !n)			break;		offset += n;		if (offset == PAGE_SIZE) {			page++;			offset = 0;		}	}	return res;}EXPORT_SYMBOL(copy_page_to_iter_nofault); size_t copy_page_from_iter(struct page *page, size_t offset, size_t bytes,			 struct iov_iter *i){	size_t res = 0;	if (!page_copy_sane(page, offset, bytes))		return 0;	page += offset / PAGE_SIZE; // first subpage	offset %= PAGE_SIZE;	while (1) {		void *kaddr = kmap_local_page(page);		size_t n = min(bytes, (size_t)PAGE_SIZE - offset);		n = _copy_from_iter(kaddr + offset, n, i);		kunmap_local(kaddr);		res += n;		bytes -= n;		if (!bytes || !n)			break;		offset += n;		if (offset == PAGE_SIZE) {			page++;			offset = 0;		}	}	return res;}EXPORT_SYMBOL(copy_page_from_iter); static __always_inlinesize_t zero_to_user_iter(void __user *iter_to, size_t progress,			 size_t len, void *priv, void *priv2){	return clear_user(iter_to, len);} static __always_inlinesize_t zero_to_iter(void *iter_to, size_t progress,		    size_t len, void *priv, void *priv2){	memset(iter_to, 0, len);	return 0;} size_t iov_iter_zero(size_t bytes, struct iov_iter *i){	return iterate_and_advance(i, bytes, NULL,				   zero_to_user_iter, zero_to_iter);}EXPORT_SYMBOL(iov_iter_zero); size_t copy_folio_from_iter_atomic(struct folio *folio, size_t offset,		size_t bytes, struct iov_iter *i){	size_t n, copied = 0; 	if (!page_copy_sane(&folio->page, offset, bytes))		return 0;	if (WARN_ON_ONCE(!i->data_source))		return 0; 	do {		char *to = kmap_local_folio(folio, offset); 		n = bytes - copied;		if (folio_test_partial_kmap(folio) &&		    n > PAGE_SIZE - offset_in_page(offset))			n = PAGE_SIZE - offset_in_page(offset); 		pagefault_disable();		n = __copy_from_iter(to, n, i);		pagefault_enable();		kunmap_local(to);		copied += n;		offset += n;	} while (copied != bytes && n > 0); 	return copied;}EXPORT_SYMBOL(copy_folio_from_iter_atomic);

Lines 1–500 of 1971.