Commit 2b06545e authored by Long Li's avatar Long Li
Browse files

xfs: fix ag count overflow during growfs

Offering: HULK
hulk inclusion
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/I73AXQ



--------------------------------

syzkaller found a UAF:

==================================================================
BUG: KASAN: use-after-free in __rb_erase_augmented include/linux/rbtree_augmented.h:225 [inline]
BUG: KASAN: use-after-free in rb_erase+0x16e/0x690 lib/rbtree.c:443
Write of size 8 at addr ffff888101990a40 by task kworker/1:1H/114
CPU: 1 PID: 114 Comm: kworker/1:1H Not tainted 5.10.0-00734-gc980ff0a1f18-dirty #1
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996),
	 BIOS rel-1.15.0-0-g2dd4b9b3f840-prebuilt.qemu.org 04/01/2014
Workqueue: xfs-log/sda xlog_ioend_work
Call Trace:
 __dump_stack lib/dump_stack.c:77 [inline]
 dump_stack+0xbe/0xfd lib/dump_stack.c:118
 kasan_report+0x3a/0x50 mm/kasan/report.c:559
 __rb_erase_augmented include/linux/rbtree_augmented.h:225 [inline]
 rb_erase+0x16e/0x690 lib/rbtree.c:443
 xfs_extent_busy_clear_one+0x5a/0x1c0 fs/xfs/xfs_extent_busy.c:517
 xfs_extent_busy_clear+0x18b/0x1d0 fs/xfs/xfs_extent_busy.c:569
 xlog_cil_committed+0x12a/0x370 fs/xfs/xfs_log_cil.c:659
 xlog_cil_process_committed+0xbc/0xe0 fs/xfs/xfs_log_cil.c:683
 xlog_state_do_iclog_callbacks+0x30c/0x4b0 fs/xfs/xfs_log.c:2777
 xlog_state_do_callback+0x99/0x150 fs/xfs/xfs_log.c:2802
 xlog_ioend_work+0x57/0xc0 fs/xfs/xfs_log.c:1308
 process_one_work+0x406/0x810 kernel/workqueue.c:2280
 worker_thread+0x96/0x720 kernel/workqueue.c:2426
 kthread+0x1f4/0x250 kernel/kthread.c:313
 ret_from_fork+0x1f/0x30 arch/x86/entry/entry_64.S:299

Allocated by task 22679:
 kasan_save_stack+0x1b/0x40 mm/kasan/common.c:48
 kasan_set_track mm/kasan/common.c:56 [inline]
 set_alloc_info mm/kasan/common.c:498 [inline]
 __kasan_kmalloc mm/kasan/common.c:530 [inline]
 __kasan_kmalloc.constprop.0+0xf0/0x130 mm/kasan/common.c:501
 kmalloc include/linux/slab.h:568 [inline]
 kmem_alloc+0xc2/0x230 fs/xfs/kmem.c:21
 kmem_zalloc fs/xfs/kmem.h:69 [inline]
 xfs_extent_busy_insert+0x3c/0x370 fs/xfs/xfs_extent_busy.c:36
 __xfs_free_extent+0x268/0x340 fs/xfs/libxfs/xfs_alloc.c:3327
 xfs_free_extent fs/xfs/libxfs/xfs_alloc.h:183 [inline]
 xfs_ag_extend_space+0x26e/0x280 fs/xfs/libxfs/xfs_ag.c:540
 xfs_growfs_data_private.isra.0+0x64e/0x6f0 fs/xfs/xfs_fsops.c:112
 xfs_growfs_data+0x287/0x360 fs/xfs/xfs_fsops.c:239
 xfs_file_ioctl+0x9f2/0x1320 fs/xfs/xfs_ioctl.c:2274
 vfs_ioctl fs/ioctl.c:48 [inline]
 __do_sys_ioctl fs/ioctl.c:753 [inline]
 __se_sys_ioctl+0x111/0x160 fs/ioctl.c:739
 do_syscall_64+0x30/0x40 arch/x86/entry/common.c:46
 entry_SYSCALL_64_after_hwframe+0x61/0xc6

Freed by task 114:
 kasan_save_stack+0x1b/0x40 mm/kasan/common.c:48
 kasan_set_track+0x1c/0x30 mm/kasan/common.c:56
 kasan_set_free_info+0x20/0x40 mm/kasan/generic.c:361
 __kasan_slab_free.part.0+0x13f/0x1b0 mm/kasan/common.c:482
 slab_free_hook mm/slub.c:1569 [inline]
 slab_free_freelist_hook mm/slub.c:1608 [inline]
 slab_free mm/slub.c:3179 [inline]
 kfree+0xce/0x860 mm/slub.c:4176
 kvfree+0x47/0x50 mm/util.c:647
 xfs_extent_busy_clear+0x18b/0x1d0 fs/xfs/xfs_extent_busy.c:569
 xlog_cil_committed+0x12a/0x370 fs/xfs/xfs_log_cil.c:659
 xlog_cil_process_committed+0xbc/0xe0 fs/xfs/xfs_log_cil.c:683
 xlog_state_do_iclog_callbacks+0x30c/0x4b0 fs/xfs/xfs_log.c:2777
 xlog_state_do_callback+0x99/0x150 fs/xfs/xfs_log.c:2802
 xlog_ioend_work+0x57/0xc0 fs/xfs/xfs_log.c:1308
 process_one_work+0x406/0x810 kernel/workqueue.c:2280
 worker_thread+0x96/0x720 kernel/workqueue.c:2426
 kthread+0x1f4/0x250 kernel/kthread.c:313
 ret_from_fork+0x1f/0x30 arch/x86/entry/entry_64.S:299

The buggy address belongs to the object at ffff888101990a40
 which belongs to the cache kmalloc-64 of size 64
The buggy address is located 0 bytes inside of
 64-byte region [ffff888101990a40, ffff888101990a80)
The buggy address belongs to the page:
page:ffffea0004066400 refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x101990
head:ffffea0004066400 order:1 compound_mapcount:0
flags: 0x17ffffc0010200(slab|head|node=0|zone=2|lastcpupid=0x1fffff)
raw: 0017ffffc0010200 ffffea00009d5d88 ffff888100040a70 ffff88810004d500
raw: 0000000000000000 0000000000100010 00000001ffffffff 0000000000000000
page dumped because: kasan: bad access detected

Memory state around the buggy address:
 ffff888101990900: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
 ffff888101990980: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
>ffff888101990a00: fc fc fc fc fc fc fc fc fa fb fb fb fb fb fb fb
                                           ^
 ffff888101990a80: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
 ffff888101990b00: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
==================================================================

The bug can be reproduced with the following sequence:

 # truncate -s  1073741824 xfs_test.img
 # mkfs.xfs -f -b size=1024 -d agcount=4 xfs_test.img
 # truncate -s 2305843009213693952  xfs_test.img
 # mount -o loop xfs_test.img /mnt/test
 # fsstress -d /mnt/test -l 0 -n 10000 >/dev/null &
 # xfs_growfs -D  1125899907891200  /mnt/test

The root cause is that during growfs, user space passed in a large value
of newblcoks to xfs_growfs_data_private(), due to current sb_agblocks is
too small, new AG count will exceed UINT_MAX. Because of AG number type
is unsigned int and it would overflow, that caused nagcount much smaller
than the actual value and new blocks in the old last AG very large. When
old last AG expand the space, xfs_extlen_t type is unsigned int, it would
overflow again, if new blocks exceed UINT_MAX and the lower 32 bit are
zero. This will cause busy extent whose length is equal to zero insert into
rbtree, xfs_extent_busy_clear_one() will free it abormally but not remove
it from tbree, UAF will be triggered when access rbtree on the next time.
Fix it by add checks for nagcount overflow inxfs_growfs_data_private.

Signed-off-by: default avatarLong Li <leo.lilong@huawei.com>
parent bf5e6e65
Loading
Loading
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment