Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

aio/vfs: cleanup of rw_copy_check_uvector() and compat_rw_copy_check_uvector()

A cleanup of rw_copy_check_uvector and compat_rw_copy_check_uvector after
changes made to support CMA in an earlier patch.

Rather than having an additional check_access parameter to these
functions, the first paramater type is overloaded to allow the caller to
specify CHECK_IOVEC_ONLY which means check that the contents of the iovec
are valid, but do not check the memory that they point to. This is used
by process_vm_readv/writev where we need to validate that a iovec passed
to the syscall is valid but do not want to check the memory that it points
to at this point because it refers to an address space in another process.

Signed-off-by: Chris Yeoh <yeohc@au1.ibm.com>
Reviewed-by: Oleg Nesterov <oleg@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Christopher Yeoh and committed by
Linus Torvalds
ac34ebb3 ee62c6b2

+29 -23
+2 -2
fs/aio.c
··· 1446 1446 ret = compat_rw_copy_check_uvector(type, 1447 1447 (struct compat_iovec __user *)kiocb->ki_buf, 1448 1448 kiocb->ki_nbytes, 1, &kiocb->ki_inline_vec, 1449 - &kiocb->ki_iovec, 1); 1449 + &kiocb->ki_iovec); 1450 1450 else 1451 1451 #endif 1452 1452 ret = rw_copy_check_uvector(type, 1453 1453 (struct iovec __user *)kiocb->ki_buf, 1454 1454 kiocb->ki_nbytes, 1, &kiocb->ki_inline_vec, 1455 - &kiocb->ki_iovec, 1); 1455 + &kiocb->ki_iovec); 1456 1456 if (ret < 0) 1457 1457 goto out; 1458 1458
+3 -3
fs/compat.c
··· 532 532 ssize_t compat_rw_copy_check_uvector(int type, 533 533 const struct compat_iovec __user *uvector, unsigned long nr_segs, 534 534 unsigned long fast_segs, struct iovec *fast_pointer, 535 - struct iovec **ret_pointer, int check_access) 535 + struct iovec **ret_pointer) 536 536 { 537 537 compat_ssize_t tot_len; 538 538 struct iovec *iov = *ret_pointer = fast_pointer; ··· 579 579 } 580 580 if (len < 0) /* size_t not fitting in compat_ssize_t .. */ 581 581 goto out; 582 - if (check_access && 582 + if (type >= 0 && 583 583 !access_ok(vrfy_dir(type), compat_ptr(buf), len)) { 584 584 ret = -EFAULT; 585 585 goto out; ··· 1094 1094 goto out; 1095 1095 1096 1096 tot_len = compat_rw_copy_check_uvector(type, uvector, nr_segs, 1097 - UIO_FASTIOV, iovstack, &iov, 1); 1097 + UIO_FASTIOV, iovstack, &iov); 1098 1098 if (tot_len == 0) { 1099 1099 ret = 0; 1100 1100 goto out;
+3 -4
fs/read_write.c
··· 633 633 ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector, 634 634 unsigned long nr_segs, unsigned long fast_segs, 635 635 struct iovec *fast_pointer, 636 - struct iovec **ret_pointer, 637 - int check_access) 636 + struct iovec **ret_pointer) 638 637 { 639 638 unsigned long seg; 640 639 ssize_t ret; ··· 689 690 ret = -EINVAL; 690 691 goto out; 691 692 } 692 - if (check_access 693 + if (type >= 0 693 694 && unlikely(!access_ok(vrfy_dir(type), buf, len))) { 694 695 ret = -EFAULT; 695 696 goto out; ··· 722 723 } 723 724 724 725 ret = rw_copy_check_uvector(type, uvector, nr_segs, 725 - ARRAY_SIZE(iovstack), iovstack, &iov, 1); 726 + ARRAY_SIZE(iovstack), iovstack, &iov); 726 727 if (ret <= 0) 727 728 goto out; 728 729
+1 -2
include/linux/compat.h
··· 577 577 const struct compat_iovec __user *uvector, 578 578 unsigned long nr_segs, 579 579 unsigned long fast_segs, struct iovec *fast_pointer, 580 - struct iovec **ret_pointer, 581 - int check_access); 580 + struct iovec **ret_pointer); 582 581 583 582 extern void __user *compat_alloc_user_space(unsigned long len); 584 583
+10 -2
include/linux/fs.h
··· 173 173 #define WRITE_FUA (WRITE | REQ_SYNC | REQ_NOIDLE | REQ_FUA) 174 174 #define WRITE_FLUSH_FUA (WRITE | REQ_SYNC | REQ_NOIDLE | REQ_FLUSH | REQ_FUA) 175 175 176 + 177 + /* 178 + * Flag for rw_copy_check_uvector and compat_rw_copy_check_uvector 179 + * that indicates that they should check the contents of the iovec are 180 + * valid, but not check the memory that the iovec elements 181 + * points too. 182 + */ 183 + #define CHECK_IOVEC_ONLY -1 184 + 176 185 #define SEL_IN 1 177 186 #define SEL_OUT 2 178 187 #define SEL_EX 4 ··· 1699 1690 ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector, 1700 1691 unsigned long nr_segs, unsigned long fast_segs, 1701 1692 struct iovec *fast_pointer, 1702 - struct iovec **ret_pointer, 1703 - int check_access); 1693 + struct iovec **ret_pointer); 1704 1694 1705 1695 extern ssize_t vfs_read(struct file *, char __user *, size_t, loff_t *); 1706 1696 extern ssize_t vfs_write(struct file *, const char __user *, size_t, loff_t *);
+8 -8
mm/process_vm_access.c
··· 371 371 /* Check iovecs */ 372 372 if (vm_write) 373 373 rc = rw_copy_check_uvector(WRITE, lvec, liovcnt, UIO_FASTIOV, 374 - iovstack_l, &iov_l, 1); 374 + iovstack_l, &iov_l); 375 375 else 376 376 rc = rw_copy_check_uvector(READ, lvec, liovcnt, UIO_FASTIOV, 377 - iovstack_l, &iov_l, 1); 377 + iovstack_l, &iov_l); 378 378 if (rc <= 0) 379 379 goto free_iovecs; 380 380 381 - rc = rw_copy_check_uvector(READ, rvec, riovcnt, UIO_FASTIOV, 382 - iovstack_r, &iov_r, 0); 381 + rc = rw_copy_check_uvector(CHECK_IOVEC_ONLY, rvec, riovcnt, UIO_FASTIOV, 382 + iovstack_r, &iov_r); 383 383 if (rc <= 0) 384 384 goto free_iovecs; 385 385 ··· 438 438 if (vm_write) 439 439 rc = compat_rw_copy_check_uvector(WRITE, lvec, liovcnt, 440 440 UIO_FASTIOV, iovstack_l, 441 - &iov_l, 1); 441 + &iov_l); 442 442 else 443 443 rc = compat_rw_copy_check_uvector(READ, lvec, liovcnt, 444 444 UIO_FASTIOV, iovstack_l, 445 - &iov_l, 1); 445 + &iov_l); 446 446 if (rc <= 0) 447 447 goto free_iovecs; 448 - rc = compat_rw_copy_check_uvector(READ, rvec, riovcnt, 448 + rc = compat_rw_copy_check_uvector(CHECK_IOVEC_ONLY, rvec, riovcnt, 449 449 UIO_FASTIOV, iovstack_r, 450 - &iov_r, 0); 450 + &iov_r); 451 451 if (rc <= 0) 452 452 goto free_iovecs; 453 453
+1 -1
security/keys/compat.c
··· 38 38 39 39 ret = compat_rw_copy_check_uvector(WRITE, _payload_iov, ioc, 40 40 ARRAY_SIZE(iovstack), 41 - iovstack, &iov, 1); 41 + iovstack, &iov); 42 42 if (ret < 0) 43 43 return ret; 44 44 if (ret == 0)
+1 -1
security/keys/keyctl.c
··· 1110 1110 goto no_payload; 1111 1111 1112 1112 ret = rw_copy_check_uvector(WRITE, _payload_iov, ioc, 1113 - ARRAY_SIZE(iovstack), iovstack, &iov, 1); 1113 + ARRAY_SIZE(iovstack), iovstack, &iov); 1114 1114 if (ret < 0) 1115 1115 return ret; 1116 1116 if (ret == 0)