aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4
diff options
context:
space:
mode:
authorThiemo Nagel <thiemo.nagel@ph.tum.de>2009-03-31 08:36:10 -0400
committerTheodore Ts'o <tytso@mit.edu>2009-03-31 08:36:10 -0400
commitfe2c8191faa29d7a09f4962198f6dfab973ceec4 (patch)
treeed1b9cf3997fb6e90bf889f028d27e1d3e5f2b63 /fs/ext4
parent563bdd61fe4dbd6b58cf7eb06f8d8f14479ae1dc (diff)
ext4: add checks of block references for non-extent inodes
Check block references in the inode and indorect blocks for non-extent inodes to make sure they are valid, and flag an error if they are invalid. Signed-off-by: Thiemo Nagel <thiemo.nagel@ph.tum.de> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'fs/ext4')
-rw-r--r--fs/ext4/inode.c59
1 files changed, 52 insertions, 7 deletions
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index c7d9250fbc3f..b3fd65d46506 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -371,6 +371,34 @@ static int ext4_block_to_path(struct inode *inode,
371 return n; 371 return n;
372} 372}
373 373
374static int __ext4_check_blockref(const char *function, struct inode *inode,
375 unsigned int *p, unsigned int max) {
376
377 unsigned int maxblocks = ext4_blocks_count(EXT4_SB(inode->i_sb)->s_es);
378 unsigned int *bref = p;
379 while (bref < p+max) {
380 if (unlikely(*bref >= maxblocks)) {
381 ext4_error(inode->i_sb, function,
382 "block reference %u >= max (%u) "
383 "in inode #%lu, offset=%d",
384 *bref, maxblocks,
385 inode->i_ino, (int)(bref-p));
386 return -EIO;
387 }
388 bref++;
389 }
390 return 0;
391}
392
393
394#define ext4_check_indirect_blockref(inode, bh) \
395 __ext4_check_blockref(__func__, inode, (__le32 *)(bh)->b_data, \
396 EXT4_ADDR_PER_BLOCK((inode)->i_sb))
397
398#define ext4_check_inode_blockref(inode) \
399 __ext4_check_blockref(__func__, inode, EXT4_I(inode)->i_data, \
400 EXT4_NDIR_BLOCKS)
401
374/** 402/**
375 * ext4_get_branch - read the chain of indirect blocks leading to data 403 * ext4_get_branch - read the chain of indirect blocks leading to data
376 * @inode: inode in question 404 * @inode: inode in question
@@ -415,9 +443,22 @@ static Indirect *ext4_get_branch(struct inode *inode, int depth,
415 if (!p->key) 443 if (!p->key)
416 goto no_block; 444 goto no_block;
417 while (--depth) { 445 while (--depth) {
418 bh = sb_bread(sb, le32_to_cpu(p->key)); 446 bh = sb_getblk(sb, le32_to_cpu(p->key));
419 if (!bh) 447 if (unlikely(!bh))
420 goto failure; 448 goto failure;
449
450 if (!bh_uptodate_or_lock(bh)) {
451 if (bh_submit_read(bh) < 0) {
452 put_bh(bh);
453 goto failure;
454 }
455 /* validate block references */
456 if (ext4_check_indirect_blockref(inode, bh)) {
457 put_bh(bh);
458 goto failure;
459 }
460 }
461
421 add_chain(++p, bh, (__le32 *)bh->b_data + *++offsets); 462 add_chain(++p, bh, (__le32 *)bh->b_data + *++offsets);
422 /* Reader: end */ 463 /* Reader: end */
423 if (!p->key) 464 if (!p->key)
@@ -4371,11 +4412,15 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
4371 if (ei->i_flags & EXT4_EXTENTS_FL) { 4412 if (ei->i_flags & EXT4_EXTENTS_FL) {
4372 /* Validate extent which is part of inode */ 4413 /* Validate extent which is part of inode */
4373 ret = ext4_ext_check_inode(inode); 4414 ret = ext4_ext_check_inode(inode);
4374 if (ret) { 4415 } else if (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
4375 brelse(bh); 4416 (S_ISLNK(inode->i_mode) &&
4376 goto bad_inode; 4417 !ext4_inode_is_fast_symlink(inode))) {
4377 } 4418 /* Validate block references which are part of inode */
4378 4419 ret = ext4_check_inode_blockref(inode);
4420 }
4421 if (ret) {
4422 brelse(bh);
4423 goto bad_inode;
4379 } 4424 }
4380 4425
4381 if (S_ISREG(inode->i_mode)) { 4426 if (S_ISREG(inode->i_mode)) {