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) |
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 5d431bacbea9..5520f8ad5504 100644 --- a/fs/read_write.c +++ b/fs/read_write.c | |||
@@ -30,18 +30,9 @@ const struct file_operations generic_ro_fops = { | |||
30 | 30 | ||
31 | EXPORT_SYMBOL(generic_ro_fops); | 31 | EXPORT_SYMBOL(generic_ro_fops); |
32 | 32 | ||
33 | static int | 33 | static inline int unsigned_offsets(struct file *file) |
34 | __negative_fpos_check(struct file *file, loff_t pos, size_t count) | ||
35 | { | 34 | { |
36 | /* | 35 | return file->f_mode & FMODE_UNSIGNED_OFFSET; |
37 | * pos or pos+count is negative here, check overflow. | ||
38 | * too big "count" will be caught in rw_verify_area(). | ||
39 | */ | ||
40 | if ((pos < 0) && (pos + count < pos)) | ||
41 | return -EOVERFLOW; | ||
42 | if (file->f_mode & FMODE_UNSIGNED_OFFSET) | ||
43 | return 0; | ||
44 | return -EINVAL; | ||
45 | } | 36 | } |
46 | 37 | ||
47 | /** | 38 | /** |
@@ -75,7 +66,7 @@ generic_file_llseek_unlocked(struct file *file, loff_t offset, int origin) | |||
75 | break; | 66 | break; |
76 | } | 67 | } |
77 | 68 | ||
78 | if (offset < 0 && __negative_fpos_check(file, offset, 0)) | 69 | if (offset < 0 && !unsigned_offsets(file)) |
79 | return -EINVAL; | 70 | return -EINVAL; |
80 | if (offset > inode->i_sb->s_maxbytes) | 71 | if (offset > inode->i_sb->s_maxbytes) |
81 | return -EINVAL; | 72 | return -EINVAL; |
@@ -152,7 +143,7 @@ loff_t default_llseek(struct file *file, loff_t offset, int origin) | |||
152 | offset += file->f_pos; | 143 | offset += file->f_pos; |
153 | } | 144 | } |
154 | retval = -EINVAL; | 145 | retval = -EINVAL; |
155 | if (offset >= 0 || !__negative_fpos_check(file, offset, 0)) { | 146 | if (offset >= 0 || unsigned_offsets(file)) { |
156 | if (offset != file->f_pos) { | 147 | if (offset != file->f_pos) { |
157 | file->f_pos = offset; | 148 | file->f_pos = offset; |
158 | file->f_version = 0; | 149 | file->f_version = 0; |
@@ -252,9 +243,13 @@ int rw_verify_area(int read_write, struct file *file, loff_t *ppos, size_t count | |||
252 | if (unlikely((ssize_t) count < 0)) | 243 | if (unlikely((ssize_t) count < 0)) |
253 | return retval; | 244 | return retval; |
254 | pos = *ppos; | 245 | pos = *ppos; |
255 | if (unlikely((pos < 0) || (loff_t) (pos + count) < 0)) { | 246 | if (unlikely(pos < 0)) { |
256 | retval = __negative_fpos_check(file, pos, count); | 247 | if (!unsigned_offsets(file)) |
257 | if (retval) | 248 | return retval; |
249 | if (count >= -pos) /* both values are in 0..LLONG_MAX */ | ||
250 | return -EOVERFLOW; | ||
251 | } else if (unlikely((loff_t) (pos + count) < 0)) { | ||
252 | if (!unsigned_offsets(file)) | ||
258 | return retval; | 253 | return retval; |
259 | } | 254 | } |
260 | 255 | ||