forked from luck/tmp_suning_uos_patched
cleanup in-kernel read and write operations
Reshuffle the (__)kernel_read and (__)kernel_write helpers, and ensure all users of in-kernel file I/O use them if they don't use iov_iter based methods already. -----BEGIN PGP SIGNATURE----- iQI/BAABCgApFiEEgdbnc3r/njty3Iq9D55TZVIEUYMFAl8Ij8gLHGhjaEBsc3Qu ZGUACgkQD55TZVIEUYOcpBAAn157ooLqRrqQisEA6j59rTgkHUuqZMUx+8XjiivX baHQPmgctza1Xzjc4PjJ1owtLpt4ywcTpY8IDj3vZF1PpffeeuWVzxMTk/aIvhNN zPK2SJpRlDQHErKEhkTTOfOYoFTgc7vPa5Hvm6AEMaJs8oPtGZ2rnQHzPXENl/TY TgcLd1ou3iuw19UIAfB+EfuC9uhq7pCPu9+tryNyT2IfM7fqdsIhRESpcodg1ve+ 1k6leFIBrXa3MWiBGVUGCrSmlpP9xd22Zl8D/w60WeYWeg7szZoUK2bjhbdIEDZI tTwkdZ73IKpcxOyzUVbfr2hqNa94zrXCKQGfEGVS/7arV7QH4yvhg9NU9lqVXZKV ruPoyjsmJkHW52FfEEv1Gfrd6v4H6qZ6iyJEm3ZYNGul85O97t1xA/kKxAIwMuPa nFhhxHIooT/We3Ao77FROhIob4D5AOfOI4gvkTE15YMzsNxT/yjilQjdDFR5An6A ckzqb+VyDvcTx2gxR/qaol7b4lzmri4S/8Jt7WXjHOtNe9eXC4kl44leitK5j31H fHZNyMLJ2+/JF5pGB2rNRNnTeQ7lXKob4Y+qAjRThddDxtdsf5COdZAiIiZbRurR Ogl2k3sMDdHgNfycK2Bg5Fab9OIWePQlpcGU14afUSPviuNkIYKLGrx92ZWef53j loI= =eYsI -----END PGP SIGNATURE----- Merge tag 'cleanup-kernel_read_write' of git://git.infradead.org/users/hch/misc Pull in-kernel read and write op cleanups from Christoph Hellwig: "Cleanup in-kernel read and write operations Reshuffle the (__)kernel_read and (__)kernel_write helpers, and ensure all users of in-kernel file I/O use them if they don't use iov_iter based methods already. The new WARN_ONs in combination with syzcaller already found a missing input validation in 9p. The fix should be on your way through the maintainer ASAP". [ This is prep-work for the real changes coming 5.9 ] * tag 'cleanup-kernel_read_write' of git://git.infradead.org/users/hch/misc: fs: remove __vfs_read fs: implement kernel_read using __kernel_read integrity/ima: switch to using __kernel_read fs: add a __kernel_read helper fs: remove __vfs_write fs: implement kernel_write using __kernel_write fs: check FMODE_WRITE in __kernel_write fs: unexport __kernel_write bpfilter: switch to kernel_write autofs: switch to kernel_write cachefiles: switch to kernel_write
This commit is contained in:
commit
b1b11d0063
|
@ -53,7 +53,7 @@ static int autofs_write(struct autofs_sb_info *sbi,
|
|||
|
||||
mutex_lock(&sbi->pipe_mutex);
|
||||
while (bytes) {
|
||||
wr = __kernel_write(file, data, bytes, &file->f_pos);
|
||||
wr = kernel_write(file, data, bytes, &file->f_pos);
|
||||
if (wr <= 0)
|
||||
break;
|
||||
data += wr;
|
||||
|
|
|
@ -937,7 +937,7 @@ int cachefiles_write_page(struct fscache_storage *op, struct page *page)
|
|||
}
|
||||
|
||||
data = kmap(page);
|
||||
ret = __kernel_write(file, data, len, &pos);
|
||||
ret = kernel_write(file, data, len, &pos);
|
||||
kunmap(page);
|
||||
fput(file);
|
||||
if (ret != len)
|
||||
|
|
135
fs/read_write.c
135
fs/read_write.c
|
@ -419,28 +419,42 @@ static ssize_t new_sync_read(struct file *filp, char __user *buf, size_t len, lo
|
|||
return ret;
|
||||
}
|
||||
|
||||
ssize_t __vfs_read(struct file *file, char __user *buf, size_t count,
|
||||
loff_t *pos)
|
||||
ssize_t __kernel_read(struct file *file, void *buf, size_t count, loff_t *pos)
|
||||
{
|
||||
if (file->f_op->read)
|
||||
return file->f_op->read(file, buf, count, pos);
|
||||
else if (file->f_op->read_iter)
|
||||
return new_sync_read(file, buf, count, pos);
|
||||
else
|
||||
mm_segment_t old_fs = get_fs();
|
||||
ssize_t ret;
|
||||
|
||||
if (WARN_ON_ONCE(!(file->f_mode & FMODE_READ)))
|
||||
return -EINVAL;
|
||||
if (!(file->f_mode & FMODE_CAN_READ))
|
||||
return -EINVAL;
|
||||
|
||||
if (count > MAX_RW_COUNT)
|
||||
count = MAX_RW_COUNT;
|
||||
set_fs(KERNEL_DS);
|
||||
if (file->f_op->read)
|
||||
ret = file->f_op->read(file, (void __user *)buf, count, pos);
|
||||
else if (file->f_op->read_iter)
|
||||
ret = new_sync_read(file, (void __user *)buf, count, pos);
|
||||
else
|
||||
ret = -EINVAL;
|
||||
set_fs(old_fs);
|
||||
if (ret > 0) {
|
||||
fsnotify_access(file);
|
||||
add_rchar(current, ret);
|
||||
}
|
||||
inc_syscr(current);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t kernel_read(struct file *file, void *buf, size_t count, loff_t *pos)
|
||||
{
|
||||
mm_segment_t old_fs;
|
||||
ssize_t result;
|
||||
ssize_t ret;
|
||||
|
||||
old_fs = get_fs();
|
||||
set_fs(KERNEL_DS);
|
||||
/* The cast to a user pointer is valid due to the set_fs() */
|
||||
result = vfs_read(file, (void __user *)buf, count, pos);
|
||||
set_fs(old_fs);
|
||||
return result;
|
||||
ret = rw_verify_area(READ, file, pos, count);
|
||||
if (ret)
|
||||
return ret;
|
||||
return __kernel_read(file, buf, count, pos);
|
||||
}
|
||||
EXPORT_SYMBOL(kernel_read);
|
||||
|
||||
|
@ -456,17 +470,22 @@ ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
|
|||
return -EFAULT;
|
||||
|
||||
ret = rw_verify_area(READ, file, pos, count);
|
||||
if (!ret) {
|
||||
if (count > MAX_RW_COUNT)
|
||||
count = MAX_RW_COUNT;
|
||||
ret = __vfs_read(file, buf, count, pos);
|
||||
if (ret > 0) {
|
||||
fsnotify_access(file);
|
||||
add_rchar(current, ret);
|
||||
}
|
||||
inc_syscr(current);
|
||||
}
|
||||
if (ret)
|
||||
return ret;
|
||||
if (count > MAX_RW_COUNT)
|
||||
count = MAX_RW_COUNT;
|
||||
|
||||
if (file->f_op->read)
|
||||
ret = file->f_op->read(file, buf, count, pos);
|
||||
else if (file->f_op->read_iter)
|
||||
ret = new_sync_read(file, buf, count, pos);
|
||||
else
|
||||
ret = -EINVAL;
|
||||
if (ret > 0) {
|
||||
fsnotify_access(file);
|
||||
add_rchar(current, ret);
|
||||
}
|
||||
inc_syscr(current);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -488,23 +507,15 @@ static ssize_t new_sync_write(struct file *filp, const char __user *buf, size_t
|
|||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t __vfs_write(struct file *file, const char __user *p,
|
||||
size_t count, loff_t *pos)
|
||||
{
|
||||
if (file->f_op->write)
|
||||
return file->f_op->write(file, p, count, pos);
|
||||
else if (file->f_op->write_iter)
|
||||
return new_sync_write(file, p, count, pos);
|
||||
else
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* caller is responsible for file_start_write/file_end_write */
|
||||
ssize_t __kernel_write(struct file *file, const void *buf, size_t count, loff_t *pos)
|
||||
{
|
||||
mm_segment_t old_fs;
|
||||
const char __user *p;
|
||||
ssize_t ret;
|
||||
|
||||
if (WARN_ON_ONCE(!(file->f_mode & FMODE_WRITE)))
|
||||
return -EBADF;
|
||||
if (!(file->f_mode & FMODE_CAN_WRITE))
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -513,7 +524,12 @@ ssize_t __kernel_write(struct file *file, const void *buf, size_t count, loff_t
|
|||
p = (__force const char __user *)buf;
|
||||
if (count > MAX_RW_COUNT)
|
||||
count = MAX_RW_COUNT;
|
||||
ret = __vfs_write(file, p, count, pos);
|
||||
if (file->f_op->write)
|
||||
ret = file->f_op->write(file, p, count, pos);
|
||||
else if (file->f_op->write_iter)
|
||||
ret = new_sync_write(file, p, count, pos);
|
||||
else
|
||||
ret = -EINVAL;
|
||||
set_fs(old_fs);
|
||||
if (ret > 0) {
|
||||
fsnotify_modify(file);
|
||||
|
@ -522,21 +538,20 @@ ssize_t __kernel_write(struct file *file, const void *buf, size_t count, loff_t
|
|||
inc_syscw(current);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(__kernel_write);
|
||||
|
||||
ssize_t kernel_write(struct file *file, const void *buf, size_t count,
|
||||
loff_t *pos)
|
||||
{
|
||||
mm_segment_t old_fs;
|
||||
ssize_t res;
|
||||
ssize_t ret;
|
||||
|
||||
old_fs = get_fs();
|
||||
set_fs(KERNEL_DS);
|
||||
/* The cast to a user pointer is valid due to the set_fs() */
|
||||
res = vfs_write(file, (__force const char __user *)buf, count, pos);
|
||||
set_fs(old_fs);
|
||||
ret = rw_verify_area(WRITE, file, pos, count);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return res;
|
||||
file_start_write(file);
|
||||
ret = __kernel_write(file, buf, count, pos);
|
||||
file_end_write(file);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(kernel_write);
|
||||
|
||||
|
@ -552,19 +567,23 @@ ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_
|
|||
return -EFAULT;
|
||||
|
||||
ret = rw_verify_area(WRITE, file, pos, count);
|
||||
if (!ret) {
|
||||
if (count > MAX_RW_COUNT)
|
||||
count = MAX_RW_COUNT;
|
||||
file_start_write(file);
|
||||
ret = __vfs_write(file, buf, count, pos);
|
||||
if (ret > 0) {
|
||||
fsnotify_modify(file);
|
||||
add_wchar(current, ret);
|
||||
}
|
||||
inc_syscw(current);
|
||||
file_end_write(file);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (count > MAX_RW_COUNT)
|
||||
count = MAX_RW_COUNT;
|
||||
file_start_write(file);
|
||||
if (file->f_op->write)
|
||||
ret = file->f_op->write(file, buf, count, pos);
|
||||
else if (file->f_op->write_iter)
|
||||
ret = new_sync_write(file, buf, count, pos);
|
||||
else
|
||||
ret = -EINVAL;
|
||||
if (ret > 0) {
|
||||
fsnotify_modify(file);
|
||||
add_wchar(current, ret);
|
||||
}
|
||||
|
||||
inc_syscw(current);
|
||||
file_end_write(file);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -1918,7 +1918,6 @@ ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector,
|
|||
struct iovec *fast_pointer,
|
||||
struct iovec **ret_pointer);
|
||||
|
||||
extern ssize_t __vfs_read(struct file *, char __user *, size_t, loff_t *);
|
||||
extern ssize_t vfs_read(struct file *, char __user *, size_t, loff_t *);
|
||||
extern ssize_t vfs_write(struct file *, const char __user *, size_t, loff_t *);
|
||||
extern ssize_t vfs_readv(struct file *, const struct iovec __user *,
|
||||
|
@ -3034,6 +3033,7 @@ extern int kernel_read_file_from_path_initns(const char *, void **, loff_t *, lo
|
|||
extern int kernel_read_file_from_fd(int, void **, loff_t *, loff_t,
|
||||
enum kernel_read_file_id);
|
||||
extern ssize_t kernel_read(struct file *, void *, size_t, loff_t *);
|
||||
ssize_t __kernel_read(struct file *file, void *buf, size_t count, loff_t *pos);
|
||||
extern ssize_t kernel_write(struct file *, const void *, size_t, loff_t *);
|
||||
extern ssize_t __kernel_write(struct file *, const void *, size_t, loff_t *);
|
||||
extern struct file * open_exec(const char *);
|
||||
|
|
|
@ -50,7 +50,7 @@ static int __bpfilter_process_sockopt(struct sock *sk, int optname,
|
|||
req.len = optlen;
|
||||
if (!bpfilter_ops.info.pid)
|
||||
goto out;
|
||||
n = __kernel_write(bpfilter_ops.info.pipe_to_umh, &req, sizeof(req),
|
||||
n = kernel_write(bpfilter_ops.info.pipe_to_umh, &req, sizeof(req),
|
||||
&pos);
|
||||
if (n != sizeof(req)) {
|
||||
pr_err("write fail %zd\n", n);
|
||||
|
|
|
@ -188,19 +188,7 @@ DEFINE_LSM(integrity) = {
|
|||
int integrity_kernel_read(struct file *file, loff_t offset,
|
||||
void *addr, unsigned long count)
|
||||
{
|
||||
mm_segment_t old_fs;
|
||||
char __user *buf = (char __user *)addr;
|
||||
ssize_t ret;
|
||||
|
||||
if (!(file->f_mode & FMODE_READ))
|
||||
return -EBADF;
|
||||
|
||||
old_fs = get_fs();
|
||||
set_fs(KERNEL_DS);
|
||||
ret = __vfs_read(file, buf, count, &offset);
|
||||
set_fs(old_fs);
|
||||
|
||||
return ret;
|
||||
return __kernel_read(file, addr, count, &offset);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in New Issue
Block a user