diff options
author | Carlos Maiolino <cmaiolino@redhat.com> | 2012-09-17 23:39:12 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2012-09-17 23:39:12 -0400 |
commit | 90b0a97323f42ead278bbccbdf0e123db2add400 (patch) | |
tree | 2b99c6b0f848af4392e8be794d3c56338d6ced85 /fs/ext4 | |
parent | bc0b75f77a944b482293972eb8fd5c88c576eb46 (diff) |
ext4: fix possible non-initialized variable in htree_dirblock_to_tree()
htree_dirblock_to_tree() declares a non-initialized 'err' variable,
which is passed as a reference to another functions expecting them to
set this variable with their error codes.
It's passed to ext4_bread(), which then passes it to ext4_getblk(). If
ext4_map_blocks() returns 0 due to a lookup failure, leaving the
ext4_getblk() buffer_head uninitialized, it will make ext4_getblk()
return to ext4_bread() without initialize the 'err' variable, and
ext4_bread() will return to htree_dirblock_to_tree() with this variable
still uninitialized. htree_dirblock_to_tree() will pass this variable
with garbage back to ext4_htree_fill_tree(), which expects a number of
directory entries added to the rb-tree. which, in case, might return a
fake non-zero value due the garbage left in the 'err' variable, leading
the kernel to an Oops in ext4_dx_readdir(), once this is expecting a
filled rb-tree node, when in turn it will have a NULL-ed one, causing an
invalid page request when trying to get a fname struct from this NULL-ed
rb-tree node in this line:
fname = rb_entry(info->curr_node, struct fname, rb_hash);
The patch itself initializes the err variable in
htree_dirblock_to_tree() to avoid usage mistakes by the called
functions, and also fix ext4_getblk() to return a initialized 'err'
variable when ext4_map_blocks() fails a lookup.
Signed-off-by: Carlos Maiolino <cmaiolino@redhat.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'fs/ext4')
-rw-r--r-- | fs/ext4/inode.c | 4 | ||||
-rw-r--r-- | fs/ext4/namei.c | 2 |
2 files changed, 4 insertions, 2 deletions
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index b4effbda7a96..ca76b5ed6c9e 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
@@ -732,11 +732,13 @@ struct buffer_head *ext4_getblk(handle_t *handle, struct inode *inode, | |||
732 | err = ext4_map_blocks(handle, inode, &map, | 732 | err = ext4_map_blocks(handle, inode, &map, |
733 | create ? EXT4_GET_BLOCKS_CREATE : 0); | 733 | create ? EXT4_GET_BLOCKS_CREATE : 0); |
734 | 734 | ||
735 | /* ensure we send some value back into *errp */ | ||
736 | *errp = 0; | ||
737 | |||
735 | if (err < 0) | 738 | if (err < 0) |
736 | *errp = err; | 739 | *errp = err; |
737 | if (err <= 0) | 740 | if (err <= 0) |
738 | return NULL; | 741 | return NULL; |
739 | *errp = 0; | ||
740 | 742 | ||
741 | bh = sb_getblk(inode->i_sb, map.m_pblk); | 743 | bh = sb_getblk(inode->i_sb, map.m_pblk); |
742 | if (!bh) { | 744 | if (!bh) { |
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 7450ff01c3c4..37c03b32e194 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c | |||
@@ -846,7 +846,7 @@ static int htree_dirblock_to_tree(struct file *dir_file, | |||
846 | { | 846 | { |
847 | struct buffer_head *bh; | 847 | struct buffer_head *bh; |
848 | struct ext4_dir_entry_2 *de, *top; | 848 | struct ext4_dir_entry_2 *de, *top; |
849 | int err, count = 0; | 849 | int err = 0, count = 0; |
850 | 850 | ||
851 | dxtrace(printk(KERN_INFO "In htree dirblock_to_tree: block %lu\n", | 851 | dxtrace(printk(KERN_INFO "In htree dirblock_to_tree: block %lu\n", |
852 | (unsigned long)block)); | 852 | (unsigned long)block)); |