From aae26b13ffb9e38bb46b8c85985761b5f196b6f6 Mon Sep 17 00:00:00 2001 From: Nick Desaulniers Date: Thu, 22 Oct 2020 10:23:47 -0700 Subject: [PATCH] fs: fix up type confusion in readv/writev The syscall interface doesn't match up with the interface libc is using or that's defined in the manual pages. ssize_t readv(int fd, const struct iovec *iov, int iovcnt); ssize_t writev(int fd, const struct iovec *iov, int iovcnt); The kernel was defining `iovcnt` as `unsigned long` which is a problem when userspace understands this to be `int`. (There's still likely a signedness bug here, but use the proper widths that import_iovec() expects.) Signed-off-by: Nick Desaulniers --- fs/read_write.c | 10 +++++----- fs/splice.c | 2 +- include/linux/fs.h | 2 +- lib/iov_iter.c | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/fs/read_write.c b/fs/read_write.c index 19f5c4bf75aa..b858f39a4475 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -890,7 +890,7 @@ ssize_t vfs_iter_write(struct file *file, struct iov_iter *iter, loff_t *ppos, EXPORT_SYMBOL(vfs_iter_write); ssize_t vfs_readv(struct file *file, const struct iovec __user *vec, - unsigned long vlen, loff_t *pos, rwf_t flags) + unsigned int vlen, loff_t *pos, rwf_t flags) { struct iovec iovstack[UIO_FASTIOV]; struct iovec *iov = iovstack; @@ -907,7 +907,7 @@ ssize_t vfs_readv(struct file *file, const struct iovec __user *vec, } static ssize_t vfs_writev(struct file *file, const struct iovec __user *vec, - unsigned long vlen, loff_t *pos, rwf_t flags) + unsigned int vlen, loff_t *pos, rwf_t flags) { struct iovec iovstack[UIO_FASTIOV]; struct iovec *iov = iovstack; @@ -925,7 +925,7 @@ static ssize_t vfs_writev(struct file *file, const struct iovec __user *vec, } static ssize_t do_readv(unsigned long fd, const struct iovec __user *vec, - unsigned long vlen, rwf_t flags) + unsigned int vlen, rwf_t flags) { struct fd f = fdget_pos(fd); ssize_t ret = -EBADF; @@ -1025,13 +1025,13 @@ static ssize_t do_pwritev(unsigned long fd, const struct iovec __user *vec, } SYSCALL_DEFINE3(readv, unsigned long, fd, const struct iovec __user *, vec, - unsigned long, vlen) + unsigned int, vlen) { return do_readv(fd, vec, vlen, 0); } SYSCALL_DEFINE3(writev, unsigned long, fd, const struct iovec __user *, vec, - unsigned long, vlen) + unsigned int, vlen) { return do_writev(fd, vec, vlen, 0); } diff --git a/fs/splice.c b/fs/splice.c index 70cc52af780b..7508eccfa143 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -342,7 +342,7 @@ const struct pipe_buf_operations nosteal_pipe_buf_ops = { EXPORT_SYMBOL(nosteal_pipe_buf_ops); static ssize_t kernel_readv(struct file *file, const struct kvec *vec, - unsigned long vlen, loff_t offset) + unsigned int vlen, loff_t offset) { mm_segment_t old_fs; loff_t pos = offset; diff --git a/include/linux/fs.h b/include/linux/fs.h index c4ae9cafbbba..211bce5e6e60 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1895,7 +1895,7 @@ static inline int call_mmap(struct file *file, struct vm_area_struct *vma) 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 *, - unsigned long, loff_t *, rwf_t); + unsigned int, loff_t *, rwf_t); extern ssize_t vfs_copy_file_range(struct file *, loff_t , struct file *, loff_t, size_t, unsigned int); extern ssize_t generic_copy_file_range(struct file *file_in, loff_t pos_in, diff --git a/lib/iov_iter.c b/lib/iov_iter.c index 1635111c5bd2..ded9d9c4eb28 100644 --- a/lib/iov_iter.c +++ b/lib/iov_iter.c @@ -1734,7 +1734,7 @@ struct iovec *iovec_from_user(const struct iovec __user *uvec, } ssize_t __import_iovec(int type, const struct iovec __user *uvec, - unsigned nr_segs, unsigned fast_segs, struct iovec **iovp, + unsigned int nr_segs, unsigned int fast_segs, struct iovec **iovp, struct iov_iter *i, bool compat) { ssize_t total_len = 0; @@ -1803,7 +1803,7 @@ ssize_t __import_iovec(int type, const struct iovec __user *uvec, * Return: Negative error code on error, bytes imported on success */ ssize_t import_iovec(int type, const struct iovec __user *uvec, - unsigned nr_segs, unsigned fast_segs, + unsigned int nr_segs, unsigned int fast_segs, struct iovec **iovp, struct iov_iter *i) { return __import_iovec(type, uvec, nr_segs, fast_segs, iovp, i, -- 2.29.0.rc1.297.gfa9743e501-goog