[syzbot] [hams?] KASAN: slab-use-after-free Read in nr_add_node

14 views
Skip to first unread message

syzbot

unread,
Sep 25, 2025, 12:35:27 PMSep 25
to da...@davemloft.net, edum...@google.com, ho...@kernel.org, ku...@kernel.org, linux...@vger.kernel.org, linux-...@vger.kernel.org, net...@vger.kernel.org, pab...@redhat.com, syzkall...@googlegroups.com
Hello,

syzbot found the following issue on:

HEAD commit: 846bd2225ec3 Add linux-next specific files for 20250919
git tree: linux-next
console output: https://syzkaller.appspot.com/x/log.txt?x=130c08e2580000
kernel config: https://syzkaller.appspot.com/x/.config?x=135377594f35b576
dashboard link: https://syzkaller.appspot.com/bug?extid=2860e75836a08b172755
compiler: Debian clang version 20.1.8 (++20250708063551+0c9f909b7976-1~exp1~20250708183702.136), Debian LLD 20.1.8
syz repro: https://syzkaller.appspot.com/x/repro.syz?x=13f3fe42580000

Downloadable assets:
disk image: https://storage.googleapis.com/syzbot-assets/c53d48022f8a/disk-846bd222.raw.xz
vmlinux: https://storage.googleapis.com/syzbot-assets/483534e784c8/vmlinux-846bd222.xz
kernel image: https://storage.googleapis.com/syzbot-assets/721b36eec9b3/bzImage-846bd222.xz

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

==================================================================
BUG: KASAN: slab-use-after-free in nr_add_node+0x251b/0x2580 net/netrom/nr_route.c:248
Read of size 2 at addr ffff888078ae2632 by task syz.0.4719/15936

CPU: 0 UID: 0 PID: 15936 Comm: syz.0.4719 Not tainted syzkaller #0 PREEMPT(full)
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 08/18/2025
Call Trace:
<TASK>
dump_stack_lvl+0x189/0x250 lib/dump_stack.c:120
print_address_description mm/kasan/report.c:378 [inline]
print_report+0xca/0x240 mm/kasan/report.c:482
kasan_report+0x118/0x150 mm/kasan/report.c:595
nr_add_node+0x251b/0x2580 net/netrom/nr_route.c:248
nr_rt_ioctl+0x9f1/0xb00 net/netrom/nr_route.c:651
sock_do_ioctl+0xdc/0x300 net/socket.c:1241
sock_ioctl+0x576/0x790 net/socket.c:1362
vfs_ioctl fs/ioctl.c:51 [inline]
__do_sys_ioctl fs/ioctl.c:597 [inline]
__se_sys_ioctl+0xfc/0x170 fs/ioctl.c:583
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0xfa/0xfa0 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7f29de38ec29
Code: ff ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 a8 ff ff ff f7 d8 64 89 01 48
RSP: 002b:00007f29df216038 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
RAX: ffffffffffffffda RBX: 00007f29de5d5fa0 RCX: 00007f29de38ec29
RDX: 0000200000000000 RSI: 000000000000890b RDI: 0000000000000004
RBP: 00007f29de411e41 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
R13: 00007f29de5d6038 R14: 00007f29de5d5fa0 R15: 00007ffedaf2ceb8
</TASK>

Allocated by task 15939:
kasan_save_stack mm/kasan/common.c:56 [inline]
kasan_save_track+0x3e/0x80 mm/kasan/common.c:77
poison_kmalloc_redzone mm/kasan/common.c:400 [inline]
__kasan_kmalloc+0x93/0xb0 mm/kasan/common.c:417
kasan_kmalloc include/linux/kasan.h:262 [inline]
__kmalloc_cache_noprof+0x3d5/0x6f0 mm/slub.c:5723
kmalloc_noprof include/linux/slab.h:957 [inline]
nr_add_node+0x804/0x2580 net/netrom/nr_route.c:146
nr_rt_ioctl+0x9f1/0xb00 net/netrom/nr_route.c:651
sock_do_ioctl+0xdc/0x300 net/socket.c:1241
sock_ioctl+0x576/0x790 net/socket.c:1362
vfs_ioctl fs/ioctl.c:51 [inline]
__do_sys_ioctl fs/ioctl.c:597 [inline]
__se_sys_ioctl+0xfc/0x170 fs/ioctl.c:583
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0xfa/0xfa0 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f

Freed by task 15936:
kasan_save_stack mm/kasan/common.c:56 [inline]
kasan_save_track+0x3e/0x80 mm/kasan/common.c:77
__kasan_save_free_info+0x46/0x50 mm/kasan/generic.c:587
kasan_save_free_info mm/kasan/kasan.h:406 [inline]
poison_slab_object mm/kasan/common.c:252 [inline]
__kasan_slab_free+0x5c/0x80 mm/kasan/common.c:284
kasan_slab_free include/linux/kasan.h:234 [inline]
slab_free_hook mm/slub.c:2507 [inline]
slab_free mm/slub.c:6557 [inline]
kfree+0x19a/0x6d0 mm/slub.c:6765
nr_add_node+0x1cbe/0x2580 net/netrom/nr_route.c:246
nr_rt_ioctl+0x9f1/0xb00 net/netrom/nr_route.c:651
sock_do_ioctl+0xdc/0x300 net/socket.c:1241
sock_ioctl+0x576/0x790 net/socket.c:1362
vfs_ioctl fs/ioctl.c:51 [inline]
__do_sys_ioctl fs/ioctl.c:597 [inline]
__se_sys_ioctl+0xfc/0x170 fs/ioctl.c:583
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0xfa/0xfa0 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f

The buggy address belongs to the object at ffff888078ae2600
which belongs to the cache kmalloc-64 of size 64
The buggy address is located 50 bytes inside of
freed 64-byte region [ffff888078ae2600, ffff888078ae2640)

The buggy address belongs to the physical page:
page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x78ae2
flags: 0xfff00000000000(node=0|zone=1|lastcpupid=0x7ff)
page_type: f5(slab)
raw: 00fff00000000000 ffff88801b0418c0 ffffea0000c51900 dead000000000004
raw: 0000000000000000 0000000000200020 00000000f5000000 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 0x52c40(GFP_NOFS|__GFP_NOWARN|__GFP_NORETRY|__GFP_COMP), pid 5233, tgid 5233 (udevd), ts 92365645188, free_ts 92323224662
set_page_owner include/linux/page_owner.h:32 [inline]
post_alloc_hook+0x240/0x2a0 mm/page_alloc.c:1850
prep_new_page mm/page_alloc.c:1858 [inline]
get_page_from_freelist+0x21e4/0x22c0 mm/page_alloc.c:3869
__alloc_frozen_pages_noprof+0x181/0x370 mm/page_alloc.c:5159
alloc_pages_mpol+0x232/0x4a0 mm/mempolicy.c:2416
alloc_slab_page mm/slub.c:3023 [inline]
allocate_slab+0x96/0x3a0 mm/slub.c:3196
new_slab mm/slub.c:3250 [inline]
___slab_alloc+0xe94/0x1920 mm/slub.c:4626
__slab_alloc+0x65/0x100 mm/slub.c:4745
__slab_alloc_node mm/slub.c:4821 [inline]
slab_alloc_node mm/slub.c:5232 [inline]
__do_kmalloc_node mm/slub.c:5601 [inline]
__kmalloc_noprof+0x471/0x7f0 mm/slub.c:5614
kmalloc_noprof include/linux/slab.h:961 [inline]
kzalloc_noprof include/linux/slab.h:1094 [inline]
tomoyo_encode2 security/tomoyo/realpath.c:45 [inline]
tomoyo_encode+0x28b/0x550 security/tomoyo/realpath.c:80
tomoyo_realpath_from_path+0x58d/0x5d0 security/tomoyo/realpath.c:283
tomoyo_get_realpath security/tomoyo/file.c:151 [inline]
tomoyo_path_perm+0x213/0x4b0 security/tomoyo/file.c:822
security_inode_getattr+0x12f/0x330 security/security.c:2416
vfs_getattr fs/stat.c:259 [inline]
vfs_fstat fs/stat.c:281 [inline]
__do_sys_newfstat fs/stat.c:555 [inline]
__se_sys_newfstat fs/stat.c:550 [inline]
__x64_sys_newfstat+0xfc/0x200 fs/stat.c:550
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0xfa/0xfa0 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f
page last free pid 5528 tgid 5528 stack trace:
reset_page_owner include/linux/page_owner.h:25 [inline]
free_pages_prepare mm/page_alloc.c:1394 [inline]
__free_frozen_pages+0xbc4/0xd30 mm/page_alloc.c:2906
rcu_do_batch kernel/rcu/tree.c:2605 [inline]
rcu_core+0xcab/0x1770 kernel/rcu/tree.c:2861
handle_softirqs+0x286/0x870 kernel/softirq.c:622
__do_softirq kernel/softirq.c:656 [inline]
invoke_softirq kernel/softirq.c:496 [inline]
__irq_exit_rcu+0xca/0x1f0 kernel/softirq.c:723
irq_exit_rcu+0x9/0x30 kernel/softirq.c:739
instr_sysvec_apic_timer_interrupt arch/x86/kernel/apic/apic.c:1052 [inline]
sysvec_apic_timer_interrupt+0xa6/0xc0 arch/x86/kernel/apic/apic.c:1052
asm_sysvec_apic_timer_interrupt+0x1a/0x20 arch/x86/include/asm/idtentry.h:697

Memory state around the buggy address:
ffff888078ae2500: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
ffff888078ae2580: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
>ffff888078ae2600: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
^
ffff888078ae2680: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
ffff888078ae2700: fa fb fb fb fb fb fb fb 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.

If the report is already addressed, let syzbot know by replying with:
#syz fix: exact-commit-title

If you want syzbot to run the reproducer, reply with:
#syz test: git://repo/address.git branch-or-commit-hash
If you attach or paste a git patch, syzbot will apply it before testing.

If you want to overwrite report's subsystems, reply with:
#syz set subsystems: new-subsystem
(See the list of subsystem names on the web dashboard)

If the report is a duplicate of another one, reply with:
#syz dup: exact-subject-of-another-report

If you want to undo deduplication, reply with:
#syz undup

syzbot

unread,
Oct 18, 2025, 4:37:32 PM (8 days ago) Oct 18
to da...@davemloft.net, edum...@google.com, ho...@kernel.org, ku...@kernel.org, linux...@vger.kernel.org, linux-...@vger.kernel.org, net...@vger.kernel.org, pab...@redhat.com, syzkall...@googlegroups.com
syzbot has found a reproducer for the following issue on:

HEAD commit: f406055cb18c Merge tag 'arm64-fixes' of git://git.kernel.o..
git tree: upstream
console output: https://syzkaller.appspot.com/x/log.txt?x=11cf767c580000
kernel config: https://syzkaller.appspot.com/x/.config?x=f3e7b5a3627a90dd
dashboard link: https://syzkaller.appspot.com/bug?extid=2860e75836a08b172755
compiler: gcc (Debian 12.2.0-14+deb12u1) 12.2.0, GNU ld (GNU Binutils for Debian) 2.40
syz repro: https://syzkaller.appspot.com/x/repro.syz?x=155f1de2580000
C reproducer: https://syzkaller.appspot.com/x/repro.c?x=12b6b52f980000

Downloadable assets:
disk image (non-bootable): https://storage.googleapis.com/syzbot-assets/d900f083ada3/non_bootable_disk-f406055c.raw.xz
vmlinux: https://storage.googleapis.com/syzbot-assets/a4db2a99bfb1/vmlinux-f406055c.xz
kernel image: https://storage.googleapis.com/syzbot-assets/91d1ca420bac/bzImage-f406055c.xz

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

==================================================================
BUG: KASAN: slab-use-after-free in nr_add_node+0x25db/0x2c00 net/netrom/nr_route.c:248
Read of size 4 at addr ffff888054b8cc30 by task syz.3.7839/22393

CPU: 3 UID: 0 PID: 22393 Comm: syz.3.7839 Not tainted syzkaller #0 PREEMPT(full)
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2~bpo12+1 04/01/2014
Call Trace:
<TASK>
__dump_stack lib/dump_stack.c:94 [inline]
dump_stack_lvl+0x116/0x1f0 lib/dump_stack.c:120
print_address_description mm/kasan/report.c:378 [inline]
print_report+0xcd/0x630 mm/kasan/report.c:482
kasan_report+0xe0/0x110 mm/kasan/report.c:595
nr_add_node+0x25db/0x2c00 net/netrom/nr_route.c:248
nr_rt_ioctl+0x11b7/0x29b0 net/netrom/nr_route.c:651
nr_ioctl+0x19a/0x2d0 net/netrom/af_netrom.c:1254
sock_do_ioctl+0x118/0x280 net/socket.c:1254
sock_ioctl+0x227/0x6b0 net/socket.c:1375
vfs_ioctl fs/ioctl.c:51 [inline]
__do_sys_ioctl fs/ioctl.c:597 [inline]
__se_sys_ioctl fs/ioctl.c:583 [inline]
__x64_sys_ioctl+0x18e/0x210 fs/ioctl.c:583
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0xcd/0xfa0 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7f7f4fb8efc9
Code: ff ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 a8 ff ff ff f7 d8 64 89 01 48
RSP: 002b:00007f7f509c5038 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
RAX: ffffffffffffffda RBX: 00007f7f4fde5fa0 RCX: 00007f7f4fb8efc9
RDX: 0000200000000280 RSI: 000000000000890b RDI: 0000000000000004
RBP: 00007f7f4fc11f91 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
R13: 00007f7f4fde6038 R14: 00007f7f4fde5fa0 R15: 00007ffd1bd56f18
</TASK>

Allocated by task 22380:
kasan_save_stack+0x33/0x60 mm/kasan/common.c:56
kasan_save_track+0x14/0x30 mm/kasan/common.c:77
poison_kmalloc_redzone mm/kasan/common.c:400 [inline]
__kasan_kmalloc+0xaa/0xb0 mm/kasan/common.c:417
kmalloc_noprof include/linux/slab.h:957 [inline]
nr_add_node+0xe4e/0x2c00 net/netrom/nr_route.c:146
nr_rt_ioctl+0x11b7/0x29b0 net/netrom/nr_route.c:651
nr_ioctl+0x19a/0x2d0 net/netrom/af_netrom.c:1254
sock_do_ioctl+0x118/0x280 net/socket.c:1254
sock_ioctl+0x227/0x6b0 net/socket.c:1375
vfs_ioctl fs/ioctl.c:51 [inline]
__do_sys_ioctl fs/ioctl.c:597 [inline]
__se_sys_ioctl fs/ioctl.c:583 [inline]
__x64_sys_ioctl+0x18e/0x210 fs/ioctl.c:583
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0xcd/0xfa0 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f

Freed by task 22393:
kasan_save_stack+0x33/0x60 mm/kasan/common.c:56
kasan_save_track+0x14/0x30 mm/kasan/common.c:77
__kasan_save_free_info+0x3b/0x60 mm/kasan/generic.c:587
kasan_save_free_info mm/kasan/kasan.h:406 [inline]
poison_slab_object mm/kasan/common.c:252 [inline]
__kasan_slab_free+0x5f/0x80 mm/kasan/common.c:284
kasan_slab_free include/linux/kasan.h:234 [inline]
slab_free_hook mm/slub.c:2523 [inline]
slab_free mm/slub.c:6611 [inline]
kfree+0x2b8/0x6d0 mm/slub.c:6818
nr_neigh_put include/net/netrom.h:143 [inline]
nr_neigh_put include/net/netrom.h:137 [inline]
nr_add_node+0x23b9/0x2c00 net/netrom/nr_route.c:246
nr_rt_ioctl+0x11b7/0x29b0 net/netrom/nr_route.c:651
nr_ioctl+0x19a/0x2d0 net/netrom/af_netrom.c:1254
sock_do_ioctl+0x118/0x280 net/socket.c:1254
sock_ioctl+0x227/0x6b0 net/socket.c:1375
vfs_ioctl fs/ioctl.c:51 [inline]
__do_sys_ioctl fs/ioctl.c:597 [inline]
__se_sys_ioctl fs/ioctl.c:583 [inline]
__x64_sys_ioctl+0x18e/0x210 fs/ioctl.c:583
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0xcd/0xfa0 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f

The buggy address belongs to the object at ffff888054b8cc00
which belongs to the cache kmalloc-64 of size 64
The buggy address is located 48 bytes inside of
freed 64-byte region [ffff888054b8cc00, ffff888054b8cc40)

The buggy address belongs to the physical page:
page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x54b8c
flags: 0xfff00000000000(node=0|zone=1|lastcpupid=0x7ff)
page_type: f5(slab)
raw: 00fff00000000000 ffff88801b4428c0 dead000000000100 dead000000000122
raw: 0000000000000000 0000000000200020 00000000f5000000 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 0x52cc0(GFP_KERNEL|__GFP_NOWARN|__GFP_NORETRY|__GFP_COMP), pid 6074, tgid 6074 (syz-executor), ts 126099390276, free_ts 126098882568
set_page_owner include/linux/page_owner.h:32 [inline]
post_alloc_hook+0x1c0/0x230 mm/page_alloc.c:1850
prep_new_page mm/page_alloc.c:1858 [inline]
get_page_from_freelist+0x10a3/0x3a30 mm/page_alloc.c:3884
__alloc_frozen_pages_noprof+0x25f/0x2470 mm/page_alloc.c:5183
alloc_pages_mpol+0x1fb/0x550 mm/mempolicy.c:2416
alloc_slab_page mm/slub.c:3039 [inline]
allocate_slab mm/slub.c:3212 [inline]
new_slab+0x24a/0x360 mm/slub.c:3266
___slab_alloc+0xdc4/0x1ae0 mm/slub.c:4636
__slab_alloc.constprop.0+0x63/0x110 mm/slub.c:4755
__slab_alloc_node mm/slub.c:4831 [inline]
slab_alloc_node mm/slub.c:5253 [inline]
__kmalloc_cache_noprof+0x477/0x780 mm/slub.c:5743
kmalloc_noprof include/linux/slab.h:957 [inline]
__team_option_inst_add+0xbf/0x330 drivers/net/team/team_core.c:160
__team_option_inst_add_option drivers/net/team/team_core.c:182 [inline]
__team_options_register+0x355/0x720 drivers/net/team/team_core.c:276
team_options_register drivers/net/team/team_core.c:341 [inline]
team_init+0x5c8/0xce0 drivers/net/team/team_core.c:1658
register_netdevice+0x653/0x2270 net/core/dev.c:11221
team_newlink+0xb4/0x190 drivers/net/team/team_core.c:2213
rtnl_newlink_create net/core/rtnetlink.c:3833 [inline]
__rtnl_newlink net/core/rtnetlink.c:3950 [inline]
rtnl_newlink+0xc45/0x2000 net/core/rtnetlink.c:4065
rtnetlink_rcv_msg+0x95e/0xe90 net/core/rtnetlink.c:6954
netlink_rcv_skb+0x158/0x420 net/netlink/af_netlink.c:2552
page last free pid 6074 tgid 6074 stack trace:
reset_page_owner include/linux/page_owner.h:25 [inline]
free_pages_prepare mm/page_alloc.c:1394 [inline]
__free_frozen_pages+0x7df/0x1160 mm/page_alloc.c:2906
selinux_genfs_get_sid security/selinux/hooks.c:1357 [inline]
inode_doinit_with_dentry+0xacb/0x12e0 security/selinux/hooks.c:1555
selinux_d_instantiate+0x26/0x30 security/selinux/hooks.c:6523
security_d_instantiate+0x142/0x1a0 security/security.c:4148
d_instantiate+0x5c/0x90 fs/dcache.c:1961
__debugfs_create_file+0x286/0x6b0 fs/debugfs/inode.c:459
debugfs_create_file_full+0x41/0x60 fs/debugfs/inode.c:469
ref_tracker_dir_debugfs+0x19d/0x290 lib/ref_tracker.c:441
ref_tracker_dir_init include/linux/ref_tracker.h:70 [inline]
alloc_netdev_mqs+0x314/0x1550 net/core/dev.c:11907
rtnl_create_link+0xc08/0xf90 net/core/rtnetlink.c:3641
rtnl_newlink_create net/core/rtnetlink.c:3823 [inline]
__rtnl_newlink net/core/rtnetlink.c:3950 [inline]
rtnl_newlink+0xb69/0x2000 net/core/rtnetlink.c:4065
rtnetlink_rcv_msg+0x95e/0xe90 net/core/rtnetlink.c:6954
netlink_rcv_skb+0x158/0x420 net/netlink/af_netlink.c:2552
netlink_unicast_kernel net/netlink/af_netlink.c:1320 [inline]
netlink_unicast+0x5aa/0x870 net/netlink/af_netlink.c:1346
netlink_sendmsg+0x8c8/0xdd0 net/netlink/af_netlink.c:1896
sock_sendmsg_nosec net/socket.c:727 [inline]
__sock_sendmsg net/socket.c:742 [inline]
__sys_sendto+0x4a3/0x520 net/socket.c:2244

Memory state around the buggy address:
ffff888054b8cb00: 00 00 00 00 00 00 00 fc fc fc fc fc fc fc fc fc
ffff888054b8cb80: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
>ffff888054b8cc00: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
^
ffff888054b8cc80: 00 00 00 00 00 00 00 00 fc fc fc fc fc fc fc fc
ffff888054b8cd00: 00 00 00 00 00 00 00 00 fc fc fc fc fc fc fc fc
==================================================================


---

syzbot

unread,
Oct 19, 2025, 1:10:14 AM (7 days ago) Oct 19
to lis...@listout.xyz, da...@davemloft.net, edum...@google.com, ho...@kernel.org, ku...@kernel.org, linux...@vger.kernel.org, linux-...@vger.kernel.org, lis...@listout.xyz, net...@vger.kernel.org, pab...@redhat.com, syzkall...@googlegroups.com
> On 18.10.2025 13:37, syzbot wrote:
>> syzbot has found a reproducer for the following issue on:
>>
>> HEAD commit: f406055cb18c Merge tag 'arm64-fixes' of git://git.kernel.o..
>> git tree: upstream
>> console output: https://syzkaller.appspot.com/x/log.txt?x=11cf767c580000
>> kernel config: https://syzkaller.appspot.com/x/.config?x=f3e7b5a3627a90dd
>> dashboard link: https://syzkaller.appspot.com/bug?extid=2860e75836a08b172755
>> compiler: gcc (Debian 12.2.0-14+deb12u1) 12.2.0, GNU ld (GNU Binutils for Debian) 2.40
>> syz repro: https://syzkaller.appspot.com/x/repro.syz?x=155f1de2580000
>> C reproducer: https://syzkaller.appspot.com/x/repro.c?x=12b6b52f980000
>>
>> Downloadable assets:
>> disk image (non-bootable): https://storage.googleapis.com/syzbot-assets/d900f083ada3/non_bootable_disk-f406055c.raw.xz
>> vmlinux: https://storage.googleapis.com/syzbot-assets/a4db2a99bfb1/vmlinux-f406055c.xz
>> kernel image: https://storage.googleapis.com/syzbot-assets/91d1ca420bac/bzImage-f406055c.xz
>>
>> IMPORTANT: if you fix the issue, please add the following tag to the commit:
>> Reported-by: syzbot+2860e7...@syzkaller.appspotmail.com
>>
>> ==================================================================
>> BUG: KASAN: slab-use-after-free in nr_add_node+0x25db/0x2c00 net/netrom/nr_route.c:248
>> Read of size 4 at addr ffff888054b8cc30 by task syz.3.7839/22393
>
> #syz test linux-next

want either no args or 2 args (repo, branch), got 1

>
> diff --git a/net/netrom/nr_route.c b/net/netrom/nr_route.c
> index b94cb2ffbaf8..5fa7d9febbbb 100644
> --- a/net/netrom/nr_route.c
> +++ b/net/netrom/nr_route.c
> @@ -245,7 +245,9 @@ static int __must_check nr_add_node(ax25_address *nr, const char *mnemonic,
> nr_node->routes[2].neighbour->count--;
> nr_neigh_put(nr_node->routes[2].neighbour);
>
> - if (nr_node->routes[2].neighbour->count == 0 && !nr_node->routes[2].neighbour->locked)
> + if (nr_node->routes[2].neighbour &&
> + nr_node->routes[2].neighbour->count == 0 &&
> + !nr_node->routes[2].neighbour->locked)
> nr_remove_neigh(nr_node->routes[2].neighbour);
>
> nr_node->routes[2].quality = quality;
>
> --
> Regards,
> listout

syzbot

unread,
Oct 19, 2025, 1:16:34 AM (7 days ago) Oct 19
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: [syzbot] [hams?] KASAN: slab-use-after-free Read in nr_add_node
Author: lis...@listout.xyz

On 18.10.2025 13:37, syzbot wrote:
> syzbot has found a reproducer for the following issue on:
>
> HEAD commit: f406055cb18c Merge tag 'arm64-fixes' of git://git.kernel.o..
> git tree: upstream
> console output: https://syzkaller.appspot.com/x/log.txt?x=11cf767c580000
> kernel config: https://syzkaller.appspot.com/x/.config?x=f3e7b5a3627a90dd
> dashboard link: https://syzkaller.appspot.com/bug?extid=2860e75836a08b172755
> IMPORTANT: if you fix the issue, please add the following tag to the commit:
> Reported-by: syzbot+2860e7...@syzkaller.appspotmail.com
>
> ==================================================================
> BUG: KASAN: slab-use-after-free in nr_add_node+0x25db/0x2c00 net/netrom/nr_route.c:248
> Read of size 4 at addr ffff888054b8cc30 by task syz.3.7839/22393

#syz test linux-next 1c64efcb083c48c85227cb4d72ab137feef2cdac

syzbot

unread,
Oct 19, 2025, 1:21:04 AM (7 days ago) Oct 19
to da...@davemloft.net, edum...@google.com, ho...@kernel.org, ku...@kernel.org, linux...@vger.kernel.org, linux-...@vger.kernel.org, lis...@listout.xyz, net...@vger.kernel.org, pab...@redhat.com, syzkall...@googlegroups.com
Hello,

syzbot has tested the proposed patch but the reproducer is still triggering an issue:
KASAN: slab-use-after-free Read in nr_add_node

==================================================================
BUG: KASAN: slab-use-after-free in nr_add_node+0x25e5/0x2c10 net/netrom/nr_route.c:249
Read of size 4 at addr ffff88805466ddb0 by task syz.1.4225/15237

CPU: 2 UID: 0 PID: 15237 Comm: syz.1.4225 Not tainted syzkaller #0 PREEMPT(full)
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2~bpo12+1 04/01/2014
Call Trace:
<TASK>
__dump_stack lib/dump_stack.c:94 [inline]
dump_stack_lvl+0x116/0x1f0 lib/dump_stack.c:120
print_address_description mm/kasan/report.c:378 [inline]
print_report+0xcd/0x630 mm/kasan/report.c:482
kasan_report+0xe0/0x110 mm/kasan/report.c:595
nr_add_node+0x25e5/0x2c10 net/netrom/nr_route.c:249
nr_rt_ioctl+0x11b7/0x29b0 net/netrom/nr_route.c:653
nr_ioctl+0x19a/0x2d0 net/netrom/af_netrom.c:1254
sock_do_ioctl+0x118/0x280 net/socket.c:1254
sock_ioctl+0x227/0x6b0 net/socket.c:1375
vfs_ioctl fs/ioctl.c:51 [inline]
__do_sys_ioctl fs/ioctl.c:597 [inline]
__se_sys_ioctl fs/ioctl.c:583 [inline]
__x64_sys_ioctl+0x18e/0x210 fs/ioctl.c:583
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0xcd/0xfa0 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7f4229d8efc9
Code: ff ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 a8 ff ff ff f7 d8 64 89 01 48
RSP: 002b:00007f422ac41038 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
RAX: ffffffffffffffda RBX: 00007f4229fe5fa0 RCX: 00007f4229d8efc9
RDX: 0000200000000280 RSI: 000000000000890b RDI: 0000000000000004
RBP: 00007f4229e11f91 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
R13: 00007f4229fe6038 R14: 00007f4229fe5fa0 R15: 00007ffe9d4efb98
</TASK>

Allocated by task 15224:
kasan_save_stack+0x33/0x60 mm/kasan/common.c:56
kasan_save_track+0x14/0x30 mm/kasan/common.c:77
poison_kmalloc_redzone mm/kasan/common.c:400 [inline]
__kasan_kmalloc+0xaa/0xb0 mm/kasan/common.c:417
kmalloc_noprof include/linux/slab.h:957 [inline]
nr_add_node+0xe4e/0x2c10 net/netrom/nr_route.c:146
nr_rt_ioctl+0x11b7/0x29b0 net/netrom/nr_route.c:653
nr_ioctl+0x19a/0x2d0 net/netrom/af_netrom.c:1254
sock_do_ioctl+0x118/0x280 net/socket.c:1254
sock_ioctl+0x227/0x6b0 net/socket.c:1375
vfs_ioctl fs/ioctl.c:51 [inline]
__do_sys_ioctl fs/ioctl.c:597 [inline]
__se_sys_ioctl fs/ioctl.c:583 [inline]
__x64_sys_ioctl+0x18e/0x210 fs/ioctl.c:583
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0xcd/0xfa0 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f

Freed by task 15237:
kasan_save_stack+0x33/0x60 mm/kasan/common.c:56
kasan_save_track+0x14/0x30 mm/kasan/common.c:77
__kasan_save_free_info+0x3b/0x60 mm/kasan/generic.c:587
kasan_save_free_info mm/kasan/kasan.h:406 [inline]
poison_slab_object mm/kasan/common.c:252 [inline]
__kasan_slab_free+0x5f/0x80 mm/kasan/common.c:284
kasan_slab_free include/linux/kasan.h:234 [inline]
slab_free_hook mm/slub.c:2530 [inline]
slab_free mm/slub.c:6619 [inline]
kfree+0x2b8/0x6d0 mm/slub.c:6826
nr_neigh_put include/net/netrom.h:143 [inline]
nr_neigh_put include/net/netrom.h:137 [inline]
nr_add_node+0x23c3/0x2c10 net/netrom/nr_route.c:246
nr_rt_ioctl+0x11b7/0x29b0 net/netrom/nr_route.c:653
nr_ioctl+0x19a/0x2d0 net/netrom/af_netrom.c:1254
sock_do_ioctl+0x118/0x280 net/socket.c:1254
sock_ioctl+0x227/0x6b0 net/socket.c:1375
vfs_ioctl fs/ioctl.c:51 [inline]
__do_sys_ioctl fs/ioctl.c:597 [inline]
__se_sys_ioctl fs/ioctl.c:583 [inline]
__x64_sys_ioctl+0x18e/0x210 fs/ioctl.c:583
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0xcd/0xfa0 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f

The buggy address belongs to the object at ffff88805466dd80
which belongs to the cache kmalloc-64 of size 64
The buggy address is located 48 bytes inside of
freed 64-byte region [ffff88805466dd80, ffff88805466ddc0)

The buggy address belongs to the physical page:
page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x5466d
flags: 0xfff00000000000(node=0|zone=1|lastcpupid=0x7ff)
page_type: f5(slab)
raw: 00fff00000000000 ffff88801b4428c0 ffffea0000867b00 dead000000000004
raw: 0000000000000000 0000000000200020 00000000f5000000 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 0x52c40(GFP_NOFS|__GFP_NOWARN|__GFP_NORETRY|__GFP_COMP), pid 5345, tgid 5345 (udevd), ts 58557594470, free_ts 0
set_page_owner include/linux/page_owner.h:32 [inline]
post_alloc_hook+0x1c0/0x230 mm/page_alloc.c:1850
prep_new_page mm/page_alloc.c:1858 [inline]
get_page_from_freelist+0x10a3/0x3a30 mm/page_alloc.c:3884
__alloc_frozen_pages_noprof+0x25f/0x2470 mm/page_alloc.c:5183
alloc_pages_mpol+0x1fb/0x550 mm/mempolicy.c:2416
alloc_slab_page mm/slub.c:3046 [inline]
allocate_slab mm/slub.c:3219 [inline]
new_slab+0x24a/0x360 mm/slub.c:3273
___slab_alloc+0xdc4/0x1ae0 mm/slub.c:4643
__slab_alloc.constprop.0+0x63/0x110 mm/slub.c:4762
__slab_alloc_node mm/slub.c:4838 [inline]
slab_alloc_node mm/slub.c:5260 [inline]
__do_kmalloc_node mm/slub.c:5633 [inline]
__kmalloc_noprof+0x501/0x880 mm/slub.c:5646
kmalloc_noprof include/linux/slab.h:961 [inline]
kzalloc_noprof include/linux/slab.h:1094 [inline]
tomoyo_encode2+0x100/0x3e0 security/tomoyo/realpath.c:45
tomoyo_encode+0x29/0x50 security/tomoyo/realpath.c:80
tomoyo_realpath_from_path+0x18f/0x6e0 security/tomoyo/realpath.c:283
tomoyo_get_realpath security/tomoyo/file.c:151 [inline]
tomoyo_check_open_permission+0x2ab/0x3c0 security/tomoyo/file.c:771
tomoyo_file_open+0x6b/0x90 security/tomoyo/tomoyo.c:334
security_file_open+0x84/0x1e0 security/security.c:3183
do_dentry_open+0x596/0x1530 fs/open.c:942
vfs_open+0x82/0x3f0 fs/open.c:1097
page_owner free stack trace missing

Memory state around the buggy address:
ffff88805466dc80: 00 00 00 00 00 00 00 fc fc fc fc fc fc fc fc fc
ffff88805466dd00: 00 00 00 00 00 00 00 fc fc fc fc fc fc fc fc fc
>ffff88805466dd80: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
^
ffff88805466de00: 00 00 00 00 00 00 00 fc fc fc fc fc fc fc fc fc
ffff88805466de80: 00 00 00 00 00 00 00 fc fc fc fc fc fc fc fc fc
==================================================================


Tested on:

commit: 1c64efcb Merge tag 'rust-rustfmt' of git://git.kernel...
git tree: upstream
console output: https://syzkaller.appspot.com/x/log.txt?x=12a8bde2580000
kernel config: https://syzkaller.appspot.com/x/.config?x=f3e7b5a3627a90dd
dashboard link: https://syzkaller.appspot.com/bug?extid=2860e75836a08b172755
compiler: gcc (Debian 12.2.0-14+deb12u1) 12.2.0, GNU ld (GNU Binutils for Debian) 2.40
patch: https://syzkaller.appspot.com/x/patch.diff?x=13e20de2580000

syzbot

unread,
Oct 19, 2025, 1:36:06 AM (7 days ago) Oct 19
to linux-...@vger.kernel.org, lis...@listout.xyz, syzkall...@googlegroups.com
Hello,

syzbot has tested the proposed patch but the reproducer is still triggering an issue:
KASAN: slab-use-after-free Read in nr_add_node

==================================================================
BUG: KASAN: slab-use-after-free in nr_add_node+0x25e5/0x2c10 net/netrom/nr_route.c:249
Read of size 4 at addr ffff88802b876030 by task syz.2.1937/10375

CPU: 0 UID: 0 PID: 10375 Comm: syz.2.1937 Not tainted syzkaller #0 PREEMPT(full)
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2~bpo12+1 04/01/2014
Call Trace:
<TASK>
__dump_stack lib/dump_stack.c:94 [inline]
dump_stack_lvl+0x116/0x1f0 lib/dump_stack.c:120
print_address_description mm/kasan/report.c:378 [inline]
print_report+0xcd/0x630 mm/kasan/report.c:482
kasan_report+0xe0/0x110 mm/kasan/report.c:595
nr_add_node+0x25e5/0x2c10 net/netrom/nr_route.c:249
nr_rt_ioctl+0x11b7/0x29b0 net/netrom/nr_route.c:653
nr_ioctl+0x19a/0x2d0 net/netrom/af_netrom.c:1254
sock_do_ioctl+0x118/0x280 net/socket.c:1254
sock_ioctl+0x227/0x6b0 net/socket.c:1375
vfs_ioctl fs/ioctl.c:51 [inline]
__do_sys_ioctl fs/ioctl.c:597 [inline]
__se_sys_ioctl fs/ioctl.c:583 [inline]
__x64_sys_ioctl+0x18e/0x210 fs/ioctl.c:583
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0xcd/0xfa0 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7f35ebf8efc9
Code: ff ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 a8 ff ff ff f7 d8 64 89 01 48
RSP: 002b:00007f35ecd77038 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
RAX: ffffffffffffffda RBX: 00007f35ec1e5fa0 RCX: 00007f35ebf8efc9
RDX: 0000200000000280 RSI: 000000000000890b RDI: 0000000000000004
RBP: 00007f35ec011f91 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
R13: 00007f35ec1e6038 R14: 00007f35ec1e5fa0 R15: 00007ffff17dcae8
</TASK>

Allocated by task 10366:
kasan_save_stack+0x33/0x60 mm/kasan/common.c:56
kasan_save_track+0x14/0x30 mm/kasan/common.c:77
poison_kmalloc_redzone mm/kasan/common.c:400 [inline]
__kasan_kmalloc+0xaa/0xb0 mm/kasan/common.c:417
kmalloc_noprof include/linux/slab.h:957 [inline]
nr_add_node+0xe4e/0x2c10 net/netrom/nr_route.c:146
nr_rt_ioctl+0x11b7/0x29b0 net/netrom/nr_route.c:653
nr_ioctl+0x19a/0x2d0 net/netrom/af_netrom.c:1254
sock_do_ioctl+0x118/0x280 net/socket.c:1254
sock_ioctl+0x227/0x6b0 net/socket.c:1375
vfs_ioctl fs/ioctl.c:51 [inline]
__do_sys_ioctl fs/ioctl.c:597 [inline]
__se_sys_ioctl fs/ioctl.c:583 [inline]
__x64_sys_ioctl+0x18e/0x210 fs/ioctl.c:583
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0xcd/0xfa0 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f

The buggy address belongs to the object at ffff88802b876000
which belongs to the cache kmalloc-64 of size 64
The buggy address is located 48 bytes inside of
freed 64-byte region [ffff88802b876000, ffff88802b876040)

The buggy address belongs to the physical page:
page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x2b876
flags: 0xfff00000000000(node=0|zone=1|lastcpupid=0x7ff)
page_type: f5(slab)
raw: 00fff00000000000 ffff88801b4428c0 ffffea0000926300 dead000000000006
raw: 0000000000000000 0000000000200020 00000000f5000000 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 0x52cc0(GFP_KERNEL|__GFP_NOWARN|__GFP_NORETRY|__GFP_COMP), pid 6284, tgid 6284 (syz-executor), ts 96678923529, free_ts 96199339256
set_page_owner include/linux/page_owner.h:32 [inline]
post_alloc_hook+0x1c0/0x230 mm/page_alloc.c:1850
prep_new_page mm/page_alloc.c:1858 [inline]
get_page_from_freelist+0x10a3/0x3a30 mm/page_alloc.c:3884
__alloc_frozen_pages_noprof+0x25f/0x2470 mm/page_alloc.c:5183
alloc_pages_mpol+0x1fb/0x550 mm/mempolicy.c:2416
alloc_slab_page mm/slub.c:3046 [inline]
allocate_slab mm/slub.c:3219 [inline]
new_slab+0x24a/0x360 mm/slub.c:3273
___slab_alloc+0xdc4/0x1ae0 mm/slub.c:4643
__slab_alloc.constprop.0+0x63/0x110 mm/slub.c:4762
__slab_alloc_node mm/slub.c:4838 [inline]
slab_alloc_node mm/slub.c:5260 [inline]
__kmalloc_cache_noprof+0x477/0x780 mm/slub.c:5750
kmalloc_noprof include/linux/slab.h:957 [inline]
kzalloc_noprof include/linux/slab.h:1094 [inline]
mpls_add_dev net/mpls/af_mpls.c:1443 [inline]
mpls_dev_notify+0x346/0xa20 net/mpls/af_mpls.c:1600
notifier_call_chain+0xbc/0x410 kernel/notifier.c:85
call_netdevice_notifiers_info+0xbe/0x140 net/core/dev.c:2229
call_netdevice_notifiers_extack net/core/dev.c:2267 [inline]
call_netdevice_notifiers net/core/dev.c:2281 [inline]
register_netdevice+0x182e/0x2270 net/core/dev.c:11332
nsim_init_netdevsim drivers/net/netdevsim/netdev.c:1059 [inline]
nsim_create+0xdd5/0x1260 drivers/net/netdevsim/netdev.c:1141
__nsim_dev_port_add+0x435/0x7d0 drivers/net/netdevsim/dev.c:1438
nsim_dev_port_add_all drivers/net/netdevsim/dev.c:1494 [inline]
nsim_drv_probe+0xe40/0x1520 drivers/net/netdevsim/dev.c:1653
call_driver_probe drivers/base/dd.c:581 [inline]
really_probe+0x241/0xa90 drivers/base/dd.c:659
page last free pid 6298 tgid 6298 stack trace:
reset_page_owner include/linux/page_owner.h:25 [inline]
free_pages_prepare mm/page_alloc.c:1394 [inline]
__free_frozen_pages+0x7df/0x1160 mm/page_alloc.c:2906
discard_slab mm/slub.c:3317 [inline]
__put_partials+0x130/0x170 mm/slub.c:3864
qlink_free mm/kasan/quarantine.c:163 [inline]
qlist_free_all+0x4d/0x120 mm/kasan/quarantine.c:179
kasan_quarantine_reduce+0x195/0x1e0 mm/kasan/quarantine.c:286
__kasan_slab_alloc+0x69/0x90 mm/kasan/common.c:352
kasan_slab_alloc include/linux/kasan.h:252 [inline]
slab_post_alloc_hook mm/slub.c:4962 [inline]
slab_alloc_node mm/slub.c:5272 [inline]
kmem_cache_alloc_noprof+0x250/0x6e0 mm/slub.c:5279
getname_flags.part.0+0x4c/0x550 fs/namei.c:146
getname_flags+0x93/0xf0 include/linux/audit.h:345
getname include/linux/fs.h:2922 [inline]
getname_maybe_null include/linux/fs.h:2929 [inline]
getname_maybe_null include/linux/fs.h:2926 [inline]
vfs_fstatat+0xe1/0xf0 fs/stat.c:370
__do_sys_newfstatat+0x97/0x120 fs/stat.c:542
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0xcd/0xfa0 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f

Memory state around the buggy address:
ffff88802b875f00: 00 00 00 00 00 00 00 00 fc fc fc fc fc fc fc fc
ffff88802b875f80: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
>ffff88802b876000: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
^
ffff88802b876080: 00 00 00 00 00 fc fc fc fc fc fc fc fc fc fc fc
ffff88802b876100: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
==================================================================


Tested on:

commit: 1c64efcb Merge tag 'rust-rustfmt' of git://git.kernel...
git tree: git://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
console output: https://syzkaller.appspot.com/x/log.txt?x=1166f67c580000
kernel config: https://syzkaller.appspot.com/x/.config?x=f3e7b5a3627a90dd
dashboard link: https://syzkaller.appspot.com/bug?extid=2860e75836a08b172755
compiler: gcc (Debian 12.2.0-14+deb12u1) 12.2.0, GNU ld (GNU Binutils for Debian) 2.40
patch: https://syzkaller.appspot.com/x/patch.diff?x=1069dc58580000

syzbot

unread,
Oct 19, 2025, 9:55:20 AM (7 days ago) Oct 19
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: [syzbot] [hams?] KASAN: slab-use-after-free Read in nr_add_node
Author: lis...@listout.xyz

On 18.10.2025 13:37, syzbot wrote:
> syzbot has found a reproducer for the following issue on:
>
> HEAD commit: f406055cb18c Merge tag 'arm64-fixes' of git://git.kernel.o..
> git tree: upstream
> dashboard link: https://syzkaller.appspot.com/bug?extid=2860e75836a08b172755
> compiler: gcc (Debian 12.2.0-14+deb12u1) 12.2.0, GNU ld (GNU Binutils for Debian) 2.40
> IMPORTANT: if you fix the issue, please add the following tag to the commit:
> Reported-by: syzbot+2860e7...@syzkaller.appspotmail.com
>
> ==================================================================
> BUG: KASAN: slab-use-after-free in nr_add_node+0x25db/0x2c00 net/netrom/nr_route.c:248
> Read of size 4 at addr ffff888054b8cc30 by task syz.3.7839/22393

#syz test linux-next 1c64efcb083c48c85227cb4d72ab137feef2cdac

diff --git a/net/netrom/nr_route.c b/net/netrom/nr_route.c
index b94cb2ffbaf8..aa72c4db2be4 100644
--- a/net/netrom/nr_route.c
+++ b/net/netrom/nr_route.c
@@ -242,11 +242,12 @@ static int __must_check nr_add_node(ax25_address *nr, const char *mnemonic,
} else {
/* It must be better than the worst */
if (quality > nr_node->routes[2].quality) {
- nr_node->routes[2].neighbour->count--;
- nr_neigh_put(nr_node->routes[2].neighbour);
+ struct nr_neigh *old_neighbour = nr_node->routes[2].neighbour;
+ old_neighbour->count--;
+ nr_neigh_put(old_neighbour);

- if (nr_node->routes[2].neighbour->count == 0 && !nr_node->routes[2].neighbour->locked)
- nr_remove_neigh(nr_node->routes[2].neighbour);
+ if (old_neighbour->count == 0 && !old_neighbour->locked)
+ nr_remove_neigh(old_neighbour);

nr_node->routes[2].quality = quality;
nr_node->routes[2].obs_count = obs_count;

--
Regards,
listout

syzbot

unread,
Oct 19, 2025, 10:12:03 AM (7 days ago) Oct 19
to linux-...@vger.kernel.org, lis...@listout.xyz, syzkall...@googlegroups.com
Hello,

syzbot has tested the proposed patch but the reproducer is still triggering an issue:
KASAN: slab-use-after-free Read in nr_add_node

==================================================================
BUG: KASAN: slab-use-after-free in nr_add_node+0x2b65/0x2bd0 net/netrom/nr_route.c:249
Read of size 4 at addr ffff8880265a73b0 by task syz.0.5221/17351

CPU: 0 UID: 0 PID: 17351 Comm: syz.0.5221 Not tainted syzkaller #0 PREEMPT(full)
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2~bpo12+1 04/01/2014
Call Trace:
<TASK>
__dump_stack lib/dump_stack.c:94 [inline]
dump_stack_lvl+0x116/0x1f0 lib/dump_stack.c:120
print_address_description mm/kasan/report.c:378 [inline]
print_report+0xcd/0x630 mm/kasan/report.c:482
kasan_report+0xe0/0x110 mm/kasan/report.c:595
nr_add_node+0x2b65/0x2bd0 net/netrom/nr_route.c:249
nr_rt_ioctl+0x11b7/0x29b0 net/netrom/nr_route.c:652
nr_ioctl+0x19a/0x2d0 net/netrom/af_netrom.c:1254
sock_do_ioctl+0x118/0x280 net/socket.c:1254
sock_ioctl+0x227/0x6b0 net/socket.c:1375
vfs_ioctl fs/ioctl.c:51 [inline]
__do_sys_ioctl fs/ioctl.c:597 [inline]
__se_sys_ioctl fs/ioctl.c:583 [inline]
__x64_sys_ioctl+0x18e/0x210 fs/ioctl.c:583
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0xcd/0xfa0 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7ff9fdb8efc9
Code: ff ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 a8 ff ff ff f7 d8 64 89 01 48
RSP: 002b:00007ff9fe9f1038 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
RAX: ffffffffffffffda RBX: 00007ff9fdde5fa0 RCX: 00007ff9fdb8efc9
RDX: 0000200000000280 RSI: 000000000000890b RDI: 0000000000000004
RBP: 00007ff9fdc11f91 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
R13: 00007ff9fdde6038 R14: 00007ff9fdde5fa0 R15: 00007ffd8e5d4ad8
</TASK>

Allocated by task 17330:
kasan_save_stack+0x33/0x60 mm/kasan/common.c:56
kasan_save_track+0x14/0x30 mm/kasan/common.c:77
poison_kmalloc_redzone mm/kasan/common.c:400 [inline]
__kasan_kmalloc+0xaa/0xb0 mm/kasan/common.c:417
kmalloc_noprof include/linux/slab.h:957 [inline]
nr_add_node+0xe4e/0x2bd0 net/netrom/nr_route.c:146
nr_rt_ioctl+0x11b7/0x29b0 net/netrom/nr_route.c:652
nr_ioctl+0x19a/0x2d0 net/netrom/af_netrom.c:1254
sock_do_ioctl+0x118/0x280 net/socket.c:1254
sock_ioctl+0x227/0x6b0 net/socket.c:1375
vfs_ioctl fs/ioctl.c:51 [inline]
__do_sys_ioctl fs/ioctl.c:597 [inline]
__se_sys_ioctl fs/ioctl.c:583 [inline]
__x64_sys_ioctl+0x18e/0x210 fs/ioctl.c:583
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0xcd/0xfa0 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f

Freed by task 17351:
kasan_save_stack+0x33/0x60 mm/kasan/common.c:56
kasan_save_track+0x14/0x30 mm/kasan/common.c:77
__kasan_save_free_info+0x3b/0x60 mm/kasan/generic.c:587
kasan_save_free_info mm/kasan/kasan.h:406 [inline]
poison_slab_object mm/kasan/common.c:252 [inline]
__kasan_slab_free+0x5f/0x80 mm/kasan/common.c:284
kasan_slab_free include/linux/kasan.h:234 [inline]
slab_free_hook mm/slub.c:2530 [inline]
slab_free mm/slub.c:6619 [inline]
kfree+0x2b8/0x6d0 mm/slub.c:6826
nr_neigh_put include/net/netrom.h:143 [inline]
nr_neigh_put include/net/netrom.h:137 [inline]
nr_add_node+0x2389/0x2bd0 net/netrom/nr_route.c:247
nr_rt_ioctl+0x11b7/0x29b0 net/netrom/nr_route.c:652
nr_ioctl+0x19a/0x2d0 net/netrom/af_netrom.c:1254
sock_do_ioctl+0x118/0x280 net/socket.c:1254
sock_ioctl+0x227/0x6b0 net/socket.c:1375
vfs_ioctl fs/ioctl.c:51 [inline]
__do_sys_ioctl fs/ioctl.c:597 [inline]
__se_sys_ioctl fs/ioctl.c:583 [inline]
__x64_sys_ioctl+0x18e/0x210 fs/ioctl.c:583
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0xcd/0xfa0 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f

The buggy address belongs to the object at ffff8880265a7380
which belongs to the cache kmalloc-64 of size 64
The buggy address is located 48 bytes inside of
freed 64-byte region [ffff8880265a7380, ffff8880265a73c0)

The buggy address belongs to the physical page:
page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x265a7
flags: 0xfff00000000000(node=0|zone=1|lastcpupid=0x7ff)
page_type: f5(slab)
raw: 00fff00000000000 ffff88801b4428c0 ffffea0000b7abc0 dead000000000004
raw: 0000000000000000 0000000000200020 00000000f5000000 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 0x52cc0(GFP_KERNEL|__GFP_NOWARN|__GFP_NORETRY|__GFP_COMP), pid 132, tgid 132 (kworker/0:2), ts 9597767021, free_ts 8864964788
set_page_owner include/linux/page_owner.h:32 [inline]
post_alloc_hook+0x1c0/0x230 mm/page_alloc.c:1850
prep_new_page mm/page_alloc.c:1858 [inline]
get_page_from_freelist+0x10a3/0x3a30 mm/page_alloc.c:3884
__alloc_frozen_pages_noprof+0x25f/0x2470 mm/page_alloc.c:5183
alloc_pages_mpol+0x1fb/0x550 mm/mempolicy.c:2416
alloc_slab_page mm/slub.c:3046 [inline]
allocate_slab mm/slub.c:3219 [inline]
new_slab+0x24a/0x360 mm/slub.c:3273
___slab_alloc+0xdc4/0x1ae0 mm/slub.c:4643
__slab_alloc.constprop.0+0x63/0x110 mm/slub.c:4762
__slab_alloc_node mm/slub.c:4838 [inline]
slab_alloc_node mm/slub.c:5260 [inline]
__do_kmalloc_node mm/slub.c:5633 [inline]
__kmalloc_noprof+0x501/0x880 mm/slub.c:5646
kmalloc_noprof include/linux/slab.h:961 [inline]
kmalloc_array_noprof include/linux/slab.h:1003 [inline]
drm_atomic_state_init+0x17b/0x320 drivers/gpu/drm/drm_atomic.c:137
drm_atomic_state_alloc drivers/gpu/drm/drm_atomic.c:176 [inline]
drm_atomic_state_alloc+0xd3/0x120 drivers/gpu/drm/drm_atomic.c:166
drm_atomic_helper_dirtyfb+0xc8/0x780 drivers/gpu/drm/drm_damage_helper.c:128
drm_fbdev_shmem_helper_fb_dirty+0x1cc/0x340 drivers/gpu/drm/drm_fbdev_shmem.c:118
drm_fb_helper_fb_dirty drivers/gpu/drm/drm_fb_helper.c:380 [inline]
drm_fb_helper_damage_work+0x27e/0x5f0 drivers/gpu/drm/drm_fb_helper.c:403
process_one_work+0x9cf/0x1b70 kernel/workqueue.c:3263
process_scheduled_works kernel/workqueue.c:3346 [inline]
worker_thread+0x6c8/0xf10 kernel/workqueue.c:3427
kthread+0x3c5/0x780 kernel/kthread.c:463
page last free pid 10 tgid 10 stack trace:
reset_page_owner include/linux/page_owner.h:25 [inline]
free_pages_prepare mm/page_alloc.c:1394 [inline]
__free_frozen_pages+0x7df/0x1160 mm/page_alloc.c:2906
vfree+0x1fd/0xb50 mm/vmalloc.c:3440
delayed_vfree_work+0x56/0x70 mm/vmalloc.c:3359
process_one_work+0x9cf/0x1b70 kernel/workqueue.c:3263
process_scheduled_works kernel/workqueue.c:3346 [inline]
worker_thread+0x6c8/0xf10 kernel/workqueue.c:3427
kthread+0x3c5/0x780 kernel/kthread.c:463
ret_from_fork+0x675/0x7d0 arch/x86/kernel/process.c:158
ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245

Memory state around the buggy address:
ffff8880265a7280: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
ffff8880265a7300: 00 00 00 00 00 00 00 fc fc fc fc fc fc fc fc fc
>ffff8880265a7380: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
^
ffff8880265a7400: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
ffff8880265a7480: 00 00 00 00 00 00 00 00 fc fc fc fc fc fc fc fc
==================================================================


Tested on:

commit: 1c64efcb Merge tag 'rust-rustfmt' of git://git.kernel...
git tree: git://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
console output: https://syzkaller.appspot.com/x/log.txt?x=135d0de2580000
kernel config: https://syzkaller.appspot.com/x/.config?x=f3e7b5a3627a90dd
dashboard link: https://syzkaller.appspot.com/bug?extid=2860e75836a08b172755
compiler: gcc (Debian 12.2.0-14+deb12u1) 12.2.0, GNU ld (GNU Binutils for Debian) 2.40
patch: https://syzkaller.appspot.com/x/patch.diff?x=14bd03cd980000

Brahmajit Das

unread,
Oct 20, 2025, 3:40:02 AM (6 days ago) Oct 20
to syzbot, da...@davemloft.net, edum...@google.com, ho...@kernel.org, ku...@kernel.org, linux...@vger.kernel.org, linux-...@vger.kernel.org, net...@vger.kernel.org, pab...@redhat.com, syzkall...@googlegroups.com
On 18.10.2025 13:37, syzbot wrote:
> syzbot has found a reproducer for the following issue on:
>
> HEAD commit: f406055cb18c Merge tag 'arm64-fixes' of git://git.kernel.o..
> git tree: upstream
> console output: https://syzkaller.appspot.com/x/log.txt?x=11cf767c580000
> kernel config: https://syzkaller.appspot.com/x/.config?x=f3e7b5a3627a90dd
> dashboard link: https://syzkaller.appspot.com/bug?extid=2860e75836a08b172755
> compiler: gcc (Debian 12.2.0-14+deb12u1) 12.2.0, GNU ld (GNU Binutils for Debian) 2.40
> syz repro: https://syzkaller.appspot.com/x/repro.syz?x=155f1de2580000
> C reproducer: https://syzkaller.appspot.com/x/repro.c?x=12b6b52f980000
>
> Downloadable assets:
> disk image (non-bootable): https://storage.googleapis.com/syzbot-assets/d900f083ada3/non_bootable_disk-f406055c.raw.xz
> vmlinux: https://storage.googleapis.com/syzbot-assets/a4db2a99bfb1/vmlinux-f406055c.xz
> kernel image: https://storage.googleapis.com/syzbot-assets/91d1ca420bac/bzImage-f406055c.xz
>
> IMPORTANT: if you fix the issue, please add the following tag to the commit:
> Reported-by: syzbot+2860e7...@syzkaller.appspotmail.com
>
> ==================================================================
> BUG: KASAN: slab-use-after-free in nr_add_node+0x25db/0x2c00 net/netrom/nr_route.c:248
> Read of size 4 at addr ffff888054b8cc30 by task syz.3.7839/22393

#syz test linux-next

diff --git a/net/netrom/nr_route.c b/net/netrom/nr_route.c
index b94cb2ffbaf8..5fa7d9febbbb 100644
--- a/net/netrom/nr_route.c
+++ b/net/netrom/nr_route.c
@@ -245,7 +245,9 @@ static int __must_check nr_add_node(ax25_address *nr, const char *mnemonic,
nr_node->routes[2].neighbour->count--;
nr_neigh_put(nr_node->routes[2].neighbour);

- if (nr_node->routes[2].neighbour->count == 0 && !nr_node->routes[2].neighbour->locked)
+ if (nr_node->routes[2].neighbour &&
+ nr_node->routes[2].neighbour->count == 0 &&
+ !nr_node->routes[2].neighbour->locked)
nr_remove_neigh(nr_node->routes[2].neighbour);

nr_node->routes[2].quality = quality;

--
Regards,
listout

Brahmajit Das

unread,
Oct 20, 2025, 3:40:02 AM (6 days ago) Oct 20
to syzbot, da...@davemloft.net, edum...@google.com, ho...@kernel.org, ku...@kernel.org, linux...@vger.kernel.org, linux-...@vger.kernel.org, net...@vger.kernel.org, pab...@redhat.com, syzkall...@googlegroups.com
On 18.10.2025 13:37, syzbot wrote:
> syzbot has found a reproducer for the following issue on:
>
> HEAD commit: f406055cb18c Merge tag 'arm64-fixes' of git://git.kernel.o..
> git tree: upstream
> console output: https://syzkaller.appspot.com/x/log.txt?x=11cf767c580000
> kernel config: https://syzkaller.appspot.com/x/.config?x=f3e7b5a3627a90dd
> dashboard link: https://syzkaller.appspot.com/bug?extid=2860e75836a08b172755
> compiler: gcc (Debian 12.2.0-14+deb12u1) 12.2.0, GNU ld (GNU Binutils for Debian) 2.40
> syz repro: https://syzkaller.appspot.com/x/repro.syz?x=155f1de2580000
> C reproducer: https://syzkaller.appspot.com/x/repro.c?x=12b6b52f980000
>
> Downloadable assets:
> disk image (non-bootable): https://storage.googleapis.com/syzbot-assets/d900f083ada3/non_bootable_disk-f406055c.raw.xz
> vmlinux: https://storage.googleapis.com/syzbot-assets/a4db2a99bfb1/vmlinux-f406055c.xz
> kernel image: https://storage.googleapis.com/syzbot-assets/91d1ca420bac/bzImage-f406055c.xz
>
> IMPORTANT: if you fix the issue, please add the following tag to the commit:
> Reported-by: syzbot+2860e7...@syzkaller.appspotmail.com
>
> ==================================================================
> BUG: KASAN: slab-use-after-free in nr_add_node+0x25db/0x2c00 net/netrom/nr_route.c:248
> Read of size 4 at addr ffff888054b8cc30 by task syz.3.7839/22393
>

#syz test

Lizhi Xu

unread,
Oct 20, 2025, 4:14:09 AM (6 days ago) Oct 20
to syzbot+2860e7...@syzkaller.appspotmail.com, da...@davemloft.net, edum...@google.com, ho...@kernel.org, ku...@kernel.org, linux...@vger.kernel.org, linux-...@vger.kernel.org, net...@vger.kernel.org, pab...@redhat.com, syzkall...@googlegroups.com
The root cause of the problem is that multiple different tasks initiate
NETROM_NODE commands to add new routes, there is no lock between them to
protect the same nr_neigh.
Task0 may add the nr_neigh.refcount value of 1 on Task1 to routes[2].
When Task3 executes nr_neigh_put(nr_node->routes[2].neighbour), it will
release the neighbour because its refcount value is 1.

In this case, the following situation causes a UAF:

Task0 Task1
===== =====
nr_add_node()
nr_neigh_get_dev() nr_add_node()
nr_node->routes[2].neighbour->count--
nr_neigh_put(nr_node->routes[2].neighbour);
nr_remove_neigh(nr_node->routes[2].neighbour)
nr_node->routes[2].neighbour = nr_neigh
nr_neigh_hold(nr_neigh);

The solution to the problem is to use a lock to synchronize each add a route
to node.

syzbot reported:
BUG: KASAN: slab-use-after-free in nr_add_node+0x25db/0x2c00 net/netrom/nr_route.c:248
Read of size 4 at addr ffff888051e6e9b0 by task syz.1.2539/8741

Call Trace:
<TASK>
nr_add_node+0x25db/0x2c00 net/netrom/nr_route.c:248

Reported-by: syzbot+2860e7...@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=2860e75836a08b172755
Signed-off-by: Lizhi Xu <lizh...@windriver.com>
---
net/netrom/nr_route.c | 2 ++
1 file changed, 2 insertions(+)

diff --git a/net/netrom/nr_route.c b/net/netrom/nr_route.c
index b94cb2ffbaf8..ae1e5ee1f52f 100644
--- a/net/netrom/nr_route.c
+++ b/net/netrom/nr_route.c
@@ -102,7 +102,9 @@ static int __must_check nr_add_node(ax25_address *nr, const char *mnemonic,
struct nr_neigh *nr_neigh;
int i, found;
struct net_device *odev;
+ static DEFINE_MUTEX(add_node_lock);

+ guard(mutex)(&add_node_lock);
if ((odev=nr_dev_get(nr)) != NULL) { /* Can't add routes to ourself */
dev_put(odev);
return -EINVAL;
--
2.43.0

Dan Carpenter

unread,
Oct 20, 2025, 6:10:17 AM (6 days ago) Oct 20
to Lizhi Xu, syzbot+2860e7...@syzkaller.appspotmail.com, da...@davemloft.net, edum...@google.com, ho...@kernel.org, ku...@kernel.org, linux...@vger.kernel.org, linux-...@vger.kernel.org, net...@vger.kernel.org, pab...@redhat.com, syzkall...@googlegroups.com
On Mon, Oct 20, 2025 at 04:13:59PM +0800, Lizhi Xu wrote:
> The root cause of the problem is that multiple different tasks initiate
> NETROM_NODE commands to add new routes, there is no lock between them to
> protect the same nr_neigh.
> Task0 may add the nr_neigh.refcount value of 1 on Task1 to routes[2].
> When Task3 executes nr_neigh_put(nr_node->routes[2].neighbour), it will

s/Task3/Task1/

> release the neighbour because its refcount value is 1.
>

The refcount would be 2 and then drop to zero. Both nr_neigh_put() and
nr_remove_neigh() drop the refcount.

> In this case, the following situation causes a UAF:
>
> Task0 Task1
> ===== =====
> nr_add_node()
> nr_neigh_get_dev() nr_add_node()
> nr_node->routes[2].neighbour->count--

Does this line really matter in terms of the use after free?

> nr_neigh_put(nr_node->routes[2].neighbour);
> nr_remove_neigh(nr_node->routes[2].neighbour)
> nr_node->routes[2].neighbour = nr_neigh
> nr_neigh_hold(nr_neigh);


This chart is confusing. It says that that the nr_neigh_hold() is the use
after free. But we called nr_remove_neigh(nr_node->routes[2].neighbour)
before we assigned nr_node->routes[2].neighbour = nr_neigh...

The sysbot report says that the free happens on:

r_neigh_put(nr_node->routes[2].neighbour);

and the use after free happens on the next line:

if (nr_node->routes[2].neighbour->count == 0 && !nr_node->routes[2].neighbour->locked)

Which does suggest that somewhere the refcount is 1 when it should be
at least 2... It could be that two threads call nr_neigh_put() at
basically the same time, but that doesn't make sense either because
we're holding the nr_node_lock(nr_node)...

regards,
dan carpenter

Lizhi Xu

unread,
Oct 20, 2025, 7:02:56 AM (6 days ago) Oct 20
to dan.ca...@linaro.org, da...@davemloft.net, edum...@google.com, ho...@kernel.org, ku...@kernel.org, linux...@vger.kernel.org, linux-...@vger.kernel.org, lizh...@windriver.com, net...@vger.kernel.org, pab...@redhat.com, syzbot+2860e7...@syzkaller.appspotmail.com, syzkall...@googlegroups.com
The root cause of the problem is that multiple different tasks initiate
NETROM_NODE commands to add new routes, there is no lock between them to
protect the same nr_neigh.
Task0 may add the nr_neigh.refcount value of 1 on Task1 to routes[2].

When Task2 executes nr_neigh_put(nr_node->routes[2].neighbour), it will
release the neighbour because its refcount value is 1.

In this case, the following situation causes a UAF:

Task0 Task1 Task2
===== ===== =====
nr_add_node()
nr_neigh_get_dev() nr_add_node()
nr_node_lock()
nr_node->routes[2].neighbour->count--
nr_neigh_put(nr_node->routes[2].neighbour);
nr_remove_neigh(nr_node->routes[2].neighbour)
nr_node_unlock()
nr_node_lock()
nr_node->routes[2].neighbour = nr_neigh
nr_neigh_hold(nr_neigh); nr_add_node()
nr_neigh_put()

The solution to the problem is to use a lock to synchronize each add a route
to node.

syzbot reported:
BUG: KASAN: slab-use-after-free in nr_add_node+0x25db/0x2c00 net/netrom/nr_route.c:248
Read of size 4 at addr ffff888051e6e9b0 by task syz.1.2539/8741

Call Trace:
<TASK>
nr_add_node+0x25db/0x2c00 net/netrom/nr_route.c:248

Reported-by: syzbot+2860e7...@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=2860e75836a08b172755
Signed-off-by: Lizhi Xu <lizh...@windriver.com>
---
V1 -> V2: update comments for cause uaf

Dan Carpenter

unread,
Oct 20, 2025, 8:25:49 AM (6 days ago) Oct 20
to Lizhi Xu, da...@davemloft.net, edum...@google.com, ho...@kernel.org, ku...@kernel.org, linux...@vger.kernel.org, linux-...@vger.kernel.org, net...@vger.kernel.org, pab...@redhat.com, syzbot+2860e7...@syzkaller.appspotmail.com, syzkall...@googlegroups.com
On Mon, Oct 20, 2025 at 07:02:44PM +0800, Lizhi Xu wrote:
> The root cause of the problem is that multiple different tasks initiate
> NETROM_NODE commands to add new routes, there is no lock between them to
> protect the same nr_neigh.
> Task0 may add the nr_neigh.refcount value of 1 on Task1 to routes[2].
>
> When Task2 executes nr_neigh_put(nr_node->routes[2].neighbour), it will
> release the neighbour because its refcount value is 1.
>
> In this case, the following situation causes a UAF:
>
> Task0 Task1 Task2
> ===== ===== =====
> nr_add_node()
> nr_neigh_get_dev() nr_add_node()
> nr_node_lock()
> nr_node->routes[2].neighbour->count--
> nr_neigh_put(nr_node->routes[2].neighbour);
> nr_remove_neigh(nr_node->routes[2].neighbour)
> nr_node_unlock()
> nr_node_lock()
> nr_node->routes[2].neighbour = nr_neigh
> nr_neigh_hold(nr_neigh); nr_add_node()
> nr_neigh_put()
>
> The solution to the problem is to use a lock to synchronize each add a route
> to node.

This chart is still not right. Let me add line numbers to your chart:

netrom/nr_route.c
214 nr_node_lock(nr_node);
215
216 if (quality != 0)
217 strscpy(nr_node->mnemonic, mnemonic);
218
219 for (found = 0, i = 0; i < nr_node->count; i++) {
220 if (nr_node->routes[i].neighbour == nr_neigh) {
221 nr_node->routes[i].quality = quality;
222 nr_node->routes[i].obs_count = obs_count;
223 found = 1;
224 break;
225 }
226 }
227
228 if (!found) {
229 /* We have space at the bottom, slot it in */
230 if (nr_node->count < 3) {
231 nr_node->routes[2] = nr_node->routes[1];
232 nr_node->routes[1] = nr_node->routes[0];
233
234 nr_node->routes[0].quality = quality;
235 nr_node->routes[0].obs_count = obs_count;
236 nr_node->routes[0].neighbour = nr_neigh;
237
238 nr_node->which++;
239 nr_node->count++;
240 nr_neigh_hold(nr_neigh);
241 nr_neigh->count++;
242 } else {
243 /* It must be better than the worst */
244 if (quality > nr_node->routes[2].quality) {
245 nr_node->routes[2].neighbour->count--;
246 nr_neigh_put(nr_node->routes[2].neighbour);
247
248 if (nr_node->routes[2].neighbour->count == 0 && !nr_node->routes[2].neighbour->locked)
249 nr_remove_neigh(nr_node->routes[2].neighbour);
250
251 nr_node->routes[2].quality = quality;
252 nr_node->routes[2].obs_count = obs_count;
253 nr_node->routes[2].neighbour = nr_neigh;
254
255 nr_neigh_hold(nr_neigh);
256 nr_neigh->count++;
257 }
258 }
259 }


Task0 Task1 Task2
===== ===== =====
[97] nr_add_node()
[113] nr_neigh_get_dev() [97] nr_add_node()
[214] nr_node_lock()
[245] nr_node->routes[2].neighbour->count--
[246] nr_neigh_put(nr_node->routes[2].neighbour);
[248] nr_remove_neigh(nr_node->routes[2].neighbour)
[283] nr_node_unlock()
[214] nr_node_lock()
[253] nr_node->routes[2].neighbour = nr_neigh
[254] nr_neigh_hold(nr_neigh); [97] nr_add_node()
[XXX] nr_neigh_put()
^^^^^^^^^^^^^^^^^^^^

These charts are supposed to be chronological so [XXX] is wrong because the
use after free happens on line [248]. Do we really need three threads to
make this race work?

>
> syzbot reported:
> BUG: KASAN: slab-use-after-free in nr_add_node+0x25db/0x2c00 net/netrom/nr_route.c:248
^^^

> Read of size 4 at addr ffff888051e6e9b0 by task syz.1.2539/8741

I'm sure you tested your patch and that it fixes the bug, but I just
wonder if it's the best possible fix?

regards,
dan carpenter


Dan Carpenter

unread,
Oct 20, 2025, 8:57:42 AM (6 days ago) Oct 20
to Lizhi Xu, da...@davemloft.net, edum...@google.com, ho...@kernel.org, ku...@kernel.org, linux...@vger.kernel.org, linux-...@vger.kernel.org, net...@vger.kernel.org, pab...@redhat.com, syzbot+2860e7...@syzkaller.appspotmail.com, syzkall...@googlegroups.com
On Mon, Oct 20, 2025 at 03:25:40PM +0300, Dan Carpenter wrote:
> netrom/nr_route.c
> 214 nr_node_lock(nr_node);

I guess nr_node is different for each thread?
Does neighbour->count means how many nr_node pointers have it in ->routes[]?
I wish this code had comments.
KTDOO: add comments explaining all the counters in netrom/nr_route.c

> 250
> 251 nr_node->routes[2].quality = quality;
> 252 nr_node->routes[2].obs_count = obs_count;
> 253 nr_node->routes[2].neighbour = nr_neigh;
> 254
> 255 nr_neigh_hold(nr_neigh);
> 256 nr_neigh->count++;

Could we just add some locking to this if statement only? I had thought
that nr_node_lock() serialized it but now I think maybe not? Or maybe we
could increment the counters before assigning it?

nr_neigh->count++;
nr_neigh_hold(nr_neigh);
nr_node->routes[2].neighbour = nr_neigh;

I'm not an expert in concerency. Does calling nr_neigh_hold() mean th
that the nr_neigh->count++ will happen before the assignment?


> 257 }
> 258 }
> 259 }

regards,
dan carpenter

Dan Carpenter

unread,
Oct 20, 2025, 8:57:47 AM (6 days ago) Oct 20
to Lizhi Xu, da...@davemloft.net, edum...@google.com, ho...@kernel.org, ku...@kernel.org, linux...@vger.kernel.org, linux-...@vger.kernel.org, net...@vger.kernel.org, pab...@redhat.com, syzbot+2860e7...@syzkaller.appspotmail.com, syzkall...@googlegroups.com
On Mon, Oct 20, 2025 at 03:25:40PM +0300, Dan Carpenter wrote:
Should we call nr_neigh->count++ if we found it? I guess I don't
really understand what nr_neigh->count is counting... It would be
really nice if someone added some comments explaining how the ref
counting worked.

> 223 found = 1;
> 224 break;
> 225 }
> 226 }

regards,
dan carpenter

Lizhi Xu

unread,
Oct 20, 2025, 9:35:07 AM (6 days ago) Oct 20
to dan.ca...@linaro.org, da...@davemloft.net, edum...@google.com, ho...@kernel.org, ku...@kernel.org, linux...@vger.kernel.org, linux-...@vger.kernel.org, lizh...@windriver.com, net...@vger.kernel.org, pab...@redhat.com, syzbot+2860e7...@syzkaller.appspotmail.com, syzkall...@googlegroups.com

On Mon, 20 Oct 2025 15:25:40 +0300, Dan Carpenter wrote:
> Task0 Task1 Task2
> ===== ===== =====
> [97] nr_add_node()
> [113] nr_neigh_get_dev() [97] nr_add_node()
> [214] nr_node_lock()
> [245] nr_node->routes[2].neighbour->count--
> [246] nr_neigh_put(nr_node->routes[2].neighbour);
> [248] nr_remove_neigh(nr_node->routes[2].neighbour)
> [283] nr_node_unlock()
> [214] nr_node_lock()
> [253] nr_node->routes[2].neighbour = nr_neigh
> [254] nr_neigh_hold(nr_neigh); [97] nr_add_node()
> [XXX] nr_neigh_put()
> ^^^^^^^^^^^^^^^^^^^^
>
> These charts are supposed to be chronological so [XXX] is wrong because the
> use after free happens on line [248]. Do we really need three threads to
> make this race work?
The UAF problem occurs in Task2. Task1 sets the refcount of nr_neigh to 1,
then Task0 adds it to routes[2]. Task2 releases routes[2].neighbour after
executing [XXX]nr_neigh_put().

BR,
Lizhi

Lizhi Xu

unread,
Oct 20, 2025, 9:49:23 AM (6 days ago) Oct 20
to lizh...@windriver.com, dan.ca...@linaro.org, da...@davemloft.net, edum...@google.com, ho...@kernel.org, ku...@kernel.org, linux...@vger.kernel.org, linux-...@vger.kernel.org, net...@vger.kernel.org, pab...@redhat.com, syzbot+2860e7...@syzkaller.appspotmail.com, syzkall...@googlegroups.com
Execution Order:
1 -> Task0
[113] nr_neigh_get_dev() // After execution, the refcount value is 3

2 -> Task1
[246] nr_neigh_put(nr_node->routes[2].neighbour); // After execution, the refcount value is 2
[248] nr_remove_neigh(nr_node->routes[2].neighbour) // After execution, the refcount value is 1

3 -> Task0
[253] nr_node->routes[2].neighbour = nr_neigh // nr_neigh's refcount value is 1 and add it to routes[2]

4 -> Task2
[XXX] nr_neigh_put(nr_node->routes[2].neighbour) // After execution, neighhour is freed
if (nr_node->routes[2].neighbour->count == 0 && !nr_node->routes[2].neighbour->locked) // Uaf occurs this line when accessing neighbour->count

BR,
Lizhi

Dan Carpenter

unread,
Oct 20, 2025, 1:59:32 PM (6 days ago) Oct 20
to Lizhi Xu, da...@davemloft.net, edum...@google.com, ho...@kernel.org, ku...@kernel.org, linux...@vger.kernel.org, linux-...@vger.kernel.org, net...@vger.kernel.org, pab...@redhat.com, syzbot+2860e7...@syzkaller.appspotmail.com, syzkall...@googlegroups.com
Let's step back a bit and look at the bigger picture design. (Which is
completely undocumented so we're just guessing).

When we put nr_neigh into nr_node->routes[] we bump the nr_neigh_hold()
reference count and nr_neigh->count++, then when we remove it from
->routes[] we drop the reference and do nr_neigh->count--.

If it's the last reference (and we are not holding ->locked) then we
remove it from the &nr_neigh_list and drop the reference count again and
free it. So we drop the reference count twice. This is a complicated
design with three variables: nr_neigh_hold(), nr_neigh->count and
->locked. Why can it not just be one counter nr_neigh_hold(). So
instead of setting locked = true we would just take an extra reference?
The nr_neigh->count++ would be replaced with nr_neigh_hold() as well.

Because that's fundamentally the problem, right? We call
nr_neigh_get_dev() so we think we're holding a reference and we're
safe, but we don't realize that calling neighbour->count-- can
result in dropping two references.

regards,
dan carpenter

Lizhi Xu

unread,
Oct 20, 2025, 10:05:46 PM (6 days ago) Oct 20
to dan.ca...@linaro.org, lizh...@windriver.com, da...@davemloft.net, edum...@google.com, ho...@kernel.org, ku...@kernel.org, linux...@vger.kernel.org, linux-...@vger.kernel.org, net...@vger.kernel.org, pab...@redhat.com, syzbot+2860e7...@syzkaller.appspotmail.com, syzkall...@googlegroups.com
locked controls whether the neighbor quality can be automatically updated;
count controls the number of different routes a neighbor is linked to;
refcount is simply used to manage the neighbor lifecycle.
>
> Because that's fundamentally the problem, right? We call
> nr_neigh_get_dev() so we think we're holding a reference and we're
> safe, but we don't realize that calling neighbour->count-- can
> result in dropping two references.
After nr_neigh_get_dev() retrieves a neighbor, there shouldn't be an
unfinished nr_add_node() call operating on the neighbor in the route.
Therefore, we need to use a lock before the nr_neigh_get_dev() operation
begins to ensure that the neighbor is added atomically to the routing table.

BR,
Lizhi

Dan Carpenter

unread,
Oct 21, 2025, 2:36:55 AM (5 days ago) Oct 21
to Lizhi Xu, da...@davemloft.net, edum...@google.com, ho...@kernel.org, ku...@kernel.org, linux...@vger.kernel.org, linux-...@vger.kernel.org, net...@vger.kernel.org, pab...@redhat.com, syzbot+2860e7...@syzkaller.appspotmail.com, syzkall...@googlegroups.com
I'm not sure your patch fixes the bug because we could still race against
nr_del_node().

I'm not saying get rid of locked completely, I'm saying get rid of code like
this:
if (nr_node->routes[2].neighbour->count == 0 && !nr_node->routes[2].neighbour->locked)
nr_remove_neigh(nr_node->routes[2].neighbour);

Right now, locked serves as a special kind of reference count, because we
don't drop the reference if it's true.

> count controls the number of different routes a neighbor is linked to;

Sure, that is interesting information for the user, so keep it around to
print in the proc file, but don't use it as a reference count.

> refcount is simply used to manage the neighbor lifecycle.

The bug is caused because our reference counting is bad.

So right now what happens is we allocate nr_neigh and we put it on the
&nr_neigh_list. Then we lock it or we add it to ->routes[] and each of
those has a different reference count. Then when we drop those references
we do:

if (nr_node->routes[2].neighbour->count == 0 && !nr_node->routes[2].neighbour->locked)
nr_remove_neigh(nr_node->routes[2].neighbour);

This removes it from the list, and hopefully this is the last reference
and it frees it.

It would be much simpler to say, we only use nr_neigh_hold()/put() for
reference counting. When we set locked we do:

nr_neigh_hold(nr_neigh);
nr_neigh->locked = true;

Incrementing the refcount means it can't be freed.

Then when we remove nr_neigh from ->routes[] we wouldn't "remove it from
the list", instead we would just drop a reference. When we dropped the
last reference, nr_neigh_put() would remove it from the list.

My proposal would be a behavior change because right now what happens is:

1: allocate nr_neigh
2: add it to ->routes[]
3: remove it from ->routes[]
(freed automatically because we drop two references)

Now it would be:
1: allocate nr_neigh
2: add it to ->routes[]
3: remove it from ->routes[]
4: needs to be freed manually with nr_del_neigh().

regards,
dan carpenter

Lizhi Xu

unread,
Oct 21, 2025, 4:34:16 AM (5 days ago) Oct 21
to dan.ca...@linaro.org, lizh...@windriver.com, da...@davemloft.net, edum...@google.com, ho...@kernel.org, ku...@kernel.org, linux...@vger.kernel.org, linux-...@vger.kernel.org, net...@vger.kernel.org, pab...@redhat.com, syzbot+2860e7...@syzkaller.appspotmail.com, syzkall...@googlegroups.com
This is fine in this issue, but for rigor, I'll add locks to all related
ioctl and route frame operations to maintain synchronization.
I will send V3 patch to improve it.
>
> I'm not saying get rid of locked completely, I'm saying get rid of code like
> this:
> if (nr_node->routes[2].neighbour->count == 0 && !nr_node->routes[2].neighbour->locked)
> nr_remove_neigh(nr_node->routes[2].neighbour);
>
> Right now, locked serves as a special kind of reference count, because we
> don't drop the reference if it's true.
I don't think this is correct.
>
> > count controls the number of different routes a neighbor is linked to;
>
> Sure, that is interesting information for the user, so keep it around to
> print in the proc file, but don't use it as a reference count.
>
> > refcount is simply used to manage the neighbor lifecycle.
>
> The bug is caused because our reference counting is bad.
>
> So right now what happens is we allocate nr_neigh and we put it on the
> &nr_neigh_list. Then we lock it or we add it to ->routes[] and each of
> those has a different reference count. Then when we drop those references
> we do:
>
> if (nr_node->routes[2].neighbour->count == 0 && !nr_node->routes[2].neighbour->locked)
> nr_remove_neigh(nr_node->routes[2].neighbour);
>
> This removes it from the list, and hopefully this is the last reference
> and it frees it.
>
> It would be much simpler to say, we only use nr_neigh_hold()/put() for
> reference counting. When we set locked we do:
>
> nr_neigh_hold(nr_neigh);
> nr_neigh->locked = true;
>
> Incrementing the refcount means it can't be freed.
No, setting locked = 1 is only done in nr_add_neigh(), and nr_neigh_hold()
is not executed, and the refcount value is 1.
>
> Then when we remove nr_neigh from ->routes[] we wouldn't "remove it from
> the list", instead we would just drop a reference. When we dropped the
> last reference, nr_neigh_put() would remove it from the list.
>
> My proposal would be a behavior change because right now what happens is:
>
> 1: allocate nr_neigh
> 2: add it to ->routes[]
> 3: remove it from ->routes[]
> (freed automatically because we drop two references)
No, No, I know where your analysis went wrong, it is here.

The problem is not when allocating neigh and adding it to routes[2],
but when nr_add_node is executed twice later, one is Task0 as I mentioned
above, and the other is Task1.
After Task1 moves the neighbor out of routes, Task0 uses nr_neigh_get_dev()
to get the neighbor that Task1 moved out, and then adds it to its routes.
This is wrong. Task0 should not use nr_neigh_get_dev() to obtain the neighbor
before other tasks move it out. This will interfere with the reference count
of the neighbor, which is the root cause of the problem.

BR,
Lizhi

Lizhi Xu

unread,
Oct 21, 2025, 4:35:14 AM (5 days ago) Oct 21
to dan.ca...@linaro.org, da...@davemloft.net, edum...@google.com, ho...@kernel.org, ku...@kernel.org, linux...@vger.kernel.org, linux-...@vger.kernel.org, lizh...@windriver.com, net...@vger.kernel.org, pab...@redhat.com, syzbot+2860e7...@syzkaller.appspotmail.com, syzkall...@googlegroups.com
The root cause of the problem is that multiple different tasks initiate
SIOCADDRT & NETROM_NODE commands to add new routes, there is no lock
between them to protect the same nr_neigh.

Task0 can add the nr_neigh.refcount value of 1 on Task1 to routes[2].
When Task2 executes nr_neigh_put(nr_node->routes[2].neighbour), it will
release the neighbour because its refcount value is 1.

In this case, the following situation causes a UAF on Task2:

Task0 Task1 Task2
===== ===== =====
nr_add_node()
nr_neigh_get_dev() nr_add_node()
nr_node_lock()
nr_node->routes[2].neighbour->count--
nr_neigh_put(nr_node->routes[2].neighbour);
nr_remove_neigh(nr_node->routes[2].neighbour)
nr_node_unlock()
nr_node_lock()
nr_node->routes[2].neighbour = nr_neigh
nr_neigh_hold(nr_neigh); nr_add_node()
nr_neigh_put()
if (nr_node->routes[2].neighbour->count
Description of the UAF triggering process:
First, Task 0 executes nr_neigh_get_dev() to set neighbor refcount to 3.
Then, Task 1 puts the same neighbor from its routes[2] and executes
nr_remove_neigh() because the count is 0. After these two operations,
the neighbor's refcount becomes 1. Then, Task 0 acquires the nr node
lock and writes it to its routes[2].neighbour.
Finally, Task 2 executes nr_neigh_put(nr_node->routes[2].neighbour) to
release the neighbor. The subsequent execution of the neighbor->count
check triggers a UAF.

The solution to the problem is to use a lock to synchronize each add a
route to node, but for rigor, I'll add locks to related ioctl and route
frame operations to maintain synchronization.

syzbot reported:
BUG: KASAN: slab-use-after-free in nr_add_node+0x25db/0x2c00 net/netrom/nr_route.c:248
Read of size 4 at addr ffff888051e6e9b0 by task syz.1.2539/8741

Call Trace:
<TASK>
nr_add_node+0x25db/0x2c00 net/netrom/nr_route.c:248

Reported-by: syzbot+2860e7...@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=2860e75836a08b172755
Signed-off-by: Lizhi Xu <lizh...@windriver.com>
---
V1 -> V2: update comments for cause uaf
V2 -> V3: sync neighbor operations in ioctl and route frame, update comments

net/netrom/nr_route.c | 4 ++++
1 file changed, 4 insertions(+)

diff --git a/net/netrom/nr_route.c b/net/netrom/nr_route.c
index b94cb2ffbaf8..debe3e925338 100644
--- a/net/netrom/nr_route.c
+++ b/net/netrom/nr_route.c
@@ -40,6 +40,7 @@ static HLIST_HEAD(nr_node_list);
static DEFINE_SPINLOCK(nr_node_list_lock);
static HLIST_HEAD(nr_neigh_list);
static DEFINE_SPINLOCK(nr_neigh_list_lock);
+static DEFINE_MUTEX(neighbor_lock);

static struct nr_node *nr_node_get(ax25_address *callsign)
{
@@ -633,6 +634,8 @@ int nr_rt_ioctl(unsigned int cmd, void __user *arg)
ax25_digi digi;
int ret;

+ guard(mutex)(&neighbor_lock);
+
switch (cmd) {
case SIOCADDRT:
if (copy_from_user(&nr_route, arg, sizeof(struct nr_route_struct)))
@@ -765,6 +768,7 @@ int nr_route_frame(struct sk_buff *skb, ax25_cb *ax25)
nr_dest = (ax25_address *)(skb->data + 7);

if (ax25 != NULL) {
+ guard(mutex)(&neighbor_lock);
ret = nr_add_node(nr_src, "", &ax25->dest_addr, ax25->digipeat,
ax25->ax25_dev->dev, 0,
READ_ONCE(sysctl_netrom_obsolescence_count_initialiser));
--
2.43.0

Paolo Abeni

unread,
Oct 23, 2025, 7:44:28 AM (3 days ago) Oct 23
to Lizhi Xu, dan.ca...@linaro.org, da...@davemloft.net, edum...@google.com, ho...@kernel.org, ku...@kernel.org, linux...@vger.kernel.org, linux-...@vger.kernel.org, net...@vger.kernel.org, syzbot+2860e7...@syzkaller.appspotmail.com, syzkall...@googlegroups.com
I think that adding another locking mechanism on top of an already
complex and not well understood locking and reference infra is not the
right direction.

Why reordering the statements as:

if (nr_node->routes[2].neighbour->count == 0 &&
!nr_node->routes[2].neighbour->locked)
nr_remove_neigh(nr_node->routes[2].neighbour);
nr_neigh_put(nr_node->routes[2].neighbour);

is not enough?
See:

https://elixir.bootlin.com/linux/v6.18-rc1/source/Documentation/process/maintainer-netdev.rst#L395

/P

Eric Dumazet

unread,
Oct 23, 2025, 7:54:27 AM (3 days ago) Oct 23
to Paolo Abeni, Lizhi Xu, dan.ca...@linaro.org, da...@davemloft.net, ho...@kernel.org, ku...@kernel.org, linux...@vger.kernel.org, linux-...@vger.kernel.org, net...@vger.kernel.org, syzbot+2860e7...@syzkaller.appspotmail.com, syzkall...@googlegroups.com
I would also try to use a single spinlock : ie fuse together
nr_node_list_lock and nr_neigh_list_lock

Having two locks for something that is primarily used by fuzzers
nowadays is wasting our time.

Lizhi Xu

unread,
Oct 23, 2025, 8:41:19 AM (3 days ago) Oct 23
to pab...@redhat.com, dan.ca...@linaro.org, da...@davemloft.net, edum...@google.com, ho...@kernel.org, ku...@kernel.org, linux...@vger.kernel.org, linux-...@vger.kernel.org, lizh...@windriver.com, net...@vger.kernel.org, syzbot+2860e7...@syzkaller.appspotmail.com, syzkall...@googlegroups.com
This is not enough, the same uaf will appear, nr_remove_neigh() will also
execute nr_neigh_put(), and then executing nr_neigh_put() again will
trigger the uaf.
Using guard is not recommended. I'll reconsider.

BR,
Lizhi

Lizhi Xu

unread,
Oct 23, 2025, 9:50:43 AM (3 days ago) Oct 23
to lizh...@windriver.com, dan.ca...@linaro.org, da...@davemloft.net, edum...@google.com, ho...@kernel.org, ku...@kernel.org, linux...@vger.kernel.org, linux-...@vger.kernel.org, net...@vger.kernel.org, pab...@redhat.com, syzbot+2860e7...@syzkaller.appspotmail.com, syzkall...@googlegroups.com
Filter out neighbors with a refcount of 1 to avoid unsafe conditions.

syzbot reported:
BUG: KASAN: slab-use-after-free in nr_add_node+0x25db/0x2c00 net/netrom/nr_route.c:248
Read of size 4 at addr ffff888051e6e9b0 by task syz.1.2539/8741

Call Trace:
<TASK>
nr_add_node+0x25db/0x2c00 net/netrom/nr_route.c:248

Reported-by: syzbot+2860e7...@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=2860e75836a08b172755
Signed-off-by: Lizhi Xu <lizh...@windriver.com>
---
V1 -> V2: update comments for cause uaf
V2 -> V3: sync neighbor operations in ioctl and route frame, update comments
V3 -> V4: Preventing the use of neighbors with a reference count of 1

net/netrom/nr_route.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/net/netrom/nr_route.c b/net/netrom/nr_route.c
index b94cb2ffbaf8..1ef2743a5ec0 100644
--- a/net/netrom/nr_route.c
+++ b/net/netrom/nr_route.c
@@ -100,7 +100,7 @@ static int __must_check nr_add_node(ax25_address *nr, const char *mnemonic,
{
struct nr_node *nr_node;
struct nr_neigh *nr_neigh;
- int i, found;
+ int i, found, ret = 0;
struct net_device *odev;

if ((odev=nr_dev_get(nr)) != NULL) { /* Can't add routes to ourself */
@@ -212,6 +212,10 @@ static int __must_check nr_add_node(ax25_address *nr, const char *mnemonic,
return 0;
}
nr_node_lock(nr_node);
+ if (refcount_read(&nr_neigh->refcount) == 1) {
+ ret = -EINVAL;
+ goto out;
+ }

if (quality != 0)
strscpy(nr_node->mnemonic, mnemonic);
@@ -279,10 +283,11 @@ static int __must_check nr_add_node(ax25_address *nr, const char *mnemonic,
}
}

+out:
nr_neigh_put(nr_neigh);
nr_node_unlock(nr_node);
nr_node_put(nr_node);
- return 0;
+ return ret;
}

static void nr_remove_node_locked(struct nr_node *nr_node)
--
2.43.0

Dan Carpenter

unread,
Oct 24, 2025, 6:45:25 AM (2 days ago) Oct 24
to Paolo Abeni, Lizhi Xu, da...@davemloft.net, edum...@google.com, ho...@kernel.org, ku...@kernel.org, linux...@vger.kernel.org, linux-...@vger.kernel.org, net...@vger.kernel.org, syzbot+2860e7...@syzkaller.appspotmail.com, syzkall...@googlegroups.com
On Thu, Oct 23, 2025 at 01:44:18PM +0200, Paolo Abeni wrote:
> Why reordering the statements as:
>
> if (nr_node->routes[2].neighbour->count == 0 &&
> !nr_node->routes[2].neighbour->locked)
> nr_remove_neigh(nr_node->routes[2].neighbour);
> nr_neigh_put(nr_node->routes[2].neighbour);
>
> is not enough?

There are so many unfortunate things like this:

net/netrom/nr_route.c
243 /* It must be better than the worst */
244 if (quality > nr_node->routes[2].quality) {
245 nr_node->routes[2].neighbour->count--;

++/-- are not atomic.

246 nr_neigh_put(nr_node->routes[2].neighbour);
247
248 if (nr_node->routes[2].neighbour->count == 0 && !nr_node->routes[2].neighbour->locked)
249 nr_remove_neigh(nr_node->routes[2].neighbour);
250
251 nr_node->routes[2].quality = quality;
252 nr_node->routes[2].obs_count = obs_count;
253 nr_node->routes[2].neighbour = nr_neigh;

This line should come after the next two lines.

254
255 nr_neigh_hold(nr_neigh);
256 nr_neigh->count++;
257 }

regards,
dan carpenter
Reply all
Reply to author
Forward
0 new messages