diff mbox series

netfilter: ebtables: fix a NULL pointer dereference in ebt_do_table()

Message ID 20220820070331.48817-1-harshit.m.mogalapalli@oracle.com (mailing list archive)
State Awaiting Upstream
Delegated to: Netdev Maintainers
Headers show
Series netfilter: ebtables: fix a NULL pointer dereference in ebt_do_table() | expand

Checks

Context Check Description
netdev/tree_selection success Guessed tree name to be net-next
netdev/fixes_present success Fixes tag not required for -next series
netdev/subject_prefix warning Target tree name not specified in the subject
netdev/cover_letter success Single patches do not need cover letters
netdev/patch_count success Link
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 85 this patch: 85
netdev/cc_maintainers success CCed 13 of 13 maintainers
netdev/build_clang success Errors and warnings before: 2 this patch: 2
netdev/module_param success Was 0 now: 0
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success Fixes tag looks correct
netdev/build_allmodconfig_warn success Errors and warnings before: 86 this patch: 86
netdev/checkpatch success total: 0 errors, 0 warnings, 0 checks, 11 lines checked
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0

Commit Message

Harshit Mogalapalli Aug. 20, 2022, 7:03 a.m. UTC
In ebt_do_table() function dereferencing 'private->hook_entry[hook]'
can lead to NULL pointer dereference. So add a check to prevent that.

Kernel panic:

[  119.229105][   T31] general protection fault, probably for
non-canonical address 0xdffffc0000000005: 0000 [#1] PREEMPT SMP KASAN
[  119.230280][   T31] KASAN: null-ptr-deref in range
[0x0000000000000028-0x000000000000002f]
[  119.231043][   T31] CPU: 3 PID: 31 Comm: kworker/3:0 Not tainted
6.0.0-rc1 #1
[  119.231652][   T31] Hardware name: QEMU Standard PC (i440FX + PIIX,
1996), BIOS 1.11.0-2.el7 04/01/2014
[  119.232440][   T31] Workqueue: mld mld_ifc_work
[  119.232846][   T31] RIP: 0010:ebt_do_table+0x1dc/0x1ce0
[  119.233291][   T31] Code: 89 fa 48 c1 ea 03 80 3c 02 00 0f 85 5c 16
00 00 48 b8 00 00 00 00 00 fc ff df 49 8b 6c df 08 48 8d 7d 2c 48 89 fa
48 c1 ea 03 <0f> b6 14 02 48 89 f8 83 e0 07 83 c0 03 38 d0 7c 08 84 d2
0f 85 88
[  119.234920][   T31] RSP: 0018:ffffc90000347178 EFLAGS: 00010217
[  119.235425][   T31] RAX: dffffc0000000000 RBX: 0000000000000003 RCX:
ffffffff8158677b
[  119.236097][   T31] RDX: 0000000000000005 RSI: ffffffff889a7b80 RDI:
000000000000002c
[  119.236764][   T31] RBP: 0000000000000000 R08: 0000000000000001 R09:
ffff888101a78443
[  119.237425][   T31] R10: ffffed102034f088 R11: 000200100040dd86 R12:
ffffc90001111018
[  119.238100][   T31] R13: ffffc90001103080 R14: ffffc90001111000 R15:
ffffc90001103000
[  119.238769][   T31] FS:  0000000000000000(0000)
GS:ffff88811a380000(0000) knlGS:0000000000000000
[  119.239592][   T31] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[  119.240221][   T31] CR2: 00007f6a9adda000 CR3: 0000000100be3000 CR4:
00000000000006e0
[  119.240970][   T31] Call Trace:
[  119.241253][   T31]  <TASK>
[  119.241495][   T31]  ? ip6_output+0x1f4/0x6e0
[  119.241877][   T31]  ? NF_HOOK.constprop.0+0xe6/0x5f0
[  119.242309][   T31]  ? mld_ifc_work+0x564/0xaa0
[  119.242708][   T31]  ? kthread+0x297/0x340
[  119.243060][   T31]  ? ret_from_fork+0x22/0x30
[  119.243454][   T31]  ? br_multicast_count+0xbf/0x8d0
[  119.243896][   T31]  ? rcu_read_lock_sched_held+0xd/0xa0
[  119.244356][   T31]  ? compat_copy_ebt_replace_from_user+0x380/0x380
[  119.244907][   T31]  ? compat_copy_ebt_replace_from_user+0x380/0x380
[  119.245454][   T31]  nf_hook_slow+0xb1/0x170
[  119.245835][   T31]  __br_forward+0x289/0x730
[  119.246219][   T31]  ? br_forward_finish+0x320/0x320
[  119.246656][   T31]  ? br_dev_queue_push_xmit+0x650/0x650
[  119.247118][   T31]  ? memcpy+0x39/0x60
[  119.247444][   T31]  ? __skb_clone+0x56c/0x750
[  119.247845][   T31]  maybe_deliver+0x24b/0x380
[  119.248234][   T31]  br_flood+0xc6/0x390
[  119.248577][   T31]  br_dev_xmit+0xa2e/0x12c0
[  119.248975][   T31]  ? rcu_read_lock_sched_held+0xd/0xa0
[  119.249498][   T31]  ? br_netpoll_setup+0x170/0x170
[  119.249987][   T31]  ? fib_rules_lookup+0x2eb/0x9d0
[  119.250462][   T31]  ? lock_repin_lock+0x30/0x420
[  119.250922][   T31]  ? rcu_read_lock_sched_held+0xd/0xa0
[  119.251376][   T31]  ? lock_acquire+0x510/0x630
[  119.251773][   T31]  ? netif_inherit_tso_max+0x1e0/0x1e0
[  119.252228][   T31]  dev_hard_start_xmit+0x151/0x660
[  119.252663][   T31]  __dev_queue_xmit+0x240e/0x3200
[  119.253080][   T31]  ? ip6mr_rtm_dumproute+0x530/0x530
[  119.253522][   T31]  ? netdev_core_pick_tx+0x2a0/0x2a0
[  119.253968][   T31]  ? unwind_next_frame+0x3de/0x1c90
[  119.254403][   T31]  ? rcu_read_lock_sched_held+0xd/0xa0
[  119.254872][   T31]  ? lock_acquire+0x510/0x630
[  119.255266][   T31]  ? rcu_read_lock_sched_held+0xd/0xa0
[  119.255724][   T31]  ? lock_release+0x5a2/0x840
[  119.256119][   T31]  ? mroute6_is_socket+0x14d/0x220
[  119.256549][   T31]  ? rcu_read_lock_sched_held+0xd/0xa0
[  119.257064][   T31]  ? lock_acquire+0x510/0x630
[  119.257507][   T31]  ? rcu_read_lock_sched_held+0xd/0xa0
[  119.258016][   T31]  ? lock_release+0x5a2/0x840
[  119.258410][   T31]  ? lock_release+0x840/0x840
[  119.258812][   T31]  ? ip6_finish_output+0x779/0x1190
[  119.259304][   T31]  ? lock_downgrade+0x7b0/0x7b0
[  119.259778][   T31]  ? rcu_read_lock_bh_held+0xd/0x90
[  119.260275][   T31]  ? ___neigh_lookup_noref.constprop.0+0x266/0x6d0
[  119.260896][   T31]  ? ip6_finish_output2+0x861/0x1690
[  119.261343][   T31]  ip6_finish_output2+0x861/0x1690
[  119.261776][   T31]  ? lock_release+0x5a2/0x840
[  119.262176][   T31]  ? __kasan_kmalloc+0x7f/0xa0
[  119.262574][   T31]  ? ip6_mtu+0x139/0x320
[  119.262942][   T31]  ? ip6_frag_next+0xcc0/0xcc0
[  119.263341][   T31]  ? rcu_read_lock_sched_held+0xd/0xa0
[  119.263816][   T31]  ? nf_ct_netns_get+0xe0/0xe0
[  119.264214][   T31]  ? rcu_read_lock_sched_held+0xd/0xa0
[  119.264679][   T31]  ? lock_release+0x5a2/0x840
[  119.265066][   T31]  ? nf_conntrack_in.cold+0x9b/0xe2
[  119.265504][   T31]  ? ip6_output+0x4c9/0x6e0
[  119.265891][   T31]  ip6_finish_output+0x779/0x1190
[  119.266315][   T31]  ? nf_hook_slow+0xb1/0x170
[  119.266711][   T31]  ip6_output+0x1f4/0x6e0
[  119.267069][   T31]  ? rcu_read_lock_sched_held+0xd/0xa0
[  119.267520][   T31]  ? ip6_finish_output+0x1190/0x1190
[  119.267969][   T31]  ? NF_HOOK.constprop.0+0x1b3/0x5f0
[  119.268415][   T31]  ? lock_pin_lock+0x184/0x380
[  119.268817][   T31]  ? ip6_fragment+0x2910/0x2910
[  119.269269][   T31]  ? nf_ct_netns_do_get+0x6c0/0x6c0
[  119.269773][   T31]  ? nf_hook_slow+0xb1/0x170
[  119.270211][   T31]  NF_HOOK.constprop.0+0xe6/0x5f0
[  119.270697][   T31]  ? igmp6_mcf_seq_next+0x460/0x460
[  119.271159][   T31]  ? igmp6_mcf_seq_stop+0x130/0x130
[  119.271600][   T31]  ? icmp6_dst_alloc+0x3dc/0x610
[  119.272030][   T31]  mld_sendpack+0x619/0xb50
[  119.272413][   T31]  ? NF_HOOK.constprop.0+0x5f0/0x5f0
[  119.272867][   T31]  ? lock_release+0x840/0x840
[  119.273254][   T31]  mld_ifc_work+0x564/0xaa0
[  119.273642][   T31]  ? pwq_activate_inactive_work+0xb2/0x190
[  119.274126][   T31]  process_one_work+0x875/0x1440
[  119.274543][   T31]  ? lock_release+0x840/0x840
[  119.274936][   T31]  ? pwq_dec_nr_in_flight+0x230/0x230
[  119.275381][   T31]  ? rwlock_bug.part.0+0x90/0x90
[  119.275801][   T31]  worker_thread+0x598/0xec0
[  119.276187][   T31]  ? process_one_work+0x1440/0x1440
[  119.276613][   T31]  kthread+0x297/0x340
[  119.276958][   T31]  ? kthread_complete_and_exit+0x20/0x20
[  119.277422][   T31]  ret_from_fork+0x22/0x30
[  119.277796][   T31]  </TASK>
[  119.278048][   T31] Modules linked in:
[  119.278377][   T31] Dumping ftrace buffer:
[  119.278733][   T31]    (ftrace buffer empty)
[  119.279151][   T31] ---[ end trace 0000000000000000 ]---
[  119.279679][   T31] RIP: 0010:ebt_do_table+0x1dc/0x1ce0
[  119.280187][   T31] Code: 89 fa 48 c1 ea 03 80 3c 02 00 0f 85 5c 16
00 00 48 b8 00 00 00 00 00 fc ff df 49 8b 6c df 08 48 8d 7d 2c 48 89 fa
48 c1 ea 03 <0f> b6 14 02 48 89 f8 83 e0 07 83 c0 03 38 d0 7c 08 84 d2
0f 85 88
[  119.282006][   T31] RSP: 0018:ffffc90000347178 EFLAGS: 00010217
[  119.282569][   T31] RAX: dffffc0000000000 RBX: 0000000000000003 RCX:
ffffffff8158677b
[  119.283308][   T31] RDX: 0000000000000005 RSI: ffffffff889a7b80 RDI:
000000000000002c
[  119.284056][   T31] RBP: 0000000000000000 R08: 0000000000000001 R09:
ffff888101a78443
[  119.284811][   T31] R10: ffffed102034f088 R11: 000200100040dd86 R12:
ffffc90001111018
[  119.285549][   T31] R13: ffffc90001103080 R14: ffffc90001111000 R15:
ffffc90001103000
[  119.286284][   T31] FS:  0000000000000000(0000)
GS:ffff88811a380000(0000) knlGS:0000000000000000
[  119.287119][   T31] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[  119.287741][   T31] CR2: 00007f6a9adda000 CR3: 0000000100be3000 CR4:
00000000000006e0
[  119.288489][   T31] Kernel panic - not syncing: Fatal exception in
interrupt
[  119.298556][   T31] Dumping ftrace buffer:
[  119.298974][   T31]    (ftrace buffer empty)
[  119.299399][   T31] Kernel Offset: disabled
[  119.299823][   T31] Rebooting in 86400 seconds..

Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Reported-by: syzkaller <syzkaller@googlegroups.com>
Signed-off-by: Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
---
Testing is only done with reproducer.

 net/bridge/netfilter/ebtables.c | 5 +++++
 1 file changed, 5 insertions(+)

Comments

Florian Westphal Aug. 20, 2022, 4:26 p.m. UTC | #1
Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com> wrote:
> In ebt_do_table() function dereferencing 'private->hook_entry[hook]'
> can lead to NULL pointer dereference. So add a check to prevent that.

This looks incorrect, i.e. paperimg over the problem.

If hook_entry[hook] is NULL, how did this make it to the eval loop?

I guess ebtables lacks a sanity check on incoming ruleset?
Harshit Mogalapalli Aug. 20, 2022, 7:18 p.m. UTC | #2
On 20/08/22 9:56 pm, Florian Westphal wrote:
> Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com> wrote:
>> In ebt_do_table() function dereferencing 'private->hook_entry[hook]'
>> can lead to NULL pointer dereference. So add a check to prevent that.
> 
Hi Florian,

Thanks a lot for checking the patch.

> This looks incorrect, i.e. paperimg over the problem.
> 

Okay.

> If hook_entry[hook] is NULL, how did this make it to the eval loop?
>

When I run the reproducer and have 'private->hook_entry[hook]' printed, 
it was NULL, so thought of adding a NULL check to prevent the NULL 
dereference.

Attaching the C reproducer.

Regards,
Harshit


> I guess ebtables lacks a sanity check on incoming ruleset?
>
{\rtf1\ansi\ansicpg1252\cocoartf2639
\cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fmodern\fcharset0 Courier;}
{\colortbl;\red255\green255\blue255;\red0\green0\blue0;}
{\*\expandedcolortbl;;\cssrgb\c0\c0\c0;}
\paperw11900\paperh16840\margl1440\margr1440\vieww11520\viewh8400\viewkind0
\deftab720
\pard\pardeftab720\partightenfactor0

\f0\fs26 \cf0 \expnd0\expndtw0\kerning0
\outl0\strokewidth0 \strokec2 #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 <pthread.h>\
#include <sched.h>\
#include <stdarg.h>\
#include <stdbool.h>\
#include <stdint.h>\
#include <stdio.h>\
#include <stdlib.h>\
#include <string.h>\
#include <sys/epoll.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/rfkill.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)\
\{\
	struct ifinfomsg hdr;\
	memset(&hdr, 0, sizeof(hdr));\
	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);\
	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);\
	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_hsr(struct nlmsg* nlmsg, int sock, const char* name,\
			    const char* slave1, const char* slave2)\
\{\
	netlink_add_device_impl(nlmsg, "hsr", name);\
	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);\
	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);\
	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);\
	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);\
	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);\
	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 struct nlmsg nlmsg;\
\
#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)\
\{\
	char buf[16];\
	sprintf(buf, "%u %u", addr, port_count);\
	if (write_file("/sys/bus/netdevsim/new_device", buf)) \{\
		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"\},\
	    \{"netdevsim", netdevsim\},\
	    \{"veth", 0\},\
	    \{"xfrm", "xfrm0"\},\
	    \{"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_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);\
\}\
\
#define MAX_FDS 30\
\
#define BTPROTO_HCI 1\
#define ACL_LINK 1\
#define SCAN_PAGE 2\
\
typedef struct \{\
	uint8_t b[6];\
\} __attribute__((packed)) bdaddr_t;\
\
#define HCI_COMMAND_PKT 1\
#define HCI_EVENT_PKT 4\
#define HCI_VENDOR_PKT 0xff\
\
struct hci_command_hdr \{\
	uint16_t opcode;\
	uint8_t plen;\
\} __attribute__((packed));\
\
struct hci_event_hdr \{\
	uint8_t evt;\
	uint8_t plen;\
\} __attribute__((packed));\
\
#define HCI_EV_CONN_COMPLETE 0x03\
struct hci_ev_conn_complete \{\
	uint8_t status;\
	uint16_t handle;\
	bdaddr_t bdaddr;\
	uint8_t link_type;\
	uint8_t encr_mode;\
\} __attribute__((packed));\
\
#define HCI_EV_CONN_REQUEST 0x04\
struct hci_ev_conn_request \{\
	bdaddr_t bdaddr;\
	uint8_t dev_class[3];\
	uint8_t link_type;\
\} __attribute__((packed));\
\
#define HCI_EV_REMOTE_FEATURES 0x0b\
struct hci_ev_remote_features \{\
	uint8_t status;\
	uint16_t handle;\
	uint8_t features[8];\
\} __attribute__((packed));\
\
#define HCI_EV_CMD_COMPLETE 0x0e\
struct hci_ev_cmd_complete \{\
	uint8_t ncmd;\
	uint16_t opcode;\
\} __attribute__((packed));\
\
#define HCI_OP_WRITE_SCAN_ENABLE 0x0c1a\
\
#define HCI_OP_READ_BUFFER_SIZE 0x1005\
struct hci_rp_read_buffer_size \{\
	uint8_t status;\
	uint16_t acl_mtu;\
	uint8_t sco_mtu;\
	uint16_t acl_max_pkt;\
	uint16_t sco_max_pkt;\
\} __attribute__((packed));\
\
#define HCI_OP_READ_BD_ADDR 0x1009\
struct hci_rp_read_bd_addr \{\
	uint8_t status;\
	bdaddr_t bdaddr;\
\} __attribute__((packed));\
\
#define HCI_EV_LE_META 0x3e\
struct hci_ev_le_meta \{\
	uint8_t subevent;\
\} __attribute__((packed));\
\
#define HCI_EV_LE_CONN_COMPLETE 0x01\
struct hci_ev_le_conn_complete \{\
	uint8_t status;\
	uint16_t handle;\
	uint8_t role;\
	uint8_t bdaddr_type;\
	bdaddr_t bdaddr;\
	uint16_t interval;\
	uint16_t latency;\
	uint16_t supervision_timeout;\
	uint8_t clk_accurancy;\
\} __attribute__((packed));\
\
struct hci_dev_req \{\
	uint16_t dev_id;\
	uint32_t dev_opt;\
\};\
\
struct vhci_vendor_pkt \{\
	uint8_t type;\
	uint8_t opcode;\
	uint16_t id;\
\};\
\
#define HCIDEVUP _IOW('H', 201, int)\
#define HCISETSCAN _IOW('H', 221, int)\
\
static int vhci_fd = -1;\
\
static void rfkill_unblock_all()\
\{\
	int fd = open("/dev/rfkill", O_WRONLY);\
	if (fd < 0)\
	exit(1);\
	struct rfkill_event event = \{0\};\
	event.idx = 0;\
	event.type = RFKILL_TYPE_ALL;\
	event.op = RFKILL_OP_CHANGE_ALL;\
	event.soft = 0;\
	event.hard = 0;\
	if (write(fd, &event, sizeof(event)) < 0)\
	exit(1);\
	close(fd);\
\}\
\
static void hci_send_event_packet(int fd, uint8_t evt, void* data, size_t data_len)\
\{\
	struct iovec iv[3];\
	struct hci_event_hdr hdr;\
	hdr.evt = evt;\
	hdr.plen = data_len;\
	uint8_t type = HCI_EVENT_PKT;\
	iv[0].iov_base = &type;\
	iv[0].iov_len = sizeof(type);\
	iv[1].iov_base = &hdr;\
	iv[1].iov_len = sizeof(hdr);\
	iv[2].iov_base = data;\
	iv[2].iov_len = data_len;\
	if (writev(fd, iv, sizeof(iv) / sizeof(struct iovec)) < 0)\
	exit(1);\
\}\
\
static void hci_send_event_cmd_complete(int fd, uint16_t opcode, void* data, size_t data_len)\
\{\
	struct iovec iv[4];\
	struct hci_event_hdr hdr;\
	hdr.evt = HCI_EV_CMD_COMPLETE;\
	hdr.plen = sizeof(struct hci_ev_cmd_complete) + data_len;\
	struct hci_ev_cmd_complete evt_hdr;\
	evt_hdr.ncmd = 1;\
	evt_hdr.opcode = opcode;\
	uint8_t type = HCI_EVENT_PKT;\
	iv[0].iov_base = &type;\
	iv[0].iov_len = sizeof(type);\
	iv[1].iov_base = &hdr;\
	iv[1].iov_len = sizeof(hdr);\
	iv[2].iov_base = &evt_hdr;\
	iv[2].iov_len = sizeof(evt_hdr);\
	iv[3].iov_base = data;\
	iv[3].iov_len = data_len;\
	if (writev(fd, iv, sizeof(iv) / sizeof(struct iovec)) < 0)\
	exit(1);\
\}\
\
static bool process_command_pkt(int fd, char* buf, ssize_t buf_size)\
\{\
	struct hci_command_hdr* hdr = (struct hci_command_hdr*)buf;\
	if (buf_size < (ssize_t)sizeof(struct hci_command_hdr) ||\
	    hdr->plen != buf_size - sizeof(struct hci_command_hdr))\
	exit(1);\
	switch (hdr->opcode) \{\
	case HCI_OP_WRITE_SCAN_ENABLE: \{\
		uint8_t status = 0;\
		hci_send_event_cmd_complete(fd, hdr->opcode, &status, sizeof(status));\
		return true;\
	\}\
	case HCI_OP_READ_BD_ADDR: \{\
		struct hci_rp_read_bd_addr rp = \{0\};\
		rp.status = 0;\
		memset(&rp.bdaddr, 0xaa, 6);\
		hci_send_event_cmd_complete(fd, hdr->opcode, &rp, sizeof(rp));\
		return false;\
	\}\
	case HCI_OP_READ_BUFFER_SIZE: \{\
		struct hci_rp_read_buffer_size rp = \{0\};\
		rp.status = 0;\
		rp.acl_mtu = 1021;\
		rp.sco_mtu = 96;\
		rp.acl_max_pkt = 4;\
		rp.sco_max_pkt = 6;\
		hci_send_event_cmd_complete(fd, hdr->opcode, &rp, sizeof(rp));\
		return false;\
	\}\
	\}\
	char dummy[0xf9] = \{0\};\
	hci_send_event_cmd_complete(fd, hdr->opcode, dummy, sizeof(dummy));\
	return false;\
\}\
\
static void* event_thread(void* arg)\
\{\
	while (1) \{\
		char buf[1024] = \{0\};\
		ssize_t buf_size = read(vhci_fd, buf, sizeof(buf));\
		if (buf_size < 0)\
	exit(1);\
		if (buf_size > 0 && buf[0] == HCI_COMMAND_PKT) \{\
			if (process_command_pkt(vhci_fd, buf + 1, buf_size - 1))\
				break;\
		\}\
	\}\
	return NULL;\
\}\
#define HCI_HANDLE_1 200\
#define HCI_HANDLE_2 201\
\
static void initialize_vhci()\
\{\
	int hci_sock = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);\
	if (hci_sock < 0)\
	exit(1);\
	vhci_fd = open("/dev/vhci", O_RDWR);\
	if (vhci_fd == -1)\
	exit(1);\
	const int kVhciFd = 202;\
	if (dup2(vhci_fd, kVhciFd) < 0)\
	exit(1);\
	close(vhci_fd);\
	vhci_fd = kVhciFd;\
	struct vhci_vendor_pkt vendor_pkt;\
	if (read(vhci_fd, &vendor_pkt, sizeof(vendor_pkt)) != sizeof(vendor_pkt))\
	exit(1);\
	if (vendor_pkt.type != HCI_VENDOR_PKT)\
	exit(1);\
	pthread_t th;\
	if (pthread_create(&th, NULL, event_thread, NULL))\
	exit(1);\
	int ret = ioctl(hci_sock, HCIDEVUP, vendor_pkt.id);\
	if (ret) \{\
		if (errno == ERFKILL) \{\
			rfkill_unblock_all();\
			ret = ioctl(hci_sock, HCIDEVUP, vendor_pkt.id);\
		\}\
		if (ret && errno != EALREADY)\
	exit(1);\
	\}\
	struct hci_dev_req dr = \{0\};\
	dr.dev_id = vendor_pkt.id;\
	dr.dev_opt = SCAN_PAGE;\
	if (ioctl(hci_sock, HCISETSCAN, &dr))\
	exit(1);\
	struct hci_ev_conn_request request;\
	memset(&request, 0, sizeof(request));\
	memset(&request.bdaddr, 0xaa, 6);\
	*(uint8_t*)&request.bdaddr.b[5] = 0x10;\
	request.link_type = ACL_LINK;\
	hci_send_event_packet(vhci_fd, HCI_EV_CONN_REQUEST, &request, sizeof(request));\
	struct hci_ev_conn_complete complete;\
	memset(&complete, 0, sizeof(complete));\
	complete.status = 0;\
	complete.handle = HCI_HANDLE_1;\
	memset(&complete.bdaddr, 0xaa, 6);\
	*(uint8_t*)&complete.bdaddr.b[5] = 0x10;\
	complete.link_type = ACL_LINK;\
	complete.encr_mode = 0;\
	hci_send_event_packet(vhci_fd, HCI_EV_CONN_COMPLETE, &complete, sizeof(complete));\
	struct hci_ev_remote_features features;\
	memset(&features, 0, sizeof(features));\
	features.status = 0;\
	features.handle = HCI_HANDLE_1;\
	hci_send_event_packet(vhci_fd, HCI_EV_REMOTE_FEATURES, &features, sizeof(features));\
	struct \{\
		struct hci_ev_le_meta le_meta;\
		struct hci_ev_le_conn_complete le_conn;\
	\} le_conn;\
	memset(&le_conn, 0, sizeof(le_conn));\
	le_conn.le_meta.subevent = HCI_EV_LE_CONN_COMPLETE;\
	memset(&le_conn.le_conn.bdaddr, 0xaa, 6);\
	*(uint8_t*)&le_conn.le_conn.bdaddr.b[5] = 0x11;\
	le_conn.le_conn.role = 1;\
	le_conn.le_conn.handle = HCI_HANDLE_2;\
	hci_send_event_packet(vhci_fd, HCI_EV_LE_META, &le_conn, sizeof(le_conn));\
	pthread_join(th, NULL);\
	close(hci_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 = 0;\
	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();\
	initialize_vhci();\
	sandbox_common();\
	drop_caps();\
	initialize_netdevices_init();\
	if (unshare(CLONE_NEWNET)) \{\
	\}\
	initialize_netdevices();\
	setup_binderfs();\
	loop();\
	exit(1);\
\}\
\
static void close_fds()\
\{\
	for (int fd = 3; fd < MAX_FDS; fd++)\
		close(fd);\
\}\
\
static void setup_binfmt_misc()\
\{\
	if (mount(0, "/proc/sys/fs/binfmt_misc", "binfmt_misc", 0, 0)) \{\
	\}\
	write_file("/proc/sys/fs/binfmt_misc/register", ":syz0:M:0:\\x01::./file0:");\
	write_file("/proc/sys/fs/binfmt_misc/register", ":syz1:M:1:\\x02::./file0:POC");\
\}\
\
static void setup_sysctl()\
\{\
	char mypid[32];\
	snprintf(mypid, sizeof(mypid), "%d", getpid());\
	struct \{\
		const char* name;\
		const char* data;\
	\} files[] = \{\
		\{"/sys/kernel/debug/x86/nmi_longest_ns", "10000000000"\},\
		\{"/proc/sys/kernel/hung_task_check_interval_secs", "20"\},\
		\{"/proc/sys/net/core/bpf_jit_kallsyms", "1"\},\
		\{"/proc/sys/net/core/bpf_jit_harden", "0"\},\
		\{"/proc/sys/kernel/kptr_restrict", "0"\},\
		\{"/proc/sys/kernel/softlockup_all_cpu_backtrace", "1"\},\
		\{"/proc/sys/fs/mount-max", "100"\},\
		\{"/proc/sys/vm/oom_dump_tasks", "0"\},\
		\{"/proc/sys/debug/exception-trace", "0"\},\
		\{"/proc/sys/kernel/printk", "7 4 1 3"\},\
		\{"/proc/sys/net/ipv4/ping_group_range", "0 65535"\},\
		\{"/proc/sys/kernel/keys/gc_delay", "1"\},\
		\{"/proc/sys/vm/oom_kill_allocating_task", "1"\},\
		\{"/proc/sys/kernel/ctrl-alt-del", "0"\},\
		\{"/proc/sys/kernel/cad_pid", mypid\},\
	\};\
	for (size_t i = 0; i < sizeof(files) / sizeof(files[0]); i++) \{\
		if (!write_file(files[i].name, files[i].data))\
			printf("write to %s failed: %s\\n", files[i].name, strerror(errno));\
	\}\
\}\
\
uint64_t r[1] = \{0xffffffffffffffff\};\
\
void loop(void)\
\{\
		intptr_t res = 0;\
	res = syscall(__NR_socket, 2ul, 2ul, 0x73);\
	if (res != -1)\
		r[0] = res;\
memcpy((void*)0x20000040, "filter\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000", 32);\
*(uint32_t*)0x20000060 = 6;\
*(uint32_t*)0x20000064 = 0;\
*(uint32_t*)0x20000068 = 0x90;\
*(uint64_t*)0x20000070 = 0;\
*(uint64_t*)0x20000078 = 0x20000400;\
*(uint64_t*)0x20000080 = 0x20000430;\
*(uint64_t*)0x20000088 = 0;\
*(uint64_t*)0x20000090 = 0;\
*(uint64_t*)0x20000098 = 0;\
*(uint32_t*)0x200000a0 = 0;\
*(uint64_t*)0x200000a8 = 0;\
*(uint64_t*)0x200000b0 = 0x20000400;\
*(uint32_t*)0x20000400 = 0;\
memset((void*)0x20000404, 0, 32);\
*(uint32_t*)0x20000424 = 0;\
*(uint32_t*)0x20000428 = -1;\
*(uint32_t*)0x2000042c = 0;\
*(uint32_t*)0x20000430 = 0;\
memset((void*)0x20000434, 0, 32);\
*(uint32_t*)0x20000454 = 0;\
*(uint32_t*)0x20000458 = -1;\
*(uint32_t*)0x2000045c = 0;\
*(uint32_t*)0x20000460 = 0;\
memset((void*)0x20000464, 0, 32);\
*(uint32_t*)0x20000484 = 0;\
*(uint32_t*)0x20000488 = 0xfffffffc;\
*(uint32_t*)0x2000048c = 0;\
	syscall(__NR_setsockopt, r[0], 0, 0x80, 0x20000040ul, 0x108ul);\
	close_fds();\
\}\
int main(void)\
\{\
		syscall(__NR_mmap, 0x1ffff000ul, 0x1000ul, 0ul, 0x32ul, -1, 0ul);\
	syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 7ul, 0x32ul, -1, 0ul);\
	syscall(__NR_mmap, 0x21000000ul, 0x1000ul, 0ul, 0x32ul, -1, 0ul);\
	setup_sysctl();\
	setup_binfmt_misc();\
			do_sandbox_none();\
	return 0;\
\}\
}
diff mbox series

Patch

diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c
index f2dbefb61ce8..d19d439a66c5 100644
--- a/net/bridge/netfilter/ebtables.c
+++ b/net/bridge/netfilter/ebtables.c
@@ -217,6 +217,11 @@  unsigned int ebt_do_table(void *priv, struct sk_buff *skb,
 	else
 		cs = NULL;
 	chaininfo = private->hook_entry[hook];
+	if (!chaininfo) {
+		read_unlock_bh(&table->lock);
+		return NF_DROP;
+	}
+
 	nentries = private->hook_entry[hook]->nentries;
 	point = (struct ebt_entry *)(private->hook_entry[hook]->data);
 	counter_base = cb_base + private->hook_entry[hook]->counter_offset;