Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b8ca9e3a authored by Eric Dumazet's avatar Eric Dumazet Committed by Linus Torvalds
Browse files

mm: tighten fault_in_pages_writeable()



copy_page_to_iter_iovec() is currently the only user of
fault_in_pages_writeable(), and it definitely can use fragments from
high order pages.

Make sure fault_in_pages_writeable() is only touching two adjacent pages
at most, as claimed.

Signed-off-by: default avatarEric Dumazet <edumazet@google.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 297880f4
Loading
Loading
Loading
Loading
+9 −15
Original line number Diff line number Diff line
@@ -518,33 +518,27 @@ void page_endio(struct page *page, int rw, int err);
extern void add_page_wait_queue(struct page *page, wait_queue_t *waiter);

/*
 * Fault a userspace page into pagetables.  Return non-zero on a fault.
 *
 * This assumes that two userspace pages are always sufficient.
 * Fault one or two userspace pages into pagetables.
 * Return -EINVAL if more than two pages would be needed.
 * Return non-zero on a fault.
 */
static inline int fault_in_pages_writeable(char __user *uaddr, int size)
{
	int ret;
	int span, ret;

	if (unlikely(size == 0))
		return 0;

	span = offset_in_page(uaddr) + size;
	if (span > 2 * PAGE_SIZE)
		return -EINVAL;
	/*
	 * Writing zeroes into userspace here is OK, because we know that if
	 * the zero gets there, we'll be overwriting it.
	 */
	ret = __put_user(0, uaddr);
	if (ret == 0) {
		char __user *end = uaddr + size - 1;

		/*
		 * If the page was already mapped, this will get a cache miss
		 * for sure, so try to avoid doing it.
		 */
		if (((unsigned long)uaddr & PAGE_MASK) !=
				((unsigned long)end & PAGE_MASK))
			ret = __put_user(0, end);
	}
	if (ret == 0 && span > PAGE_SIZE)
		ret = __put_user(0, uaddr + size - 1);
	return ret;
}