diff options
-rw-r--r-- | arch/mips/kernel/linux32.c | 4 | ||||
-rw-r--r-- | fs/compat.c | 2 | ||||
-rw-r--r-- | fs/read_write.c | 34 |
3 files changed, 28 insertions, 12 deletions
diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c index 330cf84d21fe..60353f5acc48 100644 --- a/arch/mips/kernel/linux32.c +++ b/arch/mips/kernel/linux32.c | |||
@@ -420,7 +420,7 @@ asmlinkage ssize_t sys32_pread(unsigned int fd, char * buf, | |||
420 | goto out; | 420 | goto out; |
421 | pos = merge_64(a4, a5); | 421 | pos = merge_64(a4, a5); |
422 | ret = rw_verify_area(READ, file, &pos, count); | 422 | ret = rw_verify_area(READ, file, &pos, count); |
423 | if (ret) | 423 | if (ret < 0) |
424 | goto out; | 424 | goto out; |
425 | ret = -EINVAL; | 425 | ret = -EINVAL; |
426 | if (!file->f_op || !(read = file->f_op->read)) | 426 | if (!file->f_op || !(read = file->f_op->read)) |
@@ -455,7 +455,7 @@ asmlinkage ssize_t sys32_pwrite(unsigned int fd, const char * buf, | |||
455 | goto out; | 455 | goto out; |
456 | pos = merge_64(a4, a5); | 456 | pos = merge_64(a4, a5); |
457 | ret = rw_verify_area(WRITE, file, &pos, count); | 457 | ret = rw_verify_area(WRITE, file, &pos, count); |
458 | if (ret) | 458 | if (ret < 0) |
459 | goto out; | 459 | goto out; |
460 | ret = -EINVAL; | 460 | ret = -EINVAL; |
461 | if (!file->f_op || !(write = file->f_op->write)) | 461 | if (!file->f_op || !(write = file->f_op->write)) |
diff --git a/fs/compat.c b/fs/compat.c index 818634120b69..55ac0324aaf1 100644 --- a/fs/compat.c +++ b/fs/compat.c | |||
@@ -1170,7 +1170,7 @@ static ssize_t compat_do_readv_writev(int type, struct file *file, | |||
1170 | } | 1170 | } |
1171 | 1171 | ||
1172 | ret = rw_verify_area(type, file, pos, tot_len); | 1172 | ret = rw_verify_area(type, file, pos, tot_len); |
1173 | if (ret) | 1173 | if (ret < 0) |
1174 | goto out; | 1174 | goto out; |
1175 | 1175 | ||
1176 | fnv = NULL; | 1176 | fnv = NULL; |
diff --git a/fs/read_write.c b/fs/read_write.c index a091ee4f430d..df3468a22fea 100644 --- a/fs/read_write.c +++ b/fs/read_write.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/security.h> | 14 | #include <linux/security.h> |
15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
16 | #include <linux/syscalls.h> | 16 | #include <linux/syscalls.h> |
17 | #include <linux/pagemap.h> | ||
17 | 18 | ||
18 | #include <asm/uaccess.h> | 19 | #include <asm/uaccess.h> |
19 | #include <asm/unistd.h> | 20 | #include <asm/unistd.h> |
@@ -182,22 +183,33 @@ bad: | |||
182 | } | 183 | } |
183 | #endif | 184 | #endif |
184 | 185 | ||
186 | /* | ||
187 | * rw_verify_area doesn't like huge counts. We limit | ||
188 | * them to something that fits in "int" so that others | ||
189 | * won't have to do range checks all the time. | ||
190 | */ | ||
191 | #define MAX_RW_COUNT (INT_MAX & PAGE_CACHE_MASK) | ||
185 | 192 | ||
186 | int rw_verify_area(int read_write, struct file *file, loff_t *ppos, size_t count) | 193 | int rw_verify_area(int read_write, struct file *file, loff_t *ppos, size_t count) |
187 | { | 194 | { |
188 | struct inode *inode; | 195 | struct inode *inode; |
189 | loff_t pos; | 196 | loff_t pos; |
190 | 197 | ||
191 | if (unlikely(count > INT_MAX)) | 198 | if (unlikely((ssize_t) count < 0)) |
192 | goto Einval; | 199 | goto Einval; |
193 | pos = *ppos; | 200 | pos = *ppos; |
194 | if (unlikely((pos < 0) || (loff_t) (pos + count) < 0)) | 201 | if (unlikely((pos < 0) || (loff_t) (pos + count) < 0)) |
195 | goto Einval; | 202 | goto Einval; |
196 | 203 | ||
197 | inode = file->f_dentry->d_inode; | 204 | inode = file->f_dentry->d_inode; |
198 | if (inode->i_flock && MANDATORY_LOCK(inode)) | 205 | if (inode->i_flock && MANDATORY_LOCK(inode)) { |
199 | return locks_mandatory_area(read_write == READ ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE, inode, file, pos, count); | 206 | int retval = locks_mandatory_area( |
200 | return 0; | 207 | read_write == READ ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE, |
208 | inode, file, pos, count); | ||
209 | if (retval < 0) | ||
210 | return retval; | ||
211 | } | ||
212 | return count > MAX_RW_COUNT ? MAX_RW_COUNT : count; | ||
201 | 213 | ||
202 | Einval: | 214 | Einval: |
203 | return -EINVAL; | 215 | return -EINVAL; |
@@ -244,7 +256,8 @@ ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos) | |||
244 | return -EFAULT; | 256 | return -EFAULT; |
245 | 257 | ||
246 | ret = rw_verify_area(READ, file, pos, count); | 258 | ret = rw_verify_area(READ, file, pos, count); |
247 | if (!ret) { | 259 | if (ret >= 0) { |
260 | count = ret; | ||
248 | ret = security_file_permission (file, MAY_READ); | 261 | ret = security_file_permission (file, MAY_READ); |
249 | if (!ret) { | 262 | if (!ret) { |
250 | if (file->f_op->read) | 263 | if (file->f_op->read) |
@@ -295,7 +308,8 @@ ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_ | |||
295 | return -EFAULT; | 308 | return -EFAULT; |
296 | 309 | ||
297 | ret = rw_verify_area(WRITE, file, pos, count); | 310 | ret = rw_verify_area(WRITE, file, pos, count); |
298 | if (!ret) { | 311 | if (ret >= 0) { |
312 | count = ret; | ||
299 | ret = security_file_permission (file, MAY_WRITE); | 313 | ret = security_file_permission (file, MAY_WRITE); |
300 | if (!ret) { | 314 | if (!ret) { |
301 | if (file->f_op->write) | 315 | if (file->f_op->write) |
@@ -497,7 +511,7 @@ static ssize_t do_readv_writev(int type, struct file *file, | |||
497 | } | 511 | } |
498 | 512 | ||
499 | ret = rw_verify_area(type, file, pos, tot_len); | 513 | ret = rw_verify_area(type, file, pos, tot_len); |
500 | if (ret) | 514 | if (ret < 0) |
501 | goto out; | 515 | goto out; |
502 | ret = security_file_permission(file, type == READ ? MAY_READ : MAY_WRITE); | 516 | ret = security_file_permission(file, type == READ ? MAY_READ : MAY_WRITE); |
503 | if (ret) | 517 | if (ret) |
@@ -653,8 +667,9 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, | |||
653 | if (!(in_file->f_mode & FMODE_PREAD)) | 667 | if (!(in_file->f_mode & FMODE_PREAD)) |
654 | goto fput_in; | 668 | goto fput_in; |
655 | retval = rw_verify_area(READ, in_file, ppos, count); | 669 | retval = rw_verify_area(READ, in_file, ppos, count); |
656 | if (retval) | 670 | if (retval < 0) |
657 | goto fput_in; | 671 | goto fput_in; |
672 | count = retval; | ||
658 | 673 | ||
659 | retval = security_file_permission (in_file, MAY_READ); | 674 | retval = security_file_permission (in_file, MAY_READ); |
660 | if (retval) | 675 | if (retval) |
@@ -674,8 +689,9 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, | |||
674 | goto fput_out; | 689 | goto fput_out; |
675 | out_inode = out_file->f_dentry->d_inode; | 690 | out_inode = out_file->f_dentry->d_inode; |
676 | retval = rw_verify_area(WRITE, out_file, &out_file->f_pos, count); | 691 | retval = rw_verify_area(WRITE, out_file, &out_file->f_pos, count); |
677 | if (retval) | 692 | if (retval < 0) |
678 | goto fput_out; | 693 | goto fput_out; |
694 | count = retval; | ||
679 | 695 | ||
680 | retval = security_file_permission (out_file, MAY_WRITE); | 696 | retval = security_file_permission (out_file, MAY_WRITE); |
681 | if (retval) | 697 | if (retval) |