Bug 200401

Summary: Another buffer overrun in ext4_xattr_set_entry() when operating a corrupted 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.18 Subsystem:
Regression: No Bisected commit-id:
Attachments: The (compressed) crafted image which causes crash
poc.c

Description Wen Xu 2018-07-03 23:41:05 UTC
Created attachment 277155 [details]
The (compressed) crafted image which causes crash

- Reproduce (tested w/ dev branch)
# mkdir mnt
# mount -t ext4 final.img mnt
# gcc -o poc poc.c
# ./poc ./mnt

- Kernel message
[  211.941955] ==================================================================
[  211.943725] BUG: KASAN: out-of-bounds in ext4_xattr_set_entry+0x14e2/0x1990
[  211.945175] Read of size 18446744073709551604 at addr ffff8801cf4bc3f8 by task poc/1379
[  211.946854]
[  211.947737]
[  211.948087] The buggy address belongs to the page:
[  211.949138] page:ffffea00073d2f00 count:2 mapcount:0 mapping:ffff8801e6f28610 index:0x11
[  211.950849] flags: 0x2ffff0000001074(referenced|dirty|lru|active|private)
[  211.952308] raw: 02ffff0000001074 ffff8801e6f28610 0000000000000011 00000002ffffffff
[  211.953921] raw: ffffea00073d2ee0 ffffea00073d2f60 ffff8801dc030c78 ffff8801e5212200
[  211.955548] page dumped because: kasan: bad access detected
[  211.956736] page->mem_cgroup:ffff8801e5212200
[  211.957673]
[  211.958021] Memory state around the buggy address:
[  211.959046]  ffff8801cf4bc280: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[  211.960581]  ffff8801cf4bc300: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[  211.962096] >ffff8801cf4bc380: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[  211.963637]                                                                 ^
[  211.965106]  ffff8801cf4bc400: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[  211.966630]  ffff8801cf4bc480: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[  211.968154] ==================================================================
[  212.070820] systemd[1]: segfault at 5593546f5010 ip 00005593546f5010 sp 00007ffd3ee613c0 error 15
[  212.073130] systemd[1]: segfault at 8f8 ip 00007f997d5f266a sp 00007ffd3ee60cb0 error 4 in libc-2.23.so[7f997d575000+1c0000]
[  212.165887] BUG: unable to handle kernel paging request at ffff8801da800000
[  212.167411] PGD ef40067 P4D ef40067 PUD ef47067 PMD 1da8e5063 PTE 80000001da800061
[  212.169039] Oops: 0003 [#1] SMP KASAN PTI
[  212.169923] Modules linked in: snd_hda_codec_generic snd_hda_intel snd_hda_codec snd_hwdep snd_hda_core snd_pcm snd_timer snd soundcore i2c_piix4 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 crct10dif_pclmul sysfillrect sysimgblt fb_sys_fops crc32_pclmul ttm drm aesni_intel aes_x86_64 crypto_simd cryptd glue_helper 8139cp mii pata_acpi floppy
[  212.181267] CPU: 1 PID: 1379 Comm: poc Tainted: G    B             4.17.0-rc4+ #9
[  212.182814] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014
[  212.184864] RIP: 0010:__memmove+0x5b/0x1a0
[  212.185575] request_module: kmod_concurrent_max (0) close to 0 (max_modprobes: 50), for module binfmt-003e, throttling...
[  212.185756] RSP: 0018:ffff8801f283f0e8 EFLAGS: 00010286
[  212.189141] RAX: ffff8801cf4bc3e8 RBX: fffffffffffffff4 RCX: ffffffffa0556472
[  212.190632] RDX: fffffffff4cbc3b4 RSI: ffff8801da800018 RDI: ffff8801da7fffe8
[  212.192169] RBP: ffff8801f283f108 R08: 0000000000000000 R09: 0000000000000000
[  212.193679] R10: 0000000000000000 R11: 0000441f0f66ffff R12: ffff8801cf4bc3e8
[  212.195185] R13: ffff8801cf4bc3f8 R14: ffff8801e0646d80 R15: ffff8801f283f520
[  212.196683] FS:  00007f82fc326700(0000) GS:ffff8801f7100000(0000) knlGS:0000000000000000
[  212.198365] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[  212.199580] CR2: ffff8801da800000 CR3: 00000001f37ac000 CR4: 00000000000006e0
[  212.201120] Call Trace:
[  212.201656]  ? memmove+0x45/0x50
[  212.202351]  ext4_xattr_set_entry+0x14e2/0x1990
[  212.203351]  ? save_stack+0x46/0xd0
[  212.204102]  ? kasan_kmalloc+0xad/0xe0
[  212.204896]  ? __kmalloc+0x11f/0x240
[  212.205672]  ? ext4_expand_extra_isize_ea+0x532/0xd20
[  212.206770]  ? __ext4_expand_extra_isize+0xd4/0x100
[  212.207863]  ? ext4_mark_inode_dirty+0x3a8/0x3d0
[  212.208869]  ? syscall_return_slowpath+0x80/0xd0
[  212.209851]  ? ext4_xattr_inode_get+0x430/0x430
[  212.210809]  ? __find_get_block+0x106/0x400
[  212.211724]  ? is_bpf_text_address+0xe/0x20
[  212.212644]  ? kernel_text_address+0xd6/0xf0
[  212.213550]  ? _cond_resched+0x1a/0x50
[  212.214347]  ? __getblk_gfp+0x31/0x3f0
[  212.215169]  ? kasan_check_write+0x14/0x20
[  212.216051]  ? _raw_spin_lock_irqsave+0x2a/0x60
[  212.217019]  ? strlen+0xf/0x40
[  212.217690]  ? xattr_find_entry+0x5b/0x140
[  212.218600]  ext4_xattr_ibody_set+0x58/0x120
[  212.219529]  ext4_expand_extra_isize_ea+0x897/0xd20
[  212.220578]  ? ext4_xattr_set+0x200/0x200
[  212.221483]  ? __getblk_gfp+0x31/0x3f0
[  212.222317]  ? mark_page_accessed+0x133/0x200
[  212.223428]  ? kasan_check_write+0x14/0x20
[  212.224306]  __ext4_expand_extra_isize+0xd4/0x100
[  212.225292]  ext4_mark_inode_dirty+0x3a8/0x3d0
[  212.226260]  ? ext4_expand_extra_isize+0x2e0/0x2e0
[  212.227298]  ? kasan_check_write+0x14/0x20
[  212.228180]  ? ext4_add_dirent_to_inline.isra.12+0x206/0x230
[  212.229389]  ? ext4_update_inline_data+0x340/0x340
[  212.230410]  ext4_try_add_inline_entry+0x16f/0x330
[  212.231686]  ? ext4_da_write_inline_data_end+0x110/0x110
[  212.232750]  ext4_add_entry+0x1d9/0x570
[  212.233536]  ? make_indexed_dir+0x940/0x940
[  212.234391]  ? jbd2__journal_start+0x19d/0x300
[  212.235401]  ? __ext4_journal_start_sb+0x89/0x180
[  212.236364]  ext4_rename+0xb01/0xd00
[  212.237109]  ? __x64_sys_rename+0x3b/0x50
[  212.237933]  ? ext4_tmpfile+0x2d0/0x2d0
[  212.238990]  ? ext4_find_entry+0x17d/0x770
[  212.239852]  ? legitimize_path.isra.28+0x61/0xa0
[  212.240835]  ? ext4_dx_find_entry+0x2c0/0x2c0
[  212.241755]  ? kasan_check_write+0x14/0x20
[  212.242613]  ? lockref_get+0xc2/0x140
[  212.243386]  ext4_rename2+0xa6/0x100
[  212.244122]  vfs_rename+0xaa5/0xde0
[  212.244838]  ? memcg_kmem_put_cache+0x55/0xa0
[  212.245719]  ? path_mountpoint+0x5b0/0x5b0
[  212.246551]  ? kasan_check_write+0x14/0x20
[  212.247403]  ? security_path_rename+0xcb/0x130
[  212.248302]  do_renameat2+0x7d2/0x860
[  212.249049]  ? user_path_create+0x40/0x40
[  212.249866]  ? lockref_put_return+0xd0/0x140
[  212.250731]  ? memset+0x31/0x40
[  212.251398]  ? handle_mm_fault+0x24b/0x380
[  212.252233]  ? __fput+0x28d/0x380
[  212.252916]  ? mm_fault_error+0x1f0/0x1f0
[  212.253738]  ? task_work_run+0x4d/0xf0
[  212.254506]  __x64_sys_rename+0x3b/0x50
[  212.255312]  do_syscall_64+0x78/0x170
[  212.256070]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
[  212.257095] RIP: 0033:0x7f82fbdac367
[  212.257825] RSP: 002b:00007ffcc27d23c8 EFLAGS: 00000202 ORIG_RAX: 0000000000000052
[  212.259350] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f82fbdac367
[  212.260763] RDX: 0000000001a700a0 RSI: 0000000001a700a0 RDI: 0000000001a70080
[  212.262177] RBP: 00007ffcc27d2530 R08: 0000000000000003 R09: 0000000000000000
[  212.265946] R10: 0000000000000640 R11: 0000000000000202 R12: 0000000000400c20
[  212.267382] R13: 00007ffcc27d2630 R14: 0000000000000000 R15: 0000000000000000
[  212.268798] Code: 40 38 fe 74 3b 48 83 ea 20 48 83 ea 20 4c 8b 1e 4c 8b 56 08 4c 8b 4e 10 4c 8b 46 18 48 8d 76 20 4c 89 1f 4c 89 57 08 4c 89 4f 10 <4c> 89 47 18 48 8d 7f 20 73 d4 48 83 c2 20 e9 a2 00 00 00 66 90
[  212.272600] RIP: __memmove+0x5b/0x1a0 RSP: ffff8801f283f0e8
[  212.273748] CR2: ffff8801da800000
[  212.274454] ---[ end trace c7e666925cc65cc5 ]---

- Note
This is a different issue from Bugzilla 199347
https://elixir.bootlin.com/linux/v4.18-rc3/source/fs/ext4/xattr.c#L1726
	} else if (s->not_found) {
		/* Insert new name. */
		size_t size = EXT4_XATTR_LEN(name_len);
		size_t rest = (void *)last - (void *)here + sizeof(__u32);

		memmove((void *)here + size, here, rest);
		memset(here, 0, size);
Kernel crashes at memmove with negative length

Reported by Wen Xu (wen.xu@gatech.edu) from SSLab at Gatech.
Comment 1 Wen Xu 2018-07-03 23:41:37 UTC
Created attachment 277157 [details]
poc.c
Comment 2 Theodore Tso 2018-07-30 04:37:18 UTC
Here's an even simpler repro:

# mkdir mnt
# mount -t ext4 final.img mnt
# touch mnt/foo
<crash>

This is another case of "we're trying to expand the inode's extra i_size".  Interestingly, e2fsck does *not* report the file system as corrupted.  The abnormality of the file system is found here:

% debugfs /tmp/poc-200401.img 
debugfs 1.44.3 (10-July-2018)
debugfs:  idump -x foo
magic = ea020000, length = 96, value_start =4 

offset = 4 (0004), name_len = 4, name_index = 7
value_offset = 0 (0004), value_inum = 0, value_size = 0
name = data

offset = 24 (0030), name_len = 30, name_index = 0
value_offset = 0 (0004), value_inum = 0, value_size = 0
name = ^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@

last entry found at offset 72 (0110)

The problem is that name_len is 30, but the name contains a NUL character, which the xattr code is not expecting, and fails to handle correctly.  The simple fix is to add the sanity check, and refuse to deal with an xattr entry with an embedded NUL in the name.
Comment 3 Theodore Tso 2018-07-31 03:35:29 UTC
The fix for this is here:

http://patchwork.ozlabs.org/patch/951358/