diff options
author | Zhao Lei <zhaolei@cn.fujitsu.com> | 2015-07-15 21:02:09 +0800 |
---|---|---|
committer | Chris Mason <clm@fb.com> | 2015-07-22 18:20:52 -0700 |
commit | 95ab1f64908795a2edd6b847eca94a0c63a44be4 (patch) | |
tree | 34b4e05f9ed2b15cc7488d9f7bd60cbcc9969da5 /fs | |
parent | 8a7330130470e173832385861c1aa6e37a4e50d2 (diff) | |
download | linux-95ab1f64908795a2edd6b847eca94a0c63a44be4.tar.bz2 |
btrfs: Avoid NULL pointer dereference of free_extent_buffer when read_tree_block() fail
When read_tree_block() failed, we can see following dmesg:
[ 134.371389] BUG: unable to handle kernel NULL pointer dereference at 0000000000000063
[ 134.372236] IP: [<ffffffff813a4a51>] free_extent_buffer+0x21/0x90
[ 134.372236] PGD 0
[ 134.372236] Oops: 0000 [#1] SMP
[ 134.372236] Modules linked in:
[ 134.372236] CPU: 0 PID: 2289 Comm: mount Not tainted 4.2.0-rc1_HEAD_c65b99f046843d2455aa231747b5a07a999a9f3d_+ #115
[ 134.372236] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.7.5.1-0-g8936dbb-20141113_115728-nilsson.home.kraxel.org 04/01/2014
[ 134.372236] task: ffff88003b6e1a00 ti: ffff880011e60000 task.ti: ffff880011e60000
[ 134.372236] RIP: 0010:[<ffffffff813a4a51>] [<ffffffff813a4a51>] free_extent_buffer+0x21/0x90
...
[ 134.372236] Call Trace:
[ 134.372236] [<ffffffff81379aa1>] free_root_extent_buffers+0x91/0xb0
[ 134.372236] [<ffffffff81379c3d>] free_root_pointers+0x17d/0x190
[ 134.372236] [<ffffffff813801b0>] open_ctree+0x1ca0/0x25b0
[ 134.372236] [<ffffffff8144d017>] ? disk_name+0x97/0xb0
[ 134.372236] [<ffffffff813558aa>] btrfs_mount+0x8fa/0xab0
...
Reason:
read_tree_block() changed to return error number on fail,
and this value(not NULL) is set to tree_root->node, then subsequent
code will run to:
free_root_pointers()
->free_root_extent_buffers()
->free_extent_buffer()
->atomic_read((extent_buffer *)(-E_XXX)->refs);
and trigger above error.
Fix:
Set tree_root->node to NULL on fail to make error_handle code
happy.
Signed-off-by: Zhao Lei <zhaolei@cn.fujitsu.com>
Signed-off-by: Chris Mason <clm@fb.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/disk-io.c | 3 |
1 files changed, 2 insertions, 1 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index e5aad7f535aa..84cbbb2d562e 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -2842,6 +2842,7 @@ int open_ctree(struct super_block *sb, !extent_buffer_uptodate(chunk_root->node)) { printk(KERN_ERR "BTRFS: failed to read chunk root on %s\n", sb->s_id); + chunk_root->node = NULL; goto fail_tree_roots; } btrfs_set_root_node(&chunk_root->root_item, chunk_root->node); @@ -2879,7 +2880,7 @@ retry_root_backup: !extent_buffer_uptodate(tree_root->node)) { printk(KERN_WARNING "BTRFS: failed to read tree root on %s\n", sb->s_id); - + tree_root->node = NULL; goto recovery_tree_root; } |