diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2016-03-31 21:48:20 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2016-04-03 19:51:39 -0400 |
commit | bc61384dcdd82a6faabafecdcd80040625db5e40 (patch) | |
tree | ac9b46ce9b1d9e24e8158bc9577f061e3aaaaf3a /fs | |
parent | 2958ec177e400be1e26fc37e1759f84fa2c1761c (diff) | |
download | linux-bc61384dcdd82a6faabafecdcd80040625db5e40.tar.bz2 |
rw_verify_area(): saner calling conventions
Lift length capping into the few callers that care about it. Most of
them treat all non-negatives as "success" and ignore the capped value,
and with good reasons.
Make rw_verify_area() return 0 on success.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/read_write.c | 33 |
1 files changed, 14 insertions, 19 deletions
diff --git a/fs/read_write.c b/fs/read_write.c index cf377cf9dfe3..b1a0e6ca218f 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -410,11 +410,6 @@ ssize_t vfs_iter_write(struct file *file, struct iov_iter *iter, loff_t *ppos) } EXPORT_SYMBOL(vfs_iter_write); -/* - * rw_verify_area doesn't like huge counts. We limit - * them to something that fits in "int" so that others - * won't have to do range checks all the time. - */ int rw_verify_area(int read_write, struct file *file, const loff_t *ppos, size_t count) { struct inode *inode; @@ -441,11 +436,8 @@ int rw_verify_area(int read_write, struct file *file, const loff_t *ppos, size_t if (retval < 0) return retval; } - retval = security_file_permission(file, + return security_file_permission(file, read_write == READ ? MAY_READ : MAY_WRITE); - if (retval) - return retval; - return count > MAX_RW_COUNT ? MAX_RW_COUNT : count; } static ssize_t new_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos) @@ -489,8 +481,9 @@ ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos) return -EFAULT; ret = rw_verify_area(READ, file, pos, count); - if (ret >= 0) { - count = ret; + if (!ret) { + if (count > MAX_RW_COUNT) + count = MAX_RW_COUNT; ret = __vfs_read(file, buf, count, pos); if (ret > 0) { fsnotify_access(file); @@ -572,8 +565,9 @@ ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_ return -EFAULT; ret = rw_verify_area(WRITE, file, pos, count); - if (ret >= 0) { - count = ret; + if (!ret) { + if (count > MAX_RW_COUNT) + count = MAX_RW_COUNT; file_start_write(file); ret = __vfs_write(file, buf, count, pos); if (ret > 0) { @@ -1323,7 +1317,8 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, retval = rw_verify_area(READ, in.file, &pos, count); if (retval < 0) goto fput_in; - count = retval; + if (count > MAX_RW_COUNT) + count = MAX_RW_COUNT; /* * Get output file, and verify that it is ok.. @@ -1341,7 +1336,6 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, retval = rw_verify_area(WRITE, out.file, &out_pos, count); if (retval < 0) goto fput_out; - count = retval; if (!max) max = min(in_inode->i_sb->s_maxbytes, out_inode->i_sb->s_maxbytes); @@ -1485,11 +1479,12 @@ ssize_t vfs_copy_file_range(struct file *file_in, loff_t pos_in, if (flags != 0) return -EINVAL; - /* copy_file_range allows full ssize_t len, ignoring MAX_RW_COUNT */ ret = rw_verify_area(READ, file_in, &pos_in, len); - if (ret >= 0) - ret = rw_verify_area(WRITE, file_out, &pos_out, len); - if (ret < 0) + if (unlikely(ret)) + return ret; + + ret = rw_verify_area(WRITE, file_out, &pos_out, len); + if (unlikely(ret)) return ret; if (!(file_in->f_mode & FMODE_READ) || |