Commit 90b0a973 authored by Carlos Maiolino's avatar Carlos Maiolino Committed by Theodore Ts'o

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: default avatarCarlos Maiolino <cmaiolino@redhat.com>
Signed-off-by: default avatar"Theodore Ts'o" <tytso@mit.edu>
parent bc0b75f7
...@@ -732,11 +732,13 @@ struct buffer_head *ext4_getblk(handle_t *handle, struct inode *inode, ...@@ -732,11 +732,13 @@ struct buffer_head *ext4_getblk(handle_t *handle, struct inode *inode,
err = ext4_map_blocks(handle, inode, &map, err = ext4_map_blocks(handle, inode, &map,
create ? EXT4_GET_BLOCKS_CREATE : 0); create ? EXT4_GET_BLOCKS_CREATE : 0);
/* ensure we send some value back into *errp */
*errp = 0;
if (err < 0) if (err < 0)
*errp = err; *errp = err;
if (err <= 0) if (err <= 0)
return NULL; return NULL;
*errp = 0;
bh = sb_getblk(inode->i_sb, map.m_pblk); bh = sb_getblk(inode->i_sb, map.m_pblk);
if (!bh) { if (!bh) {
......
...@@ -846,7 +846,7 @@ static int htree_dirblock_to_tree(struct file *dir_file, ...@@ -846,7 +846,7 @@ static int htree_dirblock_to_tree(struct file *dir_file,
{ {
struct buffer_head *bh; struct buffer_head *bh;
struct ext4_dir_entry_2 *de, *top; struct ext4_dir_entry_2 *de, *top;
int err, count = 0; int err = 0, count = 0;
dxtrace(printk(KERN_INFO "In htree dirblock_to_tree: block %lu\n", dxtrace(printk(KERN_INFO "In htree dirblock_to_tree: block %lu\n",
(unsigned long)block)); (unsigned long)block));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment