diff options
Diffstat (limited to 'fs/read_write.c')
-rw-r--r-- | fs/read_write.c | 28 |
1 files changed, 24 insertions, 4 deletions
diff --git a/fs/read_write.c b/fs/read_write.c index e757ef26e4ce..9cd9d148105d 100644 --- a/fs/read_write.c +++ b/fs/read_write.c | |||
@@ -31,6 +31,20 @@ const struct file_operations generic_ro_fops = { | |||
31 | 31 | ||
32 | EXPORT_SYMBOL(generic_ro_fops); | 32 | EXPORT_SYMBOL(generic_ro_fops); |
33 | 33 | ||
34 | static int | ||
35 | __negative_fpos_check(struct file *file, loff_t pos, size_t count) | ||
36 | { | ||
37 | /* | ||
38 | * pos or pos+count is negative here, check overflow. | ||
39 | * too big "count" will be caught in rw_verify_area(). | ||
40 | */ | ||
41 | if ((pos < 0) && (pos + count < pos)) | ||
42 | return -EOVERFLOW; | ||
43 | if (file->f_mode & FMODE_UNSIGNED_OFFSET) | ||
44 | return 0; | ||
45 | return -EINVAL; | ||
46 | } | ||
47 | |||
34 | /** | 48 | /** |
35 | * generic_file_llseek_unlocked - lockless generic llseek implementation | 49 | * generic_file_llseek_unlocked - lockless generic llseek implementation |
36 | * @file: file structure to seek on | 50 | * @file: file structure to seek on |
@@ -62,7 +76,9 @@ generic_file_llseek_unlocked(struct file *file, loff_t offset, int origin) | |||
62 | break; | 76 | break; |
63 | } | 77 | } |
64 | 78 | ||
65 | if (offset < 0 || offset > inode->i_sb->s_maxbytes) | 79 | if (offset < 0 && __negative_fpos_check(file, offset, 0)) |
80 | return -EINVAL; | ||
81 | if (offset > inode->i_sb->s_maxbytes) | ||
66 | return -EINVAL; | 82 | return -EINVAL; |
67 | 83 | ||
68 | /* Special lock needed here? */ | 84 | /* Special lock needed here? */ |
@@ -137,7 +153,7 @@ loff_t default_llseek(struct file *file, loff_t offset, int origin) | |||
137 | offset += file->f_pos; | 153 | offset += file->f_pos; |
138 | } | 154 | } |
139 | retval = -EINVAL; | 155 | retval = -EINVAL; |
140 | if (offset >= 0) { | 156 | if (offset >= 0 || !__negative_fpos_check(file, offset, 0)) { |
141 | if (offset != file->f_pos) { | 157 | if (offset != file->f_pos) { |
142 | file->f_pos = offset; | 158 | file->f_pos = offset; |
143 | file->f_version = 0; | 159 | file->f_version = 0; |
@@ -221,6 +237,7 @@ bad: | |||
221 | } | 237 | } |
222 | #endif | 238 | #endif |
223 | 239 | ||
240 | |||
224 | /* | 241 | /* |
225 | * rw_verify_area doesn't like huge counts. We limit | 242 | * rw_verify_area doesn't like huge counts. We limit |
226 | * them to something that fits in "int" so that others | 243 | * them to something that fits in "int" so that others |
@@ -238,8 +255,11 @@ int rw_verify_area(int read_write, struct file *file, loff_t *ppos, size_t count | |||
238 | if (unlikely((ssize_t) count < 0)) | 255 | if (unlikely((ssize_t) count < 0)) |
239 | return retval; | 256 | return retval; |
240 | pos = *ppos; | 257 | pos = *ppos; |
241 | if (unlikely((pos < 0) || (loff_t) (pos + count) < 0)) | 258 | if (unlikely((pos < 0) || (loff_t) (pos + count) < 0)) { |
242 | return retval; | 259 | retval = __negative_fpos_check(file, pos, count); |
260 | if (retval) | ||
261 | return retval; | ||
262 | } | ||
243 | 263 | ||
244 | if (unlikely(inode->i_flock && mandatory_lock(inode))) { | 264 | if (unlikely(inode->i_flock && mandatory_lock(inode))) { |
245 | retval = locks_mandatory_area( | 265 | retval = locks_mandatory_area( |