diff options
author | Zhao Lei <zhaolei@cn.fujitsu.com> | 2015-07-15 09:02:09 -0400 |
---|---|---|
committer | Chris Mason <clm@fb.com> | 2015-07-22 21:20:52 -0400 |
commit | 95ab1f64908795a2edd6b847eca94a0c63a44be4 (patch) | |
tree | 34b4e05f9ed2b15cc7488d9f7bd60cbcc9969da5 | |
parent | 8a7330130470e173832385861c1aa6e37a4e50d2 (diff) |
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>
-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, | |||
2842 | !extent_buffer_uptodate(chunk_root->node)) { | 2842 | !extent_buffer_uptodate(chunk_root->node)) { |
2843 | printk(KERN_ERR "BTRFS: failed to read chunk root on %s\n", | 2843 | printk(KERN_ERR "BTRFS: failed to read chunk root on %s\n", |
2844 | sb->s_id); | 2844 | sb->s_id); |
2845 | chunk_root->node = NULL; | ||
2845 | goto fail_tree_roots; | 2846 | goto fail_tree_roots; |
2846 | } | 2847 | } |
2847 | btrfs_set_root_node(&chunk_root->root_item, chunk_root->node); | 2848 | btrfs_set_root_node(&chunk_root->root_item, chunk_root->node); |
@@ -2879,7 +2880,7 @@ retry_root_backup: | |||
2879 | !extent_buffer_uptodate(tree_root->node)) { | 2880 | !extent_buffer_uptodate(tree_root->node)) { |
2880 | printk(KERN_WARNING "BTRFS: failed to read tree root on %s\n", | 2881 | printk(KERN_WARNING "BTRFS: failed to read tree root on %s\n", |
2881 | sb->s_id); | 2882 | sb->s_id); |
2882 | 2883 | tree_root->node = NULL; | |
2883 | goto recovery_tree_root; | 2884 | goto recovery_tree_root; |
2884 | } | 2885 | } |
2885 | 2886 | ||