diff mbox series

btrfs: fix NULL pointer dereference in extent_io_tree_panic()

Message ID 20210103050156.2866-1-l@damenly.su (mailing list archive)
State New, archived
Headers show
Series btrfs: fix NULL pointer dereference in extent_io_tree_panic() | expand

Commit Message

Su Yue Jan. 3, 2021, 5:01 a.m. UTC
while mounting the poc image user-provided, kernel panics due to the
NULL deference of @tree->inode.
========================================================================
[  109.663024] BTRFS error: found node 12582912 29360127 on insert of 37748736 29360127
[  109.663032] BUG: kernel NULL pointer dereference, address: 0000000000000028
[  109.664494] #PF: supervisor read access in kernel mode
[  109.665543] #PF: error_code(0x0000) - not-present page
[  109.666598] PGD 0 P4D 0
[  109.667119] Oops: 0000 [#1] PREEMPT SMP NOPTI
[  109.668015] CPU: 14 PID: 641 Comm: mount Tainted: G        W  O      5.11.0-rc1-custom #45
[  109.669707] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS ArchLinux 1.14.0-1 04/01/2014
[  109.671607] RIP: 0010:extent_io_tree_panic.isra.0+0x6/0x30 [btrfs]
[  109.672911] Code: 89 fe 48 c7 c7 20 0e aa c0 48 89 e5 e8 3a b9 ee dd 0f 0b be c0 13 00 00 48 c7 c7 48 0e aa c0 e8 d1 ff ff ff 0f 1f 44 00 00 55 <48> 8b 47 28 89 f1 49 c7 c0 70 0e aa c0 ba a9 02 00 00 48 c7 c6 00
[  109.676740] RSP: 0018:ffffb76c814fb948 EFLAGS: 00010282
[  109.677808] RAX: 00000000ffffffef RBX: 0000000001bfffff RCX: 0000000000000000
[  109.679271] RDX: ffffb76c814fb99c RSI: 00000000ffffffef RDI: 0000000000000000
[  109.680722] RBP: ffffb76c814fb9e0 R08: 0000000000000001 R09: 0000000000000001
[  109.682179] R10: ffffb76c814fb658 R11: 0000000000000000 R12: ffff9acac353e500
[  109.683629] R13: ffff9acac89a8228 R14: ffff9acac353e8c0 R15: 0000000002400000
[  109.685092] FS:  00007fb1f7dc3580(0000) GS:ffff9acb48c00000(0000) knlGS:0000000000000000
[  109.686749] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[  109.687927] CR2: 0000000000000028 CR3: 0000000103982000 CR4: 0000000000750ee0
[  109.689380] PKRU: 55555554
[  109.689935] Call Trace:
[  109.690438]  ? set_extent_bit.cold+0x30/0x98 [btrfs]
[  109.718452]  set_extent_bits_nowait+0x1d/0x20 [btrfs]
[  109.741357]  add_extent_mapping+0x1e0/0x2f0 [btrs]
[  109.761474]  read_one_chunk+0x33c/0x420 [btrfs]
[  109.781087]  btrfs_read_chunk_tree+0x6a4/0x870 [btrfs]
[  109.800486]  ? kvm_sched_clock_read+0x18/0x40
[  109.819669]  open_ctree+0xb32/0x1734 [btrfs]
[  109.838794]  ? bdi_register_va+0x1b/0x20
[  109.857812]  ? super_setup_bdi_name+0x79/0xd0
[  109.876880]  btrfs_mount_root.cold+0x12/0xeb [btrfs]
[  109.895860]  ? __kmalloc_track_caller+0x217/0x3b0
[  109.914731]  legacy_get_tree+0x34/0x60
[  109.933041]  vfs_get_tree+0x2d/0xc0
[  109.950757]  vfs_kern_mount.part.0+0x78/0xc0
[  109.968262]  vfs_kern_mount+0x13/0x20
[  109.984976]  btrfs_mount+0x11f/0x3c0 [btrfs]
[  110.001475]  ? kfree+0x5ff/0x670
[  110.017410]  ? __kmalloc_track_caller+0x217/0x3b0
[  110.033439]  legacy_get_tree+0x34/0x60
[  110.049000]  vfs_get_tree+0x2d/0xc0
[  110.064604]  path_mount+0x48c/0xd30
[  110.080199]  __x64_sys_mount+0x108/0x140
[  110.095918]  do_syscall_64+0x38/0x50
[  110.111366]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
[  110.126869] RIP: 0033:0x7fb1f7f42f6e
[  110.141818] Code: 48 8b 0d 05 0f 0c 00 f7 d8 64 89 01 48 83 c8 ff c3 66 2e 0f 1f 84 00 00 00 00 00 90 f3 0f 1e fa 49 89 ca b8 a5 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d d2 0e 0c 00 f7 d8 64 89 01 48
[  110.188250] RSP: 002b:00007fff152c68a8 EFLAGS: 00000246 ORIG_RAX: 00000000000000a5
[  110.220331] RAX: ffffffffffffffda RBX: 00007fb1f8067264 RCX: 00007fb1f7f42f6e
[  110.237474] RDX: 00005608be216360 RSI: 00005608be208690 RDI: 00005608be20f6c0
[  110.254718] RBP: 00005608be208440 R08: 0000000000000000 R09: 0000000000000001
[  110.272042] R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
[  110.288955] R13: 00005608be20f6c0 R14: 00005608be216360 R15: 00005608be208440
[  110.305969] Modules linked in:
[  110.458051] CR2: 0000000000000028
[  110.478548] ---[ end trace 3499c8e7baa57952 ]---
========================================================================

The image has a device extent whose end(29360127) is less than the start
(37748736). btrfs did warn but continued to insert the invalid sate
to device::alloc_state tree. Then tree_insert() returned -EEXIST
because of the duplicate end. extent_io_tree_panic() was to be called.
However, the @tree->inode is NULL in extent_io_tree_panic() and it
should be NULL here because that device::alloc_state io tree's member
@private is NULL by design.

Just pass @tree->fs_info as parameter to extent_io_tree_panic()
directly. Let it panic as expected at least.

Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=208929
Fixes: 05912a3c04eb ("btrfs: drop extent_io_ops::tree_fs_info callback")
Signed-off-by: Su Yue <l@damenly.su>

---
I don't know why insert_state() code only warns about the invalid state
and extent io operations are used in so many places. So just send the
simple patch.
---
 fs/btrfs/extent_io.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

Comments

Qu Wenruo Jan. 3, 2021, 6:52 a.m. UTC | #1
On 2021/1/3 下午1:01, Su Yue wrote:
> while mounting the poc image user-provided, kernel panics due to the
> NULL deference of @tree->inode.
> ========================================================================
> [  109.663024] BTRFS error: found node 12582912 29360127 on insert of 37748736 29360127
> [  109.663032] BUG: kernel NULL pointer dereference, address: 0000000000000028
> [  109.664494] #PF: supervisor read access in kernel mode
> [  109.665543] #PF: error_code(0x0000) - not-present page
> [  109.666598] PGD 0 P4D 0
> [  109.667119] Oops: 0000 [#1] PREEMPT SMP NOPTI
> [  109.668015] CPU: 14 PID: 641 Comm: mount Tainted: G        W  O      5.11.0-rc1-custom #45
> [  109.669707] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS ArchLinux 1.14.0-1 04/01/2014
> [  109.671607] RIP: 0010:extent_io_tree_panic.isra.0+0x6/0x30 [btrfs]
> [  109.672911] Code: 89 fe 48 c7 c7 20 0e aa c0 48 89 e5 e8 3a b9 ee dd 0f 0b be c0 13 00 00 48 c7 c7 48 0e aa c0 e8 d1 ff ff ff 0f 1f 44 00 00 55 <48> 8b 47 28 89 f1 49 c7 c0 70 0e aa c0 ba a9 02 00 00 48 c7 c6 00
> [  109.676740] RSP: 0018:ffffb76c814fb948 EFLAGS: 00010282
> [  109.677808] RAX: 00000000ffffffef RBX: 0000000001bfffff RCX: 0000000000000000
> [  109.679271] RDX: ffffb76c814fb99c RSI: 00000000ffffffef RDI: 0000000000000000
> [  109.680722] RBP: ffffb76c814fb9e0 R08: 0000000000000001 R09: 0000000000000001
> [  109.682179] R10: ffffb76c814fb658 R11: 0000000000000000 R12: ffff9acac353e500
> [  109.683629] R13: ffff9acac89a8228 R14: ffff9acac353e8c0 R15: 0000000002400000
> [  109.685092] FS:  00007fb1f7dc3580(0000) GS:ffff9acb48c00000(0000) knlGS:0000000000000000
> [  109.686749] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> [  109.687927] CR2: 0000000000000028 CR3: 0000000103982000 CR4: 0000000000750ee0
> [  109.689380] PKRU: 55555554
> [  109.689935] Call Trace:
> [  109.690438]  ? set_extent_bit.cold+0x30/0x98 [btrfs]
> [  109.718452]  set_extent_bits_nowait+0x1d/0x20 [btrfs]
> [  109.741357]  add_extent_mapping+0x1e0/0x2f0 [btrs]
> [  109.761474]  read_one_chunk+0x33c/0x420 [btrfs]
> [  109.781087]  btrfs_read_chunk_tree+0x6a4/0x870 [btrfs]
> [  109.800486]  ? kvm_sched_clock_read+0x18/0x40
> [  109.819669]  open_ctree+0xb32/0x1734 [btrfs]
> [  109.838794]  ? bdi_register_va+0x1b/0x20
> [  109.857812]  ? super_setup_bdi_name+0x79/0xd0
> [  109.876880]  btrfs_mount_root.cold+0x12/0xeb [btrfs]
> [  109.895860]  ? __kmalloc_track_caller+0x217/0x3b0
> [  109.914731]  legacy_get_tree+0x34/0x60
> [  109.933041]  vfs_get_tree+0x2d/0xc0
> [  109.950757]  vfs_kern_mount.part.0+0x78/0xc0
> [  109.968262]  vfs_kern_mount+0x13/0x20
> [  109.984976]  btrfs_mount+0x11f/0x3c0 [btrfs]
> [  110.001475]  ? kfree+0x5ff/0x670
> [  110.017410]  ? __kmalloc_track_caller+0x217/0x3b0
> [  110.033439]  legacy_get_tree+0x34/0x60
> [  110.049000]  vfs_get_tree+0x2d/0xc0
> [  110.064604]  path_mount+0x48c/0xd30
> [  110.080199]  __x64_sys_mount+0x108/0x140
> [  110.095918]  do_syscall_64+0x38/0x50
> [  110.111366]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
> [  110.126869] RIP: 0033:0x7fb1f7f42f6e
> [  110.141818] Code: 48 8b 0d 05 0f 0c 00 f7 d8 64 89 01 48 83 c8 ff c3 66 2e 0f 1f 84 00 00 00 00 00 90 f3 0f 1e fa 49 89 ca b8 a5 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d d2 0e 0c 00 f7 d8 64 89 01 48
> [  110.188250] RSP: 002b:00007fff152c68a8 EFLAGS: 00000246 ORIG_RAX: 00000000000000a5
> [  110.220331] RAX: ffffffffffffffda RBX: 00007fb1f8067264 RCX: 00007fb1f7f42f6e
> [  110.237474] RDX: 00005608be216360 RSI: 00005608be208690 RDI: 00005608be20f6c0
> [  110.254718] RBP: 00005608be208440 R08: 0000000000000000 R09: 0000000000000001
> [  110.272042] R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
> [  110.288955] R13: 00005608be20f6c0 R14: 00005608be216360 R15: 00005608be208440
> [  110.305969] Modules linked in:
> [  110.458051] CR2: 0000000000000028
> [  110.478548] ---[ end trace 3499c8e7baa57952 ]---
> ========================================================================
>
> The image has a device extent whose end(29360127) is less than the start
> (37748736). btrfs did warn but continued to insert the invalid sate
> to device::alloc_state tree. Then tree_insert() returned -EEXIST
> because of the duplicate end. extent_io_tree_panic() was to be called.
> However, the @tree->inode is NULL in extent_io_tree_panic() and it
> should be NULL here because that device::alloc_state io tree's member
> @private is NULL by design.
>
> Just pass @tree->fs_info as parameter to extent_io_tree_panic()
> directly. Let it panic as expected at least.
>
> Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=208929
> Fixes: 05912a3c04eb ("btrfs: drop extent_io_ops::tree_fs_info callback")
> Signed-off-by: Su Yue <l@damenly.su>

This looks OK as a simple fix.

Reviewed-by: Qu Wenruo <wqu@suse.com>

>
> ---
> I don't know why insert_state() code only warns about the invalid state
> and extent io operations are used in so many places. So just send the
> simple patch.

Although I'd prefer a more comprehensive fix, by doing overflow check on
device extent item to reject such tree block.

Thanks,
Qu

> ---
>   fs/btrfs/extent_io.c | 4 +---
>   1 file changed, 1 insertion(+), 3 deletions(-)
>
> diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
> index 6e3b72e63e42..c9cee458e001 100644
> --- a/fs/btrfs/extent_io.c
> +++ b/fs/btrfs/extent_io.c
> @@ -676,9 +676,7 @@ alloc_extent_state_atomic(struct extent_state *prealloc)
>
>   static void extent_io_tree_panic(struct extent_io_tree *tree, int err)
>   {
> -	struct inode *inode = tree->private_data;
> -
> -	btrfs_panic(btrfs_sb(inode->i_sb), err,
> +	btrfs_panic(tree->fs_info, err,
>   	"locking error: extent tree was modified by another thread while locked");
>   }
>
>
Su Yue Jan. 3, 2021, 9:33 a.m. UTC | #2
On Sun 03 Jan 2021 at 14:52, Qu Wenruo <quwenruo.btrfs@gmx.com> 
wrote:

> On 2021/1/3 下午1:01, Su Yue wrote:
>> while mounting the poc image user-provided, kernel panics due 
>> to the
>> NULL deference of @tree->inode.
>> ========================================================================
>> [  109.663024] BTRFS error: found node 12582912 29360127 on 
>> insert of 37748736 29360127
>> [  109.663032] BUG: kernel NULL pointer dereference, address: 
>> 0000000000000028
>> [  109.664494] #PF: supervisor read access in kernel mode
>> [  109.665543] #PF: error_code(0x0000) - not-present page
>> [  109.666598] PGD 0 P4D 0
>> [  109.667119] Oops: 0000 [#1] PREEMPT SMP NOPTI
>> [  109.668015] CPU: 14 PID: 641 Comm: mount Tainted: G        W 
>> O      5.11.0-rc1-custom #45
>> [  109.669707] Hardware name: QEMU Standard PC (i440FX + PIIX, 
>> 1996), BIOS ArchLinux 1.14.0-1 04/01/2014
>> [  109.671607] RIP: 0010:extent_io_tree_panic.isra.0+0x6/0x30 
>> [btrfs]
>> [  109.672911] Code: 89 fe 48 c7 c7 20 0e aa c0 48 89 e5 e8 3a 
>> b9 ee dd 0f 0b be c0 13 00 00 48 c7 c7 48 0e aa c0 e8 d1 ff ff 
>> ff 0f 1f 44 00 00 55 <48> 8b 47 28 89 f1 49 c7 c0 70 0e aa c0 
>> ba a9 02 00 00 48 c7 c6 00
>> [  109.676740] RSP: 0018:ffffb76c814fb948 EFLAGS: 00010282
>> [  109.677808] RAX: 00000000ffffffef RBX: 0000000001bfffff RCX: 
>> 0000000000000000
>> [  109.679271] RDX: ffffb76c814fb99c RSI: 00000000ffffffef RDI: 
>> 0000000000000000
>> [  109.680722] RBP: ffffb76c814fb9e0 R08: 0000000000000001 R09: 
>> 0000000000000001
>> [  109.682179] R10: ffffb76c814fb658 R11: 0000000000000000 R12: 
>> ffff9acac353e500
>> [  109.683629] R13: ffff9acac89a8228 R14: ffff9acac353e8c0 R15: 
>> 0000000002400000
>> [  109.685092] FS:  00007fb1f7dc3580(0000) 
>> GS:ffff9acb48c00000(0000) knlGS:0000000000000000
>> [  109.686749] CS:  0010 DS: 0000 ES: 0000 CR0: 
>> 0000000080050033
>> [  109.687927] CR2: 0000000000000028 CR3: 0000000103982000 CR4: 
>> 0000000000750ee0
>> [  109.689380] PKRU: 55555554
>> [  109.689935] Call Trace:
>> [  109.690438]  ? set_extent_bit.cold+0x30/0x98 [btrfs]
>> [  109.718452]  set_extent_bits_nowait+0x1d/0x20 [btrfs]
>> [  109.741357]  add_extent_mapping+0x1e0/0x2f0 [btrs]
>> [  109.761474]  read_one_chunk+0x33c/0x420 [btrfs]
>> [  109.781087]  btrfs_read_chunk_tree+0x6a4/0x870 [btrfs]
>> [  109.800486]  ? kvm_sched_clock_read+0x18/0x40
>> [  109.819669]  open_ctree+0xb32/0x1734 [btrfs]
>> [  109.838794]  ? bdi_register_va+0x1b/0x20
>> [  109.857812]  ? super_setup_bdi_name+0x79/0xd0
>> [  109.876880]  btrfs_mount_root.cold+0x12/0xeb [btrfs]
>> [  109.895860]  ? __kmalloc_track_caller+0x217/0x3b0
>> [  109.914731]  legacy_get_tree+0x34/0x60
>> [  109.933041]  vfs_get_tree+0x2d/0xc0
>> [  109.950757]  vfs_kern_mount.part.0+0x78/0xc0
>> [  109.968262]  vfs_kern_mount+0x13/0x20
>> [  109.984976]  btrfs_mount+0x11f/0x3c0 [btrfs]
>> [  110.001475]  ? kfree+0x5ff/0x670
>> [  110.017410]  ? __kmalloc_track_caller+0x217/0x3b0
>> [  110.033439]  legacy_get_tree+0x34/0x60
>> [  110.049000]  vfs_get_tree+0x2d/0xc0
>> [  110.064604]  path_mount+0x48c/0xd30
>> [  110.080199]  __x64_sys_mount+0x108/0x140
>> [  110.095918]  do_syscall_64+0x38/0x50
>> [  110.111366]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
>> [  110.126869] RIP: 0033:0x7fb1f7f42f6e
>> [  110.141818] Code: 48 8b 0d 05 0f 0c 00 f7 d8 64 89 01 48 83 
>> c8 ff c3 66 2e 0f 1f 84 00 00 00 00 00 90 f3 0f 1e fa 49 89 ca 
>> b8 a5 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d d2 
>> 0e 0c 00 f7 d8 64 89 01 48
>> [  110.188250] RSP: 002b:00007fff152c68a8 EFLAGS: 00000246 
>> ORIG_RAX: 00000000000000a5
>> [  110.220331] RAX: ffffffffffffffda RBX: 00007fb1f8067264 RCX: 
>> 00007fb1f7f42f6e
>> [  110.237474] RDX: 00005608be216360 RSI: 00005608be208690 RDI: 
>> 00005608be20f6c0
>> [  110.254718] RBP: 00005608be208440 R08: 0000000000000000 R09: 
>> 0000000000000001
>> [  110.272042] R10: 0000000000000000 R11: 0000000000000246 R12: 
>> 0000000000000000
>> [  110.288955] R13: 00005608be20f6c0 R14: 00005608be216360 R15: 
>> 00005608be208440
>> [  110.305969] Modules linked in:
>> [  110.458051] CR2: 0000000000000028
>> [  110.478548] ---[ end trace 3499c8e7baa57952 ]---
>> ========================================================================
>>
>> The image has a device extent whose end(29360127) is less than 
>> the start
>> (37748736). btrfs did warn but continued to insert the invalid 
>> sate
>> to device::alloc_state tree. Then tree_insert() returned 
>> -EEXIST
>> because of the duplicate end. extent_io_tree_panic() was to be 
>> called.
>> However, the @tree->inode is NULL in extent_io_tree_panic() and 
>> it
>> should be NULL here because that device::alloc_state io tree's 
>> member
>> @private is NULL by design.
>>
>> Just pass @tree->fs_info as parameter to extent_io_tree_panic()
>> directly. Let it panic as expected at least.
>>
>> Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=208929
>> Fixes: 05912a3c04eb ("btrfs: drop extent_io_ops::tree_fs_info 
>> callback")
>> Signed-off-by: Su Yue <l@damenly.su>
>
> This looks OK as a simple fix.
>
> Reviewed-by: Qu Wenruo <wqu@suse.com>
>
>>
>> ---
>> I don't know why insert_state() code only warns about the 
>> invalid state
>> and extent io operations are used in so many places. So just 
>> send the
>> simple patch.
>
> Although I'd prefer a more comprehensive fix, by doing overflow 
> check on
> device extent item to reject such tree block.
>
Sorry, wrong commit message of mine. It's overflow of one chunk 
item end.
The patch is just a fix to let btrfs reach at btrfs_panic() 
successfully.
Another fix about overflow is contained in the version 2 sent 
already.

Thanks.

> Thanks,
> Qu
>
>> ---
>>   fs/btrfs/extent_io.c | 4 +---
>>   1 file changed, 1 insertion(+), 3 deletions(-)
>>
>> diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
>> index 6e3b72e63e42..c9cee458e001 100644
>> --- a/fs/btrfs/extent_io.c
>> +++ b/fs/btrfs/extent_io.c
>> @@ -676,9 +676,7 @@ alloc_extent_state_atomic(struct 
>> extent_state *prealloc)
>>
>>   static void extent_io_tree_panic(struct extent_io_tree *tree, 
>>   int err)
>>   {
>> -	struct inode *inode = tree->private_data;
>> -
>> -	btrfs_panic(btrfs_sb(inode->i_sb), err,
>> +	btrfs_panic(tree->fs_info, err,
>>   	"locking error: extent tree was modified by another thread 
>>   while locked");
>>   }
>>
>>
diff mbox series

Patch

diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index 6e3b72e63e42..c9cee458e001 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -676,9 +676,7 @@  alloc_extent_state_atomic(struct extent_state *prealloc)
 
 static void extent_io_tree_panic(struct extent_io_tree *tree, int err)
 {
-	struct inode *inode = tree->private_data;
-
-	btrfs_panic(btrfs_sb(inode->i_sb), err,
+	btrfs_panic(tree->fs_info, err,
 	"locking error: extent tree was modified by another thread while locked");
 }