fs/proc/kcore: convert read_kcore() to read_kcore_iter()
authorLorenzo Stoakes <lstoakes@gmail.com>
Wed, 22 Mar 2023 18:57:02 +0000 (18:57 +0000)
committerAndrew Morton <akpm@linux-foundation.org>
Thu, 6 Apr 2023 02:42:56 +0000 (19:42 -0700)
For the time being we still use a bounce buffer for vread(), however in
the next patch we will convert this to interact directly with the iterator
and eliminate the bounce buffer altogether.

Link: https://lkml.kernel.org/r/ebe12c8d70eebd71f487d80095605f3ad0d1489c.1679511146.git.lstoakes@gmail.com
Signed-off-by: Lorenzo Stoakes <lstoakes@gmail.com>
Reviewed-by: David Hildenbrand <david@redhat.com>
Reviewed-by: Baoquan He <bhe@redhat.com>
Cc: Alexander Viro <viro@zeniv.linux.org.uk>
Cc: Jens Axboe <axboe@kernel.dk>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Liu Shixin <liushixin2@huawei.com>
Cc: Matthew Wilcox (Oracle) <willy@infradead.org>
Cc: Uladzislau Rezki (Sony) <urezki@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
fs/proc/kcore.c

index 556f310d6aa4ead4f322b15f0244b7ab45340b22..08b795fd80b4ac82a7a96d7bac9d7508b898171e 100644 (file)
@@ -24,7 +24,7 @@
 #include <linux/memblock.h>
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/uaccess.h>
+#include <linux/uio.h>
 #include <asm/io.h>
 #include <linux/list.h>
 #include <linux/ioport.h>
@@ -308,9 +308,12 @@ static void append_kcore_note(char *notes, size_t *i, const char *name,
 }
 
 static ssize_t
-read_kcore(struct file *file, char __user *buffer, size_t buflen, loff_t *fpos)
+read_kcore_iter(struct kiocb *iocb, struct iov_iter *iter)
 {
+       struct file *file = iocb->ki_filp;
        char *buf = file->private_data;
+       loff_t *fpos = &iocb->ki_pos;
+
        size_t phdrs_offset, notes_offset, data_offset;
        size_t page_offline_frozen = 1;
        size_t phdrs_len, notes_len;
@@ -318,6 +321,7 @@ read_kcore(struct file *file, char __user *buffer, size_t buflen, loff_t *fpos)
        size_t tsz;
        int nphdr;
        unsigned long start;
+       size_t buflen = iov_iter_count(iter);
        size_t orig_buflen = buflen;
        int ret = 0;
 
@@ -356,12 +360,11 @@ read_kcore(struct file *file, char __user *buffer, size_t buflen, loff_t *fpos)
                };
 
                tsz = min_t(size_t, buflen, sizeof(struct elfhdr) - *fpos);
-               if (copy_to_user(buffer, (char *)&ehdr + *fpos, tsz)) {
+               if (copy_to_iter((char *)&ehdr + *fpos, tsz, iter) != tsz) {
                        ret = -EFAULT;
                        goto out;
                }
 
-               buffer += tsz;
                buflen -= tsz;
                *fpos += tsz;
        }
@@ -398,15 +401,14 @@ read_kcore(struct file *file, char __user *buffer, size_t buflen, loff_t *fpos)
                }
 
                tsz = min_t(size_t, buflen, phdrs_offset + phdrs_len - *fpos);
-               if (copy_to_user(buffer, (char *)phdrs + *fpos - phdrs_offset,
-                                tsz)) {
+               if (copy_to_iter((char *)phdrs + *fpos - phdrs_offset, tsz,
+                                iter) != tsz) {
                        kfree(phdrs);
                        ret = -EFAULT;
                        goto out;
                }
                kfree(phdrs);
 
-               buffer += tsz;
                buflen -= tsz;
                *fpos += tsz;
        }
@@ -448,14 +450,13 @@ read_kcore(struct file *file, char __user *buffer, size_t buflen, loff_t *fpos)
                                  min(vmcoreinfo_size, notes_len - i));
 
                tsz = min_t(size_t, buflen, notes_offset + notes_len - *fpos);
-               if (copy_to_user(buffer, notes + *fpos - notes_offset, tsz)) {
+               if (copy_to_iter(notes + *fpos - notes_offset, tsz, iter) != tsz) {
                        kfree(notes);
                        ret = -EFAULT;
                        goto out;
                }
                kfree(notes);
 
-               buffer += tsz;
                buflen -= tsz;
                *fpos += tsz;
        }
@@ -497,7 +498,7 @@ read_kcore(struct file *file, char __user *buffer, size_t buflen, loff_t *fpos)
                }
 
                if (!m) {
-                       if (clear_user(buffer, tsz)) {
+                       if (iov_iter_zero(tsz, iter) != tsz) {
                                ret = -EFAULT;
                                goto out;
                        }
@@ -508,14 +509,14 @@ read_kcore(struct file *file, char __user *buffer, size_t buflen, loff_t *fpos)
                case KCORE_VMALLOC:
                        vread(buf, (char *)start, tsz);
                        /* we have to zero-fill user buffer even if no read */
-                       if (copy_to_user(buffer, buf, tsz)) {
+                       if (copy_to_iter(buf, tsz, iter) != tsz) {
                                ret = -EFAULT;
                                goto out;
                        }
                        break;
                case KCORE_USER:
                        /* User page is handled prior to normal kernel page: */
-                       if (copy_to_user(buffer, (char *)start, tsz)) {
+                       if (copy_to_iter((char *)start, tsz, iter) != tsz) {
                                ret = -EFAULT;
                                goto out;
                        }
@@ -531,7 +532,7 @@ read_kcore(struct file *file, char __user *buffer, size_t buflen, loff_t *fpos)
                         */
                        if (!page || PageOffline(page) ||
                            is_page_hwpoison(page) || !pfn_is_ram(pfn)) {
-                               if (clear_user(buffer, tsz)) {
+                               if (iov_iter_zero(tsz, iter) != tsz) {
                                        ret = -EFAULT;
                                        goto out;
                                }
@@ -541,17 +542,17 @@ read_kcore(struct file *file, char __user *buffer, size_t buflen, loff_t *fpos)
                case KCORE_VMEMMAP:
                case KCORE_TEXT:
                        /*
-                        * We use _copy_to_user() to bypass usermode hardening
+                        * We use _copy_to_iter() to bypass usermode hardening
                         * which would otherwise prevent this operation.
                         */
-                       if (_copy_to_user(buffer, (char *)start, tsz)) {
+                       if (_copy_to_iter((char *)start, tsz, iter) != tsz) {
                                ret = -EFAULT;
                                goto out;
                        }
                        break;
                default:
                        pr_warn_once("Unhandled KCORE type: %d\n", m->type);
-                       if (clear_user(buffer, tsz)) {
+                       if (iov_iter_zero(tsz, iter) != tsz) {
                                ret = -EFAULT;
                                goto out;
                        }
@@ -559,7 +560,6 @@ read_kcore(struct file *file, char __user *buffer, size_t buflen, loff_t *fpos)
 skip:
                buflen -= tsz;
                *fpos += tsz;
-               buffer += tsz;
                start += tsz;
                tsz = (buflen > PAGE_SIZE ? PAGE_SIZE : buflen);
        }
@@ -603,7 +603,7 @@ static int release_kcore(struct inode *inode, struct file *file)
 }
 
 static const struct proc_ops kcore_proc_ops = {
-       .proc_read      = read_kcore,
+       .proc_read_iter = read_kcore_iter,
        .proc_open      = open_kcore,
        .proc_release   = release_kcore,
        .proc_lseek     = default_llseek,