diff options
author | Jeff Mahoney <jeffm@suse.com> | 2010-10-14 09:53:37 -0400 |
---|---|---|
committer | Christoph Hellwig <hch@lst.de> | 2010-10-14 09:53:37 -0400 |
commit | ee52716245877b821f5ddbb3ace85b73084fb450 (patch) | |
tree | 3d85d8fce3bde7b1601878074cdec622705d1af2 /fs | |
parent | 40de9a7cebc4e0b23cd6863c84c2279f0ccadebb (diff) |
hfsplus: fix oops on mount with corrupted btree extent records
A particular fsfuzzer run caused an hfs file system to crash on mount. This
is due to a corrupted MDB extent record causing a miscalculation of
HFSPLUS_I(inode)->first_blocks for the extent tree. If the extent records
are zereod out, then it won't trigger the first_blocks special case and
instead falls through to the extent code, which we're in the middle
of initializing.
This patch catches the 0 size extent records, reports the corruption,
and fails the mount.
[hch: ported of commit 47f365eb575735c6b2edf5d08e0d16d26a9c23bd from hfs]
Reported-by: Ramon de Carvalho Valle <rcvalle@linux.vnet.ibm.com>
Signed-off-by: Jeff Mahoney <jeffm@suse.com>
Signed-off-by: Christoph Hellwig <hch@tuxera.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/hfsplus/btree.c | 11 |
1 files changed, 9 insertions, 2 deletions
diff --git a/fs/hfsplus/btree.c b/fs/hfsplus/btree.c index 8306479f6b3a..d4bd864ce108 100644 --- a/fs/hfsplus/btree.c +++ b/fs/hfsplus/btree.c @@ -39,10 +39,16 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id) goto free_tree; tree->inode = inode; + if (!HFSPLUS_I(tree->inode)->first_blocks) { + printk(KERN_ERR + "hfs: invalid btree extent records (0 size).\n"); + goto free_inode; + } + mapping = tree->inode->i_mapping; page = read_mapping_page(mapping, 0, NULL); if (IS_ERR(page)) - goto free_tree; + goto free_inode; /* Load the header */ head = (struct hfs_btree_header_rec *)(kmap(page) + sizeof(struct hfs_bnode_desc)); @@ -89,8 +95,9 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id) fail_page: tree->inode->i_mapping->a_ops = &hfsplus_aops; page_cache_release(page); - free_tree: + free_inode: iput(tree->inode); + free_tree: kfree(tree); return NULL; } |