Commit adfdad98 authored by Linus Torvalds's avatar Linus Torvalds Committed by Willy Tarreau

readv/writev: do the same MAX_RW_COUNT truncation that read/write does

commit 435f49a5 upstream.

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: default avatarLinus Torvalds <torvalds@linux-foundation.org>
Cc: Ben Hutchings <ben@decadent.org.uk>
Signed-off-by: default avatarWilly Tarreau <w@1wt.eu>
parent cde5406e
......@@ -210,8 +210,6 @@ SYSCALL_DEFINE5(llseek, unsigned int, fd, unsigned long, offset_high,
* them to something that fits in "int" so that others
* won't have to do range checks all the time.
*/
#define MAX_RW_COUNT (INT_MAX & PAGE_CACHE_MASK)
int rw_verify_area(int read_write, struct file *file, loff_t *ppos, size_t count)
{
struct inode *inode;
......@@ -546,7 +544,7 @@ ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector,
unsigned long nr_segs, unsigned long fast_segs,
struct iovec *fast_pointer,
struct iovec **ret_pointer)
{
{
unsigned long seg;
ssize_t ret;
struct iovec *iov = fast_pointer;
......@@ -586,6 +584,9 @@ ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector,
* if an element length is < 0 when cast to ssize_t or if the
* total length would overflow the ssize_t return value of the
* system call.
*
* Linux caps all read/write calls to MAX_RW_COUNT, and avoids the
* overflow case.
*/
ret = 0;
for (seg = 0; seg < nr_segs; seg++) {
......@@ -594,7 +595,7 @@ ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector,
/* see if we we're about to use an invalid len or if
* it's about to overflow ssize_t */
if (len < 0 || (ret + len < ret)) {
if (len < 0) {
ret = -EINVAL;
goto out;
}
......@@ -602,7 +603,10 @@ ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector,
ret = -EFAULT;
goto out;
}
if (len > MAX_RW_COUNT - ret) {
len = MAX_RW_COUNT - ret;
iov[seg].iov_len = len;
}
ret += len;
}
out:
......
......@@ -1817,6 +1817,7 @@ extern int current_umask(void);
/* /sys/fs */
extern struct kobject *fs_kobj;
#define MAX_RW_COUNT (INT_MAX & PAGE_CACHE_MASK)
extern int rw_verify_area(int, struct file *, loff_t *, size_t);
#define FLOCK_VERIFY_READ 1
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment