Bug 199865

Summary: out-of-bound write in ext4_init_block_bitmap() when mounting and operating a crafted ext4 image
Product: File System Reporter: Wen Xu (wen.xu)
Component: ext4Assignee: fs_ext4 (fs_ext4)
Status: RESOLVED CODE_FIX    
Severity: normal CC: tytso, wen.xu
Priority: P1    
Hardware: All   
OS: Linux   
Kernel Version: 4.17 Subsystem:
Regression: No Bisected commit-id:
Attachments: The (compressed) crafted image which causes crash
poc.c

Description Wen Xu 2018-05-28 19:44:06 UTC
- Overview
out-of-bound write in ext4_init_block_bitmap() when mounting and operating a crafted ext4 image

- Reproduce
# mkdir mnt
# mount -t ext4 53.img mnt
# gcc -o poc poc.c
# ./poc ./mnt

- Kernel message
[  182.079600] EXT4-fs (loop0): mounted filesystem without journal. Opts: (null)
[  195.423650] BUG: unable to handle kernel paging request at ffff8801147bf000
[  195.425469] PGD 8af40067 P4D 8af40067 PUD 8af43067 PMD 1146e0063 PTE 80000001147bf061
[  195.427263] Oops: 0003 [#1] SMP KASAN PTI
[  195.428225] Modules linked in: snd_hda_codec_generic snd_hda_intel snd_hda_codec snd_hwdep snd_hda_core snd_pcm snd_timer snd i2c_piix4 soundcore mac_hid ib_iser rdma_cm iw_cm ib_cm ib_core iscsi_tcp libiscsi_tcp libiscsi scsi_transport_iscsi autofs4 btrfs zstd_decompress zstd_compress xxhash raid10 raid456 async_raid6_recov async_memcpy async_pq async_xor async_tx xor raid6_pq raid1 raid0 multipath linear 8139too qxl drm_kms_helper syscopyarea sysfillrect sysimgblt fb_sys_fops ttm drm crct10dif_pclmul crc32_pclmul aesni_intel aes_x86_64 crypto_simd cryptd glue_helper 8139cp mii floppy pata_acpi
[  195.439795] CPU: 0 PID: 1271 Comm: a.out Not tainted 4.17.0-rc4+ #4
[  195.441172] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014
[  195.443268] RIP: 0010:ext4_read_block_bitmap_nowait+0x571/0xa40
[  195.447872] RSP: 0018:ffff8801080ff0b0 EFLAGS: 00010206
[  195.449041] RAX: 000000000009c000 RBX: ffff8801139db300 RCX: 0000000000000000
[  195.450630] RDX: 0000000000000007 RSI: dffffc0000000000 RDI: ffff8801139dbbd4
[  195.452241] RBP: ffff8801080ff140 R08: ffffed00228f5780 R09: ffff8801147ab800
[  195.453817] R10: 0000000000000080 R11: ffffed00228f577f R12: ffff8801147ab800
[  195.455405] R13: ffff8801147ab800 R14: ffff8801139dbb80 R15: 000000000009c001
[  195.457013] FS:  00007f030c6c8700(0000) GS:ffff88011b000000(0000) knlGS:0000000000000000
[  195.458825] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[  195.460101] CR2: ffff8801147bf000 CR3: 000000010af9e000 CR4: 00000000000006f0
[  195.461667] Call Trace:
[  195.462232]  ext4_mb_init_cache+0x312/0xbd0
[  195.463186]  ? ext4_mb_generate_from_pa+0x220/0x220
[  195.464298]  ? pagecache_get_page+0xca/0x300
[  195.465269]  ext4_mb_init_group+0x255/0x380
[  195.466225]  ext4_mb_good_group+0x252/0x260
[  195.467178]  ext4_mb_regular_allocator+0x5ae/0x840
[  195.468284]  ? ext4_mb_complex_scan_group+0x4b0/0x4b0
[  195.469409]  ? kasan_kmalloc+0xad/0xe0
[  195.470267]  ? ext4_mb_use_preallocated.constprop.28+0x22/0x440
[  195.471571]  ext4_mb_new_blocks+0xc8c/0x15e0
[  195.472521]  ? ext4_xattr_block_find.isra.22+0x2c0/0x2c0
[  195.473715]  ? strlen+0x25/0x40
[  195.474428]  ext4_new_meta_blocks+0x1f9/0x210
[  195.475417]  ? ext4_should_retry_alloc+0xd0/0xd0
[  195.476483]  ? dquot_initialize_needed+0x4c/0x110
[  195.477566]  ext4_xattr_block_set+0xa7e/0x1820
[  195.478578]  ? ext4_xattr_inode_array_free+0x60/0x60
[  195.479671]  ? _cond_resched+0x1a/0x50
[  195.480532]  ? __getblk_gfp+0x31/0x3f0
[  195.481370]  ? __ext4_get_inode_loc+0x231/0x680
[  195.482369]  ? ext4_xattr_ibody_set+0x58/0x120
[  195.483323]  ext4_xattr_set_handle+0x64f/0x920
[  195.484296]  ? ext4_xattr_block_set+0x1820/0x1820
[  195.485343]  ? __dquot_initialize+0xeb/0x5d0
[  195.486312]  ? dqget+0x690/0x690
[  195.487030]  ? _cond_resched+0x1a/0x50
[  195.487886]  ? ext4_journal_check_start+0x77/0xd0
[  195.488926]  ? ext4_xattr_user_list+0x50/0x50
[  195.489892]  ext4_xattr_set+0x114/0x200
[  195.490754]  ? ext4_xattr_set_handle+0x920/0x920
[  195.491811]  ? legitimize_path.isra.28+0x61/0xa0
[  195.492834]  ? strncmp+0x3d/0xc0
[  195.493555]  ext4_xattr_user_set+0x71/0x80
[  195.494495]  __vfs_setxattr+0x7c/0xa0
[  195.495313]  __vfs_setxattr_noperm+0x8d/0x200
[  195.496301]  vfs_setxattr+0xb3/0xc0
[  195.497089]  setxattr+0x1b3/0x260
[  195.497848]  ? vfs_setxattr+0xc0/0xc0
[  195.498666]  ? filename_lookup+0x191/0x280
[  195.499596]  ? filename_parentat+0x2b0/0x2b0
[  195.500547]  ? kasan_kmalloc+0xad/0xe0
[  195.501406]  ? kasan_check_write+0x14/0x20
[  195.502324]  ? strncpy_from_user+0xa8/0x1c0
[  195.503260]  ? __mnt_is_readonly.part.13+0x23/0x30
[  195.504325]  ? __mnt_want_write+0x9d/0xb0
[  195.505229]  path_setxattr+0x134/0x170
[  195.506066]  ? setxattr+0x260/0x260
[  195.506869]  __x64_sys_setxattr+0x6d/0x80
[  195.507782]  do_syscall_64+0x78/0x170
[  195.508599]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
[  195.509710] RIP: 0033:0x7f030c1e91fa
[  195.510507] RSP: 002b:00007ffe82cc4778 EFLAGS: 00000206 ORIG_RAX: 00000000000000bc
[  195.512183] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f030c1e91fa
[  195.513756] RDX: 00007ffe82cc4860 RSI: 0000000000401498 RDI: 00000000020290c0
[  195.515310] RBP: 00007ffe82cc48e0 R08: 0000000000000001 R09: 0000000000000001
[  195.516893] R10: 0000000000000071 R11: 0000000000000206 R12: 0000000000400c20
[  195.518450] R13: 00007ffe82cc49e0 R14: 0000000000000000 R15: 0000000000000000
[  195.520042] Code: ff 48 8b 7d a0 e8 c0 5c ed ff 48 8b 45 90 48 8b 7d 88 4c 8b 60 28 e8 af 5b ed ff 4c 89 f8 48 2b 45 98 41 8b 4e 54 48 d3 e8 48 98 <49> 0f ab 04 24 eb 9b 49 c7 c4 8b ff ff ff e9 65 fb ff ff 49 8b
[  195.524186] RIP: ext4_read_block_bitmap_nowait+0x571/0xa40 RSP: ffff8801080ff0b0
[  195.525803] CR2: ffff8801147bf000
[  195.526566] ---[ end trace 4883307b4e16d878 ]---

- Reason
https://elixir.bootlin.com/linux/v4.17-rc5/source/fs/ext4/balloc.c#L236

	tmp = ext4_inode_table(sb, gdp);
	for (; tmp < ext4_inode_table(sb, gdp) +
		     sbi->s_itb_per_group; tmp++) {
		if (!flex_bg || ext4_block_in_group(sb, tmp, block_group))
			ext4_set_bit(EXT4_B2C(sbi, tmp - start), bh->b_data);
	}

out-of-bound accesses happen when setting block bitmap for inode table. tmp - start exceeds the boundary of bh->b_data.

Found by Wen Xu from SSLab, Gatech.
Comment 1 Wen Xu 2018-05-28 19:44:58 UTC
Created attachment 276237 [details]
The (compressed) crafted image which causes crash
Comment 2 Wen Xu 2018-05-28 19:45:13 UTC
Created attachment 276239 [details]
poc.c
Comment 3 Theodore Tso 2018-06-13 15:42:31 UTC
This is no longer replicating on the tip of my ext4.git tree:

# /vdb/poc/do-865
[   25.099634] attempt to access beyond end of device
[   25.101223] loop0: rw=0, want=255510, limit=16384
[   25.103249] EXT2-fs (loop0): error: ext2_readdir: bad page in #2
[   25.105162] EXT2-fs (loop0): error: remounting filesystem read-only
[   25.108074] attempt to access beyond end of device
[   25.109576] loop0: rw=0, want=255510, limit=16384
Comment 4 Theodore Tso 2018-06-13 19:59:06 UTC
Never mind; I see my mistake; I needed to force the use of ext4.  The file system doesn't trigger problems on ext2.
Comment 6 Theodore Tso 2018-06-14 05:12:51 UTC
Oops, ignore comment #5; this erroneously posted to the wrong bug.

Bug #199865 is triggered by the fact block group descriptors were corrupted due to the fact that one of the allocation bitmaps overlapped with the block group descriptors.  Then when a block bitmap needed to be initialized, the corrupted block group descriptors resulted in the byte before the bitmap getting zero'ed.

This will be fixed via these patches:

    ext4: always check block group bounds in ext4_init_block_bitmap()
    ext4: make sure bitmaps and the inode table don't overlap with bg descriptors
Comment 9 Theodore Tso 2018-07-02 16:02:08 UTC
This has been assigned CVE-2018-10878

Red Hat Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1596802