[RHEL7,COMMIT] ext4: protect ext4_valid_block_bitmap from hardcore corruption

Submitted by Konstantin Khorenko on April 2, 2018, 12:28 p.m.

Details

Message ID 201804021228.w32CSMtd023354@finist_ce7.work
State New
Series "ext4: protect ext4_valid_block_bitmap from hardcore corruption"
Headers show

Commit Message

Konstantin Khorenko April 2, 2018, 12:28 p.m.
The commit is pushed to "branch-rh7-3.10.0-693.21.1.vz7.46.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-693.21.1.vz7.46.2
------>
commit 07d08d6535d23b2b2f81d1569e5b4f2f40cbe4ca
Author: Dmitry Monakhov <dmonakhov@openvz.org>
Date:   Mon Apr 2 15:28:22 2018 +0300

    ext4: protect ext4_valid_block_bitmap from hardcore corruption
    
    Assert that on-disk data values are in a expacted range, otherwise
    later this result in accessing random memory regions like follows:
    
    general protection fault: 0000 [#1] SMP
    Modules linked in: binfmt_misc xt_CHECKSUM tun target_core_mod tcp_diag inet_diag ip6t_rpfilter ipt_REJECT nf_reject_ipv4 ip6t_REJECT nf_reject_ipv6 xt_conntrack ip_set nfnetlink ebtable_nat ebtable_broute ip6table_nat nf_conntrack_ipv6 nf_defrag_ipv6 nf_nat_ipv6 ip6table_mangle ip6table_raw iptable_nat nf_conntrack_ipv4 nf_defrag_ipv4 nf_nat_ipv4 nf_nat iptable_mangle iptable_raw ebtable_filter ebtables ip6table_filter ip6_tables iptable_filter fuse kvm_intel kvm irqbypass i2c_piix4 sg ppdev virtio_balloon joydev parport_pc pcspkr parport ip_vs nf_conntrack libcrc32c br_netfilter veth overlay ip6_vzprivnet ip6_vznetstat ip_vznetstat ip_vzprivnet vziolimit vzevent vzlist vzstat vznetstat vznetdev vzmon vzdev bridge nfsd auth_rpcgss pio_kaio pio_nfs nfs_acl lockd grace pio_direct pfmt_raw
     pfmt_ploop1 ploop ip_tables ext4 mbcache jbd2 sd_mod crc_t10dif crct10dif_generic sr_mod crct10dif_common cdrom ata_generic pata_acpi 8021q garp stp llc mrp virtio_net virtio_console virtio_scsi bochs_drm drm_kms_helper syscopyarea sysfillrect sysimgblt fb_sys_fops ttm ata_piix scsi_transport_iscsi drm floppy libata virtio_pci serio_raw i2c_core virtio_ring virtio sunrpc dm_mirror dm_region_hash dm_log dm_mod
    CPU: 2 PID: 6711 Comm: vzctl ve: 0 Not tainted 3.10.0-693.1.1.vz7.37.31 #1 37.31
    Hardware name: Virtuozzo KVM, BIOS 1.10.2-3.vz7.2 04/01/2014
    task: ffff88022e0c5050 ti: ffff88021fa48000 task.ti: ffff88021fa48000
    RIP: 0010:[<ffffffff813329d7>]  [<ffffffff813329d7>] find_next_zero_bit+0x37/0xf0
    RSP: 0018:ffff88021fa4bbc8  EFLAGS: 00010206
    RAX: 03fffffffffff200 RBX: ffff8801f6334800 RCX: 0000000000000000
    RDX: 0000000000000000 RSI: 0000000000000200 RDI: fffffffffffc8000
    RBP: ffff88021fa4bbc8 R08: 1fff880096664000 R09: ffff8801f6334800
    R10: ffff8800ae698660 R11: ffff88009c2981c0 R12: 0000000000000007
    R13: ffff8801f6331000 R14: ffff88020b2d1680 R15: fffffffffffc8000
    FS:  00007f637b9734c0(0000) GS:ffff88023fd00000(0000) knlGS:0000000000000000
    CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
    CR2: 00007f0330d3a4f0 CR3: 00000000ad516000 CR4: 00000000000006e0
    DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
    DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
    Stack:
     ffff88021fa4bc28 ffffffffc029359e 0000000000000000 ffff8800ae698660
     ffff88009c2981c0 ffff8801f6334800 0000000000000007 ffff8801f6331000
     ffff88009c2981c0 0000000000000007 ffff8801f6334800 ffff88020b2d1680
    Call Trace:
     [<ffffffffc029359e>] ext4_validate_block_bitmap+0x2de/0x3c0 [ext4]
     [<ffffffffc029413f>] ext4_read_block_bitmap_nowait+0x20f/0x5f0 [ext4]
     [<ffffffffc0294539>] ext4_read_block_bitmap+0x19/0x60 [ext4]
     [<ffffffffc02d8be6>] ext4_discard_preallocations+0x216/0x450 [ext4]
     [<ffffffffc02c02da>] ext4_clear_inode+0x2a/0xb0 [ext4]
     [<ffffffffc02a2020>] ext4_evict_inode+0x90/0x4f0 [ext4]
     [<ffffffff81238229>] evict+0xa9/0x180
     [<ffffffff8123833e>] dispose_list+0x3e/0x50
     [<ffffffff812391b6>] evict_inodes+0xd6/0x140
     [<ffffffff8121dee8>] generic_shutdown_super+0x48/0x100
     [<ffffffff8121e367>] kill_block_super+0x27/0x70
     [<ffffffffc02bb1ec>] ext4_kill_sb+0x4c/0x60 [ext4]
     [<ffffffff8121e899>] deactivate_locked_super+0x49/0x80
     [<ffffffff8121e916>] deactivate_super+0x46/0x60
     [<ffffffff8123bfff>] cleanup_mnt+0x3f/0x80
     [<ffffffff8123c092>] __cleanup_mnt+0x12/0x20
     [<ffffffff810af9ed>] __task_work_run+0xad/0xd0
     [<ffffffff8102aa84>] do_notify_resume+0x94/0xb0
     [<ffffffff816b18fd>] int_signal+0x12/0x17
    Code: 8a 00 00 00 48 89 d0 48 c1 e8 06 4c 8d 04 c7 48 89 d7 48 83 e7 c0 48 29 fe 83 e2 3f 75 76 48 f7 c6 c0 ff ff ff 0f 84 a7 00 00 00 <49> 8b 00 49 8d 50 08 48 83 f8 ff 74 1a eb 49 66 2e 0f 1f 84 00
    RIP  [<ffffffff813329d7>] find_next_zero_bit+0x37/0xf0
     RSP <ffff88021fa4bbc8>
    
    https://jira.sw.ru/browse/PSBM-78434
    TODO: add testcase to xfstests
    
    Signed-off-by: Dmitry Monakhov <dmonakhov@openvz.org>
---
 fs/ext4/balloc.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

Patch hide | download patch | download mbox

diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c
index 2763c597ccfe..267efdb7c1bf 100644
--- a/fs/ext4/balloc.c
+++ b/fs/ext4/balloc.c
@@ -341,20 +341,25 @@  static ext4_fsblk_t ext4_valid_block_bitmap(struct super_block *sb,
 	/* check whether block bitmap block number is set */
 	blk = ext4_block_bitmap(sb, desc);
 	offset = blk - group_first_block;
-	if (!ext4_test_bit(EXT4_B2C(sbi, offset), bh->b_data))
+	if (EXT4_B2C(sbi, offset) >= bh->b_size * 8 ||
+		!ext4_test_bit(EXT4_B2C(sbi, offset), bh->b_data))
 		/* bad block bitmap */
 		return blk;
 
 	/* check whether the inode bitmap block number is set */
 	blk = ext4_inode_bitmap(sb, desc);
 	offset = blk - group_first_block;
-	if (!ext4_test_bit(EXT4_B2C(sbi, offset), bh->b_data))
+	if (EXT4_B2C(sbi, offset) >= bh->b_size * 8 ||
+		!ext4_test_bit(EXT4_B2C(sbi, offset), bh->b_data))
 		/* bad block bitmap */
 		return blk;
 
 	/* check whether the inode table block number is set */
 	blk = ext4_inode_table(sb, desc);
 	offset = blk - group_first_block;
+	if (EXT4_B2C(sbi, offset + sbi->s_itb_per_group) >= bh->b_size * 8)
+		/* bad bitmap for inode tables */
+		return blk;
 	next_zero_bit = ext4_find_next_zero_bit(bh->b_data,
 			EXT4_B2C(sbi, offset + EXT4_SB(sb)->s_itb_per_group),
 			EXT4_B2C(sbi, offset));