aboutsummaryrefslogtreecommitdiffstats
path: root/fs/read_write.c
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2010-12-17 07:44:05 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2011-01-12 20:06:58 -0500
commitcccb5a1e698535fa5a734ffe21c7061c97f8d8c5 (patch)
treebbb369670469641237e672217bc0db423c454979 /fs/read_write.c
parent208898c17a97610ce1c01b1cc58e51802a1d52c3 (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.c27
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
31EXPORT_SYMBOL(generic_ro_fops); 31EXPORT_SYMBOL(generic_ro_fops);
32 32
33static int 33static 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