aboutsummaryrefslogtreecommitdiffstats
path: root/fs/read_write.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2010-10-29 13:36:49 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2010-10-29 13:36:49 -0400
commit435f49a518c78eec8e2edbbadd912737246cbe20 (patch)
tree106df2617d42ace231e2fa9fcf1e0fd1075874ea /fs/read_write.c
parentf56f44001cb5b40089deac094dbb74e5c9f64d81 (diff)
readv/writev: do the same MAX_RW_COUNT truncation that read/write does
We used to protect against overflow, but rather than return an error, do what read/write does, namely to limit the total size to MAX_RW_COUNT. This is not only more consistent, but it also means that any broken low-level read/write routine that still keeps counts in 'int' can't break. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/read_write.c')
-rw-r--r--fs/read_write.c62
1 files changed, 33 insertions, 29 deletions
diff --git a/fs/read_write.c b/fs/read_write.c
index 9cd9d148105d..431a0ed610c8 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -243,8 +243,6 @@ bad:
243 * them to something that fits in "int" so that others 243 * them to something that fits in "int" so that others
244 * won't have to do range checks all the time. 244 * won't have to do range checks all the time.
245 */ 245 */
246#define MAX_RW_COUNT (INT_MAX & PAGE_CACHE_MASK)
247
248int rw_verify_area(int read_write, struct file *file, loff_t *ppos, size_t count) 246int rw_verify_area(int read_write, struct file *file, loff_t *ppos, size_t count)
249{ 247{
250 struct inode *inode; 248 struct inode *inode;
@@ -584,65 +582,71 @@ ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector,
584 unsigned long nr_segs, unsigned long fast_segs, 582 unsigned long nr_segs, unsigned long fast_segs,
585 struct iovec *fast_pointer, 583 struct iovec *fast_pointer,
586 struct iovec **ret_pointer) 584 struct iovec **ret_pointer)
587 { 585{
588 unsigned long seg; 586 unsigned long seg;
589 ssize_t ret; 587 ssize_t ret;
590 struct iovec *iov = fast_pointer; 588 struct iovec *iov = fast_pointer;
591 589
592 /* 590 /*
593 * SuS says "The readv() function *may* fail if the iovcnt argument 591 * SuS says "The readv() function *may* fail if the iovcnt argument
594 * was less than or equal to 0, or greater than {IOV_MAX}. Linux has 592 * was less than or equal to 0, or greater than {IOV_MAX}. Linux has
595 * traditionally returned zero for zero segments, so... 593 * traditionally returned zero for zero segments, so...
596 */ 594 */
597 if (nr_segs == 0) { 595 if (nr_segs == 0) {
598 ret = 0; 596 ret = 0;
599 goto out; 597 goto out;
600 } 598 }
601 599
602 /* 600 /*
603 * First get the "struct iovec" from user memory and 601 * First get the "struct iovec" from user memory and
604 * verify all the pointers 602 * verify all the pointers
605 */ 603 */
606 if (nr_segs > UIO_MAXIOV) { 604 if (nr_segs > UIO_MAXIOV) {
607 ret = -EINVAL; 605 ret = -EINVAL;
608 goto out; 606 goto out;
609 } 607 }
610 if (nr_segs > fast_segs) { 608 if (nr_segs > fast_segs) {
611 iov = kmalloc(nr_segs*sizeof(struct iovec), GFP_KERNEL); 609 iov = kmalloc(nr_segs*sizeof(struct iovec), GFP_KERNEL);
612 if (iov == NULL) { 610 if (iov == NULL) {
613 ret = -ENOMEM; 611 ret = -ENOMEM;
614 goto out; 612 goto out;
615 } 613 }
616 } 614 }
617 if (copy_from_user(iov, uvector, nr_segs*sizeof(*uvector))) { 615 if (copy_from_user(iov, uvector, nr_segs*sizeof(*uvector))) {
618 ret = -EFAULT; 616 ret = -EFAULT;
619 goto out; 617 goto out;
620 } 618 }
621 619
622 /* 620 /*
623 * According to the Single Unix Specification we should return EINVAL 621 * According to the Single Unix Specification we should return EINVAL
624 * if an element length is < 0 when cast to ssize_t or if the 622 * if an element length is < 0 when cast to ssize_t or if the
625 * total length would overflow the ssize_t return value of the 623 * total length would overflow the ssize_t return value of the
626 * system call. 624 * system call.
627 */ 625 *
626 * Linux caps all read/write calls to MAX_RW_COUNT, and avoids the
627 * overflow case.
628 */
628 ret = 0; 629 ret = 0;
629 for (seg = 0; seg < nr_segs; seg++) { 630 for (seg = 0; seg < nr_segs; seg++) {
630 void __user *buf = iov[seg].iov_base; 631 void __user *buf = iov[seg].iov_base;
631 ssize_t len = (ssize_t)iov[seg].iov_len; 632 ssize_t len = (ssize_t)iov[seg].iov_len;
632 633
633 /* see if we we're about to use an invalid len or if 634 /* see if we we're about to use an invalid len or if
634 * it's about to overflow ssize_t */ 635 * it's about to overflow ssize_t */
635 if (len < 0 || (ret + len < ret)) { 636 if (len < 0) {
636 ret = -EINVAL; 637 ret = -EINVAL;
637 goto out; 638 goto out;
638 } 639 }
639 if (unlikely(!access_ok(vrfy_dir(type), buf, len))) { 640 if (unlikely(!access_ok(vrfy_dir(type), buf, len))) {
640 ret = -EFAULT; 641 ret = -EFAULT;
641 goto out; 642 goto out;
643 }
644 if (len > MAX_RW_COUNT - ret) {
645 len = MAX_RW_COUNT - ret;
646 iov[seg].iov_len = len;
642 } 647 }
643
644 ret += len; 648 ret += len;
645 } 649 }
646out: 650out:
647 *ret_pointer = iov; 651 *ret_pointer = iov;
648 return ret; 652 return ret;