diff options
author | Bob Copeland <me@bobcopeland.com> | 2008-09-06 17:51:53 -0400 |
---|---|---|
committer | Bob Copeland <me@bobcopeland.com> | 2010-07-10 14:37:06 -0400 |
commit | f068272cb2f134a194b93e94a8e0672bfce48cd8 (patch) | |
tree | c6a2a67951646eee3d040b732b384fa5c98fe78c /fs/omfs/inode.c | |
parent | 70d9e384aa7df681cfffd65947af72b22e86690e (diff) |
omfs: check bounds on block numbers before passing to sb_bread
In case of filesystem corruption, passing unchecked block numbers into
sb_bread can result in an infinite loop in __getblk(). Introduce a wrapper
function omfs_sbread() to check the block numbers and to also perform the
clus_to_blk() scaling.
Signed-off-by: Bob Copeland <me@bobcopeland.com>
Diffstat (limited to 'fs/omfs/inode.c')
-rw-r--r-- | fs/omfs/inode.c | 27 |
1 files changed, 16 insertions, 11 deletions
diff --git a/fs/omfs/inode.c b/fs/omfs/inode.c index b5d6380e03fb..bd4bf753a63b 100644 --- a/fs/omfs/inode.c +++ b/fs/omfs/inode.c | |||
@@ -19,6 +19,15 @@ MODULE_AUTHOR("Bob Copeland <me@bobcopeland.com>"); | |||
19 | MODULE_DESCRIPTION("OMFS (ReplayTV/Karma) Filesystem for Linux"); | 19 | MODULE_DESCRIPTION("OMFS (ReplayTV/Karma) Filesystem for Linux"); |
20 | MODULE_LICENSE("GPL"); | 20 | MODULE_LICENSE("GPL"); |
21 | 21 | ||
22 | struct buffer_head *omfs_bread(struct super_block *sb, sector_t block) | ||
23 | { | ||
24 | struct omfs_sb_info *sbi = OMFS_SB(sb); | ||
25 | if (block >= sbi->s_num_blocks) | ||
26 | return NULL; | ||
27 | |||
28 | return sb_bread(sb, clus_to_blk(sbi, block)); | ||
29 | } | ||
30 | |||
22 | struct inode *omfs_new_inode(struct inode *dir, int mode) | 31 | struct inode *omfs_new_inode(struct inode *dir, int mode) |
23 | { | 32 | { |
24 | struct inode *inode; | 33 | struct inode *inode; |
@@ -93,15 +102,13 @@ static int __omfs_write_inode(struct inode *inode, int wait) | |||
93 | struct omfs_inode *oi; | 102 | struct omfs_inode *oi; |
94 | struct omfs_sb_info *sbi = OMFS_SB(inode->i_sb); | 103 | struct omfs_sb_info *sbi = OMFS_SB(inode->i_sb); |
95 | struct buffer_head *bh, *bh2; | 104 | struct buffer_head *bh, *bh2; |
96 | unsigned int block; | ||
97 | u64 ctime; | 105 | u64 ctime; |
98 | int i; | 106 | int i; |
99 | int ret = -EIO; | 107 | int ret = -EIO; |
100 | int sync_failed = 0; | 108 | int sync_failed = 0; |
101 | 109 | ||
102 | /* get current inode since we may have written sibling ptrs etc. */ | 110 | /* get current inode since we may have written sibling ptrs etc. */ |
103 | block = clus_to_blk(sbi, inode->i_ino); | 111 | bh = omfs_bread(inode->i_sb, inode->i_ino); |
104 | bh = sb_bread(inode->i_sb, block); | ||
105 | if (!bh) | 112 | if (!bh) |
106 | goto out; | 113 | goto out; |
107 | 114 | ||
@@ -140,8 +147,7 @@ static int __omfs_write_inode(struct inode *inode, int wait) | |||
140 | 147 | ||
141 | /* if mirroring writes, copy to next fsblock */ | 148 | /* if mirroring writes, copy to next fsblock */ |
142 | for (i = 1; i < sbi->s_mirrors; i++) { | 149 | for (i = 1; i < sbi->s_mirrors; i++) { |
143 | bh2 = sb_bread(inode->i_sb, block + i * | 150 | bh2 = omfs_bread(inode->i_sb, inode->i_ino + i); |
144 | (sbi->s_blocksize / sbi->s_sys_blocksize)); | ||
145 | if (!bh2) | 151 | if (!bh2) |
146 | goto out_brelse; | 152 | goto out_brelse; |
147 | 153 | ||
@@ -193,7 +199,6 @@ struct inode *omfs_iget(struct super_block *sb, ino_t ino) | |||
193 | struct omfs_sb_info *sbi = OMFS_SB(sb); | 199 | struct omfs_sb_info *sbi = OMFS_SB(sb); |
194 | struct omfs_inode *oi; | 200 | struct omfs_inode *oi; |
195 | struct buffer_head *bh; | 201 | struct buffer_head *bh; |
196 | unsigned int block; | ||
197 | u64 ctime; | 202 | u64 ctime; |
198 | unsigned long nsecs; | 203 | unsigned long nsecs; |
199 | struct inode *inode; | 204 | struct inode *inode; |
@@ -204,8 +209,7 @@ struct inode *omfs_iget(struct super_block *sb, ino_t ino) | |||
204 | if (!(inode->i_state & I_NEW)) | 209 | if (!(inode->i_state & I_NEW)) |
205 | return inode; | 210 | return inode; |
206 | 211 | ||
207 | block = clus_to_blk(sbi, ino); | 212 | bh = omfs_bread(inode->i_sb, ino); |
208 | bh = sb_bread(inode->i_sb, block); | ||
209 | if (!bh) | 213 | if (!bh) |
210 | goto iget_failed; | 214 | goto iget_failed; |
211 | 215 | ||
@@ -319,6 +323,9 @@ static int omfs_get_imap(struct super_block *sb) | |||
319 | goto nomem; | 323 | goto nomem; |
320 | 324 | ||
321 | block = clus_to_blk(sbi, sbi->s_bitmap_ino); | 325 | block = clus_to_blk(sbi, sbi->s_bitmap_ino); |
326 | if (block >= sbi->s_num_blocks) | ||
327 | goto nomem; | ||
328 | |||
322 | ptr = sbi->s_imap; | 329 | ptr = sbi->s_imap; |
323 | for (count = bitmap_size; count > 0; count -= sb->s_blocksize) { | 330 | for (count = bitmap_size; count > 0; count -= sb->s_blocksize) { |
324 | bh = sb_bread(sb, block++); | 331 | bh = sb_bread(sb, block++); |
@@ -417,7 +424,6 @@ static int omfs_fill_super(struct super_block *sb, void *data, int silent) | |||
417 | struct omfs_root_block *omfs_rb; | 424 | struct omfs_root_block *omfs_rb; |
418 | struct omfs_sb_info *sbi; | 425 | struct omfs_sb_info *sbi; |
419 | struct inode *root; | 426 | struct inode *root; |
420 | sector_t start; | ||
421 | int ret = -EINVAL; | 427 | int ret = -EINVAL; |
422 | 428 | ||
423 | save_mount_options(sb, (char *) data); | 429 | save_mount_options(sb, (char *) data); |
@@ -486,8 +492,7 @@ static int omfs_fill_super(struct super_block *sb, void *data, int silent) | |||
486 | sbi->s_block_shift = get_bitmask_order(sbi->s_blocksize) - | 492 | sbi->s_block_shift = get_bitmask_order(sbi->s_blocksize) - |
487 | get_bitmask_order(sbi->s_sys_blocksize); | 493 | get_bitmask_order(sbi->s_sys_blocksize); |
488 | 494 | ||
489 | start = clus_to_blk(sbi, be64_to_cpu(omfs_sb->s_root_block)); | 495 | bh2 = omfs_bread(sb, be64_to_cpu(omfs_sb->s_root_block)); |
490 | bh2 = sb_bread(sb, start); | ||
491 | if (!bh2) | 496 | if (!bh2) |
492 | goto out_brelse_bh; | 497 | goto out_brelse_bh; |
493 | 498 | ||