[PATCH 292/437] fs/proc: convert to read/write iterators

From: Jens Axboe
Date: Thu Apr 11 2024 - 12:47:25 EST


Signed-off-by: Jens Axboe <axboe@xxxxxxxxx>
---
fs/proc/base.c | 316 ++++++++++++++++-----------------
fs/proc/fd.c | 2 +-
fs/proc/inode.c | 18 +-
fs/proc/task_mmu.c | 37 ++--
fs/proc/task_nommu.c | 2 +-
include/linux/user_namespace.h | 10 +-
kernel/user_namespace.c | 39 ++--
7 files changed, 214 insertions(+), 210 deletions(-)

diff --git a/fs/proc/base.c b/fs/proc/base.c
index 4c6a7aafe66a..d810ede0e399 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -373,9 +373,10 @@ static ssize_t proc_pid_cmdline_read(struct file *file, char __user *buf,
*pos += ret;
return ret;
}
+FOPS_READ_ITER_HELPER(proc_pid_cmdline_read);

static const struct file_operations proc_pid_cmdline_ops = {
- .read = proc_pid_cmdline_read,
+ .read_iter = proc_pid_cmdline_read_iter,
.llseek = generic_file_llseek,
};

@@ -525,23 +526,22 @@ static int lstats_open(struct inode *inode, struct file *file)
return single_open(file, lstats_show_proc, inode);
}

-static ssize_t lstats_write(struct file *file, const char __user *buf,
- size_t count, loff_t *offs)
+static ssize_t lstats_write(struct kiocb *iocb, struct iov_iter *from)
{
- struct task_struct *task = get_proc_task(file_inode(file));
+ struct task_struct *task = get_proc_task(file_inode(iocb->ki_filp));

if (!task)
return -ESRCH;
clear_tsk_latency_tracing(task);
put_task_struct(task);

- return count;
+ return iov_iter_count(from);
}

static const struct file_operations proc_lstats_operations = {
.open = lstats_open,
- .read = seq_read,
- .write = lstats_write,
+ .read_iter = seq_read_iter,
+ .write_iter = lstats_write,
.llseek = seq_lseek,
.release = single_release,
};
@@ -788,7 +788,7 @@ static int proc_single_open(struct inode *inode, struct file *filp)

static const struct file_operations proc_single_file_operations = {
.open = proc_single_open,
- .read = seq_read,
+ .read_iter = seq_read_iter,
.llseek = seq_lseek,
.release = single_release,
};
@@ -835,11 +835,11 @@ static int mem_open(struct inode *inode, struct file *file)
return ret;
}

-static ssize_t mem_rw(struct file *file, char __user *buf,
- size_t count, loff_t *ppos, int write)
+static ssize_t mem_rw(struct kiocb *iocb, struct iov_iter *iov, int write)
{
- struct mm_struct *mm = file->private_data;
- unsigned long addr = *ppos;
+ struct mm_struct *mm = iocb->ki_filp->private_data;
+ size_t count = iov_iter_count(iov);
+ unsigned long addr = iocb->ki_pos;
ssize_t copied;
char *page;
unsigned int flags;
@@ -860,7 +860,7 @@ static ssize_t mem_rw(struct file *file, char __user *buf,
while (count > 0) {
size_t this_len = min_t(size_t, count, PAGE_SIZE);

- if (write && copy_from_user(page, buf, this_len)) {
+ if (write && !copy_from_iter_full(page, this_len, iov)) {
copied = -EFAULT;
break;
}
@@ -872,17 +872,16 @@ static ssize_t mem_rw(struct file *file, char __user *buf,
break;
}

- if (!write && copy_to_user(buf, page, this_len)) {
+ if (!write && !copy_to_iter_full(page, this_len, iov)) {
copied = -EFAULT;
break;
}

- buf += this_len;
addr += this_len;
copied += this_len;
count -= this_len;
}
- *ppos = addr;
+ iocb->ki_pos = addr;

mmput(mm);
free:
@@ -890,16 +889,14 @@ static ssize_t mem_rw(struct file *file, char __user *buf,
return copied;
}

-static ssize_t mem_read(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
+static ssize_t mem_read(struct kiocb *iocb, struct iov_iter *to)
{
- return mem_rw(file, buf, count, ppos, 0);
+ return mem_rw(iocb, to, 0);
}

-static ssize_t mem_write(struct file *file, const char __user *buf,
- size_t count, loff_t *ppos)
+static ssize_t mem_write(struct kiocb *iocb, struct iov_iter *from)
{
- return mem_rw(file, (char __user*)buf, count, ppos, 1);
+ return mem_rw(iocb, from, 1);
}

loff_t mem_lseek(struct file *file, loff_t offset, int orig)
@@ -928,8 +925,8 @@ static int mem_release(struct inode *inode, struct file *file)

static const struct file_operations proc_mem_operations = {
.llseek = mem_lseek,
- .read = mem_read,
- .write = mem_write,
+ .read_iter = mem_read,
+ .write_iter = mem_write,
.open = mem_open,
.release = mem_release,
};
@@ -939,13 +936,13 @@ static int environ_open(struct inode *inode, struct file *file)
return __mem_open(inode, file, PTRACE_MODE_READ);
}

-static ssize_t environ_read(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
+static ssize_t environ_read(struct kiocb *iocb, struct iov_iter *to)
{
+ size_t count = iov_iter_count(to);
char *page;
- unsigned long src = *ppos;
+ unsigned long src = iocb->ki_pos;
int ret = 0;
- struct mm_struct *mm = file->private_data;
+ struct mm_struct *mm = iocb->ki_filp->private_data;
unsigned long env_start, env_end;

/* Ensure the process spawned far enough to have an environment. */
@@ -984,17 +981,16 @@ static ssize_t environ_read(struct file *file, char __user *buf,
break;
}

- if (copy_to_user(buf, page, retval)) {
+ if (!copy_to_iter_full(page, retval, to)) {
ret = -EFAULT;
break;
}

ret += retval;
src += retval;
- buf += retval;
count -= retval;
}
- *ppos = src;
+ iocb->ki_pos = src;
mmput(mm);

free:
@@ -1004,7 +1000,7 @@ static ssize_t environ_read(struct file *file, char __user *buf,

static const struct file_operations proc_environ_operations = {
.open = environ_open,
- .read = environ_read,
+ .read_iter = environ_read,
.llseek = generic_file_llseek,
.release = mem_release,
};
@@ -1014,10 +1010,9 @@ static int auxv_open(struct inode *inode, struct file *file)
return __mem_open(inode, file, PTRACE_MODE_READ_FSCREDS);
}

-static ssize_t auxv_read(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
+static ssize_t auxv_read(struct kiocb *iocb, struct iov_iter *to)
{
- struct mm_struct *mm = file->private_data;
+ struct mm_struct *mm = iocb->ki_filp->private_data;
unsigned int nwords = 0;

if (!mm)
@@ -1025,21 +1020,20 @@ static ssize_t auxv_read(struct file *file, char __user *buf,
do {
nwords += 2;
} while (mm->saved_auxv[nwords - 2] != 0); /* AT_NULL */
- return simple_read_from_buffer(buf, count, ppos, mm->saved_auxv,
- nwords * sizeof(mm->saved_auxv[0]));
+ return simple_copy_to_iter(mm->saved_auxv, &iocb->ki_pos,
+ nwords * sizeof(mm->saved_auxv[0]), to);
}

static const struct file_operations proc_auxv_operations = {
.open = auxv_open,
- .read = auxv_read,
+ .read_iter = auxv_read,
.llseek = generic_file_llseek,
.release = mem_release,
};

-static ssize_t oom_adj_read(struct file *file, char __user *buf, size_t count,
- loff_t *ppos)
+static ssize_t oom_adj_read(struct kiocb *iocb, struct iov_iter *to)
{
- struct task_struct *task = get_proc_task(file_inode(file));
+ struct task_struct *task = get_proc_task(file_inode(iocb->ki_filp));
char buffer[PROC_NUMBUF];
int oom_adj = OOM_ADJUST_MIN;
size_t len;
@@ -1055,7 +1049,7 @@ static ssize_t oom_adj_read(struct file *file, char __user *buf, size_t count,
if (oom_adj > OOM_ADJUST_MAX)
oom_adj = OOM_ADJUST_MAX;
len = snprintf(buffer, sizeof(buffer), "%d\n", oom_adj);
- return simple_read_from_buffer(buf, count, ppos, buffer, len);
+ return simple_copy_to_iter(buffer, &iocb->ki_pos, len, to);
}

static int __set_oom_adj(struct file *file, int oom_adj, bool legacy)
@@ -1151,16 +1145,16 @@ static int __set_oom_adj(struct file *file, int oom_adj, bool legacy)
*
* oom_adj cannot be removed since existing userspace binaries use it.
*/
-static ssize_t oom_adj_write(struct file *file, const char __user *buf,
- size_t count, loff_t *ppos)
+static ssize_t oom_adj_write(struct kiocb *iocb, struct iov_iter *from)
{
+ size_t count = iov_iter_count(from);
char buffer[PROC_NUMBUF] = {};
int oom_adj;
int err;

if (count > sizeof(buffer) - 1)
count = sizeof(buffer) - 1;
- if (copy_from_user(buffer, buf, count)) {
+ if (!copy_from_iter_full(buffer, count, from)) {
err = -EFAULT;
goto out;
}
@@ -1183,21 +1177,20 @@ static ssize_t oom_adj_write(struct file *file, const char __user *buf,
else
oom_adj = (oom_adj * OOM_SCORE_ADJ_MAX) / -OOM_DISABLE;

- err = __set_oom_adj(file, oom_adj, true);
+ err = __set_oom_adj(iocb->ki_filp, oom_adj, true);
out:
return err < 0 ? err : count;
}

static const struct file_operations proc_oom_adj_operations = {
- .read = oom_adj_read,
- .write = oom_adj_write,
+ .read_iter = oom_adj_read,
+ .write_iter = oom_adj_write,
.llseek = generic_file_llseek,
};

-static ssize_t oom_score_adj_read(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
+static ssize_t oom_score_adj_read(struct kiocb *iocb, struct iov_iter *to)
{
- struct task_struct *task = get_proc_task(file_inode(file));
+ struct task_struct *task = get_proc_task(file_inode(iocb->ki_filp));
char buffer[PROC_NUMBUF];
short oom_score_adj = OOM_SCORE_ADJ_MIN;
size_t len;
@@ -1207,19 +1200,19 @@ static ssize_t oom_score_adj_read(struct file *file, char __user *buf,
oom_score_adj = task->signal->oom_score_adj;
put_task_struct(task);
len = snprintf(buffer, sizeof(buffer), "%hd\n", oom_score_adj);
- return simple_read_from_buffer(buf, count, ppos, buffer, len);
+ return simple_copy_to_iter(buffer, &iocb->ki_pos, len, to);
}

-static ssize_t oom_score_adj_write(struct file *file, const char __user *buf,
- size_t count, loff_t *ppos)
+static ssize_t oom_score_adj_write(struct kiocb *iocb, struct iov_iter *from)
{
+ size_t count = iov_iter_count(from);
char buffer[PROC_NUMBUF] = {};
int oom_score_adj;
int err;

if (count > sizeof(buffer) - 1)
count = sizeof(buffer) - 1;
- if (copy_from_user(buffer, buf, count)) {
+ if (!copy_from_iter_full(buffer, count, from)) {
err = -EFAULT;
goto out;
}
@@ -1233,23 +1226,22 @@ static ssize_t oom_score_adj_write(struct file *file, const char __user *buf,
goto out;
}

- err = __set_oom_adj(file, oom_score_adj, false);
+ err = __set_oom_adj(iocb->ki_filp, oom_score_adj, false);
out:
return err < 0 ? err : count;
}

static const struct file_operations proc_oom_score_adj_operations = {
- .read = oom_score_adj_read,
- .write = oom_score_adj_write,
+ .read_iter = oom_score_adj_read,
+ .write_iter = oom_score_adj_write,
.llseek = default_llseek,
};

#ifdef CONFIG_AUDIT
#define TMPBUFLEN 11
-static ssize_t proc_loginuid_read(struct file * file, char __user * buf,
- size_t count, loff_t *ppos)
+static ssize_t proc_loginuid_read(struct kiocb *iocb, struct iov_iter *to)
{
- struct inode * inode = file_inode(file);
+ struct inode * inode = file_inode(iocb->ki_filp);
struct task_struct *task = get_proc_task(inode);
ssize_t length;
char tmpbuf[TMPBUFLEN];
@@ -1257,16 +1249,16 @@ static ssize_t proc_loginuid_read(struct file * file, char __user * buf,
if (!task)
return -ESRCH;
length = scnprintf(tmpbuf, TMPBUFLEN, "%u",
- from_kuid(file->f_cred->user_ns,
+ from_kuid(iocb->ki_filp->f_cred->user_ns,
audit_get_loginuid(task)));
put_task_struct(task);
- return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
+ return simple_copy_to_iter(tmpbuf, &iocb->ki_pos, length, to);
}

-static ssize_t proc_loginuid_write(struct file * file, const char __user * buf,
- size_t count, loff_t *ppos)
+static ssize_t proc_loginuid_write(struct kiocb *iocb, struct iov_iter *from)
{
- struct inode * inode = file_inode(file);
+ struct inode * inode = file_inode(iocb->ki_filp);
+ size_t count = iov_iter_count(from);
uid_t loginuid;
kuid_t kloginuid;
int rv;
@@ -1282,12 +1274,12 @@ static ssize_t proc_loginuid_write(struct file * file, const char __user * buf,
}
rcu_read_unlock();

- if (*ppos != 0) {
+ if (iocb->ki_pos != 0) {
/* No partial writes. */
return -EINVAL;
}

- rv = kstrtou32_from_user(buf, count, 10, &loginuid);
+ rv = kstrtou32_from_iter(from, count, 10, &loginuid);
if (rv < 0)
return rv;

@@ -1295,7 +1287,7 @@ static ssize_t proc_loginuid_write(struct file * file, const char __user * buf,
if (loginuid == AUDIT_UID_UNSET) {
kloginuid = INVALID_UID;
} else {
- kloginuid = make_kuid(file->f_cred->user_ns, loginuid);
+ kloginuid = make_kuid(iocb->ki_filp->f_cred->user_ns, loginuid);
if (!uid_valid(kloginuid))
return -EINVAL;
}
@@ -1307,15 +1299,14 @@ static ssize_t proc_loginuid_write(struct file * file, const char __user * buf,
}

static const struct file_operations proc_loginuid_operations = {
- .read = proc_loginuid_read,
- .write = proc_loginuid_write,
+ .read_iter = proc_loginuid_read,
+ .write_iter = proc_loginuid_write,
.llseek = generic_file_llseek,
};

-static ssize_t proc_sessionid_read(struct file * file, char __user * buf,
- size_t count, loff_t *ppos)
+static ssize_t proc_sessionid_read(struct kiocb *iocb, struct iov_iter *to)
{
- struct inode * inode = file_inode(file);
+ struct inode * inode = file_inode(iocb->ki_filp);
struct task_struct *task = get_proc_task(inode);
ssize_t length;
char tmpbuf[TMPBUFLEN];
@@ -1325,20 +1316,19 @@ static ssize_t proc_sessionid_read(struct file * file, char __user * buf,
length = scnprintf(tmpbuf, TMPBUFLEN, "%u",
audit_get_sessionid(task));
put_task_struct(task);
- return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
+ return simple_copy_to_iter(tmpbuf, &iocb->ki_pos, length, to);
}

static const struct file_operations proc_sessionid_operations = {
- .read = proc_sessionid_read,
+ .read_iter = proc_sessionid_read,
.llseek = generic_file_llseek,
};
#endif

#ifdef CONFIG_FAULT_INJECTION
-static ssize_t proc_fault_inject_read(struct file * file, char __user * buf,
- size_t count, loff_t *ppos)
+static ssize_t proc_fault_inject_read(struct kiocb *iocb, struct iov_iter *to)
{
- struct task_struct *task = get_proc_task(file_inode(file));
+ struct task_struct *task = get_proc_task(file_inode(iocb->ki_filp));
char buffer[PROC_NUMBUF];
size_t len;
int make_it_fail;
@@ -1349,13 +1339,12 @@ static ssize_t proc_fault_inject_read(struct file * file, char __user * buf,
put_task_struct(task);

len = snprintf(buffer, sizeof(buffer), "%i\n", make_it_fail);
-
- return simple_read_from_buffer(buf, count, ppos, buffer, len);
+ return simple_copy_to_iter(buffer, &iocb->ki_pos, len, to);
}

-static ssize_t proc_fault_inject_write(struct file * file,
- const char __user * buf, size_t count, loff_t *ppos)
+static ssize_t proc_fault_inject_write(struct kiocb *iocb, struct iov_iter *from)
{
+ size_t count = iov_iter_count(from);
struct task_struct *task;
char buffer[PROC_NUMBUF] = {};
int make_it_fail;
@@ -1366,7 +1355,7 @@ static ssize_t proc_fault_inject_write(struct file * file,

if (count > sizeof(buffer) - 1)
count = sizeof(buffer) - 1;
- if (copy_from_user(buffer, buf, count))
+ if (!copy_from_iter_full(buffer, count, from))
return -EFAULT;
rv = kstrtoint(strstrip(buffer), 0, &make_it_fail);
if (rv < 0)
@@ -1374,7 +1363,7 @@ static ssize_t proc_fault_inject_write(struct file * file,
if (make_it_fail < 0 || make_it_fail > 1)
return -EINVAL;

- task = get_proc_task(file_inode(file));
+ task = get_proc_task(file_inode(iocb->ki_filp));
if (!task)
return -ESRCH;
task->make_it_fail = make_it_fail;
@@ -1384,23 +1373,23 @@ static ssize_t proc_fault_inject_write(struct file * file,
}

static const struct file_operations proc_fault_inject_operations = {
- .read = proc_fault_inject_read,
- .write = proc_fault_inject_write,
+ .read_iter = proc_fault_inject_read,
+ .write_iter = proc_fault_inject_write,
.llseek = generic_file_llseek,
};

-static ssize_t proc_fail_nth_write(struct file *file, const char __user *buf,
- size_t count, loff_t *ppos)
+static ssize_t proc_fail_nth_write(struct kiocb *iocb, struct iov_iter *from)
{
+ size_t count = iov_iter_count(from);
struct task_struct *task;
int err;
unsigned int n;

- err = kstrtouint_from_user(buf, count, 0, &n);
+ err = kstrtouint_from_iter(from, count, 0, &n);
if (err)
return err;

- task = get_proc_task(file_inode(file));
+ task = get_proc_task(file_inode(iocb->ki_filp));
if (!task)
return -ESRCH;
task->fail_nth = n;
@@ -1409,24 +1398,23 @@ static ssize_t proc_fail_nth_write(struct file *file, const char __user *buf,
return count;
}

-static ssize_t proc_fail_nth_read(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
+static ssize_t proc_fail_nth_read(struct kiocb *iocb, struct iov_iter *to)
{
struct task_struct *task;
char numbuf[PROC_NUMBUF];
ssize_t len;

- task = get_proc_task(file_inode(file));
+ task = get_proc_task(file_inode(iocb->ki_filp));
if (!task)
return -ESRCH;
len = snprintf(numbuf, sizeof(numbuf), "%u\n", task->fail_nth);
put_task_struct(task);
- return simple_read_from_buffer(buf, count, ppos, numbuf, len);
+ return simple_copy_to_iter(numbuf, &iocb->ki_pos, len, to);
}

static const struct file_operations proc_fail_nth_operations = {
- .read = proc_fail_nth_read,
- .write = proc_fail_nth_write,
+ .read_iter = proc_fail_nth_read,
+ .write_iter = proc_fail_nth_write,
};
#endif

@@ -1451,11 +1439,9 @@ static int sched_show(struct seq_file *m, void *v)
return 0;
}

-static ssize_t
-sched_write(struct file *file, const char __user *buf,
- size_t count, loff_t *offset)
+static ssize_t sched_write(struct kiocb *iocb, struct iov_iter *from)
{
- struct inode *inode = file_inode(file);
+ struct inode *inode = file_inode(iocb->ki_filp);
struct task_struct *p;

p = get_proc_task(inode);
@@ -1465,7 +1451,7 @@ sched_write(struct file *file, const char __user *buf,

put_task_struct(p);

- return count;
+ return iov_iter_count(from);
}

static int sched_open(struct inode *inode, struct file *filp)
@@ -1475,8 +1461,8 @@ static int sched_open(struct inode *inode, struct file *filp)

static const struct file_operations proc_pid_sched_operations = {
.open = sched_open,
- .read = seq_read,
- .write = sched_write,
+ .read_iter = seq_read_iter,
+ .write_iter = sched_write,
.llseek = seq_lseek,
.release = single_release,
};
@@ -1502,11 +1488,10 @@ static int sched_autogroup_show(struct seq_file *m, void *v)
return 0;
}

-static ssize_t
-sched_autogroup_write(struct file *file, const char __user *buf,
- size_t count, loff_t *offset)
+static ssize_t sched_autogroup_write(struct kiocb *iocb, struct iov_iter *from)
{
- struct inode *inode = file_inode(file);
+ struct inode *inode = file_inode(iocb->ki_filp);
+ size_t count = iov_iter_count(from);
struct task_struct *p;
char buffer[PROC_NUMBUF] = {};
int nice;
@@ -1514,7 +1499,7 @@ sched_autogroup_write(struct file *file, const char __user *buf,

if (count > sizeof(buffer) - 1)
count = sizeof(buffer) - 1;
- if (copy_from_user(buffer, buf, count))
+ if (!copy_from_iter_full(buffer, count, from))
return -EFAULT;

err = kstrtoint(strstrip(buffer), 0, &nice);
@@ -1549,8 +1534,8 @@ static int sched_autogroup_open(struct inode *inode, struct file *filp)

static const struct file_operations proc_pid_sched_autogroup_operations = {
.open = sched_autogroup_open,
- .read = seq_read,
- .write = sched_autogroup_write,
+ .read_iter = seq_read_iter,
+ .write_iter = sched_autogroup_write,
.llseek = seq_lseek,
.release = single_release,
};
@@ -1572,21 +1557,21 @@ static int timens_offsets_show(struct seq_file *m, void *v)
return 0;
}

-static ssize_t timens_offsets_write(struct file *file, const char __user *buf,
- size_t count, loff_t *ppos)
+static ssize_t timens_offsets_write(struct kiocb *iocb, struct iov_iter *from)
{
- struct inode *inode = file_inode(file);
+ struct inode *inode = file_inode(iocb->ki_filp);
+ size_t count = iov_iter_count(from);
struct proc_timens_offset offsets[2];
char *kbuf = NULL, *pos, *next_line;
struct task_struct *p;
int ret, noffsets;

/* Only allow < page size writes at the beginning of the file */
- if ((*ppos != 0) || (count >= PAGE_SIZE))
+ if ((iocb->ki_pos != 0) || (count >= PAGE_SIZE))
return -EINVAL;

/* Slurp in the user data */
- kbuf = memdup_user_nul(buf, count);
+ kbuf = iterdup_nul(from, count);
if (IS_ERR(kbuf))
return PTR_ERR(kbuf);

@@ -1634,7 +1619,7 @@ static ssize_t timens_offsets_write(struct file *file, const char __user *buf,
p = get_proc_task(inode);
if (!p)
goto out;
- ret = proc_timens_set_offset(file, p, offsets, noffsets);
+ ret = proc_timens_set_offset(iocb->ki_filp, p, offsets, noffsets);
put_task_struct(p);
if (ret)
goto out;
@@ -1652,22 +1637,22 @@ static int timens_offsets_open(struct inode *inode, struct file *filp)

static const struct file_operations proc_timens_offsets_operations = {
.open = timens_offsets_open,
- .read = seq_read,
- .write = timens_offsets_write,
+ .read_iter = seq_read_iter,
+ .write_iter = timens_offsets_write,
.llseek = seq_lseek,
.release = single_release,
};
#endif /* CONFIG_TIME_NS */

-static ssize_t comm_write(struct file *file, const char __user *buf,
- size_t count, loff_t *offset)
+static ssize_t comm_write(struct kiocb *iocb, struct iov_iter *from)
{
- struct inode *inode = file_inode(file);
+ struct inode *inode = file_inode(iocb->ki_filp);
+ size_t count = iov_iter_count(from);
struct task_struct *p;
char buffer[TASK_COMM_LEN] = {};
const size_t maxlen = sizeof(buffer) - 1;

- if (copy_from_user(buffer, buf, count > maxlen ? maxlen : count))
+ if (!copy_from_iter_full(buffer, count > maxlen ? maxlen : count, from))
return -EFAULT;

p = get_proc_task(inode);
@@ -1710,8 +1695,8 @@ static int comm_open(struct inode *inode, struct file *filp)

static const struct file_operations proc_pid_set_comm_operations = {
.open = comm_open,
- .read = seq_read,
- .write = comm_write,
+ .read_iter = seq_read_iter,
+ .write_iter = comm_write,
.llseek = seq_lseek,
.release = single_release,
};
@@ -2530,21 +2515,21 @@ static int proc_timers_open(struct inode *inode, struct file *file)

static const struct file_operations proc_timers_operations = {
.open = proc_timers_open,
- .read = seq_read,
+ .read_iter = seq_read_iter,
.llseek = seq_lseek,
.release = seq_release_private,
};
#endif

-static ssize_t timerslack_ns_write(struct file *file, const char __user *buf,
- size_t count, loff_t *offset)
+static ssize_t timerslack_ns_write(struct kiocb *iocb, struct iov_iter *from)
{
- struct inode *inode = file_inode(file);
+ struct inode *inode = file_inode(iocb->ki_filp);
+ size_t count = iov_iter_count(from);
struct task_struct *p;
u64 slack_ns;
int err;

- err = kstrtoull_from_user(buf, count, 10, &slack_ns);
+ err = kstrtoull_from_iter(from, count, 10, &slack_ns);
if (err < 0)
return err;

@@ -2622,8 +2607,8 @@ static int timerslack_ns_open(struct inode *inode, struct file *filp)

static const struct file_operations proc_pid_set_timerslack_ns_operations = {
.open = timerslack_ns_open,
- .read = seq_read,
- .write = timerslack_ns_write,
+ .read_iter = seq_read_iter,
+ .write_iter = timerslack_ns_write,
.llseek = seq_lseek,
.release = single_release,
};
@@ -2714,10 +2699,9 @@ static int proc_pid_attr_open(struct inode *inode, struct file *file)
return 0;
}

-static ssize_t proc_pid_attr_read(struct file * file, char __user * buf,
- size_t count, loff_t *ppos)
+static ssize_t proc_pid_attr_read(struct kiocb *iocb, struct iov_iter *to)
{
- struct inode * inode = file_inode(file);
+ struct inode * inode = file_inode(iocb->ki_filp);
char *p = NULL;
ssize_t length;
struct task_struct *task = get_proc_task(inode);
@@ -2726,25 +2710,25 @@ static ssize_t proc_pid_attr_read(struct file * file, char __user * buf,
return -ESRCH;

length = security_getprocattr(task, PROC_I(inode)->op.lsmid,
- file->f_path.dentry->d_name.name,
+ iocb->ki_filp->f_path.dentry->d_name.name,
&p);
put_task_struct(task);
if (length > 0)
- length = simple_read_from_buffer(buf, count, ppos, p, length);
+ length = simple_copy_to_iter(p, &iocb->ki_pos, length, to);
kfree(p);
return length;
}

-static ssize_t proc_pid_attr_write(struct file * file, const char __user * buf,
- size_t count, loff_t *ppos)
+static ssize_t proc_pid_attr_write(struct kiocb *iocb, struct iov_iter *from)
{
- struct inode * inode = file_inode(file);
+ struct inode * inode = file_inode(iocb->ki_filp);
+ size_t count = iov_iter_count(from);
struct task_struct *task;
void *page;
int rv;

/* A task may only write when it was the opener. */
- if (file->private_data != current->mm)
+ if (iocb->ki_filp->private_data != current->mm)
return -EPERM;

rcu_read_lock();
@@ -2769,10 +2753,10 @@ static ssize_t proc_pid_attr_write(struct file * file, const char __user * buf,
count = PAGE_SIZE;

/* No partial writes. */
- if (*ppos != 0)
+ if (iocb->ki_pos != 0)
return -EINVAL;

- page = memdup_user(buf, count);
+ page = iterdup(from, count);
if (IS_ERR(page)) {
rv = PTR_ERR(page);
goto out;
@@ -2784,8 +2768,8 @@ static ssize_t proc_pid_attr_write(struct file * file, const char __user * buf,
goto out_free;

rv = security_setprocattr(PROC_I(inode)->op.lsmid,
- file->f_path.dentry->d_name.name, page,
- count);
+ iocb->ki_filp->f_path.dentry->d_name.name,
+ page, count);
mutex_unlock(&current->signal->cred_guard_mutex);
out_free:
kfree(page);
@@ -2795,8 +2779,8 @@ static ssize_t proc_pid_attr_write(struct file * file, const char __user * buf,

static const struct file_operations proc_pid_attr_operations = {
.open = proc_pid_attr_open,
- .read = proc_pid_attr_read,
- .write = proc_pid_attr_write,
+ .read_iter = proc_pid_attr_read,
+ .write_iter = proc_pid_attr_write,
.llseek = generic_file_llseek,
.release = mem_release,
};
@@ -2892,10 +2876,9 @@ static const struct inode_operations proc_attr_dir_inode_operations = {
#endif

#ifdef CONFIG_ELF_CORE
-static ssize_t proc_coredump_filter_read(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
+static ssize_t proc_coredump_filter_read(struct kiocb *iocb, struct iov_iter *to)
{
- struct task_struct *task = get_proc_task(file_inode(file));
+ struct task_struct *task = get_proc_task(file_inode(iocb->ki_filp));
struct mm_struct *mm;
char buffer[PROC_NUMBUF];
size_t len;
@@ -2911,7 +2894,7 @@ static ssize_t proc_coredump_filter_read(struct file *file, char __user *buf,
((mm->flags & MMF_DUMP_FILTER_MASK) >>
MMF_DUMP_FILTER_SHIFT));
mmput(mm);
- ret = simple_read_from_buffer(buf, count, ppos, buffer, len);
+ ret = simple_copy_to_iter(buffer, &iocb->ki_pos, len, to);
}

put_task_struct(task);
@@ -2919,11 +2902,10 @@ static ssize_t proc_coredump_filter_read(struct file *file, char __user *buf,
return ret;
}

-static ssize_t proc_coredump_filter_write(struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
+static ssize_t proc_coredump_filter_write(struct kiocb *iocb,
+ struct iov_iter *from)
{
+ size_t count = iov_iter_count(from);
struct task_struct *task;
struct mm_struct *mm;
unsigned int val;
@@ -2931,12 +2913,12 @@ static ssize_t proc_coredump_filter_write(struct file *file,
int i;
unsigned long mask;

- ret = kstrtouint_from_user(buf, count, 0, &val);
+ ret = kstrtouint_from_iter(from, count, 0, &val);
if (ret < 0)
return ret;

ret = -ESRCH;
- task = get_proc_task(file_inode(file));
+ task = get_proc_task(file_inode(iocb->ki_filp));
if (!task)
goto out_no_task;

@@ -2962,8 +2944,8 @@ static ssize_t proc_coredump_filter_write(struct file *file,
}

static const struct file_operations proc_coredump_filter_operations = {
- .read = proc_coredump_filter_read,
- .write = proc_coredump_filter_write,
+ .read_iter = proc_coredump_filter_read,
+ .write_iter = proc_coredump_filter_write,
.llseek = generic_file_llseek,
};
#endif
@@ -3098,24 +3080,24 @@ static int proc_projid_map_open(struct inode *inode, struct file *file)

static const struct file_operations proc_uid_map_operations = {
.open = proc_uid_map_open,
- .write = proc_uid_map_write,
- .read = seq_read,
+ .write_iter = proc_uid_map_write_iter,
+ .read_iter = seq_read_iter,
.llseek = seq_lseek,
.release = proc_id_map_release,
};

static const struct file_operations proc_gid_map_operations = {
.open = proc_gid_map_open,
- .write = proc_gid_map_write,
- .read = seq_read,
+ .write_iter = proc_gid_map_write_iter,
+ .read_iter = seq_read_iter,
.llseek = seq_lseek,
.release = proc_id_map_release,
};

static const struct file_operations proc_projid_map_operations = {
.open = proc_projid_map_open,
- .write = proc_projid_map_write,
- .read = seq_read,
+ .write_iter = proc_projid_map_write_iter,
+ .read_iter = seq_read_iter,
.llseek = seq_lseek,
.release = proc_id_map_release,
};
@@ -3165,8 +3147,8 @@ static int proc_setgroups_release(struct inode *inode, struct file *file)

static const struct file_operations proc_setgroups_operations = {
.open = proc_setgroups_open,
- .write = proc_setgroups_write,
- .read = seq_read,
+ .write_iter = proc_setgroups_write,
+ .read_iter = seq_read_iter,
.llseek = seq_lseek,
.release = proc_setgroups_release,
};
diff --git a/fs/proc/fd.c b/fs/proc/fd.c
index 63a3aebdf223..ee3f608559e5 100644
--- a/fs/proc/fd.c
+++ b/fs/proc/fd.c
@@ -103,7 +103,7 @@ static int seq_fdinfo_open(struct inode *inode, struct file *file)

static const struct file_operations proc_fdinfo_file_operations = {
.open = seq_fdinfo_open,
- .read = seq_read,
+ .read_iter = seq_read_iter,
.llseek = seq_lseek,
.release = single_release,
};
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index dcd513dccf55..092164889e74 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -325,6 +325,11 @@ static ssize_t proc_reg_read(struct file *file, char __user *buf, size_t count,
return rv;
}

+static ssize_t __proc_reg_read_iter(struct kiocb *iocb, struct iov_iter *to)
+{
+ return vfs_read_iter(iocb, to, proc_reg_read);
+}
+
static ssize_t pde_write(struct proc_dir_entry *pde, struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
typeof_member(struct proc_ops, proc_write) write;
@@ -348,6 +353,7 @@ static ssize_t proc_reg_write(struct file *file, const char __user *buf, size_t
}
return rv;
}
+FOPS_WRITE_ITER_HELPER(proc_reg_write);

static __poll_t pde_poll(struct proc_dir_entry *pde, struct file *file, struct poll_table_struct *pts)
{
@@ -571,8 +577,8 @@ static int proc_reg_release(struct inode *inode, struct file *file)

static const struct file_operations proc_reg_file_ops = {
.llseek = proc_reg_llseek,
- .read = proc_reg_read,
- .write = proc_reg_write,
+ .read_iter = __proc_reg_read_iter,
+ .write_iter = proc_reg_write_iter,
.poll = proc_reg_poll,
.unlocked_ioctl = proc_reg_unlocked_ioctl,
.mmap = proc_reg_mmap,
@@ -584,7 +590,7 @@ static const struct file_operations proc_reg_file_ops = {
static const struct file_operations proc_iter_file_ops = {
.llseek = proc_reg_llseek,
.read_iter = proc_reg_read_iter,
- .write = proc_reg_write,
+ .write_iter = proc_reg_write_iter,
.splice_read = copy_splice_read,
.poll = proc_reg_poll,
.unlocked_ioctl = proc_reg_unlocked_ioctl,
@@ -597,8 +603,8 @@ static const struct file_operations proc_iter_file_ops = {
#ifdef CONFIG_COMPAT
static const struct file_operations proc_reg_file_ops_compat = {
.llseek = proc_reg_llseek,
- .read = proc_reg_read,
- .write = proc_reg_write,
+ .read_iter = proc_reg_read_iter,
+ .write_iter = proc_reg_write_iter,
.poll = proc_reg_poll,
.unlocked_ioctl = proc_reg_unlocked_ioctl,
.compat_ioctl = proc_reg_compat_ioctl,
@@ -612,7 +618,7 @@ static const struct file_operations proc_iter_file_ops_compat = {
.llseek = proc_reg_llseek,
.read_iter = proc_reg_read_iter,
.splice_read = copy_splice_read,
- .write = proc_reg_write,
+ .write_iter = proc_reg_write_iter,
.poll = proc_reg_poll,
.unlocked_ioctl = proc_reg_unlocked_ioctl,
.compat_ioctl = proc_reg_compat_ioctl,
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 23fbab954c20..ff86fe94fcba 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -360,7 +360,7 @@ static int pid_maps_open(struct inode *inode, struct file *file)

const struct file_operations proc_pid_maps_operations = {
.open = pid_maps_open,
- .read = seq_read,
+ .read_iter = seq_read_iter,
.llseek = seq_lseek,
.release = proc_map_release,
};
@@ -1049,14 +1049,14 @@ static int smaps_rollup_release(struct inode *inode, struct file *file)

const struct file_operations proc_pid_smaps_operations = {
.open = pid_smaps_open,
- .read = seq_read,
+ .read_iter = seq_read_iter,
.llseek = seq_lseek,
.release = proc_map_release,
};

const struct file_operations proc_pid_smaps_rollup_operations = {
.open = smaps_rollup_open,
- .read = seq_read,
+ .read_iter = seq_read_iter,
.llseek = seq_lseek,
.release = smaps_rollup_release,
};
@@ -1242,9 +1242,9 @@ static const struct mm_walk_ops clear_refs_walk_ops = {
.walk_lock = PGWALK_WRLOCK,
};

-static ssize_t clear_refs_write(struct file *file, const char __user *buf,
- size_t count, loff_t *ppos)
+static ssize_t clear_refs_write(struct kiocb *iocb, struct iov_iter *from)
{
+ size_t count = iov_iter_count(from);
struct task_struct *task;
char buffer[PROC_NUMBUF] = {};
struct mm_struct *mm;
@@ -1255,7 +1255,7 @@ static ssize_t clear_refs_write(struct file *file, const char __user *buf,

if (count > sizeof(buffer) - 1)
count = sizeof(buffer) - 1;
- if (copy_from_user(buffer, buf, count))
+ if (!copy_from_iter_full(buffer, count, from))
return -EFAULT;
rv = kstrtoint(strstrip(buffer), 10, &itype);
if (rv < 0)
@@ -1264,7 +1264,7 @@ static ssize_t clear_refs_write(struct file *file, const char __user *buf,
if (type < CLEAR_REFS_ALL || type >= CLEAR_REFS_LAST)
return -EINVAL;

- task = get_proc_task(file_inode(file));
+ task = get_proc_task(file_inode(iocb->ki_filp));
if (!task)
return -ESRCH;
mm = get_task_mm(task);
@@ -1318,7 +1318,7 @@ static ssize_t clear_refs_write(struct file *file, const char __user *buf,
}

const struct file_operations proc_clear_refs_operations = {
- .write = clear_refs_write,
+ .write_iter = clear_refs_write,
.llseek = noop_llseek,
};

@@ -1645,10 +1645,10 @@ static const struct mm_walk_ops pagemap_ops = {
* determine which areas of memory are actually mapped and llseek to
* skip over unmapped regions.
*/
-static ssize_t pagemap_read(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
+static ssize_t pagemap_read(struct kiocb *iocb, struct iov_iter *to)
{
- struct mm_struct *mm = file->private_data;
+ struct mm_struct *mm = iocb->ki_filp->private_data;
+ size_t count = iov_iter_count(to);
struct pagemapread pm;
unsigned long src;
unsigned long svpfn;
@@ -1661,7 +1661,7 @@ static ssize_t pagemap_read(struct file *file, char __user *buf,

ret = -EINVAL;
/* file position must be aligned */
- if ((*ppos % PM_ENTRY_BYTES) || (count % PM_ENTRY_BYTES))
+ if ((iocb->ki_pos % PM_ENTRY_BYTES) || (count % PM_ENTRY_BYTES))
goto out_mm;

ret = 0;
@@ -1669,7 +1669,7 @@ static ssize_t pagemap_read(struct file *file, char __user *buf,
goto out_mm;

/* do not disclose physical addresses: attack vector */
- pm.show_pfn = file_ns_capable(file, &init_user_ns, CAP_SYS_ADMIN);
+ pm.show_pfn = file_ns_capable(iocb->ki_filp, &init_user_ns, CAP_SYS_ADMIN);

pm.len = (PAGEMAP_WALK_SIZE >> PAGE_SHIFT);
pm.buffer = kmalloc_array(pm.len, PM_ENTRY_BYTES, GFP_KERNEL);
@@ -1677,7 +1677,7 @@ static ssize_t pagemap_read(struct file *file, char __user *buf,
if (!pm.buffer)
goto out_mm;

- src = *ppos;
+ src = iocb->ki_pos;
svpfn = src / PM_ENTRY_BYTES;
end_vaddr = mm->task_size;

@@ -1719,15 +1719,14 @@ static ssize_t pagemap_read(struct file *file, char __user *buf,
start_vaddr = end;

len = min(count, PM_ENTRY_BYTES * pm.pos);
- if (copy_to_user(buf, pm.buffer, len)) {
+ if (!copy_to_iter_full(pm.buffer, len, to)) {
ret = -EFAULT;
goto out_free;
}
copied += len;
- buf += len;
count -= len;
}
- *ppos += copied;
+ iocb->ki_pos += copied;
if (!ret || ret == PM_END_OF_BUFFER)
ret = copied;

@@ -2518,7 +2517,7 @@ static long do_pagemap_cmd(struct file *file, unsigned int cmd,

const struct file_operations proc_pagemap_operations = {
.llseek = mem_lseek, /* borrow this */
- .read = pagemap_read,
+ .read_iter = pagemap_read,
.open = pagemap_open,
.release = pagemap_release,
.unlocked_ioctl = do_pagemap_cmd,
@@ -2787,7 +2786,7 @@ static int pid_numa_maps_open(struct inode *inode, struct file *file)

const struct file_operations proc_pid_numa_maps_operations = {
.open = pid_numa_maps_open,
- .read = seq_read,
+ .read_iter = seq_read_iter,
.llseek = seq_lseek,
.release = proc_map_release,
};
diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c
index bce674533000..b1385bf8dd05 100644
--- a/fs/proc/task_nommu.c
+++ b/fs/proc/task_nommu.c
@@ -289,7 +289,7 @@ static int pid_maps_open(struct inode *inode, struct file *file)

const struct file_operations proc_pid_maps_operations = {
.open = pid_maps_open,
- .read = seq_read,
+ .read_iter = seq_read_iter,
.llseek = seq_lseek,
.release = map_release,
};
diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h
index 6030a8235617..181ba788a56b 100644
--- a/include/linux/user_namespace.h
+++ b/include/linux/user_namespace.h
@@ -174,13 +174,15 @@ static inline void put_user_ns(struct user_namespace *ns)
}

struct seq_operations;
+struct kiocb;
+struct iov_iter;
extern const struct seq_operations proc_uid_seq_operations;
extern const struct seq_operations proc_gid_seq_operations;
extern const struct seq_operations proc_projid_seq_operations;
-extern ssize_t proc_uid_map_write(struct file *, const char __user *, size_t, loff_t *);
-extern ssize_t proc_gid_map_write(struct file *, const char __user *, size_t, loff_t *);
-extern ssize_t proc_projid_map_write(struct file *, const char __user *, size_t, loff_t *);
-extern ssize_t proc_setgroups_write(struct file *, const char __user *, size_t, loff_t *);
+ssize_t proc_uid_map_write_iter(struct kiocb *iocb, struct iov_iter *from);
+ssize_t proc_gid_map_write_iter(struct kiocb *iocb, struct iov_iter *from);
+ssize_t proc_projid_map_write_iter(struct kiocb *iocb, struct iov_iter *from);
+ssize_t proc_setgroups_write(struct kiocb *iocb, struct iov_iter *from);
extern int proc_setgroups_show(struct seq_file *m, void *v);
extern bool userns_may_setgroups(const struct user_namespace *ns);
extern bool in_userns(const struct user_namespace *ancestor,
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c
index 0b0b95418b16..05ec5be1c2d7 100644
--- a/kernel/user_namespace.c
+++ b/kernel/user_namespace.c
@@ -1108,8 +1108,8 @@ static ssize_t map_write(struct file *file, const char __user *buf,
return ret;
}

-ssize_t proc_uid_map_write(struct file *file, const char __user *buf,
- size_t size, loff_t *ppos)
+static ssize_t proc_uid_map_write(struct file *file, const char __user *buf,
+ size_t size, loff_t *ppos)
{
struct seq_file *seq = file->private_data;
struct user_namespace *ns = seq->private;
@@ -1125,8 +1125,13 @@ ssize_t proc_uid_map_write(struct file *file, const char __user *buf,
&ns->uid_map, &ns->parent->uid_map);
}

-ssize_t proc_gid_map_write(struct file *file, const char __user *buf,
- size_t size, loff_t *ppos)
+ssize_t proc_uid_map_write_iter(struct kiocb *iocb, struct iov_iter *from)
+{
+ return vfs_write_iter(iocb, from, proc_uid_map_write);
+}
+
+static ssize_t proc_gid_map_write(struct file *file, const char __user *buf,
+ size_t size, loff_t *ppos)
{
struct seq_file *seq = file->private_data;
struct user_namespace *ns = seq->private;
@@ -1142,8 +1147,13 @@ ssize_t proc_gid_map_write(struct file *file, const char __user *buf,
&ns->gid_map, &ns->parent->gid_map);
}

-ssize_t proc_projid_map_write(struct file *file, const char __user *buf,
- size_t size, loff_t *ppos)
+ssize_t proc_gid_map_write_iter(struct kiocb *iocb, struct iov_iter *from)
+{
+ return vfs_write_iter(iocb, from, proc_gid_map_write);
+}
+
+static ssize_t proc_projid_map_write(struct file *file, const char __user *buf,
+ size_t size, loff_t *ppos)
{
struct seq_file *seq = file->private_data;
struct user_namespace *ns = seq->private;
@@ -1160,6 +1170,11 @@ ssize_t proc_projid_map_write(struct file *file, const char __user *buf,
&ns->projid_map, &ns->parent->projid_map);
}

+ssize_t proc_projid_map_write_iter(struct kiocb *iocb, struct iov_iter *from)
+{
+ return vfs_write_iter(iocb, from, proc_projid_map_write);
+}
+
static bool new_idmap_permitted(const struct file *file,
struct user_namespace *ns, int cap_setid,
struct uid_gid_map *new_map)
@@ -1213,23 +1228,23 @@ int proc_setgroups_show(struct seq_file *seq, void *v)
return 0;
}

-ssize_t proc_setgroups_write(struct file *file, const char __user *buf,
- size_t count, loff_t *ppos)
+ssize_t proc_setgroups_write(struct kiocb *iocb, struct iov_iter *from)
{
- struct seq_file *seq = file->private_data;
+ struct seq_file *seq = iocb->ki_filp->private_data;
struct user_namespace *ns = seq->private;
+ size_t count = iov_iter_count(from);
char kbuf[8], *pos;
bool setgroups_allowed;
ssize_t ret;

/* Only allow a very narrow range of strings to be written */
ret = -EINVAL;
- if ((*ppos != 0) || (count >= sizeof(kbuf)))
+ if ((iocb->ki_pos != 0) || (count >= sizeof(kbuf)))
goto out;

/* What was written? */
ret = -EFAULT;
- if (copy_from_user(kbuf, buf, count))
+ if (!copy_from_iter_full(kbuf, count, from))
goto out;
kbuf[count] = '\0';
pos = kbuf;
@@ -1271,7 +1286,7 @@ ssize_t proc_setgroups_write(struct file *file, const char __user *buf,
mutex_unlock(&userns_state_mutex);

/* Report a successful write */
- *ppos = count;
+ iocb->ki_pos = count;
ret = count;
out:
return ret;
--
2.43.0