diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-26 17:58:44 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-26 17:58:44 -0700 |
commit | 426e1f5cec4821945642230218876b0e89aafab1 (patch) | |
tree | 2728ace018d0698886989da586210ef1543a7098 /fs/read_write.c | |
parent | 9e5fca251f44832cb996961048ea977f80faf6ea (diff) | |
parent | 63997e98a3be68d7cec806d22bf9b02b2e1daabb (diff) | |
download | linux-426e1f5cec4821945642230218876b0e89aafab1.tar.bz2 |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6: (52 commits)
split invalidate_inodes()
fs: skip I_FREEING inodes in writeback_sb_inodes
fs: fold invalidate_list into invalidate_inodes
fs: do not drop inode_lock in dispose_list
fs: inode split IO and LRU lists
fs: switch bdev inode bdi's correctly
fs: fix buffer invalidation in invalidate_list
fsnotify: use dget_parent
smbfs: use dget_parent
exportfs: use dget_parent
fs: use RCU read side protection in d_validate
fs: clean up dentry lru modification
fs: split __shrink_dcache_sb
fs: improve DCACHE_REFERENCED usage
fs: use percpu counter for nr_dentry and nr_dentry_unused
fs: simplify __d_free
fs: take dcache_lock inside __d_path
fs: do not assign default i_ino in new_inode
fs: introduce a per-cpu last_ino allocator
new helper: ihold()
...
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 = { EXPORT_SYMBOL(generic_ro_fops); +static int +__negative_fpos_check(struct file *file, loff_t pos, size_t count) +{ + /* + * pos or pos+count is negative here, check overflow. + * too big "count" will be caught in rw_verify_area(). + */ + if ((pos < 0) && (pos + count < pos)) + return -EOVERFLOW; + if (file->f_mode & FMODE_UNSIGNED_OFFSET) + return 0; + return -EINVAL; +} + /** * generic_file_llseek_unlocked - lockless generic llseek implementation * @file: file structure to seek on @@ -62,7 +76,9 @@ generic_file_llseek_unlocked(struct file *file, loff_t offset, int origin) break; } - if (offset < 0 || offset > inode->i_sb->s_maxbytes) + if (offset < 0 && __negative_fpos_check(file, offset, 0)) + return -EINVAL; + if (offset > inode->i_sb->s_maxbytes) return -EINVAL; /* Special lock needed here? */ @@ -137,7 +153,7 @@ loff_t default_llseek(struct file *file, loff_t offset, int origin) offset += file->f_pos; } retval = -EINVAL; - if (offset >= 0) { + if (offset >= 0 || !__negative_fpos_check(file, offset, 0)) { if (offset != file->f_pos) { file->f_pos = offset; file->f_version = 0; @@ -221,6 +237,7 @@ bad: } #endif + /* * rw_verify_area doesn't like huge counts. We limit * 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 if (unlikely((ssize_t) count < 0)) return retval; pos = *ppos; - if (unlikely((pos < 0) || (loff_t) (pos + count) < 0)) - return retval; + if (unlikely((pos < 0) || (loff_t) (pos + count) < 0)) { + retval = __negative_fpos_check(file, pos, count); + if (retval) + return retval; + } if (unlikely(inode->i_flock && mandatory_lock(inode))) { retval = locks_mandatory_area( |