diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-29 10:36:49 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-29 10:36:49 -0700 |
commit | 435f49a518c78eec8e2edbbadd912737246cbe20 (patch) | |
tree | 106df2617d42ace231e2fa9fcf1e0fd1075874ea /fs/compat.c | |
parent | f56f44001cb5b40089deac094dbb74e5c9f64d81 (diff) | |
download | lwn-435f49a518c78eec8e2edbbadd912737246cbe20.tar.gz lwn-435f49a518c78eec8e2edbbadd912737246cbe20.zip |
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, /* * Single unix specification: * We should -EINVAL if an element length is not >= 0 and fitting an - * ssize_t. The total length is fitting an ssize_t + * ssize_t. * - * Be careful here because iov_len is a size_t not an ssize_t + * In Linux, the total length is limited to MAX_RW_COUNT, there is + * no overflow possibility. */ tot_len = 0; ret = -EINVAL; for (seg = 0; seg < nr_segs; seg++) { - compat_ssize_t tmp = tot_len; compat_uptr_t buf; compat_ssize_t len; @@ -624,13 +624,13 @@ ssize_t compat_rw_copy_check_uvector(int type, } if (len < 0) /* size_t not fitting in compat_ssize_t .. */ goto out; - tot_len += len; - if (tot_len < tmp) /* maths overflow on the compat_ssize_t */ - goto out; if (!access_ok(vrfy_dir(type), compat_ptr(buf), len)) { ret = -EFAULT; goto out; } + if (len > MAX_RW_COUNT - tot_len) + len = MAX_RW_COUNT - tot_len; + tot_len += len; iov->iov_base = compat_ptr(buf); iov->iov_len = (compat_size_t) len; uvector++; |