aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristopher Yeoh <cyeoh@au1.ibm.com>2012-05-31 19:26:42 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-05-31 20:49:32 -0400
commitac34ebb3a67e699edcb5ac72f19d31679369dfaa (patch)
tree21785208005952128545c0d7804c2dddf177766f
parentee62c6b2dc93c09585b51fad18449dc5edb9977f (diff)
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>
-rw-r--r--fs/aio.c4
-rw-r--r--fs/compat.c6
-rw-r--r--fs/read_write.c7
-rw-r--r--include/linux/compat.h3
-rw-r--r--include/linux/fs.h12
-rw-r--r--mm/process_vm_access.c16
-rw-r--r--security/keys/compat.c2
-rw-r--r--security/keys/keyctl.c2
8 files changed, 29 insertions, 23 deletions
diff --git a/fs/aio.c b/fs/aio.c
index e7f2fad7b4ce..8c7c8b805372 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)
1446 ret = compat_rw_copy_check_uvector(type, 1446 ret = compat_rw_copy_check_uvector(type,
1447 (struct compat_iovec __user *)kiocb->ki_buf, 1447 (struct compat_iovec __user *)kiocb->ki_buf,
1448 kiocb->ki_nbytes, 1, &kiocb->ki_inline_vec, 1448 kiocb->ki_nbytes, 1, &kiocb->ki_inline_vec,
1449 &kiocb->ki_iovec, 1); 1449 &kiocb->ki_iovec);
1450 else 1450 else
1451#endif 1451#endif
1452 ret = rw_copy_check_uvector(type, 1452 ret = rw_copy_check_uvector(type,
1453 (struct iovec __user *)kiocb->ki_buf, 1453 (struct iovec __user *)kiocb->ki_buf,
1454 kiocb->ki_nbytes, 1, &kiocb->ki_inline_vec, 1454 kiocb->ki_nbytes, 1, &kiocb->ki_inline_vec,
1455 &kiocb->ki_iovec, 1); 1455 &kiocb->ki_iovec);
1456 if (ret < 0) 1456 if (ret < 0)
1457 goto out; 1457 goto out;
1458 1458
diff --git a/fs/compat.c b/fs/compat.c
index 0781e619a62a..6556a9ce8a28 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -532,7 +532,7 @@ out:
532ssize_t compat_rw_copy_check_uvector(int type, 532ssize_t compat_rw_copy_check_uvector(int type,
533 const struct compat_iovec __user *uvector, unsigned long nr_segs, 533 const struct compat_iovec __user *uvector, unsigned long nr_segs,
534 unsigned long fast_segs, struct iovec *fast_pointer, 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 compat_ssize_t tot_len; 537 compat_ssize_t tot_len;
538 struct iovec *iov = *ret_pointer = fast_pointer; 538 struct iovec *iov = *ret_pointer = fast_pointer;
@@ -579,7 +579,7 @@ ssize_t compat_rw_copy_check_uvector(int type,
579 } 579 }
580 if (len < 0) /* size_t not fitting in compat_ssize_t .. */ 580 if (len < 0) /* size_t not fitting in compat_ssize_t .. */
581 goto out; 581 goto out;
582 if (check_access && 582 if (type >= 0 &&
583 !access_ok(vrfy_dir(type), compat_ptr(buf), len)) { 583 !access_ok(vrfy_dir(type), compat_ptr(buf), len)) {
584 ret = -EFAULT; 584 ret = -EFAULT;
585 goto out; 585 goto out;
@@ -1094,7 +1094,7 @@ static ssize_t compat_do_readv_writev(int type, struct file *file,
1094 goto out; 1094 goto out;
1095 1095
1096 tot_len = compat_rw_copy_check_uvector(type, uvector, nr_segs, 1096 tot_len = compat_rw_copy_check_uvector(type, uvector, nr_segs,
1097 UIO_FASTIOV, iovstack, &iov, 1); 1097 UIO_FASTIOV, iovstack, &iov);
1098 if (tot_len == 0) { 1098 if (tot_len == 0) {
1099 ret = 0; 1099 ret = 0;
1100 goto out; 1100 goto out;
diff --git a/fs/read_write.c b/fs/read_write.c
index ffc99d22e0a3..c20614f86c01 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,
633ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector, 633ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector,
634 unsigned long nr_segs, unsigned long fast_segs, 634 unsigned long nr_segs, unsigned long fast_segs,
635 struct iovec *fast_pointer, 635 struct iovec *fast_pointer,
636 struct iovec **ret_pointer, 636 struct iovec **ret_pointer)
637 int check_access)
638{ 637{
639 unsigned long seg; 638 unsigned long seg;
640 ssize_t ret; 639 ssize_t ret;
@@ -690,7 +689,7 @@ ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector,
690 ret = -EINVAL; 689 ret = -EINVAL;
691 goto out; 690 goto out;
692 } 691 }
693 if (check_access 692 if (type >= 0
694 && unlikely(!access_ok(vrfy_dir(type), buf, len))) { 693 && unlikely(!access_ok(vrfy_dir(type), buf, len))) {
695 ret = -EFAULT; 694 ret = -EFAULT;
696 goto out; 695 goto out;
@@ -723,7 +722,7 @@ static ssize_t do_readv_writev(int type, struct file *file,
723 } 722 }
724 723
725 ret = rw_copy_check_uvector(type, uvector, nr_segs, 724 ret = rw_copy_check_uvector(type, uvector, nr_segs,
726 ARRAY_SIZE(iovstack), iovstack, &iov, 1); 725 ARRAY_SIZE(iovstack), iovstack, &iov);
727 if (ret <= 0) 726 if (ret <= 0)
728 goto out; 727 goto out;
729 728
diff --git a/include/linux/compat.h b/include/linux/compat.h
index 5d46217f84ad..4e890394ef99 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,
577 const struct compat_iovec __user *uvector, 577 const struct compat_iovec __user *uvector,
578 unsigned long nr_segs, 578 unsigned long nr_segs,
579 unsigned long fast_segs, struct iovec *fast_pointer, 579 unsigned long fast_segs, struct iovec *fast_pointer,
580 struct iovec **ret_pointer, 580 struct iovec **ret_pointer);
581 int check_access);
582 581
583extern void __user *compat_alloc_user_space(unsigned long len); 582extern void __user *compat_alloc_user_space(unsigned long len);
584 583
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 038076b27ea4..cf2c5611b19b 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -173,6 +173,15 @@ struct inodes_stat_t {
173#define WRITE_FUA (WRITE | REQ_SYNC | REQ_NOIDLE | REQ_FUA) 173#define WRITE_FUA (WRITE | REQ_SYNC | REQ_NOIDLE | REQ_FUA)
174#define WRITE_FLUSH_FUA (WRITE | REQ_SYNC | REQ_NOIDLE | REQ_FLUSH | REQ_FUA) 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#define SEL_IN 1 185#define SEL_IN 1
177#define SEL_OUT 2 186#define SEL_OUT 2
178#define SEL_EX 4 187#define SEL_EX 4
@@ -1690,8 +1699,7 @@ struct seq_file;
1690ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector, 1699ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector,
1691 unsigned long nr_segs, unsigned long fast_segs, 1700 unsigned long nr_segs, unsigned long fast_segs,
1692 struct iovec *fast_pointer, 1701 struct iovec *fast_pointer,
1693 struct iovec **ret_pointer, 1702 struct iovec **ret_pointer);
1694 int check_access);
1695 1703
1696extern ssize_t vfs_read(struct file *, char __user *, size_t, loff_t *); 1704extern ssize_t vfs_read(struct file *, char __user *, size_t, loff_t *);
1697extern ssize_t vfs_write(struct file *, const char __user *, size_t, loff_t *); 1705extern 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 c20ff48994c2..926b46649749 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,
371 /* Check iovecs */ 371 /* Check iovecs */
372 if (vm_write) 372 if (vm_write)
373 rc = rw_copy_check_uvector(WRITE, lvec, liovcnt, UIO_FASTIOV, 373 rc = rw_copy_check_uvector(WRITE, lvec, liovcnt, UIO_FASTIOV,
374 iovstack_l, &iov_l, 1); 374 iovstack_l, &iov_l);
375 else 375 else
376 rc = rw_copy_check_uvector(READ, lvec, liovcnt, UIO_FASTIOV, 376 rc = rw_copy_check_uvector(READ, lvec, liovcnt, UIO_FASTIOV,
377 iovstack_l, &iov_l, 1); 377 iovstack_l, &iov_l);
378 if (rc <= 0) 378 if (rc <= 0)
379 goto free_iovecs; 379 goto free_iovecs;
380 380
381 rc = rw_copy_check_uvector(READ, rvec, riovcnt, UIO_FASTIOV, 381 rc = rw_copy_check_uvector(CHECK_IOVEC_ONLY, rvec, riovcnt, UIO_FASTIOV,
382 iovstack_r, &iov_r, 0); 382 iovstack_r, &iov_r);
383 if (rc <= 0) 383 if (rc <= 0)
384 goto free_iovecs; 384 goto free_iovecs;
385 385
@@ -438,16 +438,16 @@ compat_process_vm_rw(compat_pid_t pid,
438 if (vm_write) 438 if (vm_write)
439 rc = compat_rw_copy_check_uvector(WRITE, lvec, liovcnt, 439 rc = compat_rw_copy_check_uvector(WRITE, lvec, liovcnt,
440 UIO_FASTIOV, iovstack_l, 440 UIO_FASTIOV, iovstack_l,
441 &iov_l, 1); 441 &iov_l);
442 else 442 else
443 rc = compat_rw_copy_check_uvector(READ, lvec, liovcnt, 443 rc = compat_rw_copy_check_uvector(READ, lvec, liovcnt,
444 UIO_FASTIOV, iovstack_l, 444 UIO_FASTIOV, iovstack_l,
445 &iov_l, 1); 445 &iov_l);
446 if (rc <= 0) 446 if (rc <= 0)
447 goto free_iovecs; 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 UIO_FASTIOV, iovstack_r, 449 UIO_FASTIOV, iovstack_r,
450 &iov_r, 0); 450 &iov_r);
451 if (rc <= 0) 451 if (rc <= 0)
452 goto free_iovecs; 452 goto free_iovecs;
453 453
diff --git a/security/keys/compat.c b/security/keys/compat.c
index fab4f8dda6c6..c92d42b021aa 100644
--- a/security/keys/compat.c
+++ b/security/keys/compat.c
@@ -38,7 +38,7 @@ long compat_keyctl_instantiate_key_iov(
38 38
39 ret = compat_rw_copy_check_uvector(WRITE, _payload_iov, ioc, 39 ret = compat_rw_copy_check_uvector(WRITE, _payload_iov, ioc,
40 ARRAY_SIZE(iovstack), 40 ARRAY_SIZE(iovstack),
41 iovstack, &iov, 1); 41 iovstack, &iov);
42 if (ret < 0) 42 if (ret < 0)
43 return ret; 43 return ret;
44 if (ret == 0) 44 if (ret == 0)
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index 18f29de88fda..21907ea35b15 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -1110,7 +1110,7 @@ long keyctl_instantiate_key_iov(key_serial_t id,
1110 goto no_payload; 1110 goto no_payload;
1111 1111
1112 ret = rw_copy_check_uvector(WRITE, _payload_iov, ioc, 1112 ret = rw_copy_check_uvector(WRITE, _payload_iov, ioc,
1113 ARRAY_SIZE(iovstack), iovstack, &iov, 1); 1113 ARRAY_SIZE(iovstack), iovstack, &iov);
1114 if (ret < 0) 1114 if (ret < 0)
1115 return ret; 1115 return ret;
1116 if (ret == 0) 1116 if (ret == 0)