mirror of
https://github.com/torvalds/linux.git
synced 2024-11-22 12:11:40 +00:00
fs/proc/kcore: convert read_kcore() to read_kcore_iter()
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>
This commit is contained in:
parent
2e1c017077
commit
46c0d6d090
@ -24,7 +24,7 @@
|
|||||||
#include <linux/memblock.h>
|
#include <linux/memblock.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/uaccess.h>
|
#include <linux/uio.h>
|
||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
#include <linux/list.h>
|
#include <linux/list.h>
|
||||||
#include <linux/ioport.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
|
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;
|
char *buf = file->private_data;
|
||||||
|
loff_t *fpos = &iocb->ki_pos;
|
||||||
|
|
||||||
size_t phdrs_offset, notes_offset, data_offset;
|
size_t phdrs_offset, notes_offset, data_offset;
|
||||||
size_t page_offline_frozen = 1;
|
size_t page_offline_frozen = 1;
|
||||||
size_t phdrs_len, notes_len;
|
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;
|
size_t tsz;
|
||||||
int nphdr;
|
int nphdr;
|
||||||
unsigned long start;
|
unsigned long start;
|
||||||
|
size_t buflen = iov_iter_count(iter);
|
||||||
size_t orig_buflen = buflen;
|
size_t orig_buflen = buflen;
|
||||||
int ret = 0;
|
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);
|
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;
|
ret = -EFAULT;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer += tsz;
|
|
||||||
buflen -= tsz;
|
buflen -= tsz;
|
||||||
*fpos += 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);
|
tsz = min_t(size_t, buflen, phdrs_offset + phdrs_len - *fpos);
|
||||||
if (copy_to_user(buffer, (char *)phdrs + *fpos - phdrs_offset,
|
if (copy_to_iter((char *)phdrs + *fpos - phdrs_offset, tsz,
|
||||||
tsz)) {
|
iter) != tsz) {
|
||||||
kfree(phdrs);
|
kfree(phdrs);
|
||||||
ret = -EFAULT;
|
ret = -EFAULT;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
kfree(phdrs);
|
kfree(phdrs);
|
||||||
|
|
||||||
buffer += tsz;
|
|
||||||
buflen -= tsz;
|
buflen -= tsz;
|
||||||
*fpos += 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));
|
min(vmcoreinfo_size, notes_len - i));
|
||||||
|
|
||||||
tsz = min_t(size_t, buflen, notes_offset + notes_len - *fpos);
|
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);
|
kfree(notes);
|
||||||
ret = -EFAULT;
|
ret = -EFAULT;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
kfree(notes);
|
kfree(notes);
|
||||||
|
|
||||||
buffer += tsz;
|
|
||||||
buflen -= tsz;
|
buflen -= tsz;
|
||||||
*fpos += tsz;
|
*fpos += tsz;
|
||||||
}
|
}
|
||||||
@ -497,7 +498,7 @@ read_kcore(struct file *file, char __user *buffer, size_t buflen, loff_t *fpos)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!m) {
|
if (!m) {
|
||||||
if (clear_user(buffer, tsz)) {
|
if (iov_iter_zero(tsz, iter) != tsz) {
|
||||||
ret = -EFAULT;
|
ret = -EFAULT;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@ -508,14 +509,14 @@ read_kcore(struct file *file, char __user *buffer, size_t buflen, loff_t *fpos)
|
|||||||
case KCORE_VMALLOC:
|
case KCORE_VMALLOC:
|
||||||
vread(buf, (char *)start, tsz);
|
vread(buf, (char *)start, tsz);
|
||||||
/* we have to zero-fill user buffer even if no read */
|
/* 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;
|
ret = -EFAULT;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case KCORE_USER:
|
case KCORE_USER:
|
||||||
/* User page is handled prior to normal kernel page: */
|
/* 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;
|
ret = -EFAULT;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@ -531,7 +532,7 @@ read_kcore(struct file *file, char __user *buffer, size_t buflen, loff_t *fpos)
|
|||||||
*/
|
*/
|
||||||
if (!page || PageOffline(page) ||
|
if (!page || PageOffline(page) ||
|
||||||
is_page_hwpoison(page) || !pfn_is_ram(pfn)) {
|
is_page_hwpoison(page) || !pfn_is_ram(pfn)) {
|
||||||
if (clear_user(buffer, tsz)) {
|
if (iov_iter_zero(tsz, iter) != tsz) {
|
||||||
ret = -EFAULT;
|
ret = -EFAULT;
|
||||||
goto out;
|
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_VMEMMAP:
|
||||||
case KCORE_TEXT:
|
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.
|
* 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;
|
ret = -EFAULT;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
pr_warn_once("Unhandled KCORE type: %d\n", m->type);
|
pr_warn_once("Unhandled KCORE type: %d\n", m->type);
|
||||||
if (clear_user(buffer, tsz)) {
|
if (iov_iter_zero(tsz, iter) != tsz) {
|
||||||
ret = -EFAULT;
|
ret = -EFAULT;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@ -559,7 +560,6 @@ read_kcore(struct file *file, char __user *buffer, size_t buflen, loff_t *fpos)
|
|||||||
skip:
|
skip:
|
||||||
buflen -= tsz;
|
buflen -= tsz;
|
||||||
*fpos += tsz;
|
*fpos += tsz;
|
||||||
buffer += tsz;
|
|
||||||
start += tsz;
|
start += tsz;
|
||||||
tsz = (buflen > PAGE_SIZE ? PAGE_SIZE : buflen);
|
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 = {
|
static const struct proc_ops kcore_proc_ops = {
|
||||||
.proc_read = read_kcore,
|
.proc_read_iter = read_kcore_iter,
|
||||||
.proc_open = open_kcore,
|
.proc_open = open_kcore,
|
||||||
.proc_release = release_kcore,
|
.proc_release = release_kcore,
|
||||||
.proc_lseek = default_llseek,
|
.proc_lseek = default_llseek,
|
||||||
|
Loading…
Reference in New Issue
Block a user