diff --git a/fs/aio.c b/fs/aio.c index e7f2fad7b4ce7cae2d334456f5d9998e795c917e..8c7c8b805372094cc5072b7cd49b5e771ab507c4 100644 --- a/fs/aio.c +++ b/fs/aio.c @@ -1446,13 +1446,13 @@ static ssize_t aio_setup_vectored_rw(int type, struct kiocb *kiocb, bool compat) ret = compat_rw_copy_check_uvector(type, (struct compat_iovec __user *)kiocb->ki_buf, kiocb->ki_nbytes, 1, &kiocb->ki_inline_vec, - &kiocb->ki_iovec, 1); + &kiocb->ki_iovec); else #endif ret = rw_copy_check_uvector(type, (struct iovec __user *)kiocb->ki_buf, kiocb->ki_nbytes, 1, &kiocb->ki_inline_vec, - &kiocb->ki_iovec, 1); + &kiocb->ki_iovec); if (ret < 0) goto out; diff --git a/fs/compat.c b/fs/compat.c index 0781e619a62a48babf8969fa5453994d784ba13c..6556a9ce8a28fecf508d2ddc34cf3ff7b5bebe18 100644 --- a/fs/compat.c +++ b/fs/compat.c @@ -532,7 +532,7 @@ compat_sys_io_getevents(aio_context_t ctx_id, ssize_t compat_rw_copy_check_uvector(int type, const struct compat_iovec __user *uvector, unsigned long nr_segs, unsigned long fast_segs, struct iovec *fast_pointer, - struct iovec **ret_pointer, int check_access) + struct iovec **ret_pointer) { compat_ssize_t tot_len; struct iovec *iov = *ret_pointer = fast_pointer; @@ -579,7 +579,7 @@ ssize_t compat_rw_copy_check_uvector(int type, } if (len < 0) /* size_t not fitting in compat_ssize_t .. */ goto out; - if (check_access && + if (type >= 0 && !access_ok(vrfy_dir(type), compat_ptr(buf), len)) { ret = -EFAULT; goto out; @@ -1094,7 +1094,7 @@ static ssize_t compat_do_readv_writev(int type, struct file *file, goto out; tot_len = compat_rw_copy_check_uvector(type, uvector, nr_segs, - UIO_FASTIOV, iovstack, &iov, 1); + UIO_FASTIOV, iovstack, &iov); if (tot_len == 0) { ret = 0; goto out; diff --git a/fs/read_write.c b/fs/read_write.c index ffc99d22e0a3656711f14ac7e094cc954d1d90bd..c20614f86c01ed88ed36a65e9dfafdabfd3ba4d3 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -633,8 +633,7 @@ ssize_t do_loop_readv_writev(struct file *filp, struct iovec *iov, ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector, unsigned long nr_segs, unsigned long fast_segs, struct iovec *fast_pointer, - struct iovec **ret_pointer, - int check_access) + struct iovec **ret_pointer) { unsigned long seg; ssize_t ret; @@ -690,7 +689,7 @@ ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector, ret = -EINVAL; goto out; } - if (check_access + if (type >= 0 && unlikely(!access_ok(vrfy_dir(type), buf, len))) { ret = -EFAULT; goto out; @@ -723,7 +722,7 @@ static ssize_t do_readv_writev(int type, struct file *file, } ret = rw_copy_check_uvector(type, uvector, nr_segs, - ARRAY_SIZE(iovstack), iovstack, &iov, 1); + ARRAY_SIZE(iovstack), iovstack, &iov); if (ret <= 0) goto out; diff --git a/include/linux/compat.h b/include/linux/compat.h index 5d46217f84adfaab0dbe679a7612da7062bb72c6..4e890394ef996e709c490439be23f0c6fe24292f 100644 --- a/include/linux/compat.h +++ b/include/linux/compat.h @@ -577,8 +577,7 @@ extern ssize_t compat_rw_copy_check_uvector(int type, const struct compat_iovec __user *uvector, unsigned long nr_segs, unsigned long fast_segs, struct iovec *fast_pointer, - struct iovec **ret_pointer, - int check_access); + struct iovec **ret_pointer); extern void __user *compat_alloc_user_space(unsigned long len); diff --git a/include/linux/fs.h b/include/linux/fs.h index 038076b27ea467c4a4c14dd9b49a51f3eec9f24c..cf2c5611b19b59e537775adb23612f0d5f3c85bd 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -173,6 +173,15 @@ struct inodes_stat_t { #define WRITE_FUA (WRITE | REQ_SYNC | REQ_NOIDLE | REQ_FUA) #define WRITE_FLUSH_FUA (WRITE | REQ_SYNC | REQ_NOIDLE | REQ_FLUSH | REQ_FUA) + +/* + * Flag for rw_copy_check_uvector and compat_rw_copy_check_uvector + * that indicates that they should check the contents of the iovec are + * valid, but not check the memory that the iovec elements + * points too. + */ +#define CHECK_IOVEC_ONLY -1 + #define SEL_IN 1 #define SEL_OUT 2 #define SEL_EX 4 @@ -1690,8 +1699,7 @@ struct seq_file; ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector, unsigned long nr_segs, unsigned long fast_segs, struct iovec *fast_pointer, - struct iovec **ret_pointer, - int check_access); + struct iovec **ret_pointer); 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 *); diff --git a/mm/process_vm_access.c b/mm/process_vm_access.c index c20ff48994c29050953c79fcdb0633e690bb653e..926b466497492f3f8463ebc623adc4fbddf9547a 100644 --- a/mm/process_vm_access.c +++ b/mm/process_vm_access.c @@ -371,15 +371,15 @@ static ssize_t process_vm_rw(pid_t pid, /* Check iovecs */ if (vm_write) rc = rw_copy_check_uvector(WRITE, lvec, liovcnt, UIO_FASTIOV, - iovstack_l, &iov_l, 1); + iovstack_l, &iov_l); else rc = rw_copy_check_uvector(READ, lvec, liovcnt, UIO_FASTIOV, - iovstack_l, &iov_l, 1); + iovstack_l, &iov_l); if (rc <= 0) goto free_iovecs; - rc = rw_copy_check_uvector(READ, rvec, riovcnt, UIO_FASTIOV, - iovstack_r, &iov_r, 0); + rc = rw_copy_check_uvector(CHECK_IOVEC_ONLY, rvec, riovcnt, UIO_FASTIOV, + iovstack_r, &iov_r); if (rc <= 0) goto free_iovecs; @@ -438,16 +438,16 @@ compat_process_vm_rw(compat_pid_t pid, if (vm_write) rc = compat_rw_copy_check_uvector(WRITE, lvec, liovcnt, UIO_FASTIOV, iovstack_l, - &iov_l, 1); + &iov_l); else rc = compat_rw_copy_check_uvector(READ, lvec, liovcnt, UIO_FASTIOV, iovstack_l, - &iov_l, 1); + &iov_l); if (rc <= 0) goto free_iovecs; - rc = compat_rw_copy_check_uvector(READ, rvec, riovcnt, + rc = compat_rw_copy_check_uvector(CHECK_IOVEC_ONLY, rvec, riovcnt, UIO_FASTIOV, iovstack_r, - &iov_r, 0); + &iov_r); if (rc <= 0) goto free_iovecs; diff --git a/security/keys/compat.c b/security/keys/compat.c index fab4f8dda6c6fdf6acdebd1385bb39caae4c8b97..c92d42b021aa47c62dea181c6b90129d80ff7e53 100644 --- a/security/keys/compat.c +++ b/security/keys/compat.c @@ -38,7 +38,7 @@ long compat_keyctl_instantiate_key_iov( ret = compat_rw_copy_check_uvector(WRITE, _payload_iov, ioc, ARRAY_SIZE(iovstack), - iovstack, &iov, 1); + iovstack, &iov); if (ret < 0) return ret; if (ret == 0) diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index 18f29de88fda22196a49e28b43175ed1935fff5b..21907ea35b15c118515eb03dea87efab7f8ad9f8 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c @@ -1110,7 +1110,7 @@ long keyctl_instantiate_key_iov(key_serial_t id, goto no_payload; ret = rw_copy_check_uvector(WRITE, _payload_iov, ioc, - ARRAY_SIZE(iovstack), iovstack, &iov, 1); + ARRAY_SIZE(iovstack), iovstack, &iov); if (ret < 0) return ret; if (ret == 0)