diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2010-12-17 07:44:05 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2011-01-12 20:06:58 -0500 |
commit | cccb5a1e698535fa5a734ffe21c7061c97f8d8c5 (patch) | |
tree | bbb369670469641237e672217bc0db423c454979 /fs/read_write.c | |
parent | 208898c17a97610ce1c01b1cc58e51802a1d52c3 (diff) | |
download | linux-3.10-cccb5a1e698535fa5a734ffe21c7061c97f8d8c5.tar.gz linux-3.10-cccb5a1e698535fa5a734ffe21c7061c97f8d8c5.tar.bz2 linux-3.10-cccb5a1e698535fa5a734ffe21c7061c97f8d8c5.zip |
fix signedness mess in rw_verify_area() on 64bit architectures
... and clean the unsigned-f_pos code, while we are at it.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/read_write.c')
-rw-r--r-- | fs/read_write.c | 27 |
1 files changed, 11 insertions, 16 deletions
diff --git a/fs/read_write.c b/fs/read_write.c index 5d431bacbea..5520f8ad550 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -30,18 +30,9 @@ const struct file_operations generic_ro_fops = { EXPORT_SYMBOL(generic_ro_fops); -static int -__negative_fpos_check(struct file *file, loff_t pos, size_t count) +static inline int unsigned_offsets(struct file *file) { - /* - * pos or pos+count is negative here, check overflow. - * too big "count" will be caught in rw_verify_area(). - */ - if ((pos < 0) && (pos + count < pos)) - return -EOVERFLOW; - if (file->f_mode & FMODE_UNSIGNED_OFFSET) - return 0; - return -EINVAL; + return file->f_mode & FMODE_UNSIGNED_OFFSET; } /** @@ -75,7 +66,7 @@ generic_file_llseek_unlocked(struct file *file, loff_t offset, int origin) break; } - if (offset < 0 && __negative_fpos_check(file, offset, 0)) + if (offset < 0 && !unsigned_offsets(file)) return -EINVAL; if (offset > inode->i_sb->s_maxbytes) return -EINVAL; @@ -152,7 +143,7 @@ loff_t default_llseek(struct file *file, loff_t offset, int origin) offset += file->f_pos; } retval = -EINVAL; - if (offset >= 0 || !__negative_fpos_check(file, offset, 0)) { + if (offset >= 0 || unsigned_offsets(file)) { if (offset != file->f_pos) { file->f_pos = offset; file->f_version = 0; @@ -252,9 +243,13 @@ int rw_verify_area(int read_write, struct file *file, loff_t *ppos, size_t count if (unlikely((ssize_t) count < 0)) return retval; pos = *ppos; - if (unlikely((pos < 0) || (loff_t) (pos + count) < 0)) { - retval = __negative_fpos_check(file, pos, count); - if (retval) + if (unlikely(pos < 0)) { + if (!unsigned_offsets(file)) + return retval; + if (count >= -pos) /* both values are in 0..LLONG_MAX */ + return -EOVERFLOW; + } else if (unlikely((loff_t) (pos + count) < 0)) { + if (!unsigned_offsets(file)) return retval; } |