[syzbot] KASAN: use-after-free Read in jfs_lazycommit

30 views
Skip to first unread message

syzbot

unread,
Oct 1, 2022, 9:43:39 AM10/1/22
to jfs-dis...@lists.sourceforge.net, linux-...@vger.kernel.org, sha...@kernel.org, syzkall...@googlegroups.com
Hello,

syzbot found the following issue on:

HEAD commit: 3800a713b607 Merge tag 'mm-hotfixes-stable-2022-09-26' of ..
git tree: upstream
console output: https://syzkaller.appspot.com/x/log.txt?x=126aa1ff080000
kernel config: https://syzkaller.appspot.com/x/.config?x=a1992c90769e07
dashboard link: https://syzkaller.appspot.com/bug?extid=885a4f3281b8d99c48d8
compiler: gcc (Debian 10.2.1-6) 10.2.1 20210110, GNU ld (GNU Binutils for Debian) 2.35.2

Unfortunately, I don't have any reproducer for this issue yet.

IMPORTANT: if you fix the issue, please add the following tag to the commit:
Reported-by: syzbot+885a4f...@syzkaller.appspotmail.com

==================================================================
BUG: KASAN: use-after-free in jfs_lazycommit+0xa39/0xb70 fs/jfs/jfs_txnmgr.c:2730
Read of size 4 at addr ffff888061559694 by task jfsCommit/152

CPU: 2 PID: 152 Comm: jfsCommit Not tainted 6.0.0-rc7-syzkaller-00029-g3800a713b607 #0
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.14.0-2 04/01/2014
Call Trace:
<TASK>
__dump_stack lib/dump_stack.c:88 [inline]
dump_stack_lvl+0xcd/0x134 lib/dump_stack.c:106
print_address_description mm/kasan/report.c:317 [inline]
print_report.cold+0x2ba/0x6e9 mm/kasan/report.c:433
kasan_report+0xb1/0x1e0 mm/kasan/report.c:495
jfs_lazycommit+0xa39/0xb70 fs/jfs/jfs_txnmgr.c:2730
kthread+0x2e4/0x3a0 kernel/kthread.c:376
ret_from_fork+0x1f/0x30 arch/x86/entry/entry_64.S:306
</TASK>

Allocated by task 7752:
kasan_save_stack+0x1e/0x40 mm/kasan/common.c:38
kasan_set_track mm/kasan/common.c:45 [inline]
set_alloc_info mm/kasan/common.c:437 [inline]
____kasan_kmalloc mm/kasan/common.c:516 [inline]
____kasan_kmalloc mm/kasan/common.c:475 [inline]
__kasan_kmalloc+0xa6/0xd0 mm/kasan/common.c:525
kasan_kmalloc include/linux/kasan.h:234 [inline]
kmem_cache_alloc_trace+0x25a/0x460 mm/slab.c:3559
kmalloc include/linux/slab.h:600 [inline]
kzalloc include/linux/slab.h:733 [inline]
jfs_fill_super+0xd9/0xc70 fs/jfs/super.c:495
mount_bdev+0x34d/0x410 fs/super.c:1400
legacy_get_tree+0x105/0x220 fs/fs_context.c:610
vfs_get_tree+0x89/0x2f0 fs/super.c:1530
do_new_mount fs/namespace.c:3040 [inline]
path_mount+0x1326/0x1e20 fs/namespace.c:3370
do_mount fs/namespace.c:3383 [inline]
__do_sys_mount fs/namespace.c:3591 [inline]
__se_sys_mount fs/namespace.c:3568 [inline]
__x64_sys_mount+0x27f/0x300 fs/namespace.c:3568
do_syscall_x64 arch/x86/entry/common.c:50 [inline]
do_syscall_64+0x35/0xb0 arch/x86/entry/common.c:80
entry_SYSCALL_64_after_hwframe+0x63/0xcd

Freed by task 3724:
kasan_save_stack+0x1e/0x40 mm/kasan/common.c:38
kasan_set_track+0x21/0x30 mm/kasan/common.c:45
kasan_set_free_info+0x20/0x30 mm/kasan/generic.c:370
____kasan_slab_free mm/kasan/common.c:367 [inline]
____kasan_slab_free+0x13d/0x1a0 mm/kasan/common.c:329
kasan_slab_free include/linux/kasan.h:200 [inline]
__cache_free mm/slab.c:3418 [inline]
kfree+0x173/0x390 mm/slab.c:3786
generic_shutdown_super+0x14c/0x400 fs/super.c:491
kill_block_super+0x97/0xf0 fs/super.c:1427
deactivate_locked_super+0x94/0x160 fs/super.c:332
deactivate_super+0xad/0xd0 fs/super.c:363
cleanup_mnt+0x2ae/0x3d0 fs/namespace.c:1186
task_work_run+0xdd/0x1a0 kernel/task_work.c:177
resume_user_mode_work include/linux/resume_user_mode.h:49 [inline]
exit_to_user_mode_loop kernel/entry/common.c:169 [inline]
exit_to_user_mode_prepare+0x23c/0x250 kernel/entry/common.c:201
__syscall_exit_to_user_mode_work kernel/entry/common.c:283 [inline]
syscall_exit_to_user_mode+0x19/0x50 kernel/entry/common.c:294
do_syscall_64+0x42/0xb0 arch/x86/entry/common.c:86
entry_SYSCALL_64_after_hwframe+0x63/0xcd

Last potentially related work creation:
kasan_save_stack+0x1e/0x40 mm/kasan/common.c:38
__kasan_record_aux_stack+0x7e/0x90 mm/kasan/generic.c:348
kvfree_call_rcu+0x74/0x940 kernel/rcu/tree.c:3322
drop_sysctl_table+0x3c0/0x4e0 fs/proc/proc_sysctl.c:1716
unregister_sysctl_table fs/proc/proc_sysctl.c:1754 [inline]
unregister_sysctl_table+0xc0/0x190 fs/proc/proc_sysctl.c:1729
mpls_dev_sysctl_unregister net/mpls/af_mpls.c:1441 [inline]
mpls_dev_notify+0x5c7/0x9b0 net/mpls/af_mpls.c:1653
notifier_call_chain+0xb5/0x200 kernel/notifier.c:87
call_netdevice_notifiers_info+0xb5/0x130 net/core/dev.c:1945
call_netdevice_notifiers_extack net/core/dev.c:1983 [inline]
call_netdevice_notifiers net/core/dev.c:1997 [inline]
unregister_netdevice_many+0xa62/0x1980 net/core/dev.c:10862
ip_tunnel_delete_nets+0x39f/0x5b0 net/ipv4/ip_tunnel.c:1126
ops_exit_list+0x125/0x170 net/core/net_namespace.c:168
cleanup_net+0x4ea/0xb00 net/core/net_namespace.c:595
process_one_work+0x991/0x1610 kernel/workqueue.c:2289
worker_thread+0x665/0x1080 kernel/workqueue.c:2436
kthread+0x2e4/0x3a0 kernel/kthread.c:376
ret_from_fork+0x1f/0x30 arch/x86/entry/entry_64.S:306

Second to last potentially related work creation:
kasan_save_stack+0x1e/0x40 mm/kasan/common.c:38
__kasan_record_aux_stack+0x7e/0x90 mm/kasan/generic.c:348
kvfree_call_rcu+0x74/0x940 kernel/rcu/tree.c:3322
drop_sysctl_table+0x3c0/0x4e0 fs/proc/proc_sysctl.c:1716
unregister_sysctl_table fs/proc/proc_sysctl.c:1754 [inline]
unregister_sysctl_table+0xc0/0x190 fs/proc/proc_sysctl.c:1729
__devinet_sysctl_unregister net/ipv4/devinet.c:2609 [inline]
devinet_sysctl_unregister net/ipv4/devinet.c:2637 [inline]
inetdev_destroy net/ipv4/devinet.c:327 [inline]
inetdev_event+0xcaa/0x1610 net/ipv4/devinet.c:1602
notifier_call_chain+0xb5/0x200 kernel/notifier.c:87
call_netdevice_notifiers_info+0xb5/0x130 net/core/dev.c:1945
call_netdevice_notifiers_extack net/core/dev.c:1983 [inline]
call_netdevice_notifiers net/core/dev.c:1997 [inline]
unregister_netdevice_many+0xa62/0x1980 net/core/dev.c:10862
ip6_tnl_exit_batch_net+0x5f5/0x890 net/ipv6/ip6_tunnel.c:2312
ops_exit_list+0x125/0x170 net/core/net_namespace.c:168
cleanup_net+0x4ea/0xb00 net/core/net_namespace.c:595
process_one_work+0x991/0x1610 kernel/workqueue.c:2289
worker_thread+0x665/0x1080 kernel/workqueue.c:2436
kthread+0x2e4/0x3a0 kernel/kthread.c:376
ret_from_fork+0x1f/0x30 arch/x86/entry/entry_64.S:306

The buggy address belongs to the object at ffff888061559600
which belongs to the cache kmalloc-256 of size 256
The buggy address is located 148 bytes inside of
256-byte region [ffff888061559600, ffff888061559700)

The buggy address belongs to the physical page:
page:ffffea0001855640 refcount:1 mapcount:0 mapping:0000000000000000 index:0xffff888061559400 pfn:0x61559
flags: 0x4fff00000000200(slab|node=1|zone=1|lastcpupid=0x7ff)
raw: 04fff00000000200 ffffea0001ad0108 ffff888040000640 ffff888011840500
raw: ffff888061559400 ffff888061559000 0000000100000005 0000000000000000
page dumped because: kasan: bad access detected
page_owner tracks the page as allocated
page last allocated via order 0, migratetype Unmovable, gfp_mask 0x140cc0(GFP_USER|__GFP_COMP), pid 5358, tgid 5356 (syz-executor.1), ts 311368910485, free_ts 310980461997
prep_new_page mm/page_alloc.c:2532 [inline]
get_page_from_freelist+0x109b/0x2ce0 mm/page_alloc.c:4283
__alloc_pages+0x1c7/0x510 mm/page_alloc.c:5549
__alloc_pages_node include/linux/gfp.h:243 [inline]
kmem_getpages mm/slab.c:1363 [inline]
cache_grow_begin+0x75/0x360 mm/slab.c:2569
fallback_alloc+0x1e2/0x2d0 mm/slab.c:3112
__do_cache_alloc mm/slab.c:3253 [inline]
slab_alloc mm/slab.c:3287 [inline]
__do_kmalloc mm/slab.c:3684 [inline]
__kmalloc+0x2da/0x4a0 mm/slab.c:3695
kmalloc include/linux/slab.h:605 [inline]
kzalloc include/linux/slab.h:733 [inline]
new_dir fs/proc/proc_sysctl.c:978 [inline]
get_subdir fs/proc/proc_sysctl.c:1022 [inline]
__register_sysctl_table+0x9eb/0x10a0 fs/proc/proc_sysctl.c:1373
neigh_sysctl_register+0x2c8/0x5e0 net/core/neighbour.c:3855
addrconf_sysctl_register+0xb6/0x1d0 net/ipv6/addrconf.c:7126
ipv6_add_dev+0xae3/0x1390 net/ipv6/addrconf.c:450
addrconf_notify+0x6f9/0x1c10 net/ipv6/addrconf.c:3528
notifier_call_chain+0xb5/0x200 kernel/notifier.c:87
call_netdevice_notifiers_info+0xb5/0x130 net/core/dev.c:1945
call_netdevice_notifiers_extack net/core/dev.c:1983 [inline]
call_netdevice_notifiers net/core/dev.c:1997 [inline]
register_netdevice+0x1127/0x1680 net/core/dev.c:10103
register_netdev+0x2d/0x50 net/core/dev.c:10196
sit_init_net+0x350/0xa30 net/ipv6/sit.c:1915
ops_init+0xaf/0x470 net/core/net_namespace.c:135
page last free stack trace:
reset_page_owner include/linux/page_owner.h:24 [inline]
free_pages_prepare mm/page_alloc.c:1449 [inline]
free_pcp_prepare+0x5e4/0xd20 mm/page_alloc.c:1499
free_unref_page_prepare mm/page_alloc.c:3380 [inline]
free_unref_page+0x19/0x4d0 mm/page_alloc.c:3476
__folio_put_small mm/swap.c:105 [inline]
__folio_put+0xc1/0x130 mm/swap.c:128
folio_put include/linux/mm.h:1125 [inline]
put_page include/linux/mm.h:1177 [inline]
free_page_and_swap_cache+0x253/0x2c0 mm/swap_state.c:296
__tlb_remove_table arch/x86/include/asm/tlb.h:34 [inline]
__tlb_remove_table_free mm/mmu_gather.c:114 [inline]
tlb_remove_table_rcu+0x85/0xe0 mm/mmu_gather.c:169
rcu_do_batch kernel/rcu/tree.c:2245 [inline]
rcu_core+0x7b5/0x1890 kernel/rcu/tree.c:2505
__do_softirq+0x1d3/0x9c6 kernel/softirq.c:571

Memory state around the buggy address:
ffff888061559580: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
ffff888061559600: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
>ffff888061559680: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
^
ffff888061559700: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
ffff888061559780: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
==================================================================


---
This report is generated by a bot. It may contain errors.
See https://goo.gl/tpsmEJ for more information about syzbot.
syzbot engineers can be reached at syzk...@googlegroups.com.

syzbot will keep track of this issue. See:
https://goo.gl/tpsmEJ#status for how to communicate with syzbot.

syzbot

unread,
Oct 12, 2022, 1:33:46 AM10/12/22
to jfs-dis...@lists.sourceforge.net, linux-...@vger.kernel.org, sha...@kernel.org, syzkall...@googlegroups.com
syzbot has found a reproducer for the following issue on:

HEAD commit: 493ffd6605b2 Merge tag 'ucount-rlimits-cleanups-for-v5.19'..
git tree: upstream
console output: https://syzkaller.appspot.com/x/log.txt?x=165e218a880000
kernel config: https://syzkaller.appspot.com/x/.config?x=d19f5d16783f901
dashboard link: https://syzkaller.appspot.com/bug?extid=885a4f3281b8d99c48d8
compiler: Debian clang version 13.0.1-++20220126092033+75e33f71c2da-1~exp1~20220126212112.63, GNU ld (GNU Binutils for Debian) 2.35.2
syz repro: https://syzkaller.appspot.com/x/repro.syz?x=1523402c880000
C reproducer: https://syzkaller.appspot.com/x/repro.c?x=15b5fc78880000

Downloadable assets:
disk image: https://storage.googleapis.com/syzbot-assets/f1ff6481e26f/disk-493ffd66.raw.xz
vmlinux: https://storage.googleapis.com/syzbot-assets/101bd3c7ae47/vmlinux-493ffd66.xz
mounted in repro: https://storage.googleapis.com/syzbot-assets/9aaa6f9b6f7e/mount_0.gz

IMPORTANT: if you fix the issue, please add the following tag to the commit:
Reported-by: syzbot+885a4f...@syzkaller.appspotmail.com

ERROR: (device loop0): remounting filesystem as read-only
blkno = 400000, nblocks = 0
ERROR: (device loop0): dbFree: block to be freed is outside the map
==================================================================
BUG: KASAN: use-after-free in jfs_lazycommit+0x746/0xba0 fs/jfs/jfs_txnmgr.c:2730
Read of size 4 at addr ffff88807ee78094 by task jfsCommit/120

CPU: 1 PID: 120 Comm: jfsCommit Not tainted 6.0.0-syzkaller-09423-g493ffd6605b2 #0
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 09/22/2022
Call Trace:
<TASK>
__dump_stack lib/dump_stack.c:88 [inline]
dump_stack_lvl+0x1b1/0x28e lib/dump_stack.c:106
print_address_description+0x65/0x4b0 mm/kasan/report.c:317
print_report+0x108/0x1f0 mm/kasan/report.c:433
kasan_report+0xc3/0xf0 mm/kasan/report.c:495
jfs_lazycommit+0x746/0xba0 fs/jfs/jfs_txnmgr.c:2730
kthread+0x266/0x300 kernel/kthread.c:376
ret_from_fork+0x1f/0x30 arch/x86/entry/entry_64.S:306
</TASK>

Allocated by task 4321:
kasan_save_stack mm/kasan/common.c:38 [inline]
kasan_set_track mm/kasan/common.c:45 [inline]
set_alloc_info mm/kasan/common.c:437 [inline]
____kasan_kmalloc+0xcd/0x100 mm/kasan/common.c:516
kasan_kmalloc include/linux/kasan.h:234 [inline]
kmem_cache_alloc_trace+0x97/0x310 mm/slub.c:3289
kmalloc include/linux/slab.h:600 [inline]
kzalloc include/linux/slab.h:733 [inline]
jfs_fill_super+0xfb/0xc50 fs/jfs/super.c:495
mount_bdev+0x26c/0x3a0 fs/super.c:1400
legacy_get_tree+0xea/0x180 fs/fs_context.c:610
vfs_get_tree+0x88/0x270 fs/super.c:1530
do_new_mount+0x289/0xad0 fs/namespace.c:3040
do_mount fs/namespace.c:3383 [inline]
__do_sys_mount fs/namespace.c:3591 [inline]
__se_sys_mount+0x2d3/0x3c0 fs/namespace.c:3568
do_syscall_x64 arch/x86/entry/common.c:50 [inline]
do_syscall_64+0x3d/0xb0 arch/x86/entry/common.c:80
entry_SYSCALL_64_after_hwframe+0x63/0xcd

Freed by task 3642:
kasan_save_stack mm/kasan/common.c:38 [inline]
kasan_set_track+0x3d/0x60 mm/kasan/common.c:45
kasan_set_free_info+0x1f/0x40 mm/kasan/generic.c:370
____kasan_slab_free+0xd8/0x120 mm/kasan/common.c:367
kasan_slab_free include/linux/kasan.h:200 [inline]
slab_free_hook mm/slub.c:1759 [inline]
slab_free_freelist_hook+0x12e/0x1a0 mm/slub.c:1785
slab_free mm/slub.c:3539 [inline]
kfree+0xda/0x210 mm/slub.c:4567
generic_shutdown_super+0x130/0x310 fs/super.c:491
kill_block_super+0x79/0xd0 fs/super.c:1427
deactivate_locked_super+0xa7/0xf0 fs/super.c:331
cleanup_mnt+0x4ce/0x560 fs/namespace.c:1186
task_work_run+0x146/0x1c0 kernel/task_work.c:177
resume_user_mode_work include/linux/resume_user_mode.h:49 [inline]
exit_to_user_mode_loop+0x124/0x150 kernel/entry/common.c:169
exit_to_user_mode_prepare+0xb2/0x140 kernel/entry/common.c:201
__syscall_exit_to_user_mode_work kernel/entry/common.c:283 [inline]
syscall_exit_to_user_mode+0x26/0x60 kernel/entry/common.c:294
do_syscall_64+0x49/0xb0 arch/x86/entry/common.c:86
entry_SYSCALL_64_after_hwframe+0x63/0xcd

The buggy address belongs to the object at ffff88807ee78000
which belongs to the cache kmalloc-256 of size 256
The buggy address is located 148 bytes inside of
256-byte region [ffff88807ee78000, ffff88807ee78100)

The buggy address belongs to the physical page:
page:ffffea0001fb9e00 refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x7ee78
head:ffffea0001fb9e00 order:1 compound_mapcount:0 compound_pincount:0
flags: 0xfff00000010200(slab|head|node=0|zone=1|lastcpupid=0x7ff)
raw: 00fff00000010200 ffffea00004bed80 dead000000000004 ffff888012041b40
raw: 0000000000000000 0000000080100010 00000001ffffffff 0000000000000000
page dumped because: kasan: bad access detected
page_owner tracks the page as allocated
page last allocated via order 1, migratetype Unmovable, gfp_mask 0xd20c0(__GFP_IO|__GFP_FS|__GFP_NOWARN|__GFP_NORETRY|__GFP_COMP|__GFP_NOMEMALLOC), pid 1, tgid 1 (init), ts 11597877098, free_ts 11078632692
prep_new_page mm/page_alloc.c:2532 [inline]
get_page_from_freelist+0x742/0x7c0 mm/page_alloc.c:4283
__alloc_pages+0x259/0x560 mm/page_alloc.c:5549
alloc_slab_page+0x70/0xf0 mm/slub.c:1829
allocate_slab+0x5e/0x520 mm/slub.c:1974
new_slab mm/slub.c:2034 [inline]
___slab_alloc+0x3ee/0xc40 mm/slub.c:3036
__slab_alloc mm/slub.c:3123 [inline]
slab_alloc_node mm/slub.c:3214 [inline]
slab_alloc mm/slub.c:3256 [inline]
__kmalloc+0x2bd/0x370 mm/slub.c:4425
kmalloc_array include/linux/slab.h:640 [inline]
kcalloc include/linux/slab.h:671 [inline]
__list_lru_init+0xa0/0x5f0 mm/list_lru.c:571
alloc_super+0x7a7/0x920 fs/super.c:272
sget_fc+0x257/0x6c0 fs/super.c:559
vfs_get_super fs/super.c:1163 [inline]
get_tree_nodev+0x26/0x160 fs/super.c:1198
vfs_get_tree+0x88/0x270 fs/super.c:1530
do_new_mount+0x289/0xad0 fs/namespace.c:3040
do_mount fs/namespace.c:3383 [inline]
__do_sys_mount fs/namespace.c:3591 [inline]
__se_sys_mount+0x2d3/0x3c0 fs/namespace.c:3568
do_syscall_x64 arch/x86/entry/common.c:50 [inline]
do_syscall_64+0x3d/0xb0 arch/x86/entry/common.c:80
entry_SYSCALL_64_after_hwframe+0x63/0xcd
page last free stack trace:
reset_page_owner include/linux/page_owner.h:24 [inline]
free_pages_prepare mm/page_alloc.c:1449 [inline]
free_pcp_prepare+0x812/0x900 mm/page_alloc.c:1499
free_unref_page_prepare mm/page_alloc.c:3380 [inline]
free_unref_page+0x7d/0x5f0 mm/page_alloc.c:3476
free_contig_range+0xa3/0x160 mm/page_alloc.c:9457
destroy_args+0xfe/0x91d mm/debug_vm_pgtable.c:1031
debug_vm_pgtable+0x43e/0x497 mm/debug_vm_pgtable.c:1354
do_one_initcall+0x1c9/0x400 init/main.c:1296
do_initcall_level+0x168/0x218 init/main.c:1369
do_initcalls+0x4b/0x8c init/main.c:1385
kernel_init_freeable+0x3f1/0x57b init/main.c:1623
kernel_init+0x19/0x2b0 init/main.c:1512
ret_from_fork+0x1f/0x30 arch/x86/entry/entry_64.S:306

Memory state around the buggy address:
ffff88807ee77f80: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
ffff88807ee78000: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
>ffff88807ee78080: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
^
ffff88807ee78100: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
ffff88807ee78180: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
==================================================================

Qianqiang Liu

unread,
Oct 12, 2024, 11:29:59 PM10/12/24
to syzbot, jfs-dis...@lists.sourceforge.net, linux-...@vger.kernel.org, sha...@kernel.org, syzkall...@googlegroups.com
#syz test

diff --git a/fs/jfs/jfs_incore.h b/fs/jfs/jfs_incore.h
index 10934f9a11be..7b75c801b239 100644
--- a/fs/jfs/jfs_incore.h
+++ b/fs/jfs/jfs_incore.h
@@ -177,11 +177,6 @@ struct jfs_sb_info {
pxd_t ait2; /* pxd describing AIT copy */
uuid_t uuid; /* 128-bit uuid for volume */
uuid_t loguuid; /* 128-bit uuid for log */
- /*
- * commit_state is used for synchronization of the jfs_commit
- * threads. It is protected by LAZY_LOCK().
- */
- int commit_state; /* commit state */
/* Formerly in ipimap */
uint gengen; /* inode generation generator*/
uint inostamp; /* shows inode belongs to fileset*/
@@ -199,9 +194,6 @@ struct jfs_sb_info {
uint minblks_trim; /* minimum blocks, for online trim */
};

-/* jfs_sb_info commit_state */
-#define IN_LAZYCOMMIT 1
-
static inline struct jfs_inode_info *JFS_IP(struct inode *inode)
{
return container_of(inode, struct jfs_inode_info, vfs_inode);
diff --git a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c
index be17e3c43582..a4817229d573 100644
--- a/fs/jfs/jfs_txnmgr.c
+++ b/fs/jfs/jfs_txnmgr.c
@@ -2700,7 +2700,6 @@ int jfs_lazycommit(void *arg)
int WorkDone;
struct tblock *tblk;
unsigned long flags;
- struct jfs_sb_info *sbi;

set_freezable();
do {
@@ -2711,17 +2710,16 @@ int jfs_lazycommit(void *arg)
list_for_each_entry(tblk, &TxAnchor.unlock_queue,
cqueue) {

- sbi = JFS_SBI(tblk->sb);
/*
* For each volume, the transactions must be
* handled in order. If another commit thread
* is handling a tblk for this superblock,
* skip it
*/
- if (sbi->commit_state & IN_LAZYCOMMIT)
+ if (tblk->commit_state & IN_LAZYCOMMIT)
continue;

- sbi->commit_state |= IN_LAZYCOMMIT;
+ tblk->commit_state |= IN_LAZYCOMMIT;
WorkDone = 1;

/*
@@ -2733,7 +2731,7 @@ int jfs_lazycommit(void *arg)
txLazyCommit(tblk);
LAZY_LOCK(flags);

- sbi->commit_state &= ~IN_LAZYCOMMIT;
+ tblk->commit_state &= ~IN_LAZYCOMMIT;
/*
* Don't continue in the for loop. (We can't
* anyway, it's unsafe!) We want to go back to
@@ -2781,7 +2779,7 @@ void txLazyUnlock(struct tblock * tblk)
* Don't wake up a commit thread if there is already one servicing
* this superblock, or if the last one we woke up hasn't started yet.
*/
- if (!(JFS_SBI(tblk->sb)->commit_state & IN_LAZYCOMMIT) &&
+ if (!(tblk->commit_state & IN_LAZYCOMMIT) &&
!jfs_commit_thread_waking) {
jfs_commit_thread_waking = 1;
wake_up(&jfs_commit_thread_wait);
diff --git a/fs/jfs/jfs_txnmgr.h b/fs/jfs/jfs_txnmgr.h
index ba71eb5ced56..3a0ee53f17cb 100644
--- a/fs/jfs/jfs_txnmgr.h
+++ b/fs/jfs/jfs_txnmgr.h
@@ -32,6 +32,11 @@ struct tblock {

/* lock management */
struct super_block *sb; /* super block */
+ /*
+ * commit_state is used for synchronization of the jfs_commit
+ * threads. It is protected by LAZY_LOCK().
+ */
+ int commit_state; /* commit state */
lid_t next; /* index of first tlock of tid */
lid_t last; /* index of last tlock of tid */
wait_queue_head_t waitor; /* tids waiting on this tid */
@@ -56,6 +61,9 @@ struct tblock {
u32 ino; /* inode number being created */
};

+/* tblock commit_state */
+#define IN_LAZYCOMMIT 1
+
extern struct tblock *TxBlock; /* transaction block table */

/* commit flags: tblk->xflag */

--
Best,
Qianqiang Liu

syzbot

unread,
Oct 13, 2024, 12:49:03 AM10/13/24
to jfs-dis...@lists.sourceforge.net, linux-...@vger.kernel.org, qianqi...@163.com, sha...@kernel.org, syzkall...@googlegroups.com
Hello,

syzbot has tested the proposed patch and the reproducer did not trigger any issue:

Reported-by: syzbot+885a4f...@syzkaller.appspotmail.com
Tested-by: syzbot+885a4f...@syzkaller.appspotmail.com

Tested on:

commit: 36c25451 Merge tag 'powerpc-6.12-4' of git://git.kerne..
git tree: upstream
console output: https://syzkaller.appspot.com/x/log.txt?x=13d1bfd0580000
kernel config: https://syzkaller.appspot.com/x/.config?x=7a3fccdd0bb995
dashboard link: https://syzkaller.appspot.com/bug?extid=885a4f3281b8d99c48d8
compiler: Debian clang version 15.0.6, GNU ld (GNU Binutils for Debian) 2.40
patch: https://syzkaller.appspot.com/x/patch.diff?x=10951087980000

Note: testing is done by a robot and is best-effort only.

Qianqiang Liu

unread,
Oct 13, 2024, 2:05:47 AM10/13/24
to dave.k...@oracle.com, sha...@kernel.org, jfs-dis...@lists.sourceforge.net, linux-...@vger.kernel.org, syzbot+885a4f...@syzkaller.appspotmail.com, syzkall...@googlegroups.com
The jfsCommit kernel thread uses the sbi->commit_state flag,
and sbi may be freed in jfs_put_super() by another thread.

To prevent this, move commit_state to struct tblock,
eliminating the need to access the sbi variable.

Reported-by: syzbot+885a4f...@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=885a4f3281b8d99c48d8
Tested-by: syzbot+885a4f...@syzkaller.appspotmail.com
Signed-off-by: Qianqiang Liu <qianqi...@163.com>
---
fs/jfs/jfs_incore.h | 8 --------
fs/jfs/jfs_txnmgr.c | 10 ++++------
fs/jfs/jfs_txnmgr.h | 8 ++++++++
3 files changed, 12 insertions(+), 14 deletions(-)
2.47.0

Dave Kleikamp

unread,
Oct 30, 2024, 10:30:43 AM10/30/24
to Qianqiang Liu, jfs-dis...@lists.sourceforge.net, linux-...@vger.kernel.org, syzbot+885a4f...@syzkaller.appspotmail.com, syzkall...@googlegroups.com
On 10/13/24 1:05AM, Qianqiang Liu wrote:
> The jfsCommit kernel thread uses the sbi->commit_state flag,
> and sbi may be freed in jfs_put_super() by another thread.
>
> To prevent this, move commit_state to struct tblock,
> eliminating the need to access the sbi variable.

I need to give this one some more thought. The unmount isn't supposed to
complete before all I/O has completed, but it's been quite I while since
I went over the mechanisms to safeguard that. I'll have to look at this
problem more closely.

Shaggy

syzbot

unread,
Apr 30, 2026, 7:13:32 PM (2 days ago) Apr 30
to linux-...@vger.kernel.org, syzkall...@googlegroups.com
For archival purposes, forwarding an incoming command email to
linux-...@vger.kernel.org, syzkall...@googlegroups.com.

***

Subject: Re: [syz] KASAN: use-after-free Read in jfs_lazycommit
Author: tri...@gmail.com

#syz test: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git master

>From a6c188149cf9056a8692aa45dfd0d429bd07d09f Mon Sep 17 00:00:00 2001
From: Tristan Madani <tri...@talencesecurity.com>
Date: Thu, 30 Apr 2026 23:12:58 +0000
Subject: [PATCH] jfs: drain lazy commit queue during unmount to prevent
use-after-free

The jfsCommit kernel thread processes committed transactions from
TxAnchor.unlock_queue via jfs_lazycommit(). During filesystem
unmount, jfs_umount() calls jfs_flush_journal(log, 2) which waits
for the log commit queue (log->cqueue) to drain. However, after
log I/O completes, lazy transactions are moved to
TxAnchor.unlock_queue for asynchronous processing by jfsCommit.

If jfs_umount() proceeds to free the jfs_log (via lmLogClose) or
jfs_sb_info (via kfree in jfs_put_super) while entries referencing
this superblock remain on unlock_queue, the jfsCommit thread will
access freed memory when it later processes these entries:

- jfs_lazycommit reads sbi->commit_state (UAF of jfs_sb_info)
- txLazyCommit accesses JFS_SBI(tblk->sb)->log and takes
log->gclock (UAF of jfs_log)

Add txLazyDrain() which waits for all entries in
TxAnchor.unlock_queue belonging to the unmounting superblock to be
processed, and also waits for any in-flight txLazyCommit
(IN_LAZYCOMMIT) for this superblock to complete. Call it from both
jfs_umount() and jfs_umount_rw() after jfs_flush_journal().

Reported-by: syzbot+c244f4...@syzkaller.appspotmail.com
Reported-by: syzbot+885a4f...@syzkaller.appspotmail.com
Fixes: 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 ("Linux-2.6.12-rc2")
Cc: sta...@vger.kernel.org
Signed-off-by: Tristan Madani <tri...@talencesecurity.com>
---
fs/jfs/jfs_txnmgr.c | 34 ++++++++++++++++++++++++++++++++++
fs/jfs/jfs_txnmgr.h | 1 +
fs/jfs/jfs_umount.c | 8 ++++++++
3 files changed, 43 insertions(+)

diff --git a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c
index 083dbbb0c3268..e3b2cee416c19 100644
--- a/fs/jfs/jfs_txnmgr.c
+++ b/fs/jfs/jfs_txnmgr.c
@@ -2791,6 +2791,40 @@ void txLazyUnlock(struct tblock * tblk)
LAZY_UNLOCK(flags);
}

+
+/*
+ * txLazyDrain
+ *
+ * Wait for all pending lazy commit entries for this superblock
+ * to be processed by the jfsCommit thread. Must be called
+ * before freeing per-filesystem structures during unmount.
+ */
+void txLazyDrain(struct super_block *sb)
+{
+ struct jfs_sb_info *sbi = JFS_SBI(sb);
+ struct tblock *tblk;
+ unsigned long flags;
+ bool found;
+
+ do {
+ found = false;
+ LAZY_LOCK(flags);
+ list_for_each_entry(tblk, &TxAnchor.unlock_queue, cqueue) {
+ if (tblk->sb == sb) {
+ found = true;
+ break;
+ }
+ }
+ if (!found && (sbi->commit_state & IN_LAZYCOMMIT))
+ found = true;
+ LAZY_UNLOCK(flags);
+
+ if (found) {
+ wake_up(&jfs_commit_thread_wait);
+ schedule_timeout_uninterruptible(1);
+ }
+ } while (found);
+}
static void LogSyncRelease(struct metapage * mp)
{
struct jfs_log *log = mp->log;
diff --git a/fs/jfs/jfs_txnmgr.h b/fs/jfs/jfs_txnmgr.h
index ba71eb5ced567..fbbaed26c52bd 100644
--- a/fs/jfs/jfs_txnmgr.h
+++ b/fs/jfs/jfs_txnmgr.h
@@ -291,6 +291,7 @@ extern void txFreelock(struct inode *);
extern int lmLog(struct jfs_log *, struct tblock *, struct lrd *,
struct tlock *);
extern void txQuiesce(struct super_block *);
+extern void txLazyDrain(struct super_block *);
extern void txResume(struct super_block *);
extern void txLazyUnlock(struct tblock *);
extern int jfs_lazycommit(void *);
diff --git a/fs/jfs/jfs_umount.c b/fs/jfs/jfs_umount.c
index 18569f1eaabdb..657707361be2a 100644
--- a/fs/jfs/jfs_umount.c
+++ b/fs/jfs/jfs_umount.c
@@ -58,6 +58,13 @@ int jfs_umount(struct super_block *sb)
*/
jfs_flush_journal(log, 2);

+ /*
+ * Drain any pending lazy commit entries for this filesystem so
+ * the jfsCommit thread does not access freed structures.
+ */
+ if (log)
+ txLazyDrain(sb);
+
/*
* Hold log lock so write_special_inodes (lmLogSync) cannot see
* this sbi with a NULL inode pointer while iterating log->sb_list.
@@ -142,6 +149,7 @@ int jfs_umount_rw(struct super_block *sb)
* remove file system from log active file system list.
*/
jfs_flush_journal(log, 2);
+ txLazyDrain(sb);

/*
* Make sure all metadata makes it to disk
--
2.47.3

Reply all
Reply to author
Forward
0 new messages