diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-29 13:36:49 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-29 13:36:49 -0400 |
commit | 435f49a518c78eec8e2edbbadd912737246cbe20 (patch) | |
tree | 106df2617d42ace231e2fa9fcf1e0fd1075874ea /fs/compat.c | |
parent | f56f44001cb5b40089deac094dbb74e5c9f64d81 (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/compat.c')
-rw-r--r-- | fs/compat.c | 12 |
1 files changed, 6 insertions, 6 deletions
diff --git a/fs/compat.c b/fs/compat.c index 52cfeb61da77..ff66c0d7583d 100644 --- a/fs/compat.c +++ b/fs/compat.c | |||
@@ -606,14 +606,14 @@ ssize_t compat_rw_copy_check_uvector(int type, | |||
606 | /* | 606 | /* |
607 | * Single unix specification: | 607 | * Single unix specification: |
608 | * We should -EINVAL if an element length is not >= 0 and fitting an | 608 | * We should -EINVAL if an element length is not >= 0 and fitting an |
609 | * ssize_t. The total length is fitting an ssize_t | 609 | * ssize_t. |
610 | * | 610 | * |
611 | * Be careful here because iov_len is a size_t not an ssize_t | 611 | * In Linux, the total length is limited to MAX_RW_COUNT, there is |
612 | * no overflow possibility. | ||
612 | */ | 613 | */ |
613 | tot_len = 0; | 614 | tot_len = 0; |
614 | ret = -EINVAL; | 615 | ret = -EINVAL; |
615 | for (seg = 0; seg < nr_segs; seg++) { | 616 | for (seg = 0; seg < nr_segs; seg++) { |
616 | compat_ssize_t tmp = tot_len; | ||
617 | compat_uptr_t buf; | 617 | compat_uptr_t buf; |
618 | compat_ssize_t len; | 618 | compat_ssize_t len; |
619 | 619 | ||
@@ -624,13 +624,13 @@ ssize_t compat_rw_copy_check_uvector(int type, | |||
624 | } | 624 | } |
625 | if (len < 0) /* size_t not fitting in compat_ssize_t .. */ | 625 | if (len < 0) /* size_t not fitting in compat_ssize_t .. */ |
626 | goto out; | 626 | goto out; |
627 | tot_len += len; | ||
628 | if (tot_len < tmp) /* maths overflow on the compat_ssize_t */ | ||
629 | goto out; | ||
630 | if (!access_ok(vrfy_dir(type), compat_ptr(buf), len)) { | 627 | if (!access_ok(vrfy_dir(type), compat_ptr(buf), len)) { |
631 | ret = -EFAULT; | 628 | ret = -EFAULT; |
632 | goto out; | 629 | goto out; |
633 | } | 630 | } |
631 | if (len > MAX_RW_COUNT - tot_len) | ||
632 | len = MAX_RW_COUNT - tot_len; | ||
633 | tot_len += len; | ||
634 | iov->iov_base = compat_ptr(buf); | 634 | iov->iov_base = compat_ptr(buf); |
635 | iov->iov_len = (compat_size_t) len; | 635 | iov->iov_len = (compat_size_t) len; |
636 | uvector++; | 636 | uvector++; |