Skip to contentSkip to conversation

KASAN: use-after-free Write in page_counter_uncharge

DISCUSSION syzbot 5 participants 6 messages Aug 18, 2020 – Aug 25, 2020

Subsystems (2)
lore
Share & tools
lore

syzbot

author syzbot
#0 lore raw

Hello,

syzbot found the following issue on:

HEAD commit:    a1d21081 Merge git://git.kernel.org/pub/scm/linux/kernel/g..
git tree:       upstream
console output: https://syzkaller.appspot.com/x/log.txt?x=17ceb0ce900000
kernel config:  https://syzkaller.appspot.com/x/.config?x=21f0d1d2df6d5fc
dashboard link: https://syzkaller.appspot.com/bug?extid=b305848212deec86eabe
compiler:       clang version 10.0.0 (https://github.com/llvm/llvm-project/ c2443155a0fb245c8f17f2c1c72b6ea391e86e81)

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 [email protected]

==================================================================

BUG: KASAN: use-after-free in instrument_atomic_write include/linux/instrumented.h:71 [inline]
BUG: KASAN: use-after-free in atomic64_sub_return include/asm-generic/atomic-instrumented.h:970 [inline]
BUG: KASAN: use-after-free in atomic_long_sub_return include/asm-generic/atomic-long.h:113 [inline]
BUG: KASAN: use-after-free in page_counter_cancel mm/page_counter.c:54 [inline]
BUG: KASAN: use-after-free in page_counter_uncharge+0x3d/0xc0 mm/page_counter.c:155
Write of size 8 at addr ffff8880371c0148 by task syz-executor.0/9304

CPU: 0 PID: 9304 Comm: syz-executor.0 Not tainted 5.8.0-syzkaller #0
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011
Call Trace:
 __dump_stack lib/dump_stack.c:77 [inline]
 dump_stack+0x1f0/0x31e lib/dump_stack.c:118
 print_address_description+0x66/0x620 mm/kasan/report.c:383
 __kasan_report mm/kasan/report.c:513 [inline]
 kasan_report+0x132/0x1d0 mm/kasan/report.c:530
 check_memory_region_inline mm/kasan/generic.c:183 [inline]
 check_memory_region+0x2b5/0x2f0 mm/kasan/generic.c:192
 instrument_atomic_write include/linux/instrumented.h:71 [inline]
 atomic64_sub_return include/asm-generic/atomic-instrumented.h:970 [inline]
 atomic_long_sub_return include/asm-generic/atomic-long.h:113 [inline]
 page_counter_cancel mm/page_counter.c:54 [inline]
 page_counter_uncharge+0x3d/0xc0 mm/page_counter.c:155
 uncharge_batch+0x6c/0x350 mm/memcontrol.c:6764
 uncharge_page+0x115/0x430 mm/memcontrol.c:6796
 uncharge_list mm/memcontrol.c:6835 [inline]
 mem_cgroup_uncharge_list+0x70/0xe0 mm/memcontrol.c:6877
 release_pages+0x13a2/0x1550 mm/swap.c:911
 tlb_batch_pages_flush mm/mmu_gather.c:49 [inline]
 tlb_flush_mmu_free mm/mmu_gather.c:242 [inline]
 tlb_flush_mmu+0x780/0x910 mm/mmu_gather.c:249
 tlb_finish_mmu+0xcb/0x200 mm/mmu_gather.c:328
 exit_mmap+0x296/0x550 mm/mmap.c:3185
 __mmput+0x113/0x370 kernel/fork.c:1076
 exit_mm+0x4cd/0x550 kernel/exit.c:483
 do_exit+0x576/0x1f20 kernel/exit.c:793
 do_group_exit+0x161/0x2d0 kernel/exit.c:903
 get_signal+0x139b/0x1d30 kernel/signal.c:2743
 arch_do_signal+0x33/0x610 arch/x86/kernel/signal.c:811
 exit_to_user_mode_loop kernel/entry/common.c:135 [inline]
 exit_to_user_mode_prepare+0x8d/0x1b0 kernel/entry/common.c:166
 syscall_exit_to_user_mode+0x5e/0x1a0 kernel/entry/common.c:241
 entry_SYSCALL_64_after_hwframe+0x44/0xa9
RIP: 0033:0x45d239
Code: Bad RIP value.
RSP: 002b:00007f3d8a21acf8 EFLAGS: 00000246 ORIG_RAX: 00000000000000ca
RAX: 0000000000000001 RBX: 000000000118cf48 RCX: 000000000045d239
RDX: 00000000000f4240 RSI: 0000000000000081 RDI: 000000000118cf4c
RBP: 000000000118cf40 R08: 0000000000000009 R09: 0000000000000000
R10: ffffffffffffffff R11: 0000000000000246 R12: 000000000118cf4c
R13: 00007fff2711787f R14: 00007f3d8a21b9c0 R15: 000000000118cf4c

Allocated by task 9270:
 kasan_save_stack mm/kasan/common.c:48 [inline]
 kasan_set_track mm/kasan/common.c:56 [inline]
 __kasan_kmalloc+0x100/0x130 mm/kasan/common.c:461
 __do_kmalloc mm/slab.c:3655 [inline]
 __kmalloc+0x218/0x320 mm/slab.c:3664
 mem_cgroup_alloc mm/memcontrol.c:5210 [inline]
 mem_cgroup_css_alloc+0x86/0x1590 mm/memcontrol.c:5278
 css_create kernel/cgroup/cgroup.c:5128 [inline]
 cgroup_apply_control_enable+0x581/0x1200 kernel/cgroup/cgroup.c:3059
 cgroup_apply_control+0x37/0x6c0 kernel/cgroup/cgroup.c:3141
 cgroup_subtree_control_write+0x95b/0x10c0 kernel/cgroup/cgroup.c:3299
 cgroup_file_write+0x21e/0x5c0 kernel/cgroup/cgroup.c:3697
 kernfs_fop_write+0x3f4/0x4f0 fs/kernfs/file.c:315
 vfs_write+0x2d3/0xd10 fs/read_write.c:576
 ksys_write+0x11b/0x220 fs/read_write.c:631
 do_syscall_64+0x31/0x70 arch/x86/entry/common.c:46
 entry_SYSCALL_64_after_hwframe+0x44/0xa9

Freed by task 8108:
 kasan_save_stack mm/kasan/common.c:48 [inline]
 kasan_set_track+0x3d/0x70 mm/kasan/common.c:56
 kasan_set_free_info+0x17/0x30 mm/kasan/generic.c:355
 __kasan_slab_free+0xdd/0x110 mm/kasan/common.c:422
 __cache_free mm/slab.c:3418 [inline]
 kfree+0x10a/0x220 mm/slab.c:3756
 mem_cgroup_free+0x97f/0x9b0 mm/memcontrol.c:5196
 css_free_rwork_fn+0xe4/0x970 kernel/cgroup/cgroup.c:4941
 process_one_work+0x789/0xfc0 kernel/workqueue.c:2269
 worker_thread+0xaa4/0x1460 kernel/workqueue.c:2415
 kthread+0x37e/0x3a0 drivers/block/aoe/aoecmd.c:1234
 ret_from_fork+0x1f/0x30 arch/x86/entry/entry_64.S:294

Last call_rcu():

 kasan_save_stack+0x27/0x50 mm/kasan/common.c:48
 kasan_record_aux_stack+0x7b/0xb0 mm/kasan/generic.c:346
 __call_rcu kernel/rcu/tree.c:2894 [inline]
 call_rcu+0x139/0x840 kernel/rcu/tree.c:2968
 queue_rcu_work+0x74/0x90 kernel/workqueue.c:1747
 process_one_work+0x789/0xfc0 kernel/workqueue.c:2269
 worker_thread+0xaa4/0x1460 kernel/workqueue.c:2415
 kthread+0x37e/0x3a0 drivers/block/aoe/aoecmd.c:1234
 ret_from_fork+0x1f/0x30 arch/x86/entry/entry_64.S:294

Second to last call_rcu():

 kasan_save_stack+0x27/0x50 mm/kasan/common.c:48
 kasan_record_aux_stack+0x7b/0xb0 mm/kasan/generic.c:346
 __call_rcu kernel/rcu/tree.c:2894 [inline]
 call_rcu+0x139/0x840 kernel/rcu/tree.c:2968
 __percpu_ref_switch_to_atomic lib/percpu-refcount.c:192 [inline]
 __percpu_ref_switch_mode+0x2c1/0x4f0 lib/percpu-refcount.c:237
 percpu_ref_kill_and_confirm+0x8f/0x130 lib/percpu-refcount.c:350
 cgroup_apply_control_disable kernel/cgroup/cgroup.c:3108 [inline]
 cgroup_finalize_control+0x7c5/0xd60 kernel/cgroup/cgroup.c:3171
 cgroup_subtree_control_write+0x968/0x10c0 kernel/cgroup/cgroup.c:3300
 cgroup_file_write+0x21e/0x5c0 kernel/cgroup/cgroup.c:3697
 kernfs_fop_write+0x3f4/0x4f0 fs/kernfs/file.c:315
 vfs_write+0x2d3/0xd10 fs/read_write.c:576
 ksys_write+0x11b/0x220 fs/read_write.c:631
 do_syscall_64+0x31/0x70 arch/x86/entry/common.c:46
 entry_SYSCALL_64_after_hwframe+0x44/0xa9

The buggy address belongs to the object at ffff8880371c0000
 which belongs to the cache kmalloc-4k of size 4096
The buggy address is located 328 bytes inside of
 4096-byte region [ffff8880371c0000, ffff8880371c1000)
The buggy address belongs to the page:
page:00000000cea4402b refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x371c0
head:00000000cea4402b order:1 compound_mapcount:0
flags: 0xfffe0000010200(slab|head)
raw: 00fffe0000010200 ffffea0001337088 ffffea0000dc7088 ffff8880aa440900
raw: 0000000000000000 ffff8880371c0000 0000000100000001 0000000000000000
page dumped because: kasan: bad access detected

Memory state around the buggy address:
 ffff8880371c0000: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
 ffff8880371c0080: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
>ffff8880371c0100: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
                                              ^
 ffff8880371c0180: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
 ffff8880371c0200: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
==================================================================

---
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 [email protected].

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

maintainer
#1 lore raw
Quoted 10 lines · On Tue, 18 Aug 2020 07:50:28 -0700 syzbot…

Hello,

syzbot found the following issue on:

HEAD commit:    a1d21081 Merge git://git.kernel.org/pub/scm/linux/kernel/g..
git tree:       upstream
console output: https://syzkaller.appspot.com/x/log.txt?x=17ceb0ce900000
kernel config:  https://syzkaller.appspot.com/x/.config?x=21f0d1d2df6d5fc
dashboard link: https://syzkaller.appspot.com/bug?extid=b305848212deec86eabe
compiler:       clang version 10.0.0 (https://github.com/llvm/llvm-project/ c2443155a0fb245c8f17f2c1c72b6ea391e86e81)

Presumably this is the same as
http://lkml.kernel.org/r/[email protected].

Quoted 148 lines

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 [email protected]

==================================================================

BUG: KASAN: use-after-free in instrument_atomic_write include/linux/instrumented.h:71 [inline]
BUG: KASAN: use-after-free in atomic64_sub_return include/asm-generic/atomic-instrumented.h:970 [inline]
BUG: KASAN: use-after-free in atomic_long_sub_return include/asm-generic/atomic-long.h:113 [inline]
BUG: KASAN: use-after-free in page_counter_cancel mm/page_counter.c:54 [inline]
BUG: KASAN: use-after-free in page_counter_uncharge+0x3d/0xc0 mm/page_counter.c:155
Write of size 8 at addr ffff8880371c0148 by task syz-executor.0/9304

CPU: 0 PID: 9304 Comm: syz-executor.0 Not tainted 5.8.0-syzkaller #0
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011
Call Trace:
 __dump_stack lib/dump_stack.c:77 [inline]
 dump_stack+0x1f0/0x31e lib/dump_stack.c:118
 print_address_description+0x66/0x620 mm/kasan/report.c:383
 __kasan_report mm/kasan/report.c:513 [inline]
 kasan_report+0x132/0x1d0 mm/kasan/report.c:530
 check_memory_region_inline mm/kasan/generic.c:183 [inline]
 check_memory_region+0x2b5/0x2f0 mm/kasan/generic.c:192
 instrument_atomic_write include/linux/instrumented.h:71 [inline]
 atomic64_sub_return include/asm-generic/atomic-instrumented.h:970 [inline]
 atomic_long_sub_return include/asm-generic/atomic-long.h:113 [inline]
 page_counter_cancel mm/page_counter.c:54 [inline]
 page_counter_uncharge+0x3d/0xc0 mm/page_counter.c:155
 uncharge_batch+0x6c/0x350 mm/memcontrol.c:6764
 uncharge_page+0x115/0x430 mm/memcontrol.c:6796
 uncharge_list mm/memcontrol.c:6835 [inline]
 mem_cgroup_uncharge_list+0x70/0xe0 mm/memcontrol.c:6877
 release_pages+0x13a2/0x1550 mm/swap.c:911
 tlb_batch_pages_flush mm/mmu_gather.c:49 [inline]
 tlb_flush_mmu_free mm/mmu_gather.c:242 [inline]
 tlb_flush_mmu+0x780/0x910 mm/mmu_gather.c:249
 tlb_finish_mmu+0xcb/0x200 mm/mmu_gather.c:328
 exit_mmap+0x296/0x550 mm/mmap.c:3185
 __mmput+0x113/0x370 kernel/fork.c:1076
 exit_mm+0x4cd/0x550 kernel/exit.c:483
 do_exit+0x576/0x1f20 kernel/exit.c:793
 do_group_exit+0x161/0x2d0 kernel/exit.c:903
 get_signal+0x139b/0x1d30 kernel/signal.c:2743
 arch_do_signal+0x33/0x610 arch/x86/kernel/signal.c:811
 exit_to_user_mode_loop kernel/entry/common.c:135 [inline]
 exit_to_user_mode_prepare+0x8d/0x1b0 kernel/entry/common.c:166
 syscall_exit_to_user_mode+0x5e/0x1a0 kernel/entry/common.c:241
 entry_SYSCALL_64_after_hwframe+0x44/0xa9
RIP: 0033:0x45d239
Code: Bad RIP value.
RSP: 002b:00007f3d8a21acf8 EFLAGS: 00000246 ORIG_RAX: 00000000000000ca
RAX: 0000000000000001 RBX: 000000000118cf48 RCX: 000000000045d239
RDX: 00000000000f4240 RSI: 0000000000000081 RDI: 000000000118cf4c
RBP: 000000000118cf40 R08: 0000000000000009 R09: 0000000000000000
R10: ffffffffffffffff R11: 0000000000000246 R12: 000000000118cf4c
R13: 00007fff2711787f R14: 00007f3d8a21b9c0 R15: 000000000118cf4c

Allocated by task 9270:
 kasan_save_stack mm/kasan/common.c:48 [inline]
 kasan_set_track mm/kasan/common.c:56 [inline]
 __kasan_kmalloc+0x100/0x130 mm/kasan/common.c:461
 __do_kmalloc mm/slab.c:3655 [inline]
 __kmalloc+0x218/0x320 mm/slab.c:3664
 mem_cgroup_alloc mm/memcontrol.c:5210 [inline]
 mem_cgroup_css_alloc+0x86/0x1590 mm/memcontrol.c:5278
 css_create kernel/cgroup/cgroup.c:5128 [inline]
 cgroup_apply_control_enable+0x581/0x1200 kernel/cgroup/cgroup.c:3059
 cgroup_apply_control+0x37/0x6c0 kernel/cgroup/cgroup.c:3141
 cgroup_subtree_control_write+0x95b/0x10c0 kernel/cgroup/cgroup.c:3299
 cgroup_file_write+0x21e/0x5c0 kernel/cgroup/cgroup.c:3697
 kernfs_fop_write+0x3f4/0x4f0 fs/kernfs/file.c:315
 vfs_write+0x2d3/0xd10 fs/read_write.c:576
 ksys_write+0x11b/0x220 fs/read_write.c:631
 do_syscall_64+0x31/0x70 arch/x86/entry/common.c:46
 entry_SYSCALL_64_after_hwframe+0x44/0xa9

Freed by task 8108:
 kasan_save_stack mm/kasan/common.c:48 [inline]
 kasan_set_track+0x3d/0x70 mm/kasan/common.c:56
 kasan_set_free_info+0x17/0x30 mm/kasan/generic.c:355
 __kasan_slab_free+0xdd/0x110 mm/kasan/common.c:422
 __cache_free mm/slab.c:3418 [inline]
 kfree+0x10a/0x220 mm/slab.c:3756
 mem_cgroup_free+0x97f/0x9b0 mm/memcontrol.c:5196
 css_free_rwork_fn+0xe4/0x970 kernel/cgroup/cgroup.c:4941
 process_one_work+0x789/0xfc0 kernel/workqueue.c:2269
 worker_thread+0xaa4/0x1460 kernel/workqueue.c:2415
 kthread+0x37e/0x3a0 drivers/block/aoe/aoecmd.c:1234
 ret_from_fork+0x1f/0x30 arch/x86/entry/entry_64.S:294

Last call_rcu():

 kasan_save_stack+0x27/0x50 mm/kasan/common.c:48
 kasan_record_aux_stack+0x7b/0xb0 mm/kasan/generic.c:346
 __call_rcu kernel/rcu/tree.c:2894 [inline]
 call_rcu+0x139/0x840 kernel/rcu/tree.c:2968
 queue_rcu_work+0x74/0x90 kernel/workqueue.c:1747
 process_one_work+0x789/0xfc0 kernel/workqueue.c:2269
 worker_thread+0xaa4/0x1460 kernel/workqueue.c:2415
 kthread+0x37e/0x3a0 drivers/block/aoe/aoecmd.c:1234
 ret_from_fork+0x1f/0x30 arch/x86/entry/entry_64.S:294

Second to last call_rcu():

 kasan_save_stack+0x27/0x50 mm/kasan/common.c:48
 kasan_record_aux_stack+0x7b/0xb0 mm/kasan/generic.c:346
 __call_rcu kernel/rcu/tree.c:2894 [inline]
 call_rcu+0x139/0x840 kernel/rcu/tree.c:2968
 __percpu_ref_switch_to_atomic lib/percpu-refcount.c:192 [inline]
 __percpu_ref_switch_mode+0x2c1/0x4f0 lib/percpu-refcount.c:237
 percpu_ref_kill_and_confirm+0x8f/0x130 lib/percpu-refcount.c:350
 cgroup_apply_control_disable kernel/cgroup/cgroup.c:3108 [inline]
 cgroup_finalize_control+0x7c5/0xd60 kernel/cgroup/cgroup.c:3171
 cgroup_subtree_control_write+0x968/0x10c0 kernel/cgroup/cgroup.c:3300
 cgroup_file_write+0x21e/0x5c0 kernel/cgroup/cgroup.c:3697
 kernfs_fop_write+0x3f4/0x4f0 fs/kernfs/file.c:315
 vfs_write+0x2d3/0xd10 fs/read_write.c:576
 ksys_write+0x11b/0x220 fs/read_write.c:631
 do_syscall_64+0x31/0x70 arch/x86/entry/common.c:46
 entry_SYSCALL_64_after_hwframe+0x44/0xa9

The buggy address belongs to the object at ffff8880371c0000
 which belongs to the cache kmalloc-4k of size 4096
The buggy address is located 328 bytes inside of
 4096-byte region [ffff8880371c0000, ffff8880371c1000)
The buggy address belongs to the page:
page:00000000cea4402b refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x371c0
head:00000000cea4402b order:1 compound_mapcount:0
flags: 0xfffe0000010200(slab|head)
raw: 00fffe0000010200 ffffea0001337088 ffffea0000dc7088 ffff8880aa440900
raw: 0000000000000000 ffff8880371c0000 0000000100000001 0000000000000000
page dumped because: kasan: bad access detected

Memory state around the buggy address:
 ffff8880371c0000: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
 ffff8880371c0080: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
>ffff8880371c0100: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
                                              ^
 ffff8880371c0180: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
 ffff8880371c0200: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
==================================================================

---
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 [email protected].

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

#2 lore raw
Quoted 13 lines · Andrew Morton
Quoted 10 lines · On Tue, 18 Aug 2020 07:50:28 -0700 syzbot…

Hello,

syzbot found the following issue on:

HEAD commit:    a1d21081 Merge git://git.kernel.org/pub/scm/linux/kernel/g..
git tree:       upstream
console output: https://syzkaller.appspot.com/x/log.txt?x=17ceb0ce900000
kernel config:  https://syzkaller.appspot.com/x/.config?x=21f0d1d2df6d5fc
dashboard link: https://syzkaller.appspot.com/bug?extid=b305848212deec86eabe
compiler:       clang version 10.0.0 (https://github.com/llvm/llvm-project/ c2443155a0fb245c8f17f2c1c72b6ea391e86e81)
Quoted 2 lines

Presumably this is the same as
http://lkml.kernel.org/r/[email protected].

Very likely.

Quoted 25 lines
Quoted 25 lines

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 [email protected]

==================================================================

BUG: KASAN: use-after-free in instrument_atomic_write include/linux/instrumented.h:71 [inline]
BUG: KASAN: use-after-free in atomic64_sub_return include/asm-generic/atomic-instrumented.h:970 [inline]
BUG: KASAN: use-after-free in atomic_long_sub_return include/asm-generic/atomic-long.h:113 [inline]
BUG: KASAN: use-after-free in page_counter_cancel mm/page_counter.c:54 [inline]
BUG: KASAN: use-after-free in page_counter_uncharge+0x3d/0xc0 mm/page_counter.c:155
Write of size 8 at addr ffff8880371c0148 by task syz-executor.0/9304

CPU: 0 PID: 9304 Comm: syz-executor.0 Not tainted 5.8.0-syzkaller #0
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011
Call Trace:
 __dump_stack lib/dump_stack.c:77 [inline]
 dump_stack+0x1f0/0x31e lib/dump_stack.c:118
 print_address_description+0x66/0x620 mm/kasan/report.c:383
 __kasan_report mm/kasan/report.c:513 [inline]
 kasan_report+0x132/0x1d0 mm/kasan/report.c:530
 check_memory_region_inline mm/kasan/generic.c:183 [inline]
 check_memory_region+0x2b5/0x2f0 mm/kasan/generic.c:192
 instrument_atomic_write include/linux/instrumented.h:71 [inline]
 atomic64_sub_return include/asm-generic/atomic-instrumented.h:970 [inline]
Quoted 8 lines
Quoted 8 lines
 atomic_long_sub_return include/asm-generic/atomic-long.h:113 [inline]
 page_counter_cancel mm/page_counter.c:54 [inline]
 page_counter_uncharge+0x3d/0xc0 mm/page_counter.c:155
 uncharge_batch+0x6c/0x350 mm/memcontrol.c:6764
 uncharge_page+0x115/0x430 mm/memcontrol.c:6796
 uncharge_list mm/memcontrol.c:6835 [inline]
 mem_cgroup_uncharge_list+0x70/0xe0 mm/memcontrol.c:6877
 release_pages+0x13a2/0x1550 mm/swap.c:911

This looks like a reference count unbalance when memcg is released early. My first guess would be 1a3e1f40962c ("mm: memcontrol: decouple reference counting from page accounting").

Unless I am missing something nothing really prevents the memcg for the current batch to go away. uncharge_page collects all the charges for the same memcg but it later drops the reference for the current page. Later on when the memcg changes or when the final clean up is done in uncharge_list uncharge_batch needs to access memcg but this might be after the last page dropped the reference and memcg went away. The whole process of tear down is quite complex and takes some time with all the RCU/WQ involvement so this is quite unlikely to hit.

That being said the below should cure the reference count but I am not sure this is a complete fix. If this looks reasonable I will post the full patch. Johannes?

---

mm/memcontrol.c +2 -0
index b807952b4d43..11b6dd1c4f64 100644
@@ -6753,6 +6753,7 @@ struct uncharge_gather {
 
 static inline void uncharge_gather_clear(struct uncharge_gather *ug)
 {
+	css_put(&ug->memcg->css);
 	memset(ug, 0, sizeof(*ug));
 }
 
@@ -6797,6 +6798,7 @@ static void uncharge_page(struct page *page, struct uncharge_gather *ug)
 			uncharge_gather_clear(ug);
 		}
 		ug->memcg = page->mem_cgroup;
+		css_get(&ug->memcg->css);
 	}
 
 	nr_pages = compound_nr(page);
Signature · 2 lines
Michal Hocko
SUSE Labs
#3 lore raw

On Wed 19-08-20 08:34:22, Michal Hocko wrote:
[...]

Quoted 13 lines
mm/memcontrol.c +1 -0
index b807952b4d43..11b6dd1c4f64 100644
@@ -6753,6 +6753,7 @@ struct uncharge_gather {
 
 static inline void uncharge_gather_clear(struct uncharge_gather *ug)
 {
+	css_put(&ug->memcg->css);
 	memset(ug, 0, sizeof(*ug));
 }
 

mm/memcontrol.c static void uncharge_page(struct page *page, struct uncharge_gather *ug) · line 6804

Quoted 7 lines
mm/memcontrol.c +1 -0
@@ -6797,6 +6798,7 @@ static void uncharge_page(struct page *page, struct uncharge_gather *ug)
 			uncharge_gather_clear(ug);
 		}
 		ug->memcg = page->mem_cgroup;
+		css_get(&ug->memcg->css);
 	}
 
 	nr_pages = compound_nr(page);

This is not a proper fix because uncharge_gather_clear is called also to initialize the initial state so ug->memcg would be a garbage from the stack. The proper fix with the full changelog should be. Let's add more people involved in the original commit to the CC. The initial report is
http://lkml.kernel.org/r/[email protected] resp.
http://lkml.kernel.org/r/[email protected]

From 73a40589cab12122170fb9f90222982e81d41423 Mon Sep 17 00:00:00 2001
From: Michal Hocko <[email protected]>
Date: Thu, 20 Aug 2020 10:44:58 +0200
Subject: [PATCH] memcg: fix use-after-free in uncharge_batch

syzbot has reported an use-after-free in the uncharge_batch path

BUG: KASAN: use-after-free in instrument_atomic_write include/linux/instrumented.h:71 [inline]
BUG: KASAN: use-after-free in atomic64_sub_return include/asm-generic/atomic-instrumented.h:970 [inline]
BUG: KASAN: use-after-free in atomic_long_sub_return include/asm-generic/atomic-long.h:113 [inline]
BUG: KASAN: use-after-free in page_counter_cancel mm/page_counter.c:54 [inline]
BUG: KASAN: use-after-free in page_counter_uncharge+0x3d/0xc0 mm/page_counter.c:155
Write of size 8 at addr ffff8880371c0148 by task syz-executor.0/9304

CPU: 0 PID: 9304 Comm: syz-executor.0 Not tainted 5.8.0-syzkaller #0
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011
Call Trace:
 __dump_stack lib/dump_stack.c:77 [inline]
 dump_stack+0x1f0/0x31e lib/dump_stack.c:118
 print_address_description+0x66/0x620 mm/kasan/report.c:383
 __kasan_report mm/kasan/report.c:513 [inline]
 kasan_report+0x132/0x1d0 mm/kasan/report.c:530
 check_memory_region_inline mm/kasan/generic.c:183 [inline]
 check_memory_region+0x2b5/0x2f0 mm/kasan/generic.c:192
 instrument_atomic_write include/linux/instrumented.h:71 [inline]
 atomic64_sub_return include/asm-generic/atomic-instrumented.h:970 [inline]
 atomic_long_sub_return include/asm-generic/atomic-long.h:113 [inline]
 page_counter_cancel mm/page_counter.c:54 [inline]
 page_counter_uncharge+0x3d/0xc0 mm/page_counter.c:155
 uncharge_batch+0x6c/0x350 mm/memcontrol.c:6764
 uncharge_page+0x115/0x430 mm/memcontrol.c:6796
 uncharge_list mm/memcontrol.c:6835 [inline]
 mem_cgroup_uncharge_list+0x70/0xe0 mm/memcontrol.c:6877
 release_pages+0x13a2/0x1550 mm/swap.c:911
 tlb_batch_pages_flush mm/mmu_gather.c:49 [inline]
 tlb_flush_mmu_free mm/mmu_gather.c:242 [inline]
 tlb_flush_mmu+0x780/0x910 mm/mmu_gather.c:249
 tlb_finish_mmu+0xcb/0x200 mm/mmu_gather.c:328
 exit_mmap+0x296/0x550 mm/mmap.c:3185
 __mmput+0x113/0x370 kernel/fork.c:1076
 exit_mm+0x4cd/0x550 kernel/exit.c:483
 do_exit+0x576/0x1f20 kernel/exit.c:793
 do_group_exit+0x161/0x2d0 kernel/exit.c:903
 get_signal+0x139b/0x1d30 kernel/signal.c:2743
 arch_do_signal+0x33/0x610 arch/x86/kernel/signal.c:811
 exit_to_user_mode_loop kernel/entry/common.c:135 [inline]
 exit_to_user_mode_prepare+0x8d/0x1b0 kernel/entry/common.c:166
 syscall_exit_to_user_mode+0x5e/0x1a0 kernel/entry/common.c:241
 entry_SYSCALL_64_after_hwframe+0x44/0xa9

1a3e1f40962c ("mm: memcontrol: decouple reference counting from page accounting") has reworked the memcg lifetime to be bound the the struct page rather than charges. It has also removed the css_put_many from uncharge_batch and that is causing the above splat. uncharge_batch is supposed to uncharge accumulated charges for all pages freed from the same memcg. The queuing is done by uncharge_page which however drops the memcg reference after it adds charges to the batch. If the current page happens to be the last one holding the reference for its memcg then the memcg is OK to go and the next page to be freed will trigger batched uncharge which needs to access the memcg which is gone already.

Fix the issue by taking a reference for the memcg in the current batch.

Fixes 1a3e1f40962c ("mm: memcontrol: decouple reference counting from page accounting")
Reported-by [email protected]
Reported-by [email protected]
---
 mm/memcontrol.c | 6 ++++++
 1 file changed, 6 insertions(+)
mm/memcontrol.c +6 -0
index b807952b4d43..cfa6cbad21d5 100644
@@ -6774,6 +6774,9 @@ static void uncharge_batch(const struct uncharge_gather *ug)
 	__this_cpu_add(ug->memcg->vmstats_percpu->nr_page_events, ug->nr_pages);
 	memcg_check_events(ug->memcg, ug->dummy_page);
 	local_irq_restore(flags);
+
+	/* drop reference from uncharge_page */
+	css_put(&ug->memcg->css);
 }
 
 static void uncharge_page(struct page *page, struct uncharge_gather *ug)
@@ -6797,6 +6800,9 @@ static void uncharge_page(struct page *page, struct uncharge_gather *ug)
 			uncharge_gather_clear(ug);
 		}
 		ug->memcg = page->mem_cgroup;
+
+		/* pairs with css_put in uncharge_batch */
+		css_get(&ug->memcg->css);
 	}
 
 	nr_pages = compound_nr(page);
Signature · 5 lines
2.28.0

-- 
Michal Hocko
SUSE Labs
Reviewed-by
#4 lore raw
Quoted 91 lines · Michal Hocko

On Wed 19-08-20 08:34:22, Michal Hocko wrote:
[...]

Quoted 13 lines
mm/memcontrol.c +1 -0
index b807952b4d43..11b6dd1c4f64 100644
@@ -6753,6 +6753,7 @@ struct uncharge_gather {
 
 static inline void uncharge_gather_clear(struct uncharge_gather *ug)
 {
+     css_put(&ug->memcg->css);
      memset(ug, 0, sizeof(*ug));
 }
 

mm/memcontrol.c static void uncharge_page(struct page *page, struct uncharge_gather *ug) · line 6804

Quoted 7 lines
mm/memcontrol.c +1 -0
@@ -6797,6 +6798,7 @@ static void uncharge_page(struct page *page, struct uncharge_gather *ug)
                      uncharge_gather_clear(ug);
              }
              ug->memcg = page->mem_cgroup;
+             css_get(&ug->memcg->css);
      }
 
      nr_pages = compound_nr(page);

This is not a proper fix because uncharge_gather_clear is called also to initialize the initial state so ug->memcg would be a garbage from the stack. The proper fix with the full changelog should be. Let's add more people involved in the original commit to the CC. The initial report is
http://lkml.kernel.org/r/[email protected] resp.
http://lkml.kernel.org/r/[email protected]

From 73a40589cab12122170fb9f90222982e81d41423 Mon Sep 17 00:00:00 2001
From: Michal Hocko <[email protected]>
Date: Thu, 20 Aug 2020 10:44:58 +0200
Subject: [PATCH] memcg: fix use-after-free in uncharge_batch

syzbot has reported an use-after-free in the uncharge_batch path

BUG: KASAN: use-after-free in instrument_atomic_write include/linux/instrumented.h:71 [inline]
BUG: KASAN: use-after-free in atomic64_sub_return include/asm-generic/atomic-instrumented.h:970 [inline]
BUG: KASAN: use-after-free in atomic_long_sub_return include/asm-generic/atomic-long.h:113 [inline]
BUG: KASAN: use-after-free in page_counter_cancel mm/page_counter.c:54 [inline]
BUG: KASAN: use-after-free in page_counter_uncharge+0x3d/0xc0 mm/page_counter.c:155
Write of size 8 at addr ffff8880371c0148 by task syz-executor.0/9304

CPU: 0 PID: 9304 Comm: syz-executor.0 Not tainted 5.8.0-syzkaller #0
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011
Call Trace:
 __dump_stack lib/dump_stack.c:77 [inline]
 dump_stack+0x1f0/0x31e lib/dump_stack.c:118
 print_address_description+0x66/0x620 mm/kasan/report.c:383
 __kasan_report mm/kasan/report.c:513 [inline]
 kasan_report+0x132/0x1d0 mm/kasan/report.c:530
 check_memory_region_inline mm/kasan/generic.c:183 [inline]
 check_memory_region+0x2b5/0x2f0 mm/kasan/generic.c:192
 instrument_atomic_write include/linux/instrumented.h:71 [inline]
 atomic64_sub_return include/asm-generic/atomic-instrumented.h:970 [inline]
 atomic_long_sub_return include/asm-generic/atomic-long.h:113 [inline]
 page_counter_cancel mm/page_counter.c:54 [inline]
 page_counter_uncharge+0x3d/0xc0 mm/page_counter.c:155
 uncharge_batch+0x6c/0x350 mm/memcontrol.c:6764
 uncharge_page+0x115/0x430 mm/memcontrol.c:6796
 uncharge_list mm/memcontrol.c:6835 [inline]
 mem_cgroup_uncharge_list+0x70/0xe0 mm/memcontrol.c:6877
 release_pages+0x13a2/0x1550 mm/swap.c:911
 tlb_batch_pages_flush mm/mmu_gather.c:49 [inline]
 tlb_flush_mmu_free mm/mmu_gather.c:242 [inline]
 tlb_flush_mmu+0x780/0x910 mm/mmu_gather.c:249
 tlb_finish_mmu+0xcb/0x200 mm/mmu_gather.c:328
 exit_mmap+0x296/0x550 mm/mmap.c:3185
 __mmput+0x113/0x370 kernel/fork.c:1076
 exit_mm+0x4cd/0x550 kernel/exit.c:483
 do_exit+0x576/0x1f20 kernel/exit.c:793
 do_group_exit+0x161/0x2d0 kernel/exit.c:903
 get_signal+0x139b/0x1d30 kernel/signal.c:2743
 arch_do_signal+0x33/0x610 arch/x86/kernel/signal.c:811
 exit_to_user_mode_loop kernel/entry/common.c:135 [inline]
 exit_to_user_mode_prepare+0x8d/0x1b0 kernel/entry/common.c:166
 syscall_exit_to_user_mode+0x5e/0x1a0 kernel/entry/common.c:241
 entry_SYSCALL_64_after_hwframe+0x44/0xa9

1a3e1f40962c ("mm: memcontrol: decouple reference counting from page accounting") has reworked the memcg lifetime to be bound the the struct page rather than charges. It has also removed the css_put_many from uncharge_batch and that is causing the above splat. uncharge_batch is supposed to uncharge accumulated charges for all pages freed from the same memcg. The queuing is done by uncharge_page which however drops the memcg reference after it adds charges to the batch. If the current page happens to be the last one holding the reference for its memcg then the memcg is OK to go and the next page to be freed will trigger batched uncharge which needs to access the memcg which is gone already.

Quoted 6 lines

Fix the issue by taking a reference for the memcg in the current batch.

Fixes 1a3e1f40962c ("mm: memcontrol: decouple reference counting from page accounting")
Reported-by [email protected]
Reported-by [email protected]

Seems correct to me.

maintainer Acked-by
#5 lore raw
In reply to Michal Hocko
Quoted 60 lines · Michal Hocko

From 73a40589cab12122170fb9f90222982e81d41423 Mon Sep 17 00:00:00 2001
From: Michal Hocko <[email protected]>
Date: Thu, 20 Aug 2020 10:44:58 +0200
Subject: [PATCH] memcg: fix use-after-free in uncharge_batch

syzbot has reported an use-after-free in the uncharge_batch path

BUG: KASAN: use-after-free in instrument_atomic_write include/linux/instrumented.h:71 [inline]
BUG: KASAN: use-after-free in atomic64_sub_return include/asm-generic/atomic-instrumented.h:970 [inline]
BUG: KASAN: use-after-free in atomic_long_sub_return include/asm-generic/atomic-long.h:113 [inline]
BUG: KASAN: use-after-free in page_counter_cancel mm/page_counter.c:54 [inline]
BUG: KASAN: use-after-free in page_counter_uncharge+0x3d/0xc0 mm/page_counter.c:155
Write of size 8 at addr ffff8880371c0148 by task syz-executor.0/9304

CPU: 0 PID: 9304 Comm: syz-executor.0 Not tainted 5.8.0-syzkaller #0
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011
Call Trace:
 __dump_stack lib/dump_stack.c:77 [inline]
 dump_stack+0x1f0/0x31e lib/dump_stack.c:118
 print_address_description+0x66/0x620 mm/kasan/report.c:383
 __kasan_report mm/kasan/report.c:513 [inline]
 kasan_report+0x132/0x1d0 mm/kasan/report.c:530
 check_memory_region_inline mm/kasan/generic.c:183 [inline]
 check_memory_region+0x2b5/0x2f0 mm/kasan/generic.c:192
 instrument_atomic_write include/linux/instrumented.h:71 [inline]
 atomic64_sub_return include/asm-generic/atomic-instrumented.h:970 [inline]
 atomic_long_sub_return include/asm-generic/atomic-long.h:113 [inline]
 page_counter_cancel mm/page_counter.c:54 [inline]
 page_counter_uncharge+0x3d/0xc0 mm/page_counter.c:155
 uncharge_batch+0x6c/0x350 mm/memcontrol.c:6764
 uncharge_page+0x115/0x430 mm/memcontrol.c:6796
 uncharge_list mm/memcontrol.c:6835 [inline]
 mem_cgroup_uncharge_list+0x70/0xe0 mm/memcontrol.c:6877
 release_pages+0x13a2/0x1550 mm/swap.c:911
 tlb_batch_pages_flush mm/mmu_gather.c:49 [inline]
 tlb_flush_mmu_free mm/mmu_gather.c:242 [inline]
 tlb_flush_mmu+0x780/0x910 mm/mmu_gather.c:249
 tlb_finish_mmu+0xcb/0x200 mm/mmu_gather.c:328
 exit_mmap+0x296/0x550 mm/mmap.c:3185
 __mmput+0x113/0x370 kernel/fork.c:1076
 exit_mm+0x4cd/0x550 kernel/exit.c:483
 do_exit+0x576/0x1f20 kernel/exit.c:793
 do_group_exit+0x161/0x2d0 kernel/exit.c:903
 get_signal+0x139b/0x1d30 kernel/signal.c:2743
 arch_do_signal+0x33/0x610 arch/x86/kernel/signal.c:811
 exit_to_user_mode_loop kernel/entry/common.c:135 [inline]
 exit_to_user_mode_prepare+0x8d/0x1b0 kernel/entry/common.c:166
 syscall_exit_to_user_mode+0x5e/0x1a0 kernel/entry/common.c:241
 entry_SYSCALL_64_after_hwframe+0x44/0xa9

1a3e1f40962c ("mm: memcontrol: decouple reference counting from page accounting") has reworked the memcg lifetime to be bound the the struct page rather than charges. It has also removed the css_put_many from uncharge_batch and that is causing the above splat. uncharge_batch is supposed to uncharge accumulated charges for all pages freed from the same memcg. The queuing is done by uncharge_page which however drops the memcg reference after it adds charges to the batch. If the current page happens to be the last one holding the reference for its memcg then the memcg is OK to go and the next page to be freed will trigger batched uncharge which needs to access the memcg which is gone already.

Quoted 6 lines

Fix the issue by taking a reference for the memcg in the current batch.

Fixes 1a3e1f40962c ("mm: memcontrol: decouple reference counting from page accounting")
Reported-by [email protected]
Reported-by [email protected]

Nice catch! The fix looks correct - ug now holds a reference count for its ug->memcg pointer.