aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@g5.osdl.org>2006-01-04 19:20:40 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-01-04 19:20:40 -0500
commite28cc71572da38a5a12c1cfe4d7032017adccf69 (patch)
treebea9af22a98ea2988a38f5e9fc2467ccbbf3ae70 /fs
parenta020ff412f0ecbb1e4aae1681b287e5785dd77b5 (diff)
Relax the rw_verify_area() error checking.
In particular, allow over-large read- or write-requests to be downgraded to a more reasonable range, rather than considering them outright errors. We want to protect lower layers from (the sadly all too common) overflow conditions, but prefer to do so by chopping the requests up, rather than just refusing them outright. Cc: Peter Anvin <hpa@zytor.com> Cc: Ulrich Drepper <drepper@redhat.com> Cc: Andi Kleen <ak@suse.de> Cc: Al Viro <viro@ftp.linux.org.uk> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs')
-rw-r--r--fs/compat.c2
-rw-r--r--fs/read_write.c34
2 files changed, 26 insertions, 10 deletions
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
186int rw_verify_area(int read_write, struct file *file, loff_t *ppos, size_t count) 193int 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
202Einval: 214Einval:
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)