Created attachment 276243 [details] The (compressed) crafted image which causes crash - Overview use-after-free in ext4_journal_get_write_access() when mounting and operating a crafted ext4 image - Reproduce I tested with both ext4 dev branch and upstream kernel. # mkdir mnt # mount -t ext4 242.img mnt # gcc -o poc poc.c # ./poc ./mnt - Kernel message (KASAN build) [ 539.561185] EXT4-fs (loop0): barriers disabled [ 539.567687] EXT4-fs (loop0): mounted filesystem with ordered data mode. Opts: (null) [ 550.378164] EXT4-fs error (device loop0): ext4_map_blocks:592: inode #14: block 1048576: comm poc: lblock 41 mapped to illegal pblock (length 1) [ 550.385965] EXT4-fs error (device loop0): ext4_clear_blocks:843: inode #14: comm poc: attempt to clear invalid blocks 1048576 len 1 [ 550.424114] ================================================================== [ 550.425590] BUG: KASAN: use-after-free in do_get_write_access+0x119/0x6a0 [ 550.426961] Read of size 8 at addr ffff8801e932cdc8 by task poc/1472 [ 550.428567] CPU: 1 PID: 1472 Comm: poc Not tainted 4.17.0-rc5+ #6 [ 550.428570] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014 [ 550.428572] Call Trace: [ 550.428584] dump_stack+0x7b/0xb5 [ 550.428595] print_address_description+0x70/0x290 [ 550.428602] kasan_report+0x291/0x390 [ 550.428607] ? do_get_write_access+0x119/0x6a0 [ 550.428613] __asan_load8+0x54/0x90 [ 550.428619] do_get_write_access+0x119/0x6a0 [ 550.428626] jbd2_journal_get_write_access+0x5f/0x80 [ 550.428636] __ext4_journal_get_write_access+0x3b/0x80 [ 550.428646] ext4_xattr_release_block+0x74/0x3f0 [ 550.428654] ext4_xattr_delete_inode+0x431/0x700 [ 550.428662] ? ext4_xattr_set_credits+0xf0/0xf0 [ 550.428672] ? ext4_punch_hole+0x680/0x680 [ 550.428679] ? __ext4_journal_start_sb+0x89/0x180 [ 550.428685] ext4_evict_inode+0x4ba/0x9b0 [ 550.428692] ? ext4_da_write_begin+0x610/0x610 [ 550.428702] evict+0x16f/0x290 [ 550.428708] iput+0x280/0x300 [ 550.428716] do_unlinkat+0x2c6/0x440 [ 550.428723] ? __ia32_sys_rmdir+0x30/0x30 [ 550.428730] ? kasan_unpoison_shadow+0x36/0x50 [ 550.428736] ? kasan_kmalloc+0xad/0xe0 [ 550.428742] ? kasan_check_write+0x14/0x20 [ 550.428750] ? strncpy_from_user+0xa8/0x1c0 [ 550.428757] ? getname_flags+0x110/0x2c0 [ 550.428764] __x64_sys_unlink+0x30/0x40 [ 550.428771] do_syscall_64+0x78/0x170 [ 550.428777] entry_SYSCALL_64_after_hwframe+0x44/0xa9 [ 550.428782] RIP: 0033:0x7f4490535a97 [ 550.428785] RSP: 002b:00007ffc3e1ab708 EFLAGS: 00000286 ORIG_RAX: 0000000000000057 [ 550.428791] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f4490535a97 [ 550.428794] RDX: 0000000000000001 RSI: 0000000000000001 RDI: 00000000011de0a0 [ 550.428798] RBP: 00007ffc3e1ab870 R08: 0000000000000003 R09: 0000000000000000 [ 550.428801] R10: 00000000000001d4 R11: 0000000000000286 R12: 0000000000400c20 [ 550.428804] R13: 00007ffc3e1ab970 R14: 0000000000000000 R15: 0000000000000000 [ 550.429132] Allocated by task 1239: [ 550.429843] save_stack+0x46/0xd0 [ 550.429849] kasan_kmalloc+0xad/0xe0 [ 550.429854] kasan_slab_alloc+0x11/0x20 [ 550.429859] kmem_cache_alloc+0xd1/0x1e0 [ 550.429864] getname_flags+0x76/0x2c0 [ 550.429870] user_path_at_empty+0x23/0x40 [ 550.429877] vfs_statx+0xce/0x160 [ 550.429883] __do_sys_newlstat+0x8c/0xe0 [ 550.429889] __x64_sys_newlstat+0x31/0x40 [ 550.429894] do_syscall_64+0x78/0x170 [ 550.429899] entry_SYSCALL_64_after_hwframe+0x44/0xa9 [ 550.430221] Freed by task 1239: [ 550.430864] save_stack+0x46/0xd0 [ 550.430869] __kasan_slab_free+0x13c/0x1a0 [ 550.430875] kasan_slab_free+0xe/0x10 [ 550.430879] kmem_cache_free+0x89/0x1e0 [ 550.430884] putname+0x80/0x90 [ 550.430889] filename_lookup+0x191/0x280 [ 550.430894] user_path_at_empty+0x36/0x40 [ 550.430899] vfs_statx+0xce/0x160 [ 550.430905] __do_sys_newlstat+0x8c/0xe0 [ 550.430911] __x64_sys_newlstat+0x31/0x40 [ 550.430916] do_syscall_64+0x78/0x170 [ 550.430921] entry_SYSCALL_64_after_hwframe+0x44/0xa9 [ 550.431244] The buggy address belongs to the object at ffff8801e932c400 which belongs to the cache names_cache of size 4096 [ 550.433730] The buggy address is located 2504 bytes inside of 4096-byte region [ffff8801e932c400, ffff8801e932d400) [ 550.436081] The buggy address belongs to the page: [ 550.437063] page:ffffea0007a4ca00 count:1 mapcount:0 mapping:0000000000000000 index:0x0 compound_mapcount: 0 [ 550.439002] flags: 0x2ffff0000008100(slab|head) [ 550.439931] raw: 02ffff0000008100 0000000000000000 0000000000000000 0000000100070007 [ 550.441459] raw: dead000000000100 dead000000000200 ffff8801f6da0380 0000000000000000 [ 550.442989] page dumped because: kasan: bad access detected [ 550.444423] Memory state around the buggy address: [ 550.445376] ffff8801e932cc80: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 550.446832] ffff8801e932cd00: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 550.448278] >ffff8801e932cd80: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 550.449704] ^ [ 550.450813] ffff8801e932ce00: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 550.452250] ffff8801e932ce80: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 550.453675] ================================================================== [ 550.455102] Disabling lock debugging due to kernel taint [ 550.455584] BUG: unable to handle kernel paging request at 0000000074726f6a [ 550.457030] PGD 80000001f0a56067 P4D 80000001f0a56067 PUD 0 [ 550.458162] Oops: 0000 [#1] SMP KASAN PTI [ 550.458968] 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 mac_hid soundcore ib_iser rdma_cm iw_cm ib_cm ib_core iscsi_tcp libiscsi_tcp libiscsi scsi_transport_iscsi autofs4 raid10 raid456 async_raid6_recov async_memcpy async_pq async_xor async_tx raid1 raid0 multipath linear 8139too qxl crct10dif_pclmul crc32_pclmul drm_kms_helper aesni_intel syscopyarea sysfillrect sysimgblt fb_sys_fops ttm aes_x86_64 crypto_simd drm cryptd glue_helper floppy 8139cp mii pata_acpi [ 550.469505] CPU: 1 PID: 1472 Comm: poc Tainted: G B 4.17.0-rc5+ #6 [ 550.470986] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014 [ 550.472874] RIP: 0010:__find_get_block+0x192/0x400 [ 550.473838] RSP: 0018:ffff8801dec47958 EFLAGS: 00010286 [ 550.474883] RAX: 0000000000000000 RBX: 0000000000000000 RCX: ffffffffb94373c2 [ 550.476310] RDX: 0000000000000000 RSI: 0000000000000008 RDI: 0000000074726f6a [ 550.477748] RBP: ffff8801dec479a8 R08: ffffed003bde1c30 R09: ffffed003bde1c30 [ 550.479162] R10: 0000000000000001 R11: ffffed003bde1c2f R12: 00000000866efaf8 [ 550.480589] R13: 0000000000000010 R14: 0000000074726f62 R15: ffff8801eb4b61f8 [ 550.482005] FS: 00007f4490a22700(0000) GS:ffff8801f7100000(0000) knlGS:0000000000000000 [ 550.483606] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 550.484771] CR2: 0000000074726f6a CR3: 00000001f0c14000 CR4: 00000000000006e0 [ 550.486195] Call Trace: [ 550.486721] ? kasan_check_write+0x14/0x20 [ 550.487551] ? _raw_spin_lock+0x17/0x40 [ 550.488344] jbd2_journal_cancel_revoke+0x12b/0x170 [ 550.489326] do_get_write_access+0x5ac/0x6a0 [ 550.490188] jbd2_journal_get_write_access+0x5f/0x80 [ 550.491185] __ext4_journal_get_write_access+0x3b/0x80 [ 550.492232] ext4_xattr_release_block+0x74/0x3f0 [ 550.493164] ext4_xattr_delete_inode+0x431/0x700 [ 550.494095] ? ext4_xattr_set_credits+0xf0/0xf0 [ 550.495010] ? ext4_punch_hole+0x680/0x680 [ 550.495838] ? __ext4_journal_start_sb+0x89/0x180 [ 550.496813] ext4_evict_inode+0x4ba/0x9b0 [ 550.497629] ? ext4_da_write_begin+0x610/0x610 [ 550.498530] evict+0x16f/0x290 [ 550.499161] iput+0x280/0x300 [ 550.499774] do_unlinkat+0x2c6/0x440 [ 550.500520] ? __ia32_sys_rmdir+0x30/0x30 [ 550.501336] ? kasan_unpoison_shadow+0x36/0x50 [ 550.502238] ? kasan_kmalloc+0xad/0xe0 [ 550.503004] ? kasan_check_write+0x14/0x20 [ 550.503837] ? strncpy_from_user+0xa8/0x1c0 [ 550.504699] ? getname_flags+0x110/0x2c0 [ 550.505500] __x64_sys_unlink+0x30/0x40 [ 550.506282] do_syscall_64+0x78/0x170 [ 550.507051] entry_SYSCALL_64_after_hwframe+0x44/0xa9 [ 550.508078] RIP: 0033:0x7f4490535a97 [ 550.508807] RSP: 002b:00007ffc3e1ab708 EFLAGS: 00000286 ORIG_RAX: 0000000000000057 [ 550.510322] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f4490535a97 [ 550.511746] RDX: 0000000000000001 RSI: 0000000000000001 RDI: 00000000011de0a0 [ 550.516314] RBP: 00007ffc3e1ab870 R08: 0000000000000003 R09: 0000000000000000 [ 550.517759] R10: 00000000000001d4 R11: 0000000000000286 R12: 0000000000400c20 [ 550.519177] R13: 00007ffc3e1ab970 R14: 0000000000000000 R15: 0000000000000000 [ 550.520608] Code: 48 89 de e8 e1 bd fc 00 4c 89 e7 e8 c9 bd f5 ff 4d 8b 2c 24 4d 85 ed 75 d4 e9 6f ff ff ff 4c 8b 75 d0 49 8d 7e 08 e8 ae bd f5 ff <49> 8b 46 08 48 8d 78 30 49 89 c6 48 89 45 b8 e8 9a bd f5 ff 4c [ 550.524384] RIP: __find_get_block+0x192/0x400 RSP: ffff8801dec47958 [ 550.525637] CR2: 0000000074726f6a [ 550.526392] ---[ end trace f568c098f25eca21 ]--- - Brief analysis UAF location: https://elixir.bootlin.com/linux/v4.17-rc5/source/fs/jbd2/transaction.c#L869 if (buffer_dirty(bh)) { bh is already freed when executing this line. Later in the same function, kernel executes jbd2_journal_cancel_revoke(). See https://elixir.bootlin.com/linux/v4.17-rc5/source/fs/jbd2/revoke.c#L459 bh2 = __find_get_block(bh->b_bdev, bh->b_blocknr, bh->b_size); bh is freed, which makes bh->b_bdev have invalid value leading to crash. - Credit Found by Wen Xu from SSLab, Gatech.
Created attachment 276245 [details] poc.c
This is a dup of #200001. With "ext4: always verify the magic number in xattr blocks" applied, I'm no longer seeing crashes and instead we get the following: root@kvm-xfstests:~# /vdb/poc/do-869 [ 82.775704] EXT4-fs (loop0): barriers disabled [ 82.778168] EXT4-fs (loop0): mounted filesystem with ordered data mode. Opts: (null) [ 82.786417] EXT4-fs error (device loop0): ext4_get_branch:171: inode #14: block 1048576: comm poc-199869: invalid block [ 82.790189] EXT4-fs error (device loop0): ext4_map_blocks:592: inode #14: block 1048576: comm poc-199869: lblock 41 mapped to illegal pblock (length 1) [ 82.795350] EXT4-fs error (device loop0): ext4_clear_blocks:849: inode #14: comm poc-199869: attempt to clear invalid blocks 1048576 len 1 [ 82.811524] EXT4-fs error (device loop0): ext4_xattr_block_get:533: inode #14: comm poc-199869: corrupted xattr block 97 [ 82.813991] EXT4-fs error (device loop0): ext4_xattr_block_get:533: inode #14: comm poc-199869: corrupted xattr block 97 [ 82.817136] EXT4-fs error (device loop0): ext4_xattr_block_get:533: inode #14: comm poc-199869: corrupted xattr block 97 [ 82.819888] EXT4-fs error (device loop0): ext4_xattr_block_get:533: inode #14: comm poc-199869: corrupted xattr block 97 [ 82.822414] EXT4-fs error (device loop0): ext4_xattr_block_get:533: inode #14: comm poc-199869: corrupted xattr block 97 [ 82.824712] EXT4-fs error (device loop0): ext4_xattr_block_get:533: inode #14: comm poc-199869: corrupted xattr block 97 [ 82.826988] EXT4-fs error (device loop0): ext4_xattr_block_get:533: inode #14: comm poc-199869: corrupted xattr block 97 [ 82.829463] EXT4-fs warning (device loop0): ext4_evict_inode:302: xattr delete (err -117) *** This bug has been marked as a duplicate of bug 200001 ***