diff options
author | Neil Brown <neilb@suse.de> | 2006-08-30 17:58:44 +0200 |
---|---|---|
committer | Adrian Bunk <bunk@stusta.de> | 2006-08-30 17:58:44 +0200 |
commit | 06e346507acbf0feb78abf2179a7d46b7114690a (patch) | |
tree | b107f8bc09a89f6baeb3cf2249e89a22903542e9 | |
parent | 439fc6b301c680195fdb18caa5cebdbdf2f9d670 (diff) |
ext3: avoid triggering ext3_error on bad NFS file handle
The inode number out of an NFS file handle gets passed eventually to
ext3_get_inode_block() without any checking. If ext3_get_inode_block()
allows it to trigger an error, then bad filehandles can have unpleasant
effect - ext3_error() will usually cause a forced read-only remount, or a
panic if `errors=panic' was used.
So remove the call to ext3_error there and put a matching check in
ext3/namei.c where inode numbers are read off storage.
Andrew Morton fixed an off-by-one error.
Dann Frazier ported the patch to 2.6.16.
Signed-off-by: Neil Brown <neilb@suse.de>
Signed-off-by: Adrian Bunk <bunk@stusta.de>
-rw-r--r-- | fs/ext3/inode.c | 15 | ||||
-rw-r--r-- | fs/ext3/namei.c | 15 | ||||
-rw-r--r-- | include/linux/ext3_fs.h | 9 |
3 files changed, 29 insertions, 10 deletions
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index 0384e539b88..cbad292b4c3 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c @@ -2259,16 +2259,15 @@ static unsigned long ext3_get_inode_block(struct super_block *sb, struct ext3_group_desc * gdp; - if ((ino != EXT3_ROOT_INO && - ino != EXT3_JOURNAL_INO && - ino != EXT3_RESIZE_INO && - ino < EXT3_FIRST_INO(sb)) || - ino > le32_to_cpu( - EXT3_SB(sb)->s_es->s_inodes_count)) { - ext3_error (sb, "ext3_get_inode_block", - "bad inode number: %lu", ino); + if (!ext3_valid_inum(sb, ino)) { + /* + * This error is already checked for in namei.c unless we are + * looking at an NFS filehandle, in which case no error + * report is needed + */ return 0; } + block_group = (ino - 1) / EXT3_INODES_PER_GROUP(sb); if (block_group >= EXT3_SB(sb)->s_groups_count) { ext3_error (sb, "ext3_get_inode_block", diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c index b8f5cd1e540..7be89fe95d7 100644 --- a/fs/ext3/namei.c +++ b/fs/ext3/namei.c @@ -1000,7 +1000,12 @@ static struct dentry *ext3_lookup(struct inode * dir, struct dentry *dentry, str if (bh) { unsigned long ino = le32_to_cpu(de->inode); brelse (bh); - inode = iget(dir->i_sb, ino); + if (!ext3_valid_inum(dir->i_sb, ino)) { + ext3_error(dir->i_sb, "ext3_lookup", + "bad inode number: %lu", ino); + inode = NULL; + } else + inode = iget(dir->i_sb, ino); if (!inode) return ERR_PTR(-EACCES); @@ -1028,7 +1033,13 @@ struct dentry *ext3_get_parent(struct dentry *child) return ERR_PTR(-ENOENT); ino = le32_to_cpu(de->inode); brelse(bh); - inode = iget(child->d_inode->i_sb, ino); + + if (!ext3_valid_inum(child->d_inode->i_sb, ino)) { + ext3_error(child->d_inode->i_sb, "ext3_get_parent", + "bad inode number: %lu", ino); + inode = NULL; + } else + inode = iget(child->d_inode->i_sb, ino); if (!inode) return ERR_PTR(-EACCES); diff --git a/include/linux/ext3_fs.h b/include/linux/ext3_fs.h index c0272d73ab2..c23ec09e356 100644 --- a/include/linux/ext3_fs.h +++ b/include/linux/ext3_fs.h @@ -494,6 +494,15 @@ static inline struct ext3_inode_info *EXT3_I(struct inode *inode) { return container_of(inode, struct ext3_inode_info, vfs_inode); } + +static inline int ext3_valid_inum(struct super_block *sb, unsigned long ino) +{ + return ino == EXT3_ROOT_INO || + ino == EXT3_JOURNAL_INO || + ino == EXT3_RESIZE_INO || + (ino >= EXT3_FIRST_INO(sb) && + ino <= le32_to_cpu(EXT3_SB(sb)->s_es->s_inodes_count)); +} #else /* Assume that user mode programs are passing in an ext3fs superblock, not * a kernel struct super_block. This will allow us to call the feature-test |