162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * linux/mm/process_vm_access.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2010-2011 Christopher Yeoh <cyeoh@au1.ibm.com>, IBM Corp.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/compat.h>
962306a36Sopenharmony_ci#include <linux/mm.h>
1062306a36Sopenharmony_ci#include <linux/uio.h>
1162306a36Sopenharmony_ci#include <linux/sched.h>
1262306a36Sopenharmony_ci#include <linux/sched/mm.h>
1362306a36Sopenharmony_ci#include <linux/highmem.h>
1462306a36Sopenharmony_ci#include <linux/ptrace.h>
1562306a36Sopenharmony_ci#include <linux/slab.h>
1662306a36Sopenharmony_ci#include <linux/syscalls.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci/**
1962306a36Sopenharmony_ci * process_vm_rw_pages - read/write pages from task specified
2062306a36Sopenharmony_ci * @pages: array of pointers to pages we want to copy
2162306a36Sopenharmony_ci * @offset: offset in page to start copying from/to
2262306a36Sopenharmony_ci * @len: number of bytes to copy
2362306a36Sopenharmony_ci * @iter: where to copy to/from locally
2462306a36Sopenharmony_ci * @vm_write: 0 means copy from, 1 means copy to
2562306a36Sopenharmony_ci * Returns 0 on success, error code otherwise
2662306a36Sopenharmony_ci */
2762306a36Sopenharmony_cistatic int process_vm_rw_pages(struct page **pages,
2862306a36Sopenharmony_ci			       unsigned offset,
2962306a36Sopenharmony_ci			       size_t len,
3062306a36Sopenharmony_ci			       struct iov_iter *iter,
3162306a36Sopenharmony_ci			       int vm_write)
3262306a36Sopenharmony_ci{
3362306a36Sopenharmony_ci	/* Do the copy for each page */
3462306a36Sopenharmony_ci	while (len && iov_iter_count(iter)) {
3562306a36Sopenharmony_ci		struct page *page = *pages++;
3662306a36Sopenharmony_ci		size_t copy = PAGE_SIZE - offset;
3762306a36Sopenharmony_ci		size_t copied;
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci		if (copy > len)
4062306a36Sopenharmony_ci			copy = len;
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci		if (vm_write)
4362306a36Sopenharmony_ci			copied = copy_page_from_iter(page, offset, copy, iter);
4462306a36Sopenharmony_ci		else
4562306a36Sopenharmony_ci			copied = copy_page_to_iter(page, offset, copy, iter);
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci		len -= copied;
4862306a36Sopenharmony_ci		if (copied < copy && iov_iter_count(iter))
4962306a36Sopenharmony_ci			return -EFAULT;
5062306a36Sopenharmony_ci		offset = 0;
5162306a36Sopenharmony_ci	}
5262306a36Sopenharmony_ci	return 0;
5362306a36Sopenharmony_ci}
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci/* Maximum number of pages kmalloc'd to hold struct page's during copy */
5662306a36Sopenharmony_ci#define PVM_MAX_KMALLOC_PAGES (PAGE_SIZE * 2)
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci/**
5962306a36Sopenharmony_ci * process_vm_rw_single_vec - read/write pages from task specified
6062306a36Sopenharmony_ci * @addr: start memory address of target process
6162306a36Sopenharmony_ci * @len: size of area to copy to/from
6262306a36Sopenharmony_ci * @iter: where to copy to/from locally
6362306a36Sopenharmony_ci * @process_pages: struct pages area that can store at least
6462306a36Sopenharmony_ci *  nr_pages_to_copy struct page pointers
6562306a36Sopenharmony_ci * @mm: mm for task
6662306a36Sopenharmony_ci * @task: task to read/write from
6762306a36Sopenharmony_ci * @vm_write: 0 means copy from, 1 means copy to
6862306a36Sopenharmony_ci * Returns 0 on success or on failure error code
6962306a36Sopenharmony_ci */
7062306a36Sopenharmony_cistatic int process_vm_rw_single_vec(unsigned long addr,
7162306a36Sopenharmony_ci				    unsigned long len,
7262306a36Sopenharmony_ci				    struct iov_iter *iter,
7362306a36Sopenharmony_ci				    struct page **process_pages,
7462306a36Sopenharmony_ci				    struct mm_struct *mm,
7562306a36Sopenharmony_ci				    struct task_struct *task,
7662306a36Sopenharmony_ci				    int vm_write)
7762306a36Sopenharmony_ci{
7862306a36Sopenharmony_ci	unsigned long pa = addr & PAGE_MASK;
7962306a36Sopenharmony_ci	unsigned long start_offset = addr - pa;
8062306a36Sopenharmony_ci	unsigned long nr_pages;
8162306a36Sopenharmony_ci	ssize_t rc = 0;
8262306a36Sopenharmony_ci	unsigned long max_pages_per_loop = PVM_MAX_KMALLOC_PAGES
8362306a36Sopenharmony_ci		/ sizeof(struct pages *);
8462306a36Sopenharmony_ci	unsigned int flags = 0;
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	/* Work out address and page range required */
8762306a36Sopenharmony_ci	if (len == 0)
8862306a36Sopenharmony_ci		return 0;
8962306a36Sopenharmony_ci	nr_pages = (addr + len - 1) / PAGE_SIZE - addr / PAGE_SIZE + 1;
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	if (vm_write)
9262306a36Sopenharmony_ci		flags |= FOLL_WRITE;
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	while (!rc && nr_pages && iov_iter_count(iter)) {
9562306a36Sopenharmony_ci		int pinned_pages = min(nr_pages, max_pages_per_loop);
9662306a36Sopenharmony_ci		int locked = 1;
9762306a36Sopenharmony_ci		size_t bytes;
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci		/*
10062306a36Sopenharmony_ci		 * Get the pages we're interested in.  We must
10162306a36Sopenharmony_ci		 * access remotely because task/mm might not
10262306a36Sopenharmony_ci		 * current/current->mm
10362306a36Sopenharmony_ci		 */
10462306a36Sopenharmony_ci		mmap_read_lock(mm);
10562306a36Sopenharmony_ci		pinned_pages = pin_user_pages_remote(mm, pa, pinned_pages,
10662306a36Sopenharmony_ci						     flags, process_pages,
10762306a36Sopenharmony_ci						     &locked);
10862306a36Sopenharmony_ci		if (locked)
10962306a36Sopenharmony_ci			mmap_read_unlock(mm);
11062306a36Sopenharmony_ci		if (pinned_pages <= 0)
11162306a36Sopenharmony_ci			return -EFAULT;
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci		bytes = pinned_pages * PAGE_SIZE - start_offset;
11462306a36Sopenharmony_ci		if (bytes > len)
11562306a36Sopenharmony_ci			bytes = len;
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci		rc = process_vm_rw_pages(process_pages,
11862306a36Sopenharmony_ci					 start_offset, bytes, iter,
11962306a36Sopenharmony_ci					 vm_write);
12062306a36Sopenharmony_ci		len -= bytes;
12162306a36Sopenharmony_ci		start_offset = 0;
12262306a36Sopenharmony_ci		nr_pages -= pinned_pages;
12362306a36Sopenharmony_ci		pa += pinned_pages * PAGE_SIZE;
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci		/* If vm_write is set, the pages need to be made dirty: */
12662306a36Sopenharmony_ci		unpin_user_pages_dirty_lock(process_pages, pinned_pages,
12762306a36Sopenharmony_ci					    vm_write);
12862306a36Sopenharmony_ci	}
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	return rc;
13162306a36Sopenharmony_ci}
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci/* Maximum number of entries for process pages array
13462306a36Sopenharmony_ci   which lives on stack */
13562306a36Sopenharmony_ci#define PVM_MAX_PP_ARRAY_COUNT 16
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci/**
13862306a36Sopenharmony_ci * process_vm_rw_core - core of reading/writing pages from task specified
13962306a36Sopenharmony_ci * @pid: PID of process to read/write from/to
14062306a36Sopenharmony_ci * @iter: where to copy to/from locally
14162306a36Sopenharmony_ci * @rvec: iovec array specifying where to copy to/from in the other process
14262306a36Sopenharmony_ci * @riovcnt: size of rvec array
14362306a36Sopenharmony_ci * @flags: currently unused
14462306a36Sopenharmony_ci * @vm_write: 0 if reading from other process, 1 if writing to other process
14562306a36Sopenharmony_ci *
14662306a36Sopenharmony_ci * Returns the number of bytes read/written or error code. May
14762306a36Sopenharmony_ci *  return less bytes than expected if an error occurs during the copying
14862306a36Sopenharmony_ci *  process.
14962306a36Sopenharmony_ci */
15062306a36Sopenharmony_cistatic ssize_t process_vm_rw_core(pid_t pid, struct iov_iter *iter,
15162306a36Sopenharmony_ci				  const struct iovec *rvec,
15262306a36Sopenharmony_ci				  unsigned long riovcnt,
15362306a36Sopenharmony_ci				  unsigned long flags, int vm_write)
15462306a36Sopenharmony_ci{
15562306a36Sopenharmony_ci	struct task_struct *task;
15662306a36Sopenharmony_ci	struct page *pp_stack[PVM_MAX_PP_ARRAY_COUNT];
15762306a36Sopenharmony_ci	struct page **process_pages = pp_stack;
15862306a36Sopenharmony_ci	struct mm_struct *mm;
15962306a36Sopenharmony_ci	unsigned long i;
16062306a36Sopenharmony_ci	ssize_t rc = 0;
16162306a36Sopenharmony_ci	unsigned long nr_pages = 0;
16262306a36Sopenharmony_ci	unsigned long nr_pages_iov;
16362306a36Sopenharmony_ci	ssize_t iov_len;
16462306a36Sopenharmony_ci	size_t total_len = iov_iter_count(iter);
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	/*
16762306a36Sopenharmony_ci	 * Work out how many pages of struct pages we're going to need
16862306a36Sopenharmony_ci	 * when eventually calling get_user_pages
16962306a36Sopenharmony_ci	 */
17062306a36Sopenharmony_ci	for (i = 0; i < riovcnt; i++) {
17162306a36Sopenharmony_ci		iov_len = rvec[i].iov_len;
17262306a36Sopenharmony_ci		if (iov_len > 0) {
17362306a36Sopenharmony_ci			nr_pages_iov = ((unsigned long)rvec[i].iov_base
17462306a36Sopenharmony_ci					+ iov_len)
17562306a36Sopenharmony_ci				/ PAGE_SIZE - (unsigned long)rvec[i].iov_base
17662306a36Sopenharmony_ci				/ PAGE_SIZE + 1;
17762306a36Sopenharmony_ci			nr_pages = max(nr_pages, nr_pages_iov);
17862306a36Sopenharmony_ci		}
17962306a36Sopenharmony_ci	}
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	if (nr_pages == 0)
18262306a36Sopenharmony_ci		return 0;
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	if (nr_pages > PVM_MAX_PP_ARRAY_COUNT) {
18562306a36Sopenharmony_ci		/* For reliability don't try to kmalloc more than
18662306a36Sopenharmony_ci		   2 pages worth */
18762306a36Sopenharmony_ci		process_pages = kmalloc(min_t(size_t, PVM_MAX_KMALLOC_PAGES,
18862306a36Sopenharmony_ci					      sizeof(struct pages *)*nr_pages),
18962306a36Sopenharmony_ci					GFP_KERNEL);
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci		if (!process_pages)
19262306a36Sopenharmony_ci			return -ENOMEM;
19362306a36Sopenharmony_ci	}
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	/* Get process information */
19662306a36Sopenharmony_ci	task = find_get_task_by_vpid(pid);
19762306a36Sopenharmony_ci	if (!task) {
19862306a36Sopenharmony_ci		rc = -ESRCH;
19962306a36Sopenharmony_ci		goto free_proc_pages;
20062306a36Sopenharmony_ci	}
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	mm = mm_access(task, PTRACE_MODE_ATTACH_REALCREDS);
20362306a36Sopenharmony_ci	if (!mm || IS_ERR(mm)) {
20462306a36Sopenharmony_ci		rc = IS_ERR(mm) ? PTR_ERR(mm) : -ESRCH;
20562306a36Sopenharmony_ci		/*
20662306a36Sopenharmony_ci		 * Explicitly map EACCES to EPERM as EPERM is a more
20762306a36Sopenharmony_ci		 * appropriate error code for process_vw_readv/writev
20862306a36Sopenharmony_ci		 */
20962306a36Sopenharmony_ci		if (rc == -EACCES)
21062306a36Sopenharmony_ci			rc = -EPERM;
21162306a36Sopenharmony_ci		goto put_task_struct;
21262306a36Sopenharmony_ci	}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	for (i = 0; i < riovcnt && iov_iter_count(iter) && !rc; i++)
21562306a36Sopenharmony_ci		rc = process_vm_rw_single_vec(
21662306a36Sopenharmony_ci			(unsigned long)rvec[i].iov_base, rvec[i].iov_len,
21762306a36Sopenharmony_ci			iter, process_pages, mm, task, vm_write);
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	/* copied = space before - space after */
22062306a36Sopenharmony_ci	total_len -= iov_iter_count(iter);
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	/* If we have managed to copy any data at all then
22362306a36Sopenharmony_ci	   we return the number of bytes copied. Otherwise
22462306a36Sopenharmony_ci	   we return the error code */
22562306a36Sopenharmony_ci	if (total_len)
22662306a36Sopenharmony_ci		rc = total_len;
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	mmput(mm);
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ciput_task_struct:
23162306a36Sopenharmony_ci	put_task_struct(task);
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_cifree_proc_pages:
23462306a36Sopenharmony_ci	if (process_pages != pp_stack)
23562306a36Sopenharmony_ci		kfree(process_pages);
23662306a36Sopenharmony_ci	return rc;
23762306a36Sopenharmony_ci}
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci/**
24062306a36Sopenharmony_ci * process_vm_rw - check iovecs before calling core routine
24162306a36Sopenharmony_ci * @pid: PID of process to read/write from/to
24262306a36Sopenharmony_ci * @lvec: iovec array specifying where to copy to/from locally
24362306a36Sopenharmony_ci * @liovcnt: size of lvec array
24462306a36Sopenharmony_ci * @rvec: iovec array specifying where to copy to/from in the other process
24562306a36Sopenharmony_ci * @riovcnt: size of rvec array
24662306a36Sopenharmony_ci * @flags: currently unused
24762306a36Sopenharmony_ci * @vm_write: 0 if reading from other process, 1 if writing to other process
24862306a36Sopenharmony_ci *
24962306a36Sopenharmony_ci * Returns the number of bytes read/written or error code. May
25062306a36Sopenharmony_ci *  return less bytes than expected if an error occurs during the copying
25162306a36Sopenharmony_ci *  process.
25262306a36Sopenharmony_ci */
25362306a36Sopenharmony_cistatic ssize_t process_vm_rw(pid_t pid,
25462306a36Sopenharmony_ci			     const struct iovec __user *lvec,
25562306a36Sopenharmony_ci			     unsigned long liovcnt,
25662306a36Sopenharmony_ci			     const struct iovec __user *rvec,
25762306a36Sopenharmony_ci			     unsigned long riovcnt,
25862306a36Sopenharmony_ci			     unsigned long flags, int vm_write)
25962306a36Sopenharmony_ci{
26062306a36Sopenharmony_ci	struct iovec iovstack_l[UIO_FASTIOV];
26162306a36Sopenharmony_ci	struct iovec iovstack_r[UIO_FASTIOV];
26262306a36Sopenharmony_ci	struct iovec *iov_l = iovstack_l;
26362306a36Sopenharmony_ci	struct iovec *iov_r;
26462306a36Sopenharmony_ci	struct iov_iter iter;
26562306a36Sopenharmony_ci	ssize_t rc;
26662306a36Sopenharmony_ci	int dir = vm_write ? ITER_SOURCE : ITER_DEST;
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	if (flags != 0)
26962306a36Sopenharmony_ci		return -EINVAL;
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	/* Check iovecs */
27262306a36Sopenharmony_ci	rc = import_iovec(dir, lvec, liovcnt, UIO_FASTIOV, &iov_l, &iter);
27362306a36Sopenharmony_ci	if (rc < 0)
27462306a36Sopenharmony_ci		return rc;
27562306a36Sopenharmony_ci	if (!iov_iter_count(&iter))
27662306a36Sopenharmony_ci		goto free_iov_l;
27762306a36Sopenharmony_ci	iov_r = iovec_from_user(rvec, riovcnt, UIO_FASTIOV, iovstack_r,
27862306a36Sopenharmony_ci				in_compat_syscall());
27962306a36Sopenharmony_ci	if (IS_ERR(iov_r)) {
28062306a36Sopenharmony_ci		rc = PTR_ERR(iov_r);
28162306a36Sopenharmony_ci		goto free_iov_l;
28262306a36Sopenharmony_ci	}
28362306a36Sopenharmony_ci	rc = process_vm_rw_core(pid, &iter, iov_r, riovcnt, flags, vm_write);
28462306a36Sopenharmony_ci	if (iov_r != iovstack_r)
28562306a36Sopenharmony_ci		kfree(iov_r);
28662306a36Sopenharmony_cifree_iov_l:
28762306a36Sopenharmony_ci	kfree(iov_l);
28862306a36Sopenharmony_ci	return rc;
28962306a36Sopenharmony_ci}
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ciSYSCALL_DEFINE6(process_vm_readv, pid_t, pid, const struct iovec __user *, lvec,
29262306a36Sopenharmony_ci		unsigned long, liovcnt, const struct iovec __user *, rvec,
29362306a36Sopenharmony_ci		unsigned long, riovcnt,	unsigned long, flags)
29462306a36Sopenharmony_ci{
29562306a36Sopenharmony_ci	return process_vm_rw(pid, lvec, liovcnt, rvec, riovcnt, flags, 0);
29662306a36Sopenharmony_ci}
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ciSYSCALL_DEFINE6(process_vm_writev, pid_t, pid,
29962306a36Sopenharmony_ci		const struct iovec __user *, lvec,
30062306a36Sopenharmony_ci		unsigned long, liovcnt, const struct iovec __user *, rvec,
30162306a36Sopenharmony_ci		unsigned long, riovcnt,	unsigned long, flags)
30262306a36Sopenharmony_ci{
30362306a36Sopenharmony_ci	return process_vm_rw(pid, lvec, liovcnt, rvec, riovcnt, flags, 1);
30462306a36Sopenharmony_ci}
305