Skip to content

Commit

Permalink
[PATCH] ext3: avoid triggering ext3_error on bad NFS file handle
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Neil Brown authored and Linus Torvalds committed Jul 31, 2006
1 parent f712c0c commit 2ccb48e
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 8 deletions.
13 changes: 7 additions & 6 deletions fs/ext3/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -2402,14 +2402,15 @@ static ext3_fsblk_t ext3_get_inode_block(struct super_block *sb,
struct buffer_head *bh;
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","group >= groups count");
Expand Down
15 changes: 13 additions & 2 deletions fs/ext3/namei.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
9 changes: 9 additions & 0 deletions include/linux/ext3_fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

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
Expand Down

0 comments on commit 2ccb48e

Please sign in to comment.