[syzbot] [net?] possible deadlock in team_port_change_check (2)

25 views
Skip to first unread message

syzbot

unread,
Feb 29, 2024, 11:02:28 AMFeb 29
to da...@davemloft.net, edum...@google.com, ji...@resnulli.us, ku...@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: 2a770cdc4382 tun: Fix xdp_rxq_info's queue_index when deta..
git tree: net
console output: https://syzkaller.appspot.com/x/log.txt?x=11bfb032180000
kernel config: https://syzkaller.appspot.com/x/.config?x=eff9f3183d0a20dd
dashboard link: https://syzkaller.appspot.com/bug?extid=3c47b5843403a45aef57
compiler: Debian clang version 15.0.6, GNU ld (GNU Binutils for Debian) 2.40

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

Downloadable assets:
disk image: https://storage.googleapis.com/syzbot-assets/54ceb0944449/disk-2a770cdc.raw.xz
vmlinux: https://storage.googleapis.com/syzbot-assets/69b79e7b7a86/vmlinux-2a770cdc.xz
kernel image: https://storage.googleapis.com/syzbot-assets/dedbc599c2f7/bzImage-2a770cdc.xz

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

============================================
WARNING: possible recursive locking detected
6.8.0-rc5-syzkaller-00129-g2a770cdc4382 #0 Not tainted
--------------------------------------------
syz-executor.1/20275 is trying to acquire lock:
ffff888045338d00 (team->team_lock_key#2){+.+.}-{3:3}, at: team_port_change_check+0x51/0x1e0 drivers/net/team/team.c:2997

but task is already holding lock:
ffff888045338d00 (team->team_lock_key#2){+.+.}-{3:3}, at: team_add_slave+0xad/0x2750 drivers/net/team/team.c:1974

other info that might help us debug this:
Possible unsafe locking scenario:

CPU0
----
lock(team->team_lock_key#2);
lock(team->team_lock_key#2);

*** DEADLOCK ***

May be due to missing lock nesting notation

2 locks held by syz-executor.1/20275:
#0: ffffffff8f3759c8 (rtnl_mutex){+.+.}-{3:3}, at: rtnl_lock net/core/rtnetlink.c:79 [inline]
#0: ffffffff8f3759c8 (rtnl_mutex){+.+.}-{3:3}, at: rtnetlink_rcv_msg+0x82c/0x1040 net/core/rtnetlink.c:6615
#1: ffff888045338d00 (team->team_lock_key#2){+.+.}-{3:3}, at: team_add_slave+0xad/0x2750 drivers/net/team/team.c:1974

stack backtrace:
CPU: 0 PID: 20275 Comm: syz-executor.1 Not tainted 6.8.0-rc5-syzkaller-00129-g2a770cdc4382 #0
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/25/2024
Call Trace:
<TASK>
__dump_stack lib/dump_stack.c:88 [inline]
dump_stack_lvl+0x1e7/0x2e0 lib/dump_stack.c:106
check_deadlock kernel/locking/lockdep.c:3062 [inline]
validate_chain+0x15c0/0x58e0 kernel/locking/lockdep.c:3856
__lock_acquire+0x1345/0x1fd0 kernel/locking/lockdep.c:5137
lock_acquire+0x1e3/0x530 kernel/locking/lockdep.c:5754
__mutex_lock_common kernel/locking/mutex.c:608 [inline]
__mutex_lock+0x136/0xd70 kernel/locking/mutex.c:752
team_port_change_check+0x51/0x1e0 drivers/net/team/team.c:2997
team_device_event+0x161/0x5b0 drivers/net/team/team.c:3023
notifier_call_chain+0x18f/0x3b0 kernel/notifier.c:93
call_netdevice_notifiers_extack net/core/dev.c:2004 [inline]
call_netdevice_notifiers net/core/dev.c:2018 [inline]
dev_close_many+0x33c/0x4c0 net/core/dev.c:1559
vlan_device_event+0x18b7/0x1de0 net/8021q/vlan.c:449
notifier_call_chain+0x18f/0x3b0 kernel/notifier.c:93
call_netdevice_notifiers_extack net/core/dev.c:2004 [inline]
call_netdevice_notifiers net/core/dev.c:2018 [inline]
dev_close_many+0x33c/0x4c0 net/core/dev.c:1559
dev_close+0x1c0/0x2c0 net/core/dev.c:1581
team_port_add drivers/net/team/team.c:1312 [inline]
team_add_slave+0x1aef/0x2750 drivers/net/team/team.c:1975
do_set_master net/core/rtnetlink.c:2707 [inline]
do_setlink+0xe58/0x41c0 net/core/rtnetlink.c:2913
rtnl_setlink+0x40d/0x5a0 net/core/rtnetlink.c:3209
rtnetlink_rcv_msg+0x885/0x1040 net/core/rtnetlink.c:6618
netlink_rcv_skb+0x1e3/0x430 net/netlink/af_netlink.c:2543
netlink_unicast_kernel net/netlink/af_netlink.c:1341 [inline]
netlink_unicast+0x7ea/0x980 net/netlink/af_netlink.c:1367
netlink_sendmsg+0xa3b/0xd70 net/netlink/af_netlink.c:1908
sock_sendmsg_nosec net/socket.c:730 [inline]
__sock_sendmsg+0x221/0x270 net/socket.c:745
sock_write_iter+0x2dd/0x400 net/socket.c:1160
do_iter_readv_writev+0x46c/0x640
vfs_writev+0x395/0xbb0 fs/read_write.c:971
do_writev+0x1b1/0x350 fs/read_write.c:1018
do_syscall_64+0xf9/0x240
entry_SYSCALL_64_after_hwframe+0x6f/0x77
RIP: 0033:0x7ff40be7dda9
Code: 28 00 00 00 75 05 48 83 c4 28 c3 e8 e1 20 00 00 90 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 b0 ff ff ff f7 d8 64 89 01 48
RSP: 002b:00007ff40cb2f0c8 EFLAGS: 00000246 ORIG_RAX: 0000000000000014
RAX: ffffffffffffffda RBX: 00007ff40bfabf80 RCX: 00007ff40be7dda9
RDX: 0000000000000001 RSI: 0000000020000400 RDI: 0000000000000003
RBP: 00007ff40beca47a R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
R13: 000000000000000b R14: 00007ff40bfabf80 R15: 00007ffdeb79a408
</TASK>


---
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 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

Jiri Pirko

unread,
Feb 29, 2024, 11:58:31 AMFeb 29
to syzbot, da...@davemloft.net, edum...@google.com, ku...@kernel.org, linux-...@vger.kernel.org, net...@vger.kernel.org, pab...@redhat.com, syzkall...@googlegroups.com
Interesting. Looks like syscaller is adding netdev to team when the vlan
on the same netdev is enslaved in the same team. In real life, does not
make any sense at all. Will try to fix this deadlock tomorrow.

xingwei lee

unread,
Mar 2, 2024, 8:52:37 AMMar 2
to syzbot+3c47b5...@syzkaller.appspotmail.com, da...@davemloft.net, Eric Dumazet, ji...@resnulli.us, ku...@kernel.org, linux-...@vger.kernel.org, net...@vger.kernel.org, pab...@redhat.com, syzkall...@googlegroups.com
Hello, I reproduced this bug and comfired in the latest net tree.
However, I can only make sure syzlang reproducer can work, C
reproducer can’t work.
Anyway, I uploaded it here.

If you fix this issue, please add the following tag to the commit:
Reported-by: xingwei lee <xrive...@gmail.com>

I use the same configuation with syzbot dashboard.
kernel version: net tree 2a770cdc4382b457ca3d43d03f0f0064f905a0d0
kernel config: https://syzkaller.appspot.com/text?tag=KernelConfig&x=eff9f3183d0a20dd
with KASAN enabled
compiler: Debian clang version 15.0.6, GNU ld (GNU Binutils for Debian) 2.40

root@syzkaller:~/linux_amd64# ./syz-execprog -repeat 0 ../repro.txt
[ 6971.160730][T106447] team0: Device veth0_vlan failed to register rx_handler
[ 6971.239311][T106447]
[ 6971.240256][T106447] ============================================
[ 6971.248075][T106447] WARNING: possible recursive locking detected
[ 6971.252130][T106447] 6.8.0-rc5 #1 Not tainted
[ 6971.253807][T106447] --------------------------------------------
[ 6971.258294][T106447] syz-executor/106447 is trying to acquire lock:
[ 6971.262149][T106447] ffff888023bfad00
(team->team_lock_key#6){+.+.}-{3:3}, at: team_port_change_che0
[ 6971.272457][T106447]
[ 6971.272457][T106447] but task is already holding lock:
[ 6971.275722][T106447] ffff888023bfad00
(team->team_lock_key#6){+.+.}-{3:3}, at: team_add_slave+0xb2/0
[ 6971.277391][T106447]
[ 6971.277391][T106447] other info that might help us debug this:
[ 6971.278742][T106447] Possible unsafe locking scenario:
[ 6971.278742][T106447]
[ 6971.285531][T106447] CPU0
[ 6971.286119][T106447] ----
[ 6971.286685][T106447] lock(team->team_lock_key#6);
[ 6971.294371][T106447] lock(team->team_lock_key#6);
[ 6971.295269][T106447]
[ 6971.295269][T106447] *** DEADLOCK ***
[ 6971.295269][T106447]
[ 6971.336594][T106447] May be due to missing lock nesting notation
[ 6971.336594][T106447]
[ 6971.337974][T106447] 2 locks held by syz-executor/106447:
[ 6971.338906][T106447] #0: ffffffff8f7759c8
(rtnl_mutex){+.+.}-{3:3}, at: rtnetlink_rcv_msg+0x890/0x0
[ 6971.345377][T106447] #1: ffff888023bfad00
(team->team_lock_key#6){+.+.}-{3:3}, at: team_add_slave+0
[ 6971.347076][T106447]
[ 6971.347076][T106447] stack backtrace:
[ 6971.358055][T106447] CPU: 1 PID: 106447 Comm: syz-executor Not
tainted 6.8.0-rc5 #1
[ 6971.375491][T106447] Hardware name: QEMU Standard PC (i440FX +
PIIX, 1996), BIOS 1.16.2-debian-1.164
[ 6971.384912][T106447] Call Trace:
[ 6971.386057][T106447] <TASK>
[ 6971.387087][T106447] dump_stack_lvl+0x1f4/0x2f0
[ 6971.391295][T106447] ? __pfx_dump_stack_lvl+0x10/0x10
[ 6971.400249][T106447] ? print_deadlock_bug+0x479/0x620
[ 6971.402409][T106447] ? _find_first_zero_bit+0xe1/0x110
[ 6971.404284][T106447] validate_chain+0x15c0/0x58e0
[ 6971.407870][T106447] ? mark_lock+0x9a/0x350
[ 6971.410151][T106447] ? __pfx_validate_chain+0x10/0x10
[ 6971.447513][T106447] ? __lock_acquire+0x1345/0x1fd0
[ 6971.452451][T106447] ? mark_lock+0x9a/0x350
[ 6971.453974][T106447] ? __lock_acquire+0x1345/0x1fd0
[ 6971.459800][T106447] ? mark_lock+0x9a/0x350
[ 6971.467966][T106447] __lock_acquire+0x1345/0x1fd0
[ 6971.469667][T106447] lock_acquire+0x1e3/0x530
[ 6971.471195][T106447] ? team_port_change_check+0x56/0x200
[ 6971.485003][T106447] ? __pfx_lock_acquire+0x10/0x10
[ 6971.486723][T106447] ? lockdep_hardirqs_on+0x98/0x140
[ 6971.495451][T106447] ? __pfx___might_resched+0x10/0x10
[ 6971.497220][T106447] ? _raw_spin_unlock_irqrestore+0xdd/0x140
[ 6971.510125][T106447] ? __pfx_cfg80211_netdev_notifier_call+0x10/0x10
[ 6971.516047][T106447] ? lock_timer_base+0x257/0x270
[ 6971.517711][T106447] __mutex_lock+0x136/0xd70
[ 6971.524165][T106447] ? team_port_change_check+0x56/0x200
[ 6971.531180][T106447] ? bond_netdev_event+0xe6/0xf80
[ 6971.552437][T106447] ? __timer_delete_sync+0x165/0x320
[ 6971.555487][T106447] ? team_port_change_check+0x56/0x200
[ 6971.557402][T106447] ? __pfx___mutex_lock+0x10/0x10
[ 6971.585609][T106447] ? __asan_memset+0x23/0x50
[ 6971.588329][T106447] team_port_change_check+0x56/0x200
[ 6971.613558][T106447] team_device_event+0x172/0x5e0
[ 6971.615307][T106447] ? notifier_call_chain+0x171/0x3e0
[ 6971.617138][T106447] notifier_call_chain+0x19c/0x3e0
[ 6971.640031][T106447] dev_close_many+0x344/0x4d0
[ 6971.663799][T106447] ? __pfx_dev_close_many+0x10/0x10
[ 6971.665582][T106447] vlan_device_event+0x1962/0x1e90
[ 6971.667257][T106447] ? br_device_event+0x151/0x9d0
[ 6971.668865][T106447] ? __pfx_phonet_device_notify+0x10/0x10
[ 6971.681103][T106447] ? __pfx_vlan_device_event+0x10/0x10
[ 6971.689708][T106447] ? __pfx_br_device_event+0x10/0x10
[ 6971.702341][T106447] ? raw_notifier+0xa6/0x770
[ 6971.703945][T106447] ? cgw_notifier+0xdd/0x3c0
[ 6971.717620][T106447] notifier_call_chain+0x19c/0x3e0
[ 6971.719396][T106447] dev_close_many+0x344/0x4d0
[ 6971.723625][T106447] ? __pfx_dev_close_many+0x10/0x10
[ 6971.725406][T106447] dev_close+0x1c9/0x2d0
[ 6971.736927][T106447] ? __pfx_dev_close+0x10/0x10
[ 6971.741054][T106447] ? vlan_vids_del_by_dev+0x2b5/0x310
[ 6971.742923][T106447] team_add_slave+0x1bf3/0x28b0
[ 6971.747342][T106447] ? __pfx___dev_notify_flags+0x10/0x10
[ 6971.749385][T106447] ? __dev_change_flags+0x536/0x710
[ 6971.753249][T106447] ? __pfx_team_add_slave+0x10/0x10
[ 6971.760179][T106447] ? __pfx___dev_change_flags+0x10/0x10
[ 6971.762084][T106447] ? __pfx_lockdep_hardirqs_on_prepare+0x10/0x10
[ 6971.764253][T106447] ? mutex_is_locked+0x12/0x50
[ 6971.765935][T106447] do_setlink+0xed1/0x43f0
[ 6971.769819][T106447] ? __pfx____ratelimit+0x10/0x10
[ 6971.771521][T106447] ? __pfx_do_setlink+0x10/0x10
[ 6971.779962][T106447] ? __nla_validate_parse+0x26b1/0x3140
[ 6971.781727][T106447] ? __pfx___nla_validate_parse+0x10/0x10
[ 6971.783590][T106447] ? __pfx_validate_chain+0x10/0x10
[ 6971.785386][T106447] ? __pfx_lock_acquire+0x10/0x10
[ 6971.787128][T106447] ? is_bpf_text_address+0x2b/0x2d0
[ 6971.788900][T106447] ? validate_linkmsg+0x75d/0x960
[ 6971.795596][T106447] rtnl_setlink+0x431/0x5d0
[ 6971.797190][T106447] ? mark_lock+0x9a/0x350
[ 6971.798632][T106447] ? __pfx_rtnl_setlink+0x10/0x10
[ 6971.812898][T106447] ? __kernel_text_address+0xd/0x40
[ 6971.814699][T106447] ? rcu_read_unlock+0x9b/0xb0
[ 6971.816298][T106447] ? __pfx___mutex_lock+0x10/0x10
[ 6971.821333][T106447] ? __pfx_rtnl_setlink+0x10/0x10
[ 6971.835950][T106447] rtnetlink_rcv_msg+0x8eb/0x10e0
[ 6971.836899][T106447] ? rtnetlink_rcv_msg+0x227/0x10e0
[ 6971.837816][T106447] ? __pfx_rtnetlink_rcv_msg+0x10/0x10
[ 6971.838758][T106447] ? lockdep_hardirqs_on_prepare+0x43c/0x780
[ 6971.851410][T106447] ? __pfx_lockdep_hardirqs_on_prepare+0x10/0x10
[ 6971.852604][T106447] ? __local_bh_enable_ip+0x168/0x200
[ 6971.853545][T106447] ? lockdep_hardirqs_on+0x98/0x140
[ 6971.863452][T106447] ? __local_bh_enable_ip+0x168/0x200
[ 6971.865250][T106447] ? __dev_queue_xmit+0x2d1/0x3c70
[ 6971.866978][T106447] ? __pfx___local_bh_enable_ip+0x10/0x10
[ 6971.880602][T106447] ? __dev_queue_xmit+0x2d1/0x3c70
[ 6971.882349][T106447] ? __dev_queue_xmit+0x169b/0x3c70
[ 6971.886063][T106447] ? __dev_queue_xmit+0x2d1/0x3c70
[ 6971.895914][T106447] ? ref_tracker_free+0x648/0x7e0
[ 6971.897626][T106447] netlink_rcv_skb+0x1ee/0x450
[ 6971.899256][T106447] ? __pfx_rtnetlink_rcv_msg+0x10/0x10
[ 6971.901113][T106447] ? __pfx_netlink_rcv_skb+0x10/0x10
[ 6971.908171][T106447] ? netlink_deliver_tap+0x33/0x1c0
[ 6971.915811][T106447] netlink_unicast+0x80d/0x9b0
[ 6971.916649][T106447] ? __pfx_netlink_unicast+0x10/0x10
[ 6971.917598][T106447] ? __virt_addr_valid+0x4a8/0x580
[ 6971.918508][T106447] ? __phys_addr_symbol+0x36/0x80
[ 6971.927482][T106447] ? __check_object_size+0x4e2/0xa60
[ 6971.928527][T106447] ? bpf_lsm_netlink_send+0xe/0x20
[ 6971.929516][T106447] netlink_sendmsg+0xa63/0xda0
[ 6971.930477][T106447] ? __pfx_netlink_sendmsg+0x10/0x10
[ 6971.959582][T106447] ? aa_sock_msg_perm+0x9e/0x160
[ 6971.960633][T106447] ? bpf_lsm_socket_sendmsg+0xe/0x20
[ 6971.961575][T106447] ? security_socket_sendmsg+0x92/0xb0
[ 6971.962546][T106447] ? __pfx_netlink_sendmsg+0x10/0x10
[ 6971.991813][T106447] __sock_sendmsg+0x230/0x280
[ 6971.993488][T106447] sock_write_iter+0x2f9/0x420
[ 6971.995138][T106447] ? __pfx_sock_write_iter+0x10/0x10
[ 6972.001110][T106447] ? futex_wait_queue+0x156/0x1e0
[ 6972.004680][T106447] ? futex_unqueue+0xd8/0x100
[ 6972.015657][T106447] do_iter_readv_writev+0x489/0x660
[ 6972.018731][T106447] ? __pfx_do_iter_readv_writev+0x10/0x10
[ 6972.022915][T106447] ? bpf_lsm_file_permission+0xe/0x20
[ 6972.045752][T106447] ? security_file_permission+0x8a/0xb0
[ 6972.046896][T106447] ? rw_verify_area+0x1e7/0x5b0
[ 6972.047864][T106447] vfs_writev+0x3a8/0xbe0
[ 6972.048632][T106447] ? __pfx_vfs_writev+0x10/0x10
[ 6972.049483][T106447] ? __fget_files+0x2d/0x4a0
[ 6972.050281][T106447] ? __fdget_pos+0x1aa/0x340
[ 6972.064863][T106447] do_writev+0x1bf/0x360
[ 6972.079653][T106447] ? __pfx_do_writev+0x10/0x10
[ 6972.080726][T106447] ? do_syscall_64+0x108/0x240
[ 6972.081604][T106447] ? do_syscall_64+0xb4/0x240
[ 6972.082447][T106447] do_syscall_64+0xf9/0x240
[ 6972.100393][T106447] entry_SYSCALL_64_after_hwframe+0x6f/0x77
[ 6972.112331][T106447] RIP: 0033:0x7fca8767dde9
[ 6972.114344][T106447] Code: 28 00 00 00 75 05 48 83 c4 28 c3 e8 e1
20 00 00 90 48 89 f8 48 89 f7 48 8
[ 6972.146796][T106447] RSP: 002b:00007fca883de0c8 EFLAGS: 00000246
ORIG_RAX: 0000000000000014
[ 6972.175640][T106447] RAX: ffffffffffffffda RBX: 00007fca877abf80
RCX: 00007fca8767dde9
[ 6972.191791][T106447] RDX: 0000000000000001 RSI: 0000000020000400
RDI: 0000000000000003
[ 6972.209957][T106447] RBP: 00007fca876ca47a R08: 0000000000000000
R09: 0000000000000000
[ 6972.211305][T106447] R10: 0000000000000000 R11: 0000000000000246
R12: 0000000000000000
[ 6972.212594][T106447] R13: 000000000000000b R14: 00007fca877abf80
R15: 00007ffddc5cb5f8
[ 6972.213901][T106447] </TASK>


Remember to run this repro.txt with the command: syz-execprog -repeat
0 ./repro.txt and wait for about 1minus, the bug triggered very
steady.

=* repro.txt =*
r0 = socket$netlink(0x10, 0x3, 0x0)
writev(r0, &(0x7f0000000400)=[{&(0x7f0000000580)="3900000013000b4600bb65e1c3e4ffff0100001038000000560000022500000019000a001000000007fd17e5ffff080004000000000000000a",
0x39}], 0x1)
writev(0xffffffffffffffff,
&(0x7f0000000400)=[{&(0x7f0000000580)="3900000013000b4600bb65e1c3e4ffff0100000936000000560000022500000019000a001000000007fd17e5ffff080004000000000000000a",
0x39}], 0x1)

and see also in
https://gist.github.com/xrivendell7/dea2d84fe5efdb17eedcdb3e17297ffe

I hope it helps.
xingwei Lee

xingwei lee

unread,
Mar 3, 2024, 3:39:57 AMMar 3
to xingwei lee, da...@davemloft.net, Eric Dumazet, ji...@resnulli.us, ku...@kernel.org, linux-...@vger.kernel.org, net...@vger.kernel.org, pab...@redhat.com, syzbot+3c47b5...@syzkaller.appspotmail.com, syzkall...@googlegroups.com
Hello, I found a more stable reproducer

=* repro.txt =*
r0 = socket$netlink(0x10, 0x3, 0x0)
writev(r0, &(0x7f0000000040)=[{&(0x7f0000000080)="3900000013000b4600bb65e1c3e4fffff9ffff7f37000000560000022500000019000a001000000007fd17e5ffff080004000000000000000a",
0x39}], 0x1)
r1 = socket$netlink(0x10, 0x3, 0x0)
writev(r1, &(0x7f0000000040)=[{&(0x7f0000000080)="3900000013000b4600bb65e1c3e4ffff0100000036000000560000022500000019000a001000000007fd17e5ffff080004000000000000000a",
0x39}], 0x1)

=* repro.c =*
#define _GNU_SOURCE

#include <arpa/inet.h>
#include <endian.h>
#include <errno.h>
#include <fcntl.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <netinet/in.h>
#include <sched.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mount.h>
#include <sys/prctl.h>
#include <sys/resource.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/wait.h>
#include <unistd.h>

#include <linux/capability.h>
#include <linux/genetlink.h>
#include <linux/if_addr.h>
#include <linux/if_ether.h>
#include <linux/if_link.h>
#include <linux/if_tun.h>
#include <linux/in6.h>
#include <linux/ip.h>
#include <linux/neighbour.h>
#include <linux/net.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <linux/tcp.h>
#include <linux/veth.h>

static unsigned long long procid;

static bool write_file(const char* file, const char* what, ...) {
char buf[1024];
va_list args;
va_start(args, what);
vsnprintf(buf, sizeof(buf), what, args);
va_end(args);
buf[sizeof(buf) - 1] = 0;
int len = strlen(buf);
int fd = open(file, O_WRONLY | O_CLOEXEC);
if (fd == -1)
return false;
if (write(fd, buf, len) != len) {
int err = errno;
close(fd);
errno = err;
return false;
}
close(fd);
return true;
}

struct nlmsg {
char* pos;
int nesting;
struct nlattr* nested[8];
char buf[4096];
};

static void netlink_init(struct nlmsg* nlmsg,
int typ,
int flags,
const void* data,
int size) {
memset(nlmsg, 0, sizeof(*nlmsg));
struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
hdr->nlmsg_type = typ;
hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
memcpy(hdr + 1, data, size);
nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
}

static void netlink_attr(struct nlmsg* nlmsg,
int typ,
const void* data,
int size) {
struct nlattr* attr = (struct nlattr*)nlmsg->pos;
attr->nla_len = sizeof(*attr) + size;
attr->nla_type = typ;
if (size > 0)
memcpy(attr + 1, data, size);
nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
}

static void netlink_nest(struct nlmsg* nlmsg, int typ) {
struct nlattr* attr = (struct nlattr*)nlmsg->pos;
attr->nla_type = typ;
nlmsg->pos += sizeof(*attr);
nlmsg->nested[nlmsg->nesting++] = attr;
}

static void netlink_done(struct nlmsg* nlmsg) {
struct nlattr* attr = nlmsg->nested[--nlmsg->nesting];
attr->nla_len = nlmsg->pos - (char*)attr;
}

static int netlink_send_ext(struct nlmsg* nlmsg,
int sock,
uint16_t reply_type,
int* reply_len,
bool dofail) {
if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
exit(1);
struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
struct sockaddr_nl addr;
memset(&addr, 0, sizeof(addr));
addr.nl_family = AF_NETLINK;
ssize_t n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
(struct sockaddr*)&addr, sizeof(addr));
if (n != (ssize_t)hdr->nlmsg_len) {
if (dofail)
exit(1);
return -1;
}
n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
if (reply_len)
*reply_len = 0;
if (n < 0) {
if (dofail)
exit(1);
return -1;
}
if (n < (ssize_t)sizeof(struct nlmsghdr)) {
errno = EINVAL;
if (dofail)
exit(1);
return -1;
}
if (hdr->nlmsg_type == NLMSG_DONE)
return 0;
if (reply_len && hdr->nlmsg_type == reply_type) {
*reply_len = n;
return 0;
}
if (n < (ssize_t)(sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))) {
errno = EINVAL;
if (dofail)
exit(1);
return -1;
}
if (hdr->nlmsg_type != NLMSG_ERROR) {
errno = EINVAL;
if (dofail)
exit(1);
return -1;
}
errno = -((struct nlmsgerr*)(hdr + 1))->error;
return -errno;
}

static int netlink_send(struct nlmsg* nlmsg, int sock) {
return netlink_send_ext(nlmsg, sock, 0, NULL, true);
}

static int netlink_query_family_id(struct nlmsg* nlmsg,
int sock,
const char* family_name,
bool dofail) {
struct genlmsghdr genlhdr;
memset(&genlhdr, 0, sizeof(genlhdr));
genlhdr.cmd = CTRL_CMD_GETFAMILY;
netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, family_name,
strnlen(family_name, GENL_NAMSIZ - 1) + 1);
int n = 0;
int err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n, dofail);
if (err < 0) {
return -1;
}
uint16_t id = 0;
struct nlattr* attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
NLMSG_ALIGN(sizeof(genlhdr)));
for (; (char*)attr < nlmsg->buf + n;
attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
id = *(uint16_t*)(attr + 1);
break;
}
}
if (!id) {
errno = EINVAL;
return -1;
}
recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
return id;
}

static int netlink_next_msg(struct nlmsg* nlmsg,
unsigned int offset,
unsigned int total_len) {
struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
if (offset == total_len || offset + hdr->nlmsg_len > total_len)
return -1;
return hdr->nlmsg_len;
}

static void netlink_add_device_impl(struct nlmsg* nlmsg,
const char* type,
const char* name,
bool up) {
struct ifinfomsg hdr;
memset(&hdr, 0, sizeof(hdr));
if (up)
hdr.ifi_flags = hdr.ifi_change = IFF_UP;
netlink_init(nlmsg, RTM_NEWLINK, NLM_F_EXCL | NLM_F_CREATE, &hdr,
sizeof(hdr));
if (name)
netlink_attr(nlmsg, IFLA_IFNAME, name, strlen(name));
netlink_nest(nlmsg, IFLA_LINKINFO);
netlink_attr(nlmsg, IFLA_INFO_KIND, type, strlen(type));
}

static void netlink_add_device(struct nlmsg* nlmsg,
int sock,
const char* type,
const char* name) {
netlink_add_device_impl(nlmsg, type, name, false);
netlink_done(nlmsg);
int err = netlink_send(nlmsg, sock);
if (err < 0) {
}
}

static void netlink_add_veth(struct nlmsg* nlmsg,
int sock,
const char* name,
const char* peer) {
netlink_add_device_impl(nlmsg, "veth", name, false);
netlink_nest(nlmsg, IFLA_INFO_DATA);
netlink_nest(nlmsg, VETH_INFO_PEER);
nlmsg->pos += sizeof(struct ifinfomsg);
netlink_attr(nlmsg, IFLA_IFNAME, peer, strlen(peer));
netlink_done(nlmsg);
netlink_done(nlmsg);
netlink_done(nlmsg);
int err = netlink_send(nlmsg, sock);
if (err < 0) {
}
}

static void netlink_add_xfrm(struct nlmsg* nlmsg, int sock, const char* name) {
netlink_add_device_impl(nlmsg, "xfrm", name, true);
netlink_nest(nlmsg, IFLA_INFO_DATA);
int if_id = 1;
netlink_attr(nlmsg, 2, &if_id, sizeof(if_id));
netlink_done(nlmsg);
netlink_done(nlmsg);
int err = netlink_send(nlmsg, sock);
if (err < 0) {
}
}

static void netlink_add_hsr(struct nlmsg* nlmsg,
int sock,
const char* name,
const char* slave1,
const char* slave2) {
netlink_add_device_impl(nlmsg, "hsr", name, false);
netlink_nest(nlmsg, IFLA_INFO_DATA);
int ifindex1 = if_nametoindex(slave1);
netlink_attr(nlmsg, IFLA_HSR_SLAVE1, &ifindex1, sizeof(ifindex1));
int ifindex2 = if_nametoindex(slave2);
netlink_attr(nlmsg, IFLA_HSR_SLAVE2, &ifindex2, sizeof(ifindex2));
netlink_done(nlmsg);
netlink_done(nlmsg);
int err = netlink_send(nlmsg, sock);
if (err < 0) {
}
}

static void netlink_add_linked(struct nlmsg* nlmsg,
int sock,
const char* type,
const char* name,
const char* link) {
netlink_add_device_impl(nlmsg, type, name, false);
netlink_done(nlmsg);
int ifindex = if_nametoindex(link);
netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
int err = netlink_send(nlmsg, sock);
if (err < 0) {
}
}

static void netlink_add_vlan(struct nlmsg* nlmsg,
int sock,
const char* name,
const char* link,
uint16_t id,
uint16_t proto) {
netlink_add_device_impl(nlmsg, "vlan", name, false);
netlink_nest(nlmsg, IFLA_INFO_DATA);
netlink_attr(nlmsg, IFLA_VLAN_ID, &id, sizeof(id));
netlink_attr(nlmsg, IFLA_VLAN_PROTOCOL, &proto, sizeof(proto));
netlink_done(nlmsg);
netlink_done(nlmsg);
int ifindex = if_nametoindex(link);
netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
int err = netlink_send(nlmsg, sock);
if (err < 0) {
}
}

static void netlink_add_macvlan(struct nlmsg* nlmsg,
int sock,
const char* name,
const char* link) {
netlink_add_device_impl(nlmsg, "macvlan", name, false);
netlink_nest(nlmsg, IFLA_INFO_DATA);
uint32_t mode = MACVLAN_MODE_BRIDGE;
netlink_attr(nlmsg, IFLA_MACVLAN_MODE, &mode, sizeof(mode));
netlink_done(nlmsg);
netlink_done(nlmsg);
int ifindex = if_nametoindex(link);
netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
int err = netlink_send(nlmsg, sock);
if (err < 0) {
}
}

static void netlink_add_geneve(struct nlmsg* nlmsg,
int sock,
const char* name,
uint32_t vni,
struct in_addr* addr4,
struct in6_addr* addr6) {
netlink_add_device_impl(nlmsg, "geneve", name, false);
netlink_nest(nlmsg, IFLA_INFO_DATA);
netlink_attr(nlmsg, IFLA_GENEVE_ID, &vni, sizeof(vni));
if (addr4)
netlink_attr(nlmsg, IFLA_GENEVE_REMOTE, addr4, sizeof(*addr4));
if (addr6)
netlink_attr(nlmsg, IFLA_GENEVE_REMOTE6, addr6, sizeof(*addr6));
netlink_done(nlmsg);
netlink_done(nlmsg);
int err = netlink_send(nlmsg, sock);
if (err < 0) {
}
}

#define IFLA_IPVLAN_FLAGS 2
#define IPVLAN_MODE_L3S 2
#undef IPVLAN_F_VEPA
#define IPVLAN_F_VEPA 2

static void netlink_add_ipvlan(struct nlmsg* nlmsg,
int sock,
const char* name,
const char* link,
uint16_t mode,
uint16_t flags) {
netlink_add_device_impl(nlmsg, "ipvlan", name, false);
netlink_nest(nlmsg, IFLA_INFO_DATA);
netlink_attr(nlmsg, IFLA_IPVLAN_MODE, &mode, sizeof(mode));
netlink_attr(nlmsg, IFLA_IPVLAN_FLAGS, &flags, sizeof(flags));
netlink_done(nlmsg);
netlink_done(nlmsg);
int ifindex = if_nametoindex(link);
netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
int err = netlink_send(nlmsg, sock);
if (err < 0) {
}
}

static void netlink_device_change(struct nlmsg* nlmsg,
int sock,
const char* name,
bool up,
const char* master,
const void* mac,
int macsize,
const char* new_name) {
struct ifinfomsg hdr;
memset(&hdr, 0, sizeof(hdr));
if (up)
hdr.ifi_flags = hdr.ifi_change = IFF_UP;
hdr.ifi_index = if_nametoindex(name);
netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
if (new_name)
netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
if (master) {
int ifindex = if_nametoindex(master);
netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
}
if (macsize)
netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
int err = netlink_send(nlmsg, sock);
if (err < 0) {
}
}

static int netlink_add_addr(struct nlmsg* nlmsg,
int sock,
const char* dev,
const void* addr,
int addrsize) {
struct ifaddrmsg hdr;
memset(&hdr, 0, sizeof(hdr));
hdr.ifa_family = addrsize == 4 ? AF_INET : AF_INET6;
hdr.ifa_prefixlen = addrsize == 4 ? 24 : 120;
hdr.ifa_scope = RT_SCOPE_UNIVERSE;
hdr.ifa_index = if_nametoindex(dev);
netlink_init(nlmsg, RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr,
sizeof(hdr));
netlink_attr(nlmsg, IFA_LOCAL, addr, addrsize);
netlink_attr(nlmsg, IFA_ADDRESS, addr, addrsize);
return netlink_send(nlmsg, sock);
}

static void netlink_add_addr4(struct nlmsg* nlmsg,
int sock,
const char* dev,
const char* addr) {
struct in_addr in_addr;
inet_pton(AF_INET, addr, &in_addr);
int err = netlink_add_addr(nlmsg, sock, dev, &in_addr, sizeof(in_addr));
if (err < 0) {
}
}

static void netlink_add_addr6(struct nlmsg* nlmsg,
int sock,
const char* dev,
const char* addr) {
struct in6_addr in6_addr;
inet_pton(AF_INET6, addr, &in6_addr);
int err = netlink_add_addr(nlmsg, sock, dev, &in6_addr, sizeof(in6_addr));
if (err < 0) {
}
}

static void netlink_add_neigh(struct nlmsg* nlmsg,
int sock,
const char* name,
const void* addr,
int addrsize,
const void* mac,
int macsize) {
struct ndmsg hdr;
memset(&hdr, 0, sizeof(hdr));
hdr.ndm_family = addrsize == 4 ? AF_INET : AF_INET6;
hdr.ndm_ifindex = if_nametoindex(name);
hdr.ndm_state = NUD_PERMANENT;
netlink_init(nlmsg, RTM_NEWNEIGH, NLM_F_EXCL | NLM_F_CREATE, &hdr,
sizeof(hdr));
netlink_attr(nlmsg, NDA_DST, addr, addrsize);
netlink_attr(nlmsg, NDA_LLADDR, mac, macsize);
int err = netlink_send(nlmsg, sock);
if (err < 0) {
}
}

static struct nlmsg nlmsg;

static int tunfd = -1;

#define TUN_IFACE "syz_tun"
#define LOCAL_MAC 0xaaaaaaaaaaaa
#define REMOTE_MAC 0xaaaaaaaaaabb
#define LOCAL_IPV4 "172.20.20.170"
#define REMOTE_IPV4 "172.20.20.187"
#define LOCAL_IPV6 "fe80::aa"
#define REMOTE_IPV6 "fe80::bb"

#define IFF_NAPI 0x0010

static void initialize_tun(void) {
tunfd = open("/dev/net/tun", O_RDWR | O_NONBLOCK);
if (tunfd == -1) {
printf("tun: can't open /dev/net/tun: please enable CONFIG_TUN=y\n");
printf("otherwise fuzzing or reproducing might not work as intended\n");
return;
}
const int kTunFd = 200;
if (dup2(tunfd, kTunFd) < 0)
exit(1);
close(tunfd);
tunfd = kTunFd;
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, TUN_IFACE, IFNAMSIZ);
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0) {
exit(1);
}
char sysctl[64];
sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/accept_dad", TUN_IFACE);
write_file(sysctl, "0");
sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/router_solicitations", TUN_IFACE);
write_file(sysctl, "0");
int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (sock == -1)
exit(1);
netlink_add_addr4(&nlmsg, sock, TUN_IFACE, LOCAL_IPV4);
netlink_add_addr6(&nlmsg, sock, TUN_IFACE, LOCAL_IPV6);
uint64_t macaddr = REMOTE_MAC;
struct in_addr in_addr;
inet_pton(AF_INET, REMOTE_IPV4, &in_addr);
netlink_add_neigh(&nlmsg, sock, TUN_IFACE, &in_addr, sizeof(in_addr),
&macaddr, ETH_ALEN);
struct in6_addr in6_addr;
inet_pton(AF_INET6, REMOTE_IPV6, &in6_addr);
netlink_add_neigh(&nlmsg, sock, TUN_IFACE, &in6_addr, sizeof(in6_addr),
&macaddr, ETH_ALEN);
macaddr = LOCAL_MAC;
netlink_device_change(&nlmsg, sock, TUN_IFACE, true, 0, &macaddr, ETH_ALEN,
NULL);
close(sock);
}

#define DEVLINK_FAMILY_NAME "devlink"

#define DEVLINK_CMD_PORT_GET 5
#define DEVLINK_ATTR_BUS_NAME 1
#define DEVLINK_ATTR_DEV_NAME 2
#define DEVLINK_ATTR_NETDEV_NAME 7

static struct nlmsg nlmsg2;

static void initialize_devlink_ports(const char* bus_name,
const char* dev_name,
const char* netdev_prefix) {
struct genlmsghdr genlhdr;
int len, total_len, id, err, offset;
uint16_t netdev_index;
int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
if (sock == -1)
exit(1);
int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (rtsock == -1)
exit(1);
id = netlink_query_family_id(&nlmsg, sock, DEVLINK_FAMILY_NAME, true);
if (id == -1)
goto error;
memset(&genlhdr, 0, sizeof(genlhdr));
genlhdr.cmd = DEVLINK_CMD_PORT_GET;
netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
err = netlink_send_ext(&nlmsg, sock, id, &total_len, true);
if (err < 0) {
goto error;
}
offset = 0;
netdev_index = 0;
while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
NLMSG_ALIGN(sizeof(genlhdr)));
for (; (char*)attr < nlmsg.buf + offset + len;
attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
char* port_name;
char netdev_name[IFNAMSIZ];
port_name = (char*)(attr + 1);
snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
netdev_index);
netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
netdev_name);
break;
}
}
offset += len;
netdev_index++;
}
error:
close(rtsock);
close(sock);
}

#define DEV_IPV4 "172.20.20.%d"
#define DEV_IPV6 "fe80::%02x"
#define DEV_MAC 0x00aaaaaaaaaa

static void netdevsim_add(unsigned int addr, unsigned int port_count) {
write_file("/sys/bus/netdevsim/del_device", "%u", addr);
if (write_file("/sys/bus/netdevsim/new_device", "%u %u", addr, port_count)) {
char buf[32];
snprintf(buf, sizeof(buf), "netdevsim%d", addr);
initialize_devlink_ports("netdevsim", buf, "netdevsim");
}
}

#define WG_GENL_NAME "wireguard"
enum wg_cmd {
WG_CMD_GET_DEVICE,
WG_CMD_SET_DEVICE,
};
enum wgdevice_attribute {
WGDEVICE_A_UNSPEC,
WGDEVICE_A_IFINDEX,
WGDEVICE_A_IFNAME,
WGDEVICE_A_PRIVATE_KEY,
WGDEVICE_A_PUBLIC_KEY,
WGDEVICE_A_FLAGS,
WGDEVICE_A_LISTEN_PORT,
WGDEVICE_A_FWMARK,
WGDEVICE_A_PEERS,
};
enum wgpeer_attribute {
WGPEER_A_UNSPEC,
WGPEER_A_PUBLIC_KEY,
WGPEER_A_PRESHARED_KEY,
WGPEER_A_FLAGS,
WGPEER_A_ENDPOINT,
WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
WGPEER_A_LAST_HANDSHAKE_TIME,
WGPEER_A_RX_BYTES,
WGPEER_A_TX_BYTES,
WGPEER_A_ALLOWEDIPS,
WGPEER_A_PROTOCOL_VERSION,
};
enum wgallowedip_attribute {
WGALLOWEDIP_A_UNSPEC,
WGALLOWEDIP_A_FAMILY,
WGALLOWEDIP_A_IPADDR,
WGALLOWEDIP_A_CIDR_MASK,
};

static void netlink_wireguard_setup(void) {
const char ifname_a[] = "wg0";
const char ifname_b[] = "wg1";
const char ifname_c[] = "wg2";
const char private_a[] =
"\xa0\x5c\xa8\x4f\x6c\x9c\x8e\x38\x53\xe2\xfd\x7a\x70\xae\x0f\xb2\x0f\xa1"
"\x52\x60\x0c\xb0\x08\x45\x17\x4f\x08\x07\x6f\x8d\x78\x43";
const char private_b[] =
"\xb0\x80\x73\xe8\xd4\x4e\x91\xe3\xda\x92\x2c\x22\x43\x82\x44\xbb\x88\x5c"
"\x69\xe2\x69\xc8\xe9\xd8\x35\xb1\x14\x29\x3a\x4d\xdc\x6e";
const char private_c[] =
"\xa0\xcb\x87\x9a\x47\xf5\xbc\x64\x4c\x0e\x69\x3f\xa6\xd0\x31\xc7\x4a\x15"
"\x53\xb6\xe9\x01\xb9\xff\x2f\x51\x8c\x78\x04\x2f\xb5\x42";
const char public_a[] =
"\x97\x5c\x9d\x81\xc9\x83\xc8\x20\x9e\xe7\x81\x25\x4b\x89\x9f\x8e\xd9\x25"
"\xae\x9f\x09\x23\xc2\x3c\x62\xf5\x3c\x57\xcd\xbf\x69\x1c";
const char public_b[] =
"\xd1\x73\x28\x99\xf6\x11\xcd\x89\x94\x03\x4d\x7f\x41\x3d\xc9\x57\x63\x0e"
"\x54\x93\xc2\x85\xac\xa4\x00\x65\xcb\x63\x11\xbe\x69\x6b";
const char public_c[] =
"\xf4\x4d\xa3\x67\xa8\x8e\xe6\x56\x4f\x02\x02\x11\x45\x67\x27\x08\x2f\x5c"
"\xeb\xee\x8b\x1b\xf5\xeb\x73\x37\x34\x1b\x45\x9b\x39\x22";
const uint16_t listen_a = 20001;
const uint16_t listen_b = 20002;
const uint16_t listen_c = 20003;
const uint16_t af_inet = AF_INET;
const uint16_t af_inet6 = AF_INET6;
const struct sockaddr_in endpoint_b_v4 = {
.sin_family = AF_INET,
.sin_port = htons(listen_b),
.sin_addr = {htonl(INADDR_LOOPBACK)}};
const struct sockaddr_in endpoint_c_v4 = {
.sin_family = AF_INET,
.sin_port = htons(listen_c),
.sin_addr = {htonl(INADDR_LOOPBACK)}};
struct sockaddr_in6 endpoint_a_v6 = {.sin6_family = AF_INET6,
.sin6_port = htons(listen_a)};
endpoint_a_v6.sin6_addr = in6addr_loopback;
struct sockaddr_in6 endpoint_c_v6 = {.sin6_family = AF_INET6,
.sin6_port = htons(listen_c)};
endpoint_c_v6.sin6_addr = in6addr_loopback;
const struct in_addr first_half_v4 = {0};
const struct in_addr second_half_v4 = {(uint32_t)htonl(128 << 24)};
const struct in6_addr first_half_v6 = {{{0}}};
const struct in6_addr second_half_v6 = {{{0x80}}};
const uint8_t half_cidr = 1;
const uint16_t persistent_keepalives[] = {1, 3, 7, 9, 14, 19};
struct genlmsghdr genlhdr = {.cmd = WG_CMD_SET_DEVICE, .version = 1};
int sock;
int id, err;
sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
if (sock == -1) {
return;
}
id = netlink_query_family_id(&nlmsg, sock, WG_GENL_NAME, true);
if (id == -1)
goto error;
netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
netlink_attr(&nlmsg, WGDEVICE_A_IFNAME, ifname_a, strlen(ifname_a) + 1);
netlink_attr(&nlmsg, WGDEVICE_A_PRIVATE_KEY, private_a, 32);
netlink_attr(&nlmsg, WGDEVICE_A_LISTEN_PORT, &listen_a, 2);
netlink_nest(&nlmsg, NLA_F_NESTED | WGDEVICE_A_PEERS);
netlink_nest(&nlmsg, NLA_F_NESTED | 0);
netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_b, 32);
netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_b_v4,
sizeof(endpoint_b_v4));
netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
&persistent_keepalives[0], 2);
netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
netlink_nest(&nlmsg, NLA_F_NESTED | 0);
netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v4,
sizeof(first_half_v4));
netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
netlink_done(&nlmsg);
netlink_nest(&nlmsg, NLA_F_NESTED | 0);
netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v6,
sizeof(first_half_v6));
netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
netlink_done(&nlmsg);
netlink_done(&nlmsg);
netlink_done(&nlmsg);
netlink_nest(&nlmsg, NLA_F_NESTED | 0);
netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_c, 32);
netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_c_v6,
sizeof(endpoint_c_v6));
netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
&persistent_keepalives[1], 2);
netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
netlink_nest(&nlmsg, NLA_F_NESTED | 0);
netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v4,
sizeof(second_half_v4));
netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
netlink_done(&nlmsg);
netlink_nest(&nlmsg, NLA_F_NESTED | 0);
netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v6,
sizeof(second_half_v6));
netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
netlink_done(&nlmsg);
netlink_done(&nlmsg);
netlink_done(&nlmsg);
netlink_done(&nlmsg);
err = netlink_send(&nlmsg, sock);
if (err < 0) {
}
netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
netlink_attr(&nlmsg, WGDEVICE_A_IFNAME, ifname_b, strlen(ifname_b) + 1);
netlink_attr(&nlmsg, WGDEVICE_A_PRIVATE_KEY, private_b, 32);
netlink_attr(&nlmsg, WGDEVICE_A_LISTEN_PORT, &listen_b, 2);
netlink_nest(&nlmsg, NLA_F_NESTED | WGDEVICE_A_PEERS);
netlink_nest(&nlmsg, NLA_F_NESTED | 0);
netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_a, 32);
netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_a_v6,
sizeof(endpoint_a_v6));
netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
&persistent_keepalives[2], 2);
netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
netlink_nest(&nlmsg, NLA_F_NESTED | 0);
netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v4,
sizeof(first_half_v4));
netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
netlink_done(&nlmsg);
netlink_nest(&nlmsg, NLA_F_NESTED | 0);
netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v6,
sizeof(first_half_v6));
netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
netlink_done(&nlmsg);
netlink_done(&nlmsg);
netlink_done(&nlmsg);
netlink_nest(&nlmsg, NLA_F_NESTED | 0);
netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_c, 32);
netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_c_v4,
sizeof(endpoint_c_v4));
netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
&persistent_keepalives[3], 2);
netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
netlink_nest(&nlmsg, NLA_F_NESTED | 0);
netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v4,
sizeof(second_half_v4));
netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
netlink_done(&nlmsg);
netlink_nest(&nlmsg, NLA_F_NESTED | 0);
netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v6,
sizeof(second_half_v6));
netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
netlink_done(&nlmsg);
netlink_done(&nlmsg);
netlink_done(&nlmsg);
netlink_done(&nlmsg);
err = netlink_send(&nlmsg, sock);
if (err < 0) {
}
netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
netlink_attr(&nlmsg, WGDEVICE_A_IFNAME, ifname_c, strlen(ifname_c) + 1);
netlink_attr(&nlmsg, WGDEVICE_A_PRIVATE_KEY, private_c, 32);
netlink_attr(&nlmsg, WGDEVICE_A_LISTEN_PORT, &listen_c, 2);
netlink_nest(&nlmsg, NLA_F_NESTED | WGDEVICE_A_PEERS);
netlink_nest(&nlmsg, NLA_F_NESTED | 0);
netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_a, 32);
netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_a_v6,
sizeof(endpoint_a_v6));
netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
&persistent_keepalives[4], 2);
netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
netlink_nest(&nlmsg, NLA_F_NESTED | 0);
netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v4,
sizeof(first_half_v4));
netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
netlink_done(&nlmsg);
netlink_nest(&nlmsg, NLA_F_NESTED | 0);
netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v6,
sizeof(first_half_v6));
netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
netlink_done(&nlmsg);
netlink_done(&nlmsg);
netlink_done(&nlmsg);
netlink_nest(&nlmsg, NLA_F_NESTED | 0);
netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_b, 32);
netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_b_v4,
sizeof(endpoint_b_v4));
netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
&persistent_keepalives[5], 2);
netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
netlink_nest(&nlmsg, NLA_F_NESTED | 0);
netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v4,
sizeof(second_half_v4));
netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
netlink_done(&nlmsg);
netlink_nest(&nlmsg, NLA_F_NESTED | 0);
netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v6,
sizeof(second_half_v6));
netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
netlink_done(&nlmsg);
netlink_done(&nlmsg);
netlink_done(&nlmsg);
netlink_done(&nlmsg);
err = netlink_send(&nlmsg, sock);
if (err < 0) {
}

error:
close(sock);
}

static void initialize_netdevices(void) {
char netdevsim[16];
sprintf(netdevsim, "netdevsim%d", (int)procid);
struct {
const char* type;
const char* dev;
} devtypes[] = {
{"ip6gretap", "ip6gretap0"}, {"bridge", "bridge0"}, {"vcan", "vcan0"},
{"bond", "bond0"}, {"team", "team0"}, {"dummy", "dummy0"},
{"nlmon", "nlmon0"}, {"caif", "caif0"}, {"batadv", "batadv0"},
{"vxcan", "vxcan1"}, {"veth", 0}, {"wireguard", "wg0"},
{"wireguard", "wg1"}, {"wireguard", "wg2"},
};
const char* devmasters[] = {"bridge", "bond", "team", "batadv"};
struct {
const char* name;
int macsize;
bool noipv6;
} devices[] = {
{"lo", ETH_ALEN},
{"sit0", 0},
{"bridge0", ETH_ALEN},
{"vcan0", 0, true},
{"tunl0", 0},
{"gre0", 0},
{"gretap0", ETH_ALEN},
{"ip_vti0", 0},
{"ip6_vti0", 0},
{"ip6tnl0", 0},
{"ip6gre0", 0},
{"ip6gretap0", ETH_ALEN},
{"erspan0", ETH_ALEN},
{"bond0", ETH_ALEN},
{"veth0", ETH_ALEN},
{"veth1", ETH_ALEN},
{"team0", ETH_ALEN},
{"veth0_to_bridge", ETH_ALEN},
{"veth1_to_bridge", ETH_ALEN},
{"veth0_to_bond", ETH_ALEN},
{"veth1_to_bond", ETH_ALEN},
{"veth0_to_team", ETH_ALEN},
{"veth1_to_team", ETH_ALEN},
{"veth0_to_hsr", ETH_ALEN},
{"veth1_to_hsr", ETH_ALEN},
{"hsr0", 0},
{"dummy0", ETH_ALEN},
{"nlmon0", 0},
{"vxcan0", 0, true},
{"vxcan1", 0, true},
{"caif0", ETH_ALEN},
{"batadv0", ETH_ALEN},
{netdevsim, ETH_ALEN},
{"xfrm0", ETH_ALEN},
{"veth0_virt_wifi", ETH_ALEN},
{"veth1_virt_wifi", ETH_ALEN},
{"virt_wifi0", ETH_ALEN},
{"veth0_vlan", ETH_ALEN},
{"veth1_vlan", ETH_ALEN},
{"vlan0", ETH_ALEN},
{"vlan1", ETH_ALEN},
{"macvlan0", ETH_ALEN},
{"macvlan1", ETH_ALEN},
{"ipvlan0", ETH_ALEN},
{"ipvlan1", ETH_ALEN},
{"veth0_macvtap", ETH_ALEN},
{"veth1_macvtap", ETH_ALEN},
{"macvtap0", ETH_ALEN},
{"macsec0", ETH_ALEN},
{"veth0_to_batadv", ETH_ALEN},
{"veth1_to_batadv", ETH_ALEN},
{"batadv_slave_0", ETH_ALEN},
{"batadv_slave_1", ETH_ALEN},
{"geneve0", ETH_ALEN},
{"geneve1", ETH_ALEN},
{"wg0", 0},
{"wg1", 0},
{"wg2", 0},
};
int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (sock == -1)
exit(1);
unsigned i;
for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++)
netlink_add_device(&nlmsg, sock, devtypes[i].type, devtypes[i].dev);
for (i = 0; i < sizeof(devmasters) / (sizeof(devmasters[0])); i++) {
char master[32], slave0[32], veth0[32], slave1[32], veth1[32];
sprintf(slave0, "%s_slave_0", devmasters[i]);
sprintf(veth0, "veth0_to_%s", devmasters[i]);
netlink_add_veth(&nlmsg, sock, slave0, veth0);
sprintf(slave1, "%s_slave_1", devmasters[i]);
sprintf(veth1, "veth1_to_%s", devmasters[i]);
netlink_add_veth(&nlmsg, sock, slave1, veth1);
sprintf(master, "%s0", devmasters[i]);
netlink_device_change(&nlmsg, sock, slave0, false, master, 0, 0, NULL);
netlink_device_change(&nlmsg, sock, slave1, false, master, 0, 0, NULL);
}
netlink_add_xfrm(&nlmsg, sock, "xfrm0");
netlink_device_change(&nlmsg, sock, "bridge_slave_0", true, 0, 0, 0, NULL);
netlink_device_change(&nlmsg, sock, "bridge_slave_1", true, 0, 0, 0, NULL);
netlink_add_veth(&nlmsg, sock, "hsr_slave_0", "veth0_to_hsr");
netlink_add_veth(&nlmsg, sock, "hsr_slave_1", "veth1_to_hsr");
netlink_add_hsr(&nlmsg, sock, "hsr0", "hsr_slave_0", "hsr_slave_1");
netlink_device_change(&nlmsg, sock, "hsr_slave_0", true, 0, 0, 0, NULL);
netlink_device_change(&nlmsg, sock, "hsr_slave_1", true, 0, 0, 0, NULL);
netlink_add_veth(&nlmsg, sock, "veth0_virt_wifi", "veth1_virt_wifi");
netlink_add_linked(&nlmsg, sock, "virt_wifi", "virt_wifi0",
"veth1_virt_wifi");
netlink_add_veth(&nlmsg, sock, "veth0_vlan", "veth1_vlan");
netlink_add_vlan(&nlmsg, sock, "vlan0", "veth0_vlan", 0, htons(ETH_P_8021Q));
netlink_add_vlan(&nlmsg, sock, "vlan1", "veth0_vlan", 1, htons(ETH_P_8021AD));
netlink_add_macvlan(&nlmsg, sock, "macvlan0", "veth1_vlan");
netlink_add_macvlan(&nlmsg, sock, "macvlan1", "veth1_vlan");
netlink_add_ipvlan(&nlmsg, sock, "ipvlan0", "veth0_vlan", IPVLAN_MODE_L2, 0);
netlink_add_ipvlan(&nlmsg, sock, "ipvlan1", "veth0_vlan", IPVLAN_MODE_L3S,
IPVLAN_F_VEPA);
netlink_add_veth(&nlmsg, sock, "veth0_macvtap", "veth1_macvtap");
netlink_add_linked(&nlmsg, sock, "macvtap", "macvtap0", "veth0_macvtap");
netlink_add_linked(&nlmsg, sock, "macsec", "macsec0", "veth1_macvtap");
char addr[32];
sprintf(addr, DEV_IPV4, 14 + 10);
struct in_addr geneve_addr4;
if (inet_pton(AF_INET, addr, &geneve_addr4) <= 0)
exit(1);
struct in6_addr geneve_addr6;
if (inet_pton(AF_INET6, "fc00::01", &geneve_addr6) <= 0)
exit(1);
netlink_add_geneve(&nlmsg, sock, "geneve0", 0, &geneve_addr4, 0);
netlink_add_geneve(&nlmsg, sock, "geneve1", 1, 0, &geneve_addr6);
netdevsim_add((int)procid, 4);
netlink_wireguard_setup();
for (i = 0; i < sizeof(devices) / (sizeof(devices[0])); i++) {
char addr[32];
sprintf(addr, DEV_IPV4, i + 10);
netlink_add_addr4(&nlmsg, sock, devices[i].name, addr);
if (!devices[i].noipv6) {
sprintf(addr, DEV_IPV6, i + 10);
netlink_add_addr6(&nlmsg, sock, devices[i].name, addr);
}
uint64_t macaddr = DEV_MAC + ((i + 10ull) << 40);
netlink_device_change(&nlmsg, sock, devices[i].name, true, 0, &macaddr,
devices[i].macsize, NULL);
}
close(sock);
}
static void initialize_netdevices_init(void) {
int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (sock == -1)
exit(1);
struct {
const char* type;
int macsize;
bool noipv6;
bool noup;
} devtypes[] = {
{"nr", 7, true},
{"rose", 5, true, true},
};
unsigned i;
for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++) {
char dev[32], addr[32];
sprintf(dev, "%s%d", devtypes[i].type, (int)procid);
sprintf(addr, "172.30.%d.%d", i, (int)procid + 1);
netlink_add_addr4(&nlmsg, sock, dev, addr);
if (!devtypes[i].noipv6) {
sprintf(addr, "fe88::%02x:%02x", i, (int)procid + 1);
netlink_add_addr6(&nlmsg, sock, dev, addr);
}
int macsize = devtypes[i].macsize;
uint64_t macaddr = 0xbbbbbb +
((unsigned long long)i << (8 * (macsize - 2))) +
(procid << (8 * (macsize - 1)));
netlink_device_change(&nlmsg, sock, dev, !devtypes[i].noup, 0, &macaddr,
macsize, NULL);
}
close(sock);
}

static void setup_common() {
if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
}
}

static void setup_binderfs() {
if (mkdir("/dev/binderfs", 0777)) {
}
if (mount("binder", "/dev/binderfs", "binder", 0, NULL)) {
}
if (symlink("/dev/binderfs", "./binderfs")) {
}
}

static void loop();

static void sandbox_common() {
prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
setsid();
struct rlimit rlim;
rlim.rlim_cur = rlim.rlim_max = (200 << 20);
setrlimit(RLIMIT_AS, &rlim);
rlim.rlim_cur = rlim.rlim_max = 32 << 20;
setrlimit(RLIMIT_MEMLOCK, &rlim);
rlim.rlim_cur = rlim.rlim_max = 136 << 20;
setrlimit(RLIMIT_FSIZE, &rlim);
rlim.rlim_cur = rlim.rlim_max = 1 << 20;
setrlimit(RLIMIT_STACK, &rlim);
rlim.rlim_cur = rlim.rlim_max = 128 << 20;
setrlimit(RLIMIT_CORE, &rlim);
rlim.rlim_cur = rlim.rlim_max = 256;
setrlimit(RLIMIT_NOFILE, &rlim);
if (unshare(CLONE_NEWNS)) {
}
if (mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, NULL)) {
}
if (unshare(CLONE_NEWIPC)) {
}
if (unshare(0x02000000)) {
}
if (unshare(CLONE_NEWUTS)) {
}
if (unshare(CLONE_SYSVSEM)) {
}
typedef struct {
const char* name;
const char* value;
} sysctl_t;
static const sysctl_t sysctls[] = {
{"/proc/sys/kernel/shmmax", "16777216"},
{"/proc/sys/kernel/shmall", "536870912"},
{"/proc/sys/kernel/shmmni", "1024"},
{"/proc/sys/kernel/msgmax", "8192"},
{"/proc/sys/kernel/msgmni", "1024"},
{"/proc/sys/kernel/msgmnb", "1024"},
{"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
};
unsigned i;
for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
write_file(sysctls[i].name, sysctls[i].value);
}

static int wait_for_loop(int pid) {
if (pid < 0)
exit(1);
int status = 0;
while (waitpid(-1, &status, __WALL) != pid) {
}
return WEXITSTATUS(status);
}

static void drop_caps(void) {
struct __user_cap_header_struct cap_hdr = {};
struct __user_cap_data_struct cap_data[2] = {};
cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
cap_hdr.pid = getpid();
if (syscall(SYS_capget, &cap_hdr, &cap_data))
exit(1);
const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
cap_data[0].effective &= ~drop;
cap_data[0].permitted &= ~drop;
cap_data[0].inheritable &= ~drop;
if (syscall(SYS_capset, &cap_hdr, &cap_data))
exit(1);
}

static int do_sandbox_none(void) {
if (unshare(CLONE_NEWPID)) {
}
int pid = fork();
if (pid != 0)
return wait_for_loop(pid);
setup_common();
sandbox_common();
drop_caps();
initialize_netdevices_init();
if (unshare(CLONE_NEWNET)) {
}
write_file("/proc/sys/net/ipv4/ping_group_range", "0 65535");
initialize_tun();
initialize_netdevices();
setup_binderfs();
loop();
exit(1);
}

uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};

void loop(void) {
intptr_t res = 0;
res = syscall(__NR_socket, /*domain=*/0x10ul, /*type=*/3ul, /*proto=*/0);
if (res != -1)
r[0] = res;
*(uint64_t*)0x20000040 = 0x20000080;
memcpy((void*)0x20000080,
"\x39\x00\x00\x00\x13\x00\x0b\x46\x00\xbb\x65\xe1\xc3\xe4\xff\xff\xf9"
"\xff\xff\x7f\x37\x00\x00\x00\x56\x00\x00\x02\x25\x00\x00\x00\x19\x00"
"\x0a\x00\x10\x00\x00\x00\x07\xfd\x17\xe5\xff\xff\x08\x00\x04\x00\x00"
"\x00\x00\x00\x00\x00\x0a",
57);
*(uint64_t*)0x20000048 = 0x39;
syscall(__NR_writev, /*fd=*/r[0], /*vec=*/0x20000040ul, /*vlen=*/1ul);
res = syscall(__NR_socket, /*domain=*/0x10ul, /*type=*/3ul, /*proto=*/0);
if (res != -1)
r[1] = res;
*(uint64_t*)0x20000040 = 0x20000080;
memcpy((void*)0x20000080,
"\x39\x00\x00\x00\x13\x00\x0b\x46\x00\xbb\x65\xe1\xc3\xe4\xff\xff\x01"
"\x00\x00\x00\x36\x00\x00\x00\x56\x00\x00\x02\x25\x00\x00\x00\x19\x00"
"\x0a\x00\x10\x00\x00\x00\x07\xfd\x17\xe5\xff\xff\x08\x00\x04\x00\x00"
"\x00\x00\x00\x00\x00\x0a",
57);
*(uint64_t*)0x20000048 = 0x39;
syscall(__NR_writev, /*fd=*/r[1], /*vec=*/0x20000040ul, /*vlen=*/1ul);
}
int main(void) {
syscall(__NR_mmap, /*addr=*/0x1ffff000ul, /*len=*/0x1000ul, /*prot=*/0ul,
/*flags=*/0x32ul, /*fd=*/-1, /*offset=*/0ul);
syscall(__NR_mmap, /*addr=*/0x20000000ul, /*len=*/0x1000000ul, /*prot=*/7ul,
/*flags=*/0x32ul, /*fd=*/-1, /*offset=*/0ul);
syscall(__NR_mmap, /*addr=*/0x21000000ul, /*len=*/0x1000ul, /*prot=*/0ul,
/*flags=*/0x32ul, /*fd=*/-1, /*offset=*/0ul);
do_sandbox_none();
return 0;
}


and also https://gist.github.com/xrivendell7/dea2d84fe5efdb17eedcdb3e17297ffe

I hope it helps.
Best regards
xingwei Lee

syzbot

unread,
Mar 5, 2024, 5:44:22 PMMar 5
to da...@davemloft.net, edum...@google.com, ji...@resnulli.us, ku...@kernel.org, linux-...@vger.kernel.org, net...@vger.kernel.org, pab...@redhat.com, syzkall...@googlegroups.com, xrive...@gmail.com
syzbot has found a reproducer for the following issue on:

HEAD commit: 885c36e59f46 net: Re-use and set mono_delivery_time bit fo..
git tree: net-next
console+strace: https://syzkaller.appspot.com/x/log.txt?x=16c4c66c180000
kernel config: https://syzkaller.appspot.com/x/.config?x=92e06b597766606e
dashboard link: https://syzkaller.appspot.com/bug?extid=3c47b5843403a45aef57
compiler: Debian clang version 15.0.6, GNU ld (GNU Binutils for Debian) 2.40
syz repro: https://syzkaller.appspot.com/x/repro.syz?x=15fe09f2180000
C reproducer: https://syzkaller.appspot.com/x/repro.c?x=167cc5ee180000

Downloadable assets:
disk image: https://storage.googleapis.com/syzbot-assets/241b626fcf71/disk-885c36e5.raw.xz
vmlinux: https://storage.googleapis.com/syzbot-assets/4f0f3e287f32/vmlinux-885c36e5.xz
kernel image: https://storage.googleapis.com/syzbot-assets/c31138ef60ba/bzImage-885c36e5.xz

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

netlink: 'syz-executor286': attribute type 10 has an invalid length.
team0: Port device vlan1 added
netlink: 'syz-executor286': attribute type 10 has an invalid length.
veth0_vlan: left promiscuous mode
veth0_vlan: entered promiscuous mode
============================================
WARNING: possible recursive locking detected
6.8.0-rc6-syzkaller-01978-g885c36e59f46 #0 Not tainted
--------------------------------------------
syz-executor286/5073 is trying to acquire lock:
ffff888077f38d00 (team->team_lock_key){+.+.}-{3:3}, at: team_port_change_check+0x51/0x1e0 drivers/net/team/team.c:2995

but task is already holding lock:
ffff888077f38d00 (team->team_lock_key){+.+.}-{3:3}, at: team_add_slave+0xad/0x2750 drivers/net/team/team.c:1973

other info that might help us debug this:
Possible unsafe locking scenario:

CPU0
----
lock(team->team_lock_key);
lock(team->team_lock_key);

*** DEADLOCK ***

May be due to missing lock nesting notation

2 locks held by syz-executor286/5073:
#0: ffffffff8f378f88 (rtnl_mutex){+.+.}-{3:3}, at: rtnl_lock net/core/rtnetlink.c:79 [inline]
#0: ffffffff8f378f88 (rtnl_mutex){+.+.}-{3:3}, at: rtnetlink_rcv_msg+0x842/0x10d0 net/core/rtnetlink.c:6595
#1: ffff888077f38d00 (team->team_lock_key){+.+.}-{3:3}, at: team_add_slave+0xad/0x2750 drivers/net/team/team.c:1973

stack backtrace:
CPU: 0 PID: 5073 Comm: syz-executor286 Not tainted 6.8.0-rc6-syzkaller-01978-g885c36e59f46 #0
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/25/2024
Call Trace:
<TASK>
__dump_stack lib/dump_stack.c:88 [inline]
dump_stack_lvl+0x1e7/0x2e0 lib/dump_stack.c:106
check_deadlock kernel/locking/lockdep.c:3062 [inline]
validate_chain+0x15c0/0x58e0 kernel/locking/lockdep.c:3856
__lock_acquire+0x1345/0x1fd0 kernel/locking/lockdep.c:5137
lock_acquire+0x1e3/0x530 kernel/locking/lockdep.c:5754
__mutex_lock_common kernel/locking/mutex.c:608 [inline]
__mutex_lock+0x136/0xd70 kernel/locking/mutex.c:752
team_port_change_check+0x51/0x1e0 drivers/net/team/team.c:2995
team_device_event+0x4e6/0x5b0 drivers/net/team/team.c:3018
notifier_call_chain+0x18f/0x3b0 kernel/notifier.c:93
__dev_notify_flags+0x207/0x400
dev_change_flags+0xf0/0x1a0 net/core/dev.c:8773
vlan_device_event+0x1b81/0x1de0 net/8021q/vlan.c:468
notifier_call_chain+0x18f/0x3b0 kernel/notifier.c:93
call_netdevice_notifiers_extack net/core/dev.c:1988 [inline]
call_netdevice_notifiers net/core/dev.c:2002 [inline]
dev_open+0x13a/0x1b0 net/core/dev.c:1471
team_port_add drivers/net/team/team.c:1214 [inline]
team_add_slave+0x9b3/0x2750 drivers/net/team/team.c:1974
do_set_master net/core/rtnetlink.c:2688 [inline]
do_setlink+0xe70/0x41f0 net/core/rtnetlink.c:2894
rtnl_setlink+0x40d/0x5a0 net/core/rtnetlink.c:3188
rtnetlink_rcv_msg+0x89b/0x10d0 net/core/rtnetlink.c:6598
netlink_rcv_skb+0x1e3/0x430 net/netlink/af_netlink.c:2547
netlink_unicast_kernel net/netlink/af_netlink.c:1335 [inline]
netlink_unicast+0x7ea/0x980 net/netlink/af_netlink.c:1361
netlink_sendmsg+0x8e0/0xcb0 net/netlink/af_netlink.c:1902
sock_sendmsg_nosec net/socket.c:730 [inline]
__sock_sendmsg+0x221/0x270 net/socket.c:745
sock_write_iter+0x2dd/0x400 net/socket.c:1160
do_iter_readv_writev+0x46c/0x640
vfs_writev+0x395/0xbb0 fs/read_write.c:971
do_writev+0x1b1/0x350 fs/read_write.c:1018
do_syscall_64+0xf9/0x240
entry_SYSCALL_64_after_hwframe+0x6f/0x77
RIP: 0033:0x7f5521197a89
Code: 48 83 c4 28 c3 e8 d7 19 00 00 0f 1f 80 00 00 00 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 b8 ff ff ff f7 d8 64 89 01 48
RSP: 002b:00007ffcaa0cf2c8 EFLAGS: 00000246 ORIG_RAX: 0000000000000014
RAX: ffffffffffffffda RBX: 00007f55211e53d3 RCX: 00007f5521197a89
RDX: 0000000000000001 RSI: 0000000020000040 RDI: 0000000000000004
RBP: 00007ffcaa0cf2f0 R08: 0000000000000001 R09: 0000000000000001
R10: 0000000000000001 R11: 0000000000000246 R12: 00007ffcaa0cf300
R13: 00007f55211e5004 R14: 00007ffcaa0cf2ec R15: 0000000000000003
</TASK>


---
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.

syzbot

unread,
Mar 6, 2024, 3:27:05 AMMar 6
to da...@davemloft.net, edum...@google.com, ji...@nvidia.com, ji...@resnulli.us, ku...@kernel.org, linux-...@vger.kernel.org, liuha...@gmail.com, net...@vger.kernel.org, nicolas...@6wind.com, pab...@redhat.com, syzkall...@googlegroups.com, xrive...@gmail.com
syzbot has bisected this issue to:

commit ec4ffd100ffb396eca13ebe7d18938ea80f399c3
Author: Nicolas Dichtel <nicolas...@6wind.com>
Date: Mon Jan 8 09:41:02 2024 +0000

Revert "net: rtnetlink: Enslave device before bringing it up"

bisection log: https://syzkaller.appspot.com/x/bisect.txt?x=163d5686180000
start commit: 90d35da658da Linux 6.8-rc7
git tree: upstream
final oops: https://syzkaller.appspot.com/x/report.txt?x=153d5686180000
console output: https://syzkaller.appspot.com/x/log.txt?x=113d5686180000
kernel config: https://syzkaller.appspot.com/x/.config?x=c11c5c676adb61f0
dashboard link: https://syzkaller.appspot.com/bug?extid=3c47b5843403a45aef57
syz repro: https://syzkaller.appspot.com/x/repro.syz?x=158ae1de180000
C reproducer: https://syzkaller.appspot.com/x/repro.c?x=165f2732180000

Reported-by: syzbot+3c47b5...@syzkaller.appspotmail.com
Fixes: ec4ffd100ffb ("Revert "net: rtnetlink: Enslave device before bringing it up"")

For information about bisection process see: https://goo.gl/tpsmEJ#bisection

Edward Adam Davis

unread,
Mar 7, 2024, 4:26:28 AMMar 7
to syzbot+3c47b5...@syzkaller.appspotmail.com, linux-...@vger.kernel.org, syzkall...@googlegroups.com
please test dl in team_port_change_check

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

diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c
index f575f225d417..ecce44b16e4f 100644
--- a/drivers/net/team/team.c
+++ b/drivers/net/team/team.c
@@ -1212,7 +1212,9 @@ static int team_port_add(struct team *team, struct net_device *port_dev,
goto err_port_enter;
}

+ mutex_unlock(&team->lock);
err = dev_open(port_dev, extack);
+ mutex_lock(&team->lock);
if (err) {
netdev_dbg(dev, "Device %s opening failed\n",
portname);

syzbot

unread,
Mar 7, 2024, 4:50:04 AMMar 7
to ead...@qq.com, linux-...@vger.kernel.org, syzkall...@googlegroups.com
Hello,

syzbot has tested the proposed patch but the reproducer is still triggering an issue:
possible deadlock in team_port_change_check

veth0_vlan: left promiscuous mode
veth0_vlan: entered promiscuous mode
team0: Device veth0_vlan failed to register rx_handler
============================================
WARNING: possible recursive locking detected
6.8.0-rc7-syzkaller-00051-g67be068d31d4-dirty #0 Not tainted
--------------------------------------------
syz-executor.0/5487 is trying to acquire lock:
ffff88802dce4d00 (team->team_lock_key){+.+.}-{3:3}, at: team_port_change_check+0x51/0x1e0 drivers/net/team/team.c:2999

but task is already holding lock:
ffff88802dce4d00 (team->team_lock_key){+.+.}-{3:3}, at: team_port_add drivers/net/team/team.c:1217 [inline]
ffff88802dce4d00 (team->team_lock_key){+.+.}-{3:3}, at: team_add_slave+0x9bb/0x2710 drivers/net/team/team.c:1977

other info that might help us debug this:
Possible unsafe locking scenario:

CPU0
----
lock(team->team_lock_key);
lock(team->team_lock_key);

*** DEADLOCK ***

May be due to missing lock nesting notation

2 locks held by syz-executor.0/5487:
#0: ffffffff8f375d88 (rtnl_mutex){+.+.}-{3:3}, at: rtnl_lock net/core/rtnetlink.c:79 [inline]
#0: ffffffff8f375d88 (rtnl_mutex){+.+.}-{3:3}, at: rtnetlink_rcv_msg+0x82c/0x1040 net/core/rtnetlink.c:6614
#1: ffff88802dce4d00 (team->team_lock_key){+.+.}-{3:3}, at: team_port_add drivers/net/team/team.c:1217 [inline]
#1: ffff88802dce4d00 (team->team_lock_key){+.+.}-{3:3}, at: team_add_slave+0x9bb/0x2710 drivers/net/team/team.c:1977

stack backtrace:
CPU: 1 PID: 5487 Comm: syz-executor.0 Not tainted 6.8.0-rc7-syzkaller-00051-g67be068d31d4-dirty #0
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/25/2024
Call Trace:
<TASK>
__dump_stack lib/dump_stack.c:88 [inline]
dump_stack_lvl+0x1e7/0x2e0 lib/dump_stack.c:106
check_deadlock kernel/locking/lockdep.c:3062 [inline]
validate_chain+0x15c0/0x58e0 kernel/locking/lockdep.c:3856
__lock_acquire+0x1345/0x1fd0 kernel/locking/lockdep.c:5137
lock_acquire+0x1e3/0x530 kernel/locking/lockdep.c:5754
__mutex_lock_common kernel/locking/mutex.c:608 [inline]
__mutex_lock+0x136/0xd70 kernel/locking/mutex.c:752
team_port_change_check+0x51/0x1e0 drivers/net/team/team.c:2999
team_device_event+0x161/0x5b0 drivers/net/team/team.c:3025
notifier_call_chain+0x18f/0x3b0 kernel/notifier.c:93
call_netdevice_notifiers_extack net/core/dev.c:2004 [inline]
call_netdevice_notifiers net/core/dev.c:2018 [inline]
dev_close_many+0x33c/0x4c0 net/core/dev.c:1559
vlan_device_event+0x18b7/0x1de0 net/8021q/vlan.c:449
notifier_call_chain+0x18f/0x3b0 kernel/notifier.c:93
call_netdevice_notifiers_extack net/core/dev.c:2004 [inline]
call_netdevice_notifiers net/core/dev.c:2018 [inline]
dev_close_many+0x33c/0x4c0 net/core/dev.c:1559
dev_close+0x1c0/0x2c0 net/core/dev.c:1581
team_port_add drivers/net/team/team.c:1314 [inline]
team_add_slave+0x1ac5/0x2710 drivers/net/team/team.c:1977
do_set_master net/core/rtnetlink.c:2707 [inline]
do_setlink+0xe58/0x41c0 net/core/rtnetlink.c:2913
rtnl_setlink+0x40d/0x5a0 net/core/rtnetlink.c:3209
rtnetlink_rcv_msg+0x885/0x1040 net/core/rtnetlink.c:6617
netlink_rcv_skb+0x1e3/0x430 net/netlink/af_netlink.c:2543
netlink_unicast_kernel net/netlink/af_netlink.c:1341 [inline]
netlink_unicast+0x7ea/0x980 net/netlink/af_netlink.c:1367
netlink_sendmsg+0xa3b/0xd70 net/netlink/af_netlink.c:1908
sock_sendmsg_nosec net/socket.c:730 [inline]
__sock_sendmsg+0x221/0x270 net/socket.c:745
sock_write_iter+0x2dd/0x400 net/socket.c:1160
do_iter_readv_writev+0x46c/0x640
vfs_writev+0x395/0xbb0 fs/read_write.c:971
do_writev+0x1b1/0x350 fs/read_write.c:1018
do_syscall_64+0xf9/0x240
entry_SYSCALL_64_after_hwframe+0x6f/0x77
RIP: 0033:0x7f19b167dda9
Code: 28 00 00 00 75 05 48 83 c4 28 c3 e8 e1 20 00 00 90 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 b0 ff ff ff f7 d8 64 89 01 48
RSP: 002b:00007f19b247f0c8 EFLAGS: 00000246 ORIG_RAX: 0000000000000014
RAX: ffffffffffffffda RBX: 00007f19b17abf80 RCX: 00007f19b167dda9
RDX: 0000000000000001 RSI: 0000000020000040 RDI: 0000000000000004
RBP: 00007f19b16ca47a R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
R13: 000000000000000b R14: 00007f19b17abf80 R15: 00007ffdad2a3d88
</TASK>


Tested on:

commit: 67be068d Merge tag 'vfs-6.8-release.fixes' of git://gi..
git tree: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git master
console output: https://syzkaller.appspot.com/x/log.txt?x=16f71336180000
compiler: Debian clang version 15.0.6, GNU ld (GNU Binutils for Debian) 2.40
patch: https://syzkaller.appspot.com/x/patch.diff?x=15998cea180000

Edward Adam Davis

unread,
Mar 7, 2024, 5:02:45 AMMar 7
to syzbot+3c47b5...@syzkaller.appspotmail.com, linux-...@vger.kernel.org, syzkall...@googlegroups.com
please test dl in team_port_change_check

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

diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c
index f575f225d417..590412701402 100644
--- a/drivers/net/team/team.c
+++ b/drivers/net/team/team.c
@@ -1212,7 +1212,9 @@ static int team_port_add(struct team *team, struct net_device *port_dev,
goto err_port_enter;
}

+ mutex_unlock(&team->lock);
err = dev_open(port_dev, extack);
+ mutex_lock(&team->lock);
if (err) {
netdev_dbg(dev, "Device %s opening failed\n",
portname);
@@ -1309,7 +1311,9 @@ static int team_port_add(struct team *team, struct net_device *port_dev,
vlan_vids_del_by_dev(port_dev, dev);

err_vids_add:
+ mutex_unlock(&team->lock);
dev_close(port_dev);
+ mutex_lock(&team->lock);

err_dev_open:
team_port_leave(team, port);

syzbot

unread,
Mar 7, 2024, 5:48:03 AMMar 7
to ead...@qq.com, linux-...@vger.kernel.org, syzkall...@googlegroups.com
Hello,

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

Reported-and-tested-by: syzbot+3c47b5...@syzkaller.appspotmail.com

Tested on:

commit: 67be068d Merge tag 'vfs-6.8-release.fixes' of git://gi..
git tree: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git master
console output: https://syzkaller.appspot.com/x/log.txt?x=17c7bf61180000
kernel config: https://syzkaller.appspot.com/x/.config?x=c11c5c676adb61f0
dashboard link: https://syzkaller.appspot.com/bug?extid=3c47b5843403a45aef57
compiler: Debian clang version 15.0.6, GNU ld (GNU Binutils for Debian) 2.40
patch: https://syzkaller.appspot.com/x/patch.diff?x=113c02ea180000

Note: testing is done by a robot and is best-effort only.
Reply all
Reply to author
Forward
0 new messages