[PATCH] 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. [akpm@osdl.org: fix off-by-one error] Signed-off-by: Neil Brown <neilb@suse.de> Signed-off-by: Jan Kara <jack@suse.cz> Cc: Marcel Holtmann <marcel@holtmann.org> Cc: <stable@kernel.org> Cc: "Stephen C. Tweedie" <sct@redhat.com> Cc: Eric Sandeen <esandeen@redhat.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
parent
f712c0c7e1
commit
2ccb48ebb4
3 changed files with 29 additions and 8 deletions
|
@ -2402,14 +2402,15 @@ static ext3_fsblk_t ext3_get_inode_block(struct super_block *sb,
|
||||||
struct buffer_head *bh;
|
struct buffer_head *bh;
|
||||||
struct ext3_group_desc * gdp;
|
struct ext3_group_desc * gdp;
|
||||||
|
|
||||||
|
if (!ext3_valid_inum(sb, ino)) {
|
||||||
if ((ino != EXT3_ROOT_INO && ino != EXT3_JOURNAL_INO &&
|
/*
|
||||||
ino != EXT3_RESIZE_INO && ino < EXT3_FIRST_INO(sb)) ||
|
* This error is already checked for in namei.c unless we are
|
||||||
ino > le32_to_cpu(EXT3_SB(sb)->s_es->s_inodes_count)) {
|
* looking at an NFS filehandle, in which case no error
|
||||||
ext3_error(sb, "ext3_get_inode_block",
|
* report is needed
|
||||||
"bad inode number: %lu", ino);
|
*/
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
block_group = (ino - 1) / EXT3_INODES_PER_GROUP(sb);
|
block_group = (ino - 1) / EXT3_INODES_PER_GROUP(sb);
|
||||||
if (block_group >= EXT3_SB(sb)->s_groups_count) {
|
if (block_group >= EXT3_SB(sb)->s_groups_count) {
|
||||||
ext3_error(sb,"ext3_get_inode_block","group >= groups count");
|
ext3_error(sb,"ext3_get_inode_block","group >= groups count");
|
||||||
|
|
|
@ -1000,7 +1000,12 @@ static struct dentry *ext3_lookup(struct inode * dir, struct dentry *dentry, str
|
||||||
if (bh) {
|
if (bh) {
|
||||||
unsigned long ino = le32_to_cpu(de->inode);
|
unsigned long ino = le32_to_cpu(de->inode);
|
||||||
brelse (bh);
|
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)
|
if (!inode)
|
||||||
return ERR_PTR(-EACCES);
|
return ERR_PTR(-EACCES);
|
||||||
|
@ -1028,7 +1033,13 @@ struct dentry *ext3_get_parent(struct dentry *child)
|
||||||
return ERR_PTR(-ENOENT);
|
return ERR_PTR(-ENOENT);
|
||||||
ino = le32_to_cpu(de->inode);
|
ino = le32_to_cpu(de->inode);
|
||||||
brelse(bh);
|
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)
|
if (!inode)
|
||||||
return ERR_PTR(-EACCES);
|
return ERR_PTR(-EACCES);
|
||||||
|
|
|
@ -492,6 +492,15 @@ static inline struct ext3_inode_info *EXT3_I(struct inode *inode)
|
||||||
{
|
{
|
||||||
return container_of(inode, struct ext3_inode_info, vfs_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
|
#else
|
||||||
/* Assume that user mode programs are passing in an ext3fs superblock, not
|
/* 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
|
* a kernel struct super_block. This will allow us to call the feature-test
|
||||||
|
|
Loading…
Reference in a new issue