// Code generated by gen.go from executor/*.h. DO NOT EDIT.

package csource

var commonHeader = `


#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif

#if GOOS_freebsd || GOOS_test && HOSTGOOS_freebsd
#include <sys/endian.h>
#elif GOOS_darwin
#include <libkern/OSByteOrder.h>
#define htobe16(x) OSSwapHostToBigInt16(x)
#define htobe32(x) OSSwapHostToBigInt32(x)
#define htobe64(x) OSSwapHostToBigInt64(x)
#define le16toh(x) OSSwapLittleToHostInt16(x)
#define htole16(x) OSSwapHostToLittleInt16(x)
#elif GOOS_windows
#define htobe16 _byteswap_ushort
#define htobe32 _byteswap_ulong
#define htobe64 _byteswap_uint64
#define le16toh(x) x
#define htole16(x) x
typedef signed int ssize_t;
#else
#include <endian.h>
#endif
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#if SYZ_TRACE
#include <errno.h>
#endif

#if !SYZ_EXECUTOR
/*{{{SYSCALL_DEFINES}}}*/
#endif

#if SYZ_EXECUTOR && !GOOS_linux
#if !GOOS_windows
#include <unistd.h>
#endif
NORETURN void doexit(int status)
{
	_exit(status);
	for (;;) {
	}
}
#if !GOOS_fuchsia
NORETURN void doexit_thread(int status)
{
	doexit(status);
}
#endif
#endif

#if SYZ_EXECUTOR || SYZ_MULTI_PROC || SYZ_REPEAT && SYZ_CGROUPS ||                      \
    SYZ_NET_DEVICES || __NR_syz_mount_image || __NR_syz_read_part_table ||              \
    __NR_syz_usb_connect || __NR_syz_usb_connect_ath9k || __NR_syz_usbip_server_init || \
    (GOOS_freebsd || GOOS_darwin || GOOS_openbsd || GOOS_netbsd) && SYZ_NET_INJECTION
static unsigned long long procid;
#endif

#if !GOOS_fuchsia && !GOOS_windows
#if SYZ_EXECUTOR || SYZ_HANDLE_SEGV
#include <setjmp.h>
#include <signal.h>
#include <string.h>

#if GOOS_linux
#include <sys/syscall.h>
#endif

static __thread int clone_ongoing;
static __thread int skip_segv;
static __thread jmp_buf segv_env;

#if GOOS_akaros
#include <parlib/parlib.h>
static void recover(void)
{
	_longjmp(segv_env, 1);
}
#endif

static void segv_handler(int sig, siginfo_t* info, void* ctx)
{

	if (__atomic_load_n(&clone_ongoing, __ATOMIC_RELAXED) != 0) {
		doexit_thread(sig);
	}

	uintptr_t addr = (uintptr_t)info->si_addr;
	const uintptr_t prog_start = 1 << 20;
	const uintptr_t prog_end = 100 << 20;
	int skip = __atomic_load_n(&skip_segv, __ATOMIC_RELAXED) != 0;
	int valid = addr < prog_start || addr > prog_end;
#if GOOS_freebsd || (GOOS_test && HOSTGOOS_freebsd)
	if (sig == SIGBUS)
		valid = 1;
#endif
	if (skip && valid) {
		debug("SIGSEGV on %p, skipping\n", (void*)addr);
#if GOOS_akaros
		struct user_context* uctx = (struct user_context*)ctx;
		uctx->tf.hw_tf.tf_rip = (long)(void*)recover;
		return;
#else
		_longjmp(segv_env, 1);
#endif
	}
	debug("SIGSEGV on %p, exiting\n", (void*)addr);
	doexit(sig);
}

static void install_segv_handler(void)
{
	struct sigaction sa;
#if GOOS_linux
	memset(&sa, 0, sizeof(sa));
	sa.sa_handler = SIG_IGN;
	syscall(SYS_rt_sigaction, 0x20, &sa, NULL, 8);
	syscall(SYS_rt_sigaction, 0x21, &sa, NULL, 8);
#endif
	memset(&sa, 0, sizeof(sa));
	sa.sa_sigaction = segv_handler;
	sa.sa_flags = SA_NODEFER | SA_SIGINFO;
	sigaction(SIGSEGV, &sa, NULL);
	sigaction(SIGBUS, &sa, NULL);
}

#define NONFAILING(...)                                              \
	({                                                           \
		int ok = 1;                                          \
		__atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \
		if (_setjmp(segv_env) == 0) {                        \
			__VA_ARGS__;                                 \
		} else                                               \
			ok = 0;                                      \
		__atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \
		ok;                                                  \
	})
#endif
#endif

#if !GOOS_linux
#if (SYZ_EXECUTOR || SYZ_REPEAT) && SYZ_EXECUTOR_USES_FORK_SERVER
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>

static void kill_and_wait(int pid, int* status)
{
	kill(pid, SIGKILL);
	while (waitpid(-1, status, 0) != pid) {
	}
}
#endif
#endif

#if !GOOS_windows
#if SYZ_EXECUTOR || SYZ_THREADED || SYZ_REPEAT && SYZ_EXECUTOR_USES_FORK_SERVER || \
    __NR_syz_usb_connect || __NR_syz_usb_connect_ath9k || __NR_syz_sleep_ms ||     \
    __NR_syz_usb_control_io || __NR_syz_usb_ep_read || __NR_syz_usb_ep_write ||    \
    __NR_syz_usb_disconnect
static void sleep_ms(uint64 ms)
{
	usleep(ms * 1000);
}
#endif

#if SYZ_EXECUTOR || SYZ_THREADED || SYZ_REPEAT && SYZ_EXECUTOR_USES_FORK_SERVER || \
    SYZ_LEAK
#include <time.h>

static uint64 current_time_ms(void)
{
	struct timespec ts;
	if (clock_gettime(CLOCK_MONOTONIC, &ts))
		fail("clock_gettime failed");
	return (uint64)ts.tv_sec * 1000 + (uint64)ts.tv_nsec / 1000000;
}
#endif

#if SYZ_EXECUTOR || SYZ_SANDBOX_ANDROID || SYZ_USE_TMP_DIR
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>

static void use_temporary_dir(void)
{
#if SYZ_SANDBOX_ANDROID
	char tmpdir_template[] = "/data/local/tmp/syzkaller.XXXXXX";
#elif GOOS_fuchsia
	char tmpdir_template[] = "/tmp/syzkaller.XXXXXX";
#else
	char tmpdir_template[] = "./syzkaller.XXXXXX";
#endif
	char* tmpdir = mkdtemp(tmpdir_template);
	if (!tmpdir)
		fail("failed to mkdtemp");
	if (chmod(tmpdir, 0777))
		fail("failed to chmod");
	if (chdir(tmpdir))
		fail("failed to chdir");
}
#endif
#endif

#if GOOS_akaros || GOOS_netbsd || GOOS_freebsd || GOOS_darwin || GOOS_openbsd || GOOS_test
#if (SYZ_EXECUTOR || SYZ_REPEAT) && SYZ_EXECUTOR_USES_FORK_SERVER && (SYZ_EXECUTOR || SYZ_USE_TMP_DIR)
#include <dirent.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>

#if GOOS_freebsd
static void reset_flags(const char* filename)
{
	struct stat st;
	if (lstat(filename, &st))
		exitf("lstat(%s) failed", filename);
	st.st_flags &= ~(SF_NOUNLINK | UF_NOUNLINK | SF_IMMUTABLE | UF_IMMUTABLE | SF_APPEND | UF_APPEND);
	if (lchflags(filename, st.st_flags))
		exitf("lchflags(%s) failed", filename);
}
#endif
static void __attribute__((noinline)) remove_dir(const char* dir)
{
	DIR* dp = opendir(dir);
	if (dp == NULL) {
		if (errno == EACCES) {
			if (rmdir(dir))
				exitf("rmdir(%s) failed", dir);
			return;
		}
		exitf("opendir(%s) failed", dir);
	}
	struct dirent* ep = 0;
	while ((ep = readdir(dp))) {
		if (strcmp(ep->d_name, ".") == 0 || strcmp(ep->d_name, "..") == 0)
			continue;
		char filename[FILENAME_MAX];
		snprintf(filename, sizeof(filename), "%s/%s", dir, ep->d_name);
		struct stat st;
		if (lstat(filename, &st))
			exitf("lstat(%s) failed", filename);
		if (S_ISDIR(st.st_mode)) {
			remove_dir(filename);
			continue;
		}
		if (unlink(filename)) {
#if GOOS_freebsd
			if (errno == EPERM) {
				reset_flags(filename);
				reset_flags(dir);
				if (unlink(filename) == 0)
					continue;
			}
#endif
			exitf("unlink(%s) failed", filename);
		}
	}
	closedir(dp);
	while (rmdir(dir)) {
#if GOOS_freebsd
		if (errno == EPERM) {
			reset_flags(dir);
			if (rmdir(dir) == 0)
				break;
		}
#endif
		exitf("rmdir(%s) failed", dir);
	}
}
#endif
#endif

#if !GOOS_linux && !GOOS_netbsd
#if SYZ_EXECUTOR || SYZ_FAULT
static int inject_fault(int nth)
{
	return 0;
}
#endif

#if SYZ_FAULT
static void setup_fault()
{
}
#endif

#if SYZ_EXECUTOR
static int fault_injected(int fail_fd)
{
	return 0;
}
#endif
#endif

#if !GOOS_windows
#if SYZ_EXECUTOR || SYZ_THREADED
#include <errno.h>
#include <pthread.h>

static void thread_start(void* (*fn)(void*), void* arg)
{
	pthread_t th;
	pthread_attr_t attr;
	pthread_attr_init(&attr);
	pthread_attr_setstacksize(&attr, 128 << 10);
	int i = 0;
	for (; i < 100; i++) {
		if (pthread_create(&th, &attr, fn, arg) == 0) {
			pthread_attr_destroy(&attr);
			return;
		}
		if (errno == EAGAIN) {
			usleep(50);
			continue;
		}
		break;
	}
	exitf("pthread_create failed");
}

#endif
#endif

#if GOOS_freebsd || GOOS_darwin || GOOS_netbsd || GOOS_openbsd || GOOS_akaros || GOOS_test
#if SYZ_EXECUTOR || SYZ_THREADED

#include <pthread.h>
#include <time.h>

typedef struct {
	pthread_mutex_t mu;
	pthread_cond_t cv;
	int state;
} event_t;

static void event_init(event_t* ev)
{
	if (pthread_mutex_init(&ev->mu, 0))
		exitf("pthread_mutex_init failed");
	if (pthread_cond_init(&ev->cv, 0))
		exitf("pthread_cond_init failed");
	ev->state = 0;
}

static void event_reset(event_t* ev)
{
	ev->state = 0;
}

static void event_set(event_t* ev)
{
	pthread_mutex_lock(&ev->mu);
	if (ev->state)
		exitf("event already set");
	ev->state = 1;
	pthread_mutex_unlock(&ev->mu);
	pthread_cond_broadcast(&ev->cv);
}

static void event_wait(event_t* ev)
{
	pthread_mutex_lock(&ev->mu);
	while (!ev->state)
		pthread_cond_wait(&ev->cv, &ev->mu);
	pthread_mutex_unlock(&ev->mu);
}

static int event_isset(event_t* ev)
{
	pthread_mutex_lock(&ev->mu);
	int res = ev->state;
	pthread_mutex_unlock(&ev->mu);
	return res;
}

static int event_timedwait(event_t* ev, uint64 timeout)
{
	uint64 start = current_time_ms();
	uint64 now = start;
	pthread_mutex_lock(&ev->mu);
	for (;;) {
		if (ev->state)
			break;
		uint64 remain = timeout - (now - start);
		struct timespec ts;
		ts.tv_sec = remain / 1000;
		ts.tv_nsec = (remain % 1000) * 1000 * 1000;
		pthread_cond_timedwait(&ev->cv, &ev->mu, &ts);
		now = current_time_ms();
		if (now - start > timeout)
			break;
	}
	int res = ev->state;
	pthread_mutex_unlock(&ev->mu);
	return res;
}
#endif
#endif

#if SYZ_EXECUTOR || SYZ_USE_BITMASKS
#define BITMASK(bf_off, bf_len) (((1ull << (bf_len)) - 1) << (bf_off))
#define STORE_BY_BITMASK(type, htobe, addr, val, bf_off, bf_len)                        \
	*(type*)(addr) = htobe((htobe(*(type*)(addr)) & ~BITMASK((bf_off), (bf_len))) | \
			       (((type)(val) << (bf_off)) & BITMASK((bf_off), (bf_len))))
#endif

#if SYZ_EXECUTOR || SYZ_USE_CHECKSUMS
struct csum_inet {
	uint32 acc;
};

static void csum_inet_init(struct csum_inet* csum)
{
	csum->acc = 0;
}

static void csum_inet_update(struct csum_inet* csum, const uint8* data, size_t length)
{
	if (length == 0)
		return;

	size_t i = 0;
	for (; i < length - 1; i += 2)
		csum->acc += *(uint16*)&data[i];

	if (length & 1)
		csum->acc += le16toh((uint16)data[length - 1]);

	while (csum->acc > 0xffff)
		csum->acc = (csum->acc & 0xffff) + (csum->acc >> 16);
}

static uint16 csum_inet_digest(struct csum_inet* csum)
{
	return ~csum->acc;
}
#endif

#if GOOS_akaros

#include <ros/syscall.h>
#include <stdlib.h>
#include <unistd.h>

#if SYZ_EXECUTOR || SYZ_SANDBOX_NONE
static void loop();
static int do_sandbox_none(void)
{
	loop();
	return 0;
}
#endif

#if SYZ_EXECUTOR || SYZ_REPEAT
static void execute_one();
const char* program_name;

void child()
{
#if SYZ_EXECUTOR || SYZ_HANDLE_SEGV
	install_segv_handler();
#endif
#if SYZ_EXECUTOR
	receive_execute();
	close(kInPipeFd);
#endif
	execute_one();
	doexit(0);
}
#endif

#elif GOOS_freebsd || GOOS_darwin || GOOS_netbsd

#include <unistd.h>

#include <pwd.h>
#include <stdarg.h>
#include <stdbool.h>
#include <string.h>
#include <sys/syscall.h>

#if GOOS_netbsd

#if SYZ_EXECUTOR || __NR_syz_usb_connect || __NR_syz_usb_disconnect

#include <dev/usb/usb.h>
#include <dev/usb/usbhid.h>
#include <dev/usb/vhci.h>
#include <fcntl.h>
#include <sys/ioctl.h>

struct usb_endpoint_descriptor {
	uint8 bLength;
	uint8 bDescriptorType;
	uint8 bEndpointAddress;
	uint8 bmAttributes;
	uint16 wMaxPacketSize;
	uint8 bInterval;
	uint8 bRefresh;
	uint8 bSynchAddress;
} __attribute__((packed));

struct usb_device_descriptor {
	uint8 bLength;
	uint8 bDescriptorType;
	uint16 bcdUSB;
	uint8 bDeviceClass;
	uint8 bDeviceSubClass;
	uint8 bDeviceProtocol;
	uint8 bMaxPacketSize0;
	uint16 idVendor;
	uint16 idProduct;
	uint16 bcdDevice;
	uint8 iManufacturer;
	uint8 iProduct;
	uint8 iSerialNumber;
	uint8 bNumConfigurations;
} __attribute__((packed));

struct usb_config_descriptor {
	uint8 bLength;
	uint8 bDescriptorType;

	uint16 wTotalLength;
	uint8 bNumInterfaces;
	uint8 bConfigurationValue;
	uint8 iConfiguration;
	uint8 bmAttributes;
	uint8 bMaxPower;
} __attribute__((packed));

struct usb_interface_descriptor {
	uint8 bLength;
	uint8 bDescriptorType;
	uint8 bInterfaceNumber;
	uint8 bAlternateSetting;
	uint8 bNumEndpoints;
	uint8 bInterfaceClass;
	uint8 bInterfaceSubClass;
	uint8 bInterfaceProtocol;
	uint8 iInterface;
} __attribute__((packed));

struct usb_ctrlrequest {
	uint8 bRequestType;
	uint8 bRequest;
	uint16 wValue;
	uint16 wIndex;
	uint16 wLength;
} __attribute__((packed));

struct usb_qualifier_descriptor {
	uint8 bLength;
	uint8 bDescriptorType;
	uint16 bcdUSB;
	uint8 bDeviceClass;
	uint8 bDeviceSubClass;
	uint8 bDeviceProtocol;
	uint8 bMaxPacketSize0;
	uint8 bNumConfigurations;
	uint8 bRESERVED;
} __attribute__((packed));

#define USB_TYPE_MASK (0x03 << 5)
#define USB_TYPE_STANDARD (0x00 << 5)
#define USB_TYPE_CLASS (0x01 << 5)
#define USB_TYPE_VENDOR (0x02 << 5)
#define USB_TYPE_RESERVED (0x03 << 5)

#define USB_DT_DEVICE 0x01
#define USB_DT_CONFIG 0x02
#define USB_DT_STRING 0x03
#define USB_DT_INTERFACE 0x04
#define USB_DT_ENDPOINT 0x05
#define USB_DT_DEVICE_QUALIFIER 0x06
#define USB_DT_OTHER_SPEED_CONFIG 0x07
#define USB_DT_INTERFACE_POWER 0x08
#define USB_DT_OTG 0x09
#define USB_DT_DEBUG 0x0a
#define USB_DT_INTERFACE_ASSOCIATION 0x0b
#define USB_DT_SECURITY 0x0c
#define USB_DT_KEY 0x0d
#define USB_DT_ENCRYPTION_TYPE 0x0e
#define USB_DT_BOS 0x0f
#define USB_DT_DEVICE_CAPABILITY 0x10
#define USB_DT_WIRELESS_ENDPOINT_COMP 0x11
#define USB_DT_WIRE_ADAPTER 0x21
#define USB_DT_RPIPE 0x22
#define USB_DT_CS_RADIO_CONTROL 0x23
#define USB_DT_PIPE_USAGE 0x24
#define USB_DT_SS_ENDPOINT_COMP 0x30
#define USB_DT_SSP_ISOC_ENDPOINT_COMP 0x31

#define USB_REQ_GET_STATUS 0x00
#define USB_REQ_CLEAR_FEATURE 0x01
#define USB_REQ_SET_FEATURE 0x03
#define USB_REQ_SET_ADDRESS 0x05
#define USB_REQ_GET_DESCRIPTOR 0x06
#define USB_REQ_SET_DESCRIPTOR 0x07
#define USB_REQ_GET_CONFIGURATION 0x08
#define USB_REQ_SET_CONFIGURATION 0x09
#define USB_REQ_GET_INTERFACE 0x0A
#define USB_REQ_SET_INTERFACE 0x0B
#define USB_REQ_SYNCH_FRAME 0x0C
#define USB_REQ_SET_SEL 0x30
#define USB_REQ_SET_ISOCH_DELAY 0x31

#define USB_REQ_SET_ENCRYPTION 0x0D
#define USB_REQ_GET_ENCRYPTION 0x0E
#define USB_REQ_RPIPE_ABORT 0x0E
#define USB_REQ_SET_HANDSHAKE 0x0F
#define USB_REQ_RPIPE_RESET 0x0F
#define USB_REQ_GET_HANDSHAKE 0x10
#define USB_REQ_SET_CONNECTION 0x11
#define USB_REQ_SET_SECURITY_DATA 0x12
#define USB_REQ_GET_SECURITY_DATA 0x13
#define USB_REQ_SET_WUSB_DATA 0x14
#define USB_REQ_LOOPBACK_DATA_WRITE 0x15
#define USB_REQ_LOOPBACK_DATA_READ 0x16
#define USB_REQ_SET_INTERFACE_DS 0x17

#define USB_REQ_GET_PARTNER_PDO 20
#define USB_REQ_GET_BATTERY_STATUS 21
#define USB_REQ_SET_PDO 22
#define USB_REQ_GET_VDM 23
#define USB_REQ_SEND_VDM 24

#if SYZ_EXECUTOR || __NR_syz_usb_connect

#define USB_MAX_IFACE_NUM 4
#define USB_MAX_EP_NUM 32
#define USB_MAX_FDS 6

struct usb_endpoint_index {
	struct usb_endpoint_descriptor desc;
	int handle;
};

struct usb_iface_index {
	struct usb_interface_descriptor* iface;
	uint8 bInterfaceNumber;
	uint8 bAlternateSetting;
	uint8 bInterfaceClass;
	struct usb_endpoint_index eps[USB_MAX_EP_NUM];
	int eps_num;
};

struct usb_device_index {
	struct usb_device_descriptor* dev;
	struct usb_config_descriptor* config;
	uint8 bDeviceClass;
	uint8 bMaxPower;
	int config_length;
	struct usb_iface_index ifaces[USB_MAX_IFACE_NUM];
	int ifaces_num;
	int iface_cur;
};

struct usb_info {
	int fd;
	struct usb_device_index index;
};

#if SYZ_EXECUTOR || __NR_syz_usb_connect || __NR_syz_usb_connect_ath9k || \
    __NR_syz_usb_control_io || __NR_syz_usb_ep_read || __NR_syz_usb_ep_write
static struct usb_info usb_devices[USB_MAX_FDS];

static struct usb_device_index* lookup_usb_index(int fd)
{
	for (int i = 0; i < USB_MAX_FDS; i++) {
		if (__atomic_load_n(&usb_devices[i].fd, __ATOMIC_ACQUIRE) == fd)
			return &usb_devices[i].index;
	}
	return NULL;
}
#endif

#if SYZ_EXECUTOR || __NR_syz_usb_connect || __NR_syz_usb_connect_ath9k
static int usb_devices_num;

static bool parse_usb_descriptor(const char* buffer, size_t length, struct usb_device_index* index)
{
	if (length < sizeof(*index->dev) + sizeof(*index->config))
		return false;

	memset(index, 0, sizeof(*index));

	index->dev = (struct usb_device_descriptor*)buffer;
	index->config = (struct usb_config_descriptor*)(buffer + sizeof(*index->dev));
	index->bDeviceClass = index->dev->bDeviceClass;
	index->bMaxPower = index->config->bMaxPower;
	index->config_length = length - sizeof(*index->dev);
	index->iface_cur = -1;
	size_t offset = 0;

	while (true) {
		if (offset + 1 >= length)
			break;
		uint8 desc_length = buffer[offset];
		uint8 desc_type = buffer[offset + 1];
		if (desc_length <= 2)
			break;
		if (offset + desc_length > length)
			break;
		if (desc_type == USB_DT_INTERFACE && index->ifaces_num < USB_MAX_IFACE_NUM) {
			struct usb_interface_descriptor* iface = (struct usb_interface_descriptor*)(buffer + offset);
			debug("parse_usb_descriptor: found interface #%u (%d, %d) at %p\n",
			      index->ifaces_num, iface->bInterfaceNumber, iface->bAlternateSetting, iface);
			index->ifaces[index->ifaces_num].iface = iface;
			index->ifaces[index->ifaces_num].bInterfaceNumber = iface->bInterfaceNumber;
			index->ifaces[index->ifaces_num].bAlternateSetting = iface->bAlternateSetting;
			index->ifaces[index->ifaces_num].bInterfaceClass = iface->bInterfaceClass;
			index->ifaces_num++;
		}
		if (desc_type == USB_DT_ENDPOINT && index->ifaces_num > 0) {
			struct usb_iface_index* iface = &index->ifaces[index->ifaces_num - 1];
			debug("parse_usb_descriptor: found endpoint #%u at %p\n", iface->eps_num, buffer + offset);
			if (iface->eps_num < USB_MAX_EP_NUM) {
				memcpy(&iface->eps[iface->eps_num].desc, buffer + offset, sizeof(iface->eps[iface->eps_num].desc));
				iface->eps_num++;
			}
		}
		offset += desc_length;
	}

	return true;
}

static struct usb_device_index* add_usb_index(int fd, const char* dev, size_t dev_len)
{
	int i = __atomic_fetch_add(&usb_devices_num, 1, __ATOMIC_RELAXED);
	if (i >= USB_MAX_FDS)
		return NULL;

	if (!parse_usb_descriptor(dev, dev_len, &usb_devices[i].index))
		return NULL;

	__atomic_store_n(&usb_devices[i].fd, fd, __ATOMIC_RELEASE);
	return &usb_devices[i].index;
}

#endif

#if USB_DEBUG

#include <linux/hid.h>
#include <linux/usb/audio.h>
#include <linux/usb/cdc.h>
#include <linux/usb/ch11.h>
#include <linux/usb/ch9.h>
#define USBLP_REQ_GET_ID 0x00
#define USBLP_REQ_GET_STATUS 0x01
#define USBLP_REQ_RESET 0x02

const char* usb_class_to_string(unsigned value)
{
	switch (value) {
	case USB_CLASS_PER_INTERFACE:
		return "USB_CLASS_PER_INTERFACE";
	case USB_CLASS_AUDIO:
		return "USB_CLASS_AUDIO";
	case USB_CLASS_COMM:
		return "USB_CLASS_COMM";
	case USB_CLASS_HID:
		return "USB_CLASS_HID";
	case USB_CLASS_PHYSICAL:
		return "USB_CLASS_PHYSICAL";
	case USB_CLASS_STILL_IMAGE:
		return "USB_CLASS_STILL_IMAGE";
	case USB_CLASS_PRINTER:
		return "USB_CLASS_PRINTER";
	case USB_CLASS_MASS_STORAGE:
		return "USB_CLASS_MASS_STORAGE";
	case USB_CLASS_HUB:
		return "USB_CLASS_HUB";
	case USB_CLASS_CDC_DATA:
		return "USB_CLASS_CDC_DATA";
	case USB_CLASS_CSCID:
		return "USB_CLASS_CSCID";
	case USB_CLASS_CONTENT_SEC:
		return "USB_CLASS_CONTENT_SEC";
	case USB_CLASS_VIDEO:
		return "USB_CLASS_VIDEO";
	case USB_CLASS_WIRELESS_CONTROLLER:
		return "USB_CLASS_WIRELESS_CONTROLLER";
	case USB_CLASS_MISC:
		return "USB_CLASS_MISC";
	case USB_CLASS_APP_SPEC:
		return "USB_CLASS_APP_SPEC";
	case USB_CLASS_VENDOR_SPEC:
		return "USB_CLASS_VENDOR_SPEC";
	}
	return "unknown";
}
static void analyze_usb_device(struct usb_device_index* index)
{
	debug("analyze_usb_device: idVendor = %04x\n", (unsigned)index->dev->idVendor);
	debug("analyze_usb_device: idProduct = %04x\n", (unsigned)index->dev->idProduct);

	debug("analyze_usb_device: bDeviceClass = %x (%s)\n", (unsigned)index->dev->bDeviceClass,
	      usb_class_to_string(index->dev->bDeviceClass));
	debug("analyze_usb_device: bDeviceSubClass = %x\n", (unsigned)index->dev->bDeviceSubClass);
	debug("analyze_usb_device: bDeviceProtocol = %x\n", (unsigned)index->dev->bDeviceProtocol);

	for (int i = 0; i < index->ifaces_num; i++) {
		struct usb_interface_descriptor* iface = index->ifaces[i].iface;
		debug("analyze_usb_device: interface #%d:\n", i);
		debug("analyze_usb_device: bInterfaceClass = %x (%s)\n", (unsigned)iface->bInterfaceClass,
		      usb_class_to_string(iface->bInterfaceClass));
		debug("analyze_usb_device: bInterfaceSubClass = %x\n", (unsigned)iface->bInterfaceSubClass);
		debug("analyze_usb_device: bInterfaceProtocol = %x\n", (unsigned)iface->bInterfaceProtocol);
	}
}

static bool analyze_control_request_standard(struct usb_device_index* index, struct usb_ctrlrequest* ctrl)
{
	uint8 bDeviceClass = index->bDeviceClass;
	uint8 bInterfaceClass = index->ifaces[index->iface_cur].bInterfaceClass;
	if (bDeviceClass == USB_CLASS_HID || bInterfaceClass == USB_CLASS_HID) {
		switch (ctrl->bRequest) {
		case USB_REQ_GET_DESCRIPTOR:
			debug("analyze_control_request: req = USB_REQ_GET_DESCRIPTOR\n");
			switch (ctrl->wValue >> 8) {
			case HID_DT_HID:
				debug("analyze_control_request: desc = HID_DT_HID\n");
				return true;
			case HID_DT_REPORT:
				debug("analyze_control_request: desc = HID_DT_REPORT\n");
				return true;
			case HID_DT_PHYSICAL:
				debug("analyze_control_request: desc = HID_DT_PHYSICAL\n");
				return false;
			}
		}
	}

	switch (ctrl->bRequest) {
	case USB_REQ_GET_DESCRIPTOR:
		debug("analyze_control_request: req = USB_REQ_GET_DESCRIPTOR\n");
		switch (ctrl->wValue >> 8) {
		case USB_DT_DEVICE:
			debug("analyze_control_request: desc = USB_DT_DEVICE\n");
			return true;
		case USB_DT_CONFIG:
			debug("analyze_control_request: desc = USB_DT_CONFIG, index = %d\n", (int)(ctrl->wValue & 0xff));
			return true;
		case USB_DT_STRING:
			debug("analyze_control_request: desc = USB_DT_STRING\n");
			return true;
		case USB_DT_INTERFACE:
			debug("analyze_control_request: desc = USB_DT_INTERFACE\n");
			break;
		case USB_DT_ENDPOINT:
			debug("analyze_control_request: desc = USB_DT_ENDPOINT\n");
			break;
		case USB_DT_DEVICE_QUALIFIER:
			debug("analyze_control_request: desc = USB_DT_DEVICE_QUALIFIER\n");
			return true;
		case USB_DT_OTHER_SPEED_CONFIG:
			debug("analyze_control_request: desc = USB_DT_OTHER_SPEED_CONFIG\n");
			break;
		case USB_DT_INTERFACE_POWER:
			debug("analyze_control_request: desc = USB_DT_INTERFACE_POWER\n");
			break;
		case USB_DT_OTG:
			debug("analyze_control_request: desc = USB_DT_OTG\n");
			break;
		case USB_DT_DEBUG:
			debug("analyze_control_request: desc = USB_DT_DEBUG\n");
			break;
		case USB_DT_INTERFACE_ASSOCIATION:
			debug("analyze_control_request: desc = USB_DT_INTERFACE_ASSOCIATION\n");
			break;
		case USB_DT_SECURITY:
			debug("analyze_control_request: desc = USB_DT_SECURITY\n");
			break;
		case USB_DT_KEY:
			debug("analyze_control_request: desc = USB_DT_KEY\n");
			break;
		case USB_DT_ENCRYPTION_TYPE:
			debug("analyze_control_request: desc = USB_DT_ENCRYPTION_TYPE\n");
			break;
		case USB_DT_BOS:
			debug("analyze_control_request: desc = USB_DT_BOS\n");
			return true;
		case USB_DT_DEVICE_CAPABILITY:
			debug("analyze_control_request: desc = USB_DT_DEVICE_CAPABILITY\n");
			break;
		case USB_DT_WIRELESS_ENDPOINT_COMP:
			debug("analyze_control_request: desc = USB_DT_WIRELESS_ENDPOINT_COMP\n");
			break;
		case USB_DT_WIRE_ADAPTER:
			debug("analyze_control_request: desc = USB_DT_WIRE_ADAPTER\n");
			break;
		case USB_DT_RPIPE:
			debug("analyze_control_request: desc = USB_DT_RPIPE\n");
			break;
		case USB_DT_CS_RADIO_CONTROL:
			debug("analyze_control_request: desc = USB_DT_CS_RADIO_CONTROL\n");
			break;
		case USB_DT_PIPE_USAGE:
			debug("analyze_control_request: desc = USB_DT_PIPE_USAGE\n");
			break;
		case USB_DT_SS_ENDPOINT_COMP:
			debug("analyze_control_request: desc = USB_DT_SS_ENDPOINT_COMP\n");
			break;
		case USB_DT_SSP_ISOC_ENDPOINT_COMP:
			debug("analyze_control_request: desc = USB_DT_SSP_ISOC_ENDPOINT_COMP\n");
			break;
		default:
			debug("analyze_control_request: desc = unknown = 0x%x\n", (int)(ctrl->wValue >> 8));
			break;
		}
		break;
	case USB_REQ_GET_STATUS:
		debug("analyze_control_request: req = USB_REQ_GET_STATUS\n");
		break;
	case USB_REQ_CLEAR_FEATURE:
		debug("analyze_control_request: req = USB_REQ_CLEAR_FEATURE\n");
		break;
	case USB_REQ_SET_FEATURE:
		debug("analyze_control_request: req = USB_REQ_SET_FEATURE\n");
		break;
	case USB_REQ_GET_CONFIGURATION:
		debug("analyze_control_request: req = USB_REQ_GET_CONFIGURATION\n");
		return true;
	case USB_REQ_SET_CONFIGURATION:
		debug("analyze_control_request: req = USB_REQ_SET_CONFIGURATION\n");
		break;
	case USB_REQ_GET_INTERFACE:
		debug("analyze_control_request: req = USB_REQ_GET_INTERFACE\n");
		return true;
	case USB_REQ_SET_INTERFACE:
		debug("analyze_control_request: req = USB_REQ_SET_INTERFACE\n");
		break;
	default:
		debug("analyze_control_request: req = unknown = 0x%x\n", (int)ctrl->bRequest);
		break;
	}

	return false;
}

static bool analyze_control_request_class(struct usb_device_index* index, struct usb_ctrlrequest* ctrl)
{
	uint8 bDeviceClass = index->bDeviceClass;
	uint8 bInterfaceClass = index->ifaces[index->iface_cur].bInterfaceClass;

	if (bDeviceClass == USB_CLASS_HID || bInterfaceClass == USB_CLASS_HID) {
		switch (ctrl->bRequest) {
		case HID_REQ_GET_REPORT:
			debug("analyze_control_request: req = HID_REQ_GET_REPORT\n");
			return true;
		case HID_REQ_GET_IDLE:
			debug("analyze_control_request: req = HID_REQ_GET_IDLE\n");
			break;
		case HID_REQ_GET_PROTOCOL:
			debug("analyze_control_request: req = HID_REQ_GET_PROTOCOL\n");
			return true;
		case HID_REQ_SET_REPORT:
			debug("analyze_control_request: req = HID_REQ_SET_REPORT\n");
			break;
		case HID_REQ_SET_IDLE:
			debug("analyze_control_request: req = HID_REQ_SET_IDLE\n");
			break;
		case HID_REQ_SET_PROTOCOL:
			debug("analyze_control_request: req = HID_REQ_SET_PROTOCOL\n");
			break;
		}
	}

	if (bDeviceClass == USB_CLASS_AUDIO || bInterfaceClass == USB_CLASS_AUDIO) {
		switch (ctrl->bRequest) {
		case UAC_SET_CUR:
			debug("analyze_control_request: req = UAC_SET_CUR\n");
			break;
		case UAC_GET_CUR:
			debug("analyze_control_request: req = UAC_GET_CUR\n");
			return true;
		case UAC_SET_MIN:
			debug("analyze_control_request: req = UAC_SET_MIN\n");
			break;
		case UAC_GET_MIN:
			debug("analyze_control_request: req = UAC_GET_MIN\n");
			return true;
		case UAC_SET_MAX:
			debug("analyze_control_request: req = UAC_SET_MAX\n");
			break;
		case UAC_GET_MAX:
			debug("analyze_control_request: req = UAC_GET_MAX\n");
			return true;
		case UAC_SET_RES:
			debug("analyze_control_request: req = UAC_SET_RES\n");
			break;
		case UAC_GET_RES:
			debug("analyze_control_request: req = UAC_GET_RES\n");
			return true;
		case UAC_SET_MEM:
			debug("analyze_control_request: req = UAC_SET_MEM\n");
			break;
		case UAC_GET_MEM:
			debug("analyze_control_request: req = UAC_GET_MEM\n");
			return true;
		}
	}

	if (bDeviceClass == USB_CLASS_PRINTER || bInterfaceClass == USB_CLASS_PRINTER) {
		switch (ctrl->bRequest) {
		case USBLP_REQ_GET_ID:
			debug("analyze_control_request: req = USBLP_REQ_GET_ID\n");
			return true;
		case USBLP_REQ_GET_STATUS:
			debug("analyze_control_request: req = USBLP_REQ_GET_STATUS\n");
			return true;
		case USBLP_REQ_RESET:
			debug("analyze_control_request: req = USBLP_REQ_RESET\n");
			break;
		}
	}

	if (bDeviceClass == USB_CLASS_HUB || bInterfaceClass == USB_CLASS_HUB) {
		switch (ctrl->bRequest) {
		case USB_REQ_GET_DESCRIPTOR:
			switch (ctrl->wValue >> 8) {
			case USB_DT_HUB:
				debug("analyze_control_request: desc = USB_DT_HUB\n");
				return true;
			case USB_DT_SS_HUB:
				debug("analyze_control_request: desc = USB_DT_SS_HUB\n");
				return true;
			}
		case USB_REQ_GET_STATUS:
			debug("analyze_control_request: req = USB_REQ_GET_STATUS\n");
			return true;
		case HUB_SET_DEPTH:
			debug("analyze_control_request: req = HUB_SET_DEPTH\n");
			break;
		}
	}

	if (bInterfaceClass == USB_CLASS_COMM) {
		switch (ctrl->bRequest) {
		case USB_CDC_SEND_ENCAPSULATED_COMMAND:
			debug("analyze_control_request: req = USB_CDC_SEND_ENCAPSULATED_COMMAND\n");
			break;
		case USB_CDC_GET_ENCAPSULATED_RESPONSE:
			debug("analyze_control_request: req = USB_CDC_GET_ENCAPSULATED_RESPONSE\n");
			break;
		case USB_CDC_REQ_SET_LINE_CODING:
			debug("analyze_control_request: req = USB_CDC_REQ_SET_LINE_CODING\n");
			break;
		case USB_CDC_REQ_GET_LINE_CODING:
			debug("analyze_control_request: req = USB_CDC_REQ_GET_LINE_CODING\n");
			break;
		case USB_CDC_REQ_SET_CONTROL_LINE_STATE:
			debug("analyze_control_request: req = USB_CDC_REQ_SET_CONTROL_LINE_STATE\n");
			break;
		case USB_CDC_REQ_SEND_BREAK:
			debug("analyze_control_request: req = USB_CDC_REQ_SEND_BREAK\n");
			break;
		case USB_CDC_SET_ETHERNET_MULTICAST_FILTERS:
			debug("analyze_control_request: req = USB_CDC_SET_ETHERNET_MULTICAST_FILTERS\n");
			break;
		case USB_CDC_SET_ETHERNET_PM_PATTERN_FILTER:
			debug("analyze_control_request: req = USB_CDC_SET_ETHERNET_PM_PATTERN_FILTER\n");
			break;
		case USB_CDC_GET_ETHERNET_PM_PATTERN_FILTER:
			debug("analyze_control_request: req = USB_CDC_GET_ETHERNET_PM_PATTERN_FILTER\n");
			break;
		case USB_CDC_SET_ETHERNET_PACKET_FILTER:
			debug("analyze_control_request: req = USB_CDC_SET_ETHERNET_PACKET_FILTER\n");
			break;
		case USB_CDC_GET_ETHERNET_STATISTIC:
			debug("analyze_control_request: req = USB_CDC_GET_ETHERNET_STATISTIC\n");
			break;
		case USB_CDC_GET_NTB_PARAMETERS:
			debug("analyze_control_request: req = USB_CDC_GET_NTB_PARAMETERS\n");
			return true;
		case USB_CDC_GET_NET_ADDRESS:
			debug("analyze_control_request: req = USB_CDC_GET_NET_ADDRESS\n");
			break;
		case USB_CDC_SET_NET_ADDRESS:
			debug("analyze_control_request: req = USB_CDC_SET_NET_ADDRESS\n");
			break;
		case USB_CDC_GET_NTB_FORMAT:
			debug("analyze_control_request: req = USB_CDC_GET_NTB_FORMAT\n");
			return true;
		case USB_CDC_SET_NTB_FORMAT:
			debug("analyze_control_request: req = USB_CDC_SET_NTB_FORMAT\n");
			break;
		case USB_CDC_GET_NTB_INPUT_SIZE:
			debug("analyze_control_request: req = USB_CDC_GET_NTB_INPUT_SIZE\n");
			return true;
		case USB_CDC_SET_NTB_INPUT_SIZE:
			debug("analyze_control_request: req = USB_CDC_SET_NTB_INPUT_SIZE\n");
			break;
		case USB_CDC_GET_MAX_DATAGRAM_SIZE:
			debug("analyze_control_request: req = USB_CDC_GET_MAX_DATAGRAM_SIZE\n");
			return true;
		case USB_CDC_SET_MAX_DATAGRAM_SIZE:
			debug("analyze_control_request: req = USB_CDC_SET_MAX_DATAGRAM_SIZE\n");
			break;
		case USB_CDC_GET_CRC_MODE:
			debug("analyze_control_request: req = USB_CDC_GET_CRC_MODE\n");
			return true;
		case USB_CDC_SET_CRC_MODE:
			debug("analyze_control_request: req = USB_CDC_SET_CRC_MODE\n");
			break;
		}
	}

	return false;
}

static bool analyze_control_request_vendor(struct usb_device_index* index, struct usb_ctrlrequest* ctrl)
{
	return true;
}
static void analyze_control_request(int fd, struct usb_ctrlrequest* ctrl)
{
	struct usb_device_index* index = lookup_usb_index(fd);

	if (!index)
		return;

	switch (ctrl->bRequestType & USB_TYPE_MASK) {
	case USB_TYPE_STANDARD:
		debug("analyze_control_request: type = USB_TYPE_STANDARD\n");
		if (analyze_control_request_standard(index, ctrl))
			return;
		break;
	case USB_TYPE_CLASS:
		debug("analyze_control_request: type = USB_TYPE_CLASS\n");
		if (analyze_control_request_class(index, ctrl))
			return;
		break;
	case USB_TYPE_VENDOR:
		debug("analyze_control_request: type = USB_TYPE_VENDOR\n");
		if (analyze_control_request_vendor(index, ctrl))
			return;
		break;
	}

	if (ctrl->bRequestType & USB_DIR_IN) {
		char message[128];
		debug("analyze_control_request: unknown control request\n");
		snprintf(&message[0], sizeof(message), "BUG: unknown control request (0x%x, 0x%x, 0x%x, 0x%x, %d)",
			 ctrl->bRequestType, ctrl->bRequest, ctrl->wValue, ctrl->wIndex, ctrl->wLength);
		write_file("/dev/kmsg", &message[0]);
	}
}

#endif

struct vusb_connect_string_descriptor {
	uint32 len;
	char* str;
} __attribute__((packed));

struct vusb_connect_descriptors {
	uint32 qual_len;
	char* qual;
	uint32 bos_len;
	char* bos;
	uint32 strs_len;
	struct vusb_connect_string_descriptor strs[0];
} __attribute__((packed));

#if SYZ_EXECUTOR || __NR_syz_usb_connect || __NR_syz_usb_connect_ath9k

static const char default_string[] = {
    8, USB_DT_STRING,
    's', 0, 'y', 0, 'z', 0
};

static const char default_lang_id[] = {
    4, USB_DT_STRING,
    0x09, 0x04
};

static bool lookup_connect_response_in(int fd, const struct vusb_connect_descriptors* descs,
				       const struct usb_ctrlrequest* ctrl,
				       struct usb_qualifier_descriptor* qual,
				       char** response_data, uint32* response_length)
{
	struct usb_device_index* index = lookup_usb_index(fd);
	uint8 str_idx;

	if (!index)
		return false;

	switch (ctrl->bRequestType & USB_TYPE_MASK) {
	case USB_TYPE_STANDARD:
		switch (ctrl->bRequest) {
		case USB_REQ_GET_DESCRIPTOR:
			switch (ctrl->wValue >> 8) {
			case USB_DT_DEVICE:
				*response_data = (char*)index->dev;
				*response_length = sizeof(*index->dev);
				return true;
			case USB_DT_CONFIG:
				*response_data = (char*)index->config;
				*response_length = index->config_length;
				return true;
			case USB_DT_STRING:
				str_idx = (uint8)ctrl->wValue;
				if (descs && str_idx < descs->strs_len) {
					*response_data = descs->strs[str_idx].str;
					*response_length = descs->strs[str_idx].len;
					return true;
				}
				if (str_idx == 0) {
					*response_data = (char*)&default_lang_id[0];
					*response_length = default_lang_id[0];
					return true;
				}
				*response_data = (char*)&default_string[0];
				*response_length = default_string[0];
				return true;
			case USB_DT_BOS:
				*response_data = descs->bos;
				*response_length = descs->bos_len;
				return true;
			case USB_DT_DEVICE_QUALIFIER:
				if (!descs->qual) {
					qual->bLength = sizeof(*qual);
					qual->bDescriptorType = USB_DT_DEVICE_QUALIFIER;
					qual->bcdUSB = index->dev->bcdUSB;
					qual->bDeviceClass = index->dev->bDeviceClass;
					qual->bDeviceSubClass = index->dev->bDeviceSubClass;
					qual->bDeviceProtocol = index->dev->bDeviceProtocol;
					qual->bMaxPacketSize0 = index->dev->bMaxPacketSize0;
					qual->bNumConfigurations = index->dev->bNumConfigurations;
					qual->bRESERVED = 0;
					*response_data = (char*)qual;
					*response_length = sizeof(*qual);
					return true;
				}
				*response_data = descs->qual;
				*response_length = descs->qual_len;
				return true;
			default:
				break;
			}
			break;
		default:
			break;
		}
		break;
	default:
		break;
	}

	debug("lookup_connect_response_in: unknown request");
	return false;
}

#endif

typedef bool (*lookup_connect_out_response_t)(int fd, const struct vusb_connect_descriptors* descs,
					      const struct usb_ctrlrequest* ctrl, bool* done);

#if SYZ_EXECUTOR || __NR_syz_usb_connect
static bool lookup_connect_response_out_generic(int fd, const struct vusb_connect_descriptors* descs,
						const struct usb_ctrlrequest* ctrl, bool* done)
{
	switch (ctrl->bRequestType & USB_TYPE_MASK) {
	case USB_TYPE_STANDARD:
		switch (ctrl->bRequest) {
		case USB_REQ_SET_CONFIGURATION:
			*done = true;
			return true;
		default:
			break;
		}
		break;
	}

	debug("lookup_connect_response_out: unknown request");
	return false;
}
#endif

#if GOOS_linux && (SYZ_EXECUTOR || __NR_syz_usb_connect_ath9k)
#define ATH9K_FIRMWARE_DOWNLOAD 0x30
#define ATH9K_FIRMWARE_DOWNLOAD_COMP 0x31

static bool lookup_connect_response_out_ath9k(int fd, const struct vusb_connect_descriptors* descs,
					      const struct usb_ctrlrequest* ctrl, bool* done)
{
	switch (ctrl->bRequestType & USB_TYPE_MASK) {
	case USB_TYPE_STANDARD:
		switch (ctrl->bRequest) {
		case USB_REQ_SET_CONFIGURATION:
			return true;
		default:
			break;
		}
		break;
	case USB_TYPE_VENDOR:
		switch (ctrl->bRequest) {
		case ATH9K_FIRMWARE_DOWNLOAD:
			return true;
		case ATH9K_FIRMWARE_DOWNLOAD_COMP:
			*done = true;
			return true;
		default:
			break;
		}
		break;
	}

	debug("lookup_connect_response_out_ath9k: unknown request");
	return false;
}

#endif

#if GOOS_linux && (SYZ_EXECUTOR || __NR_syz_usb_control_io)

struct vusb_descriptor {
	uint8 req_type;
	uint8 desc_type;
	uint32 len;
	char data[0];
} __attribute__((packed));

struct vusb_descriptors {
	uint32 len;
	struct vusb_descriptor* generic;
	struct vusb_descriptor* descs[0];
} __attribute__((packed));

struct vusb_response {
	uint8 type;
	uint8 req;
	uint32 len;
	char data[0];
} __attribute__((packed));

struct vusb_responses {
	uint32 len;
	struct vusb_response* generic;
	struct vusb_response* resps[0];
} __attribute__((packed));

static bool lookup_control_response(const struct vusb_descriptors* descs, const struct vusb_responses* resps,
				    struct usb_ctrlrequest* ctrl, char** response_data, uint32* response_length)
{
	int descs_num = 0;
	int resps_num = 0;

	if (descs)
		descs_num = (descs->len - offsetof(struct vusb_descriptors, descs)) / sizeof(descs->descs[0]);
	if (resps)
		resps_num = (resps->len - offsetof(struct vusb_responses, resps)) / sizeof(resps->resps[0]);

	uint8 req = ctrl->bRequest;
	uint8 req_type = ctrl->bRequestType & USB_TYPE_MASK;
	uint8 desc_type = ctrl->wValue >> 8;

	if (req == USB_REQ_GET_DESCRIPTOR) {
		int i;

		for (i = 0; i < descs_num; i++) {
			struct vusb_descriptor* desc = descs->descs[i];
			if (!desc)
				continue;
			if (desc->req_type == req_type && desc->desc_type == desc_type) {
				*response_length = desc->len;
				if (*response_length != 0)
					*response_data = &desc->data[0];
				else
					*response_data = NULL;
				return true;
			}
		}

		if (descs && descs->generic) {
			*response_data = &descs->generic->data[0];
			*response_length = descs->generic->len;
			return true;
		}
	} else {
		int i;

		for (i = 0; i < resps_num; i++) {
			struct vusb_response* resp = resps->resps[i];
			if (!resp)
				continue;
			if (resp->type == req_type && resp->req == req) {
				*response_length = resp->len;
				if (*response_length != 0)
					*response_data = &resp->data[0];
				else
					*response_data = NULL;
				return true;
			}
		}

		if (resps && resps->generic) {
			*response_data = &resps->generic->data[0];
			*response_length = resps->generic->len;
			return true;
		}
	}

	return false;
}

#endif


static int vhci_open(void)
{
	char path[1024];

	snprintf(path, sizeof(path), "/dev/vhci%llu", procid);

	return open(path, O_RDWR);
}

static int vhci_setport(int fd, u_int port)
{
	struct vhci_ioc_set_port args;

	args.port = port;
	return ioctl(fd, VHCI_IOC_SET_PORT, &args);
}

static int vhci_usb_attach(int fd)
{
	return ioctl(fd, VHCI_IOC_USB_ATTACH, NULL);
}

static int vhci_usb_recv(int fd, void* buf, size_t size)
{
	uint8* ptr = (uint8*)buf;

	while (1) {
		ssize_t done = read(fd, ptr, size);
		if (done < 0)
			return -1;
		if ((size_t)done == size)
			return 0;
		size -= done;
		ptr += done;
	}
}

static int vhci_usb_send(int fd, void* buf, size_t size)
{
	uint8* ptr = (uint8*)buf;

	while (1) {
		ssize_t done = write(fd, ptr, size);
		if (done <= 0)
			return -1;
		if ((size_t)done == size)
			return 0;
		size -= done;
		ptr += done;
	}
}

static volatile long syz_usb_connect_impl(int fd, uint64 speed, uint64 dev_len,
					  const char* dev, const struct vusb_connect_descriptors* descs,
					  lookup_connect_out_response_t lookup_connect_response_out)
{
	struct usb_device_index* index = add_usb_index(fd, dev, dev_len);
	if (!index) {
		debug("syz_usb_connect: add_usb_index failed\n");
		return -1;
	}
	debug("syz_usb_connect: add_usb_index success\n");

#if USB_DEBUG
	analyze_usb_device(index);
#endif

	if (vhci_setport(fd, 1))
		fail("syz_usb_connect: vhci_setport failed with");

	if (vhci_usb_attach(fd)) {
		debug("syz_usb_connect: vhci_usb_attach failed with %d\n", errno);
		return -1;
	}
	debug("syz_usb_connect: vhci_usb_attach success\n");

	bool done = false;
	while (!done) {
		vhci_request_t req;

		if (vhci_usb_recv(fd, &req, sizeof(req))) {
			debug("syz_usb_connect: vhci_usb_recv failed with %d\n", errno);
			return -1;
		}
		if (req.type != VHCI_REQ_CTRL) {
			debug("syz_usb_connect: received non-control transfer\n");
			return -1;
		}

		debug("syz_usb_connect: bReqType: 0x%x (%s), bReq: 0x%x, wVal: 0x%x, wIdx: 0x%x, wLen: %d\n",
		      req.u.ctrl.bmRequestType, (req.u.ctrl.bmRequestType & UE_DIR_IN) ? "IN" : "OUT",
		      req.u.ctrl.bRequest, UGETW(req.u.ctrl.wValue), UGETW(req.u.ctrl.wIndex), UGETW(req.u.ctrl.wLength));

#if USB_DEBUG
		analyze_control_request(fd, &req.u.ctrl);
#endif

		char* response_data = NULL;
		uint32 response_length = 0;
		struct usb_qualifier_descriptor qual;
		char data[4096];

		if (req.u.ctrl.bmRequestType & UE_DIR_IN) {
			if (!lookup_connect_response_in(fd, descs, (const struct usb_ctrlrequest*)&req.u.ctrl, &qual, &response_data, &response_length)) {
				debug("syz_usb_connect: unknown control IN request\n");
				return -1;
			}
		} else {
			if (!lookup_connect_response_out(fd, descs, (const struct usb_ctrlrequest*)&req.u.ctrl, &done)) {
				debug("syz_usb_connect: unknown control OUT request\n");
				return -1;
			}
			response_data = NULL;
			response_length = UGETW(req.u.ctrl.wLength);
		}

		if ((req.u.ctrl.bmRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD &&
		    req.u.ctrl.bRequest == USB_REQ_SET_CONFIGURATION) {
		}

		if (response_length > sizeof(data))
			response_length = 0;
		if ((uint32)UGETW(req.u.ctrl.wLength) < response_length)
			response_length = UGETW(req.u.ctrl.wLength);

		if (response_data)
			memcpy(data, response_data, response_length);
		else
			memset(data, 0, response_length);

		int rv = 0;
		if (req.u.ctrl.bmRequestType & UE_DIR_IN) {
			debug("syz_usb_connect: writing %d bytes\n", response_length);
			if (response_length > 0) {
				vhci_response_t res;
				res.size = response_length;
				rv = vhci_usb_send(fd, &res, sizeof(res));
				if (rv == 0)
					rv = vhci_usb_send(fd, data, response_length);
			}
		} else {
			rv = vhci_usb_recv(fd, data, response_length);
			debug("syz_usb_connect: read %d bytes\n", response_length);
			debug_dump_data(&data[0], response_length);
		}
		if (rv < 0) {
			debug("syz_usb_connect: usb_raw_ep0_read/write failed with %d\n", rv);
			return -1;
		}
	}

	sleep_ms(200);
	debug("syz_usb_connect: configured\n");
	return fd;
}

static volatile long syz_usb_connect(volatile long a0, volatile long a1,
				     volatile long a2, volatile long a3)
{
	uint64 speed = a0;
	uint64 dev_len = a1;
	const char* dev = (const char*)a2;
	const struct vusb_connect_descriptors* descs = (const struct vusb_connect_descriptors*)a3;

	debug("syz_usb_connect: dev: %p\n", dev);
	if (!dev) {
		debug("syz_usb_connect: dev is null\n");
		return -1;
	}

	debug("syz_usb_connect: device data:\n");
	debug_dump_data(dev, dev_len);

	int fd = vhci_open();
	if (fd < 0)
		fail("syz_usb_connect: vhci_open failed");
	long res = syz_usb_connect_impl(fd, speed, dev_len, dev, descs, &lookup_connect_response_out_generic);
	close(fd);
	return res;
}
#endif

#if SYZ_EXECUTOR || __NR_syz_usb_disconnect
static volatile long syz_usb_disconnect(volatile long a0)
{
	int fd = a0;

	int rv = close(fd);

	sleep_ms(200);

	return rv;
}
#endif

#endif
#if SYZ_EXECUTOR || SYZ_USB
#include <dirent.h>
static void setup_usb(void)
{
	DIR* dir = opendir("/dev");
	if (dir == NULL)
		fail("failed to open /dev");

	struct dirent* ent = NULL;
	while ((ent = readdir(dir)) != NULL) {
		if (ent->d_type != DT_CHR)
			continue;
		if (strncmp(ent->d_name, "vhci", 4))
			continue;
		char path[1024];
		snprintf(path, sizeof(path), "/dev/%s", ent->d_name);
		if (chmod(path, 0666))
			failmsg("failed to chmod vhci", "path=%s", path);
	}

	closedir(dir);
}
#endif

#if SYZ_EXECUTOR || SYZ_FAULT
#include <fcntl.h>
#include <sys/fault.h>
#include <sys/stat.h>
static void setup_fault(void)
{
	if (chmod("/dev/fault", 0666))
		fail("failed to chmod /dev/fault");
}
static int inject_fault(int nth)
{
	struct fault_ioc_enable en;
	int fd;

	fd = open("/dev/fault", O_RDWR);
	if (fd == -1)
		fail("failed to open /dev/fault");

	en.scope = FAULT_SCOPE_LWP;
	en.mode = 0;
	en.nth = nth + 1;
	if (ioctl(fd, FAULT_IOC_ENABLE, &en) != 0)
		failmsg("FAULT_IOC_ENABLE failed", "nth=%d", nth);

	return fd;
}
#endif
#if SYZ_EXECUTOR
static int fault_injected(int fd)
{
	struct fault_ioc_getinfo info;
	struct fault_ioc_disable dis;
	int res;

	info.scope = FAULT_SCOPE_LWP;
	if (ioctl(fd, FAULT_IOC_GETINFO, &info) != 0)
		fail("FAULT_IOC_GETINFO failed");
	res = (info.nfaults > 0);

	dis.scope = FAULT_SCOPE_LWP;
	if (ioctl(fd, FAULT_IOC_DISABLE, &dis) != 0)
		fail("FAULT_IOC_DISABLE failed");

	close(fd);

	return res;
}
#endif

#endif

#if GOOS_darwin
#define __syscall syscall
#endif

#if SYZ_EXECUTOR || SYZ_NET_INJECTION

#include <fcntl.h>
#if !GOOS_darwin
#include <net/if_tun.h>
#endif
#include <sys/types.h>

static int tunfd = -1;

#if GOOS_netbsd
#define MAX_TUN 64
#elif GOOS_freebsd
#define MAX_TUN 256
#else
#define MAX_TUN 4
#endif
#define TUN_IFACE "tap%d"
#define MAX_TUN_IFACE_SIZE sizeof("tap2147483647")
#define TUN_DEVICE "/dev/tap%d"
#define MAX_TUN_DEVICE_SIZE sizeof("/dev/tap2147483647")

#define LOCAL_MAC "aa:aa:aa:aa:aa:aa"
#define REMOTE_MAC "aa:aa:aa:aa:aa:bb"
#define LOCAL_IPV4 "172.20.%d.170"
#define MAX_LOCAL_IPV4_SIZE sizeof("172.20.255.170")
#define REMOTE_IPV4 "172.20.%d.187"
#define MAX_REMOTE_IPV4_SIZE sizeof("172.20.255.187")
#define LOCAL_IPV6 "fe80::%02xaa"
#define MAX_LOCAL_IPV6_SIZE sizeof("fe80::ffaa")
#define REMOTE_IPV6 "fe80::%02xbb"
#define MAX_REMOTE_IPV6_SIZE sizeof("fe80::ffbb")

static void vsnprintf_check(char* str, size_t size, const char* format, va_list args)
{
	int rv = vsnprintf(str, size, format, args);
	if (rv < 0)
		fail("vsnprintf failed");
	if ((size_t)rv >= size)
		failmsg("vsnprintf: string doesn't fit into buffer", "string='%s'", str);
}

static void snprintf_check(char* str, size_t size, const char* format, ...)
{
	va_list args;

	va_start(args, format);
	vsnprintf_check(str, size, format, args);
	va_end(args);
}

#define COMMAND_MAX_LEN 128
#define PATH_PREFIX "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin "
#define PATH_PREFIX_LEN (sizeof(PATH_PREFIX) - 1)

static void execute_command(bool panic, const char* format, ...)
{
	va_list args;
	va_start(args, format);
	char command[PATH_PREFIX_LEN + COMMAND_MAX_LEN];
	memcpy(command, PATH_PREFIX, PATH_PREFIX_LEN);
	vsnprintf_check(command + PATH_PREFIX_LEN, COMMAND_MAX_LEN, format, args);
	va_end(args);
	int rv = system(command);
	if (rv) {
		if (panic)
			failmsg("command failed", "command=%s: %d", &command[0], rv);
		debug("command '%s': %d\n", &command[0], rv);
	}
}

static void initialize_tun(int tun_id)
{
#if SYZ_EXECUTOR
	if (!flag_net_injection)
		return;
#endif

	if (tun_id < 0 || tun_id >= MAX_TUN)
		failmsg("tun_id out of range", "tun_id=%d", tun_id);

	char tun_device[MAX_TUN_DEVICE_SIZE];
	snprintf_check(tun_device, sizeof(tun_device), TUN_DEVICE, tun_id);

	char tun_iface[MAX_TUN_IFACE_SIZE];
	snprintf_check(tun_iface, sizeof(tun_iface), TUN_IFACE, tun_id);

#if GOOS_netbsd
	execute_command(0, "ifconfig %s destroy", tun_iface);
	execute_command(0, "ifconfig %s create", tun_iface);
#else
	execute_command(0, "ifconfig %s destroy", tun_iface);
#endif

	tunfd = open(tun_device, O_RDWR | O_NONBLOCK);
#if GOOS_freebsd
	if ((tunfd < 0) && (errno == ENOENT)) {
		execute_command(0, "kldload -q if_tap");
		tunfd = open(tun_device, O_RDWR | O_NONBLOCK);
	}
#endif
	if (tunfd == -1) {
#if SYZ_EXECUTOR
		failmsg("tun: can't open device", "device=%s", tun_device);
#else
		printf("tun: can't open %s: errno=%d\n", tun_device, errno);
		return;
#endif
	}
	const int kTunFd = 200;
	if (dup2(tunfd, kTunFd) < 0)
		fail("dup2(tunfd, kTunFd) failed");
	close(tunfd);
	tunfd = kTunFd;

	char local_mac[sizeof(LOCAL_MAC)];
	snprintf_check(local_mac, sizeof(local_mac), LOCAL_MAC);
#if GOOS_netbsd
	execute_command(1, "ifconfig %s link %s", tun_iface, local_mac);
#else
	execute_command(1, "ifconfig %s ether %s", tun_iface, local_mac);
#endif
	char local_ipv4[MAX_LOCAL_IPV4_SIZE];
	snprintf_check(local_ipv4, sizeof(local_ipv4), LOCAL_IPV4, tun_id);
	execute_command(1, "ifconfig %s inet %s netmask 255.255.255.0", tun_iface, local_ipv4);
	char remote_mac[sizeof(REMOTE_MAC)];
	char remote_ipv4[MAX_REMOTE_IPV4_SIZE];
	snprintf_check(remote_mac, sizeof(remote_mac), REMOTE_MAC);
	snprintf_check(remote_ipv4, sizeof(remote_ipv4), REMOTE_IPV4, tun_id);
	execute_command(0, "arp -s %s %s", remote_ipv4, remote_mac);
	char local_ipv6[MAX_LOCAL_IPV6_SIZE];
	snprintf_check(local_ipv6, sizeof(local_ipv6), LOCAL_IPV6, tun_id);
	execute_command(1, "ifconfig %s inet6 %s", tun_iface, local_ipv6);
	char remote_ipv6[MAX_REMOTE_IPV6_SIZE];
	snprintf_check(remote_ipv6, sizeof(remote_ipv6), REMOTE_IPV6, tun_id);
	execute_command(0, "ndp -s %s%%%s %s", remote_ipv6, tun_iface, remote_mac);
}

#endif

#if !GOOS_darwin && SYZ_EXECUTOR || __NR_syz_emit_ethernet && SYZ_NET_INJECTION
#include <stdbool.h>
#include <sys/uio.h>

static long syz_emit_ethernet(volatile long a0, volatile long a1)
{
	if (tunfd < 0)
		return (uintptr_t)-1;

	size_t length = a0;
	const char* data = (char*)a1;
	debug_dump_data(data, length);

	return write(tunfd, data, length);
}
#endif

#if !GOOS_darwin && SYZ_EXECUTOR || SYZ_NET_INJECTION && (__NR_syz_extract_tcp_res || SYZ_REPEAT)
#include <errno.h>

static int read_tun(char* data, int size)
{
	if (tunfd < 0)
		return -1;

	int rv = read(tunfd, data, size);
	if (rv < 0) {
		if (errno == EAGAIN)
			return -1;
		fail("tun: read failed");
	}
	return rv;
}
#endif

#if !GOOS_darwin && SYZ_EXECUTOR || __NR_syz_extract_tcp_res && SYZ_NET_INJECTION

struct tcp_resources {
	uint32 seq;
	uint32 ack;
};

#if GOOS_freebsd || GOOS_darwin
#include <net/ethernet.h>
#else
#include <net/ethertypes.h>
#endif
#include <net/if.h>
#include <net/if_arp.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip6.h>
#include <netinet/tcp.h>
#include <netinet/if_ether.h>

static long syz_extract_tcp_res(volatile long a0, volatile long a1, volatile long a2)
{

	if (tunfd < 0)
		return (uintptr_t)-1;
	char data[1000];
	int rv = read_tun(&data[0], sizeof(data));
	if (rv == -1)
		return (uintptr_t)-1;
	size_t length = rv;
	debug_dump_data(data, length);

	if (length < sizeof(struct ether_header))
		return (uintptr_t)-1;
	struct ether_header* ethhdr = (struct ether_header*)&data[0];

	struct tcphdr* tcphdr = 0;
	if (ethhdr->ether_type == htons(ETHERTYPE_IP)) {
		if (length < sizeof(struct ether_header) + sizeof(struct ip))
			return (uintptr_t)-1;
		struct ip* iphdr = (struct ip*)&data[sizeof(struct ether_header)];
		if (iphdr->ip_p != IPPROTO_TCP)
			return (uintptr_t)-1;
		if (length < sizeof(struct ether_header) + iphdr->ip_hl * 4 + sizeof(struct tcphdr))
			return (uintptr_t)-1;
		tcphdr = (struct tcphdr*)&data[sizeof(struct ether_header) + iphdr->ip_hl * 4];
	} else {
		if (length < sizeof(struct ether_header) + sizeof(struct ip6_hdr))
			return (uintptr_t)-1;
		struct ip6_hdr* ipv6hdr = (struct ip6_hdr*)&data[sizeof(struct ether_header)];
		if (ipv6hdr->ip6_nxt != IPPROTO_TCP)
			return (uintptr_t)-1;
		if (length < sizeof(struct ether_header) + sizeof(struct ip6_hdr) + sizeof(struct tcphdr))
			return (uintptr_t)-1;
		tcphdr = (struct tcphdr*)&data[sizeof(struct ether_header) + sizeof(struct ip6_hdr)];
	}

	struct tcp_resources* res = (struct tcp_resources*)a0;
	res->seq = htonl(ntohl(tcphdr->th_seq) + (uint32)a1);
	res->ack = htonl(ntohl(tcphdr->th_ack) + (uint32)a2);

	debug("extracted seq: %08x\n", res->seq);
	debug("extracted ack: %08x\n", res->ack);

	return 0;
}
#endif

#if SYZ_EXECUTOR || SYZ_SANDBOX_SETUID || SYZ_SANDBOX_NONE

#include <sys/resource.h>
#include <unistd.h>

static void sandbox_common()
{
#if !SYZ_THREADED
#if SYZ_EXECUTOR
	if (!flag_threaded)
#endif
		if (setsid() == -1)
			fail("setsid failed");
#endif
	struct rlimit rlim;
#ifdef GOOS_freebsd
	rlim.rlim_cur = rlim.rlim_max = 128 << 20;
	setrlimit(RLIMIT_AS, &rlim);
#endif
	rlim.rlim_cur = rlim.rlim_max = 8 << 20;
	setrlimit(RLIMIT_MEMLOCK, &rlim);
	rlim.rlim_cur = rlim.rlim_max = 1 << 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);
}
#endif

#if SYZ_EXECUTOR || SYZ_SANDBOX_NONE

static void loop();

static int do_sandbox_none(void)
{
	sandbox_common();
#if SYZ_EXECUTOR || SYZ_NET_INJECTION
	initialize_tun(procid);
#endif
	loop();
	return 0;
}
#endif

#if SYZ_EXECUTOR || SYZ_SANDBOX_SETUID

#include <sys/resource.h>
#include <sys/wait.h>
#include <unistd.h>

static void loop();

static int wait_for_loop(int pid)
{
	if (pid < 0)
		fail("sandbox fork failed");
	debug("spawned loop pid %d\n", pid);
	int status = 0;
	while (waitpid(-1, &status, WUNTRACED) != pid) {
	}
	return WEXITSTATUS(status);
}

#define SYZ_HAVE_SANDBOX_SETUID 1
static int do_sandbox_setuid(void)
{
	int pid = fork();
	if (pid != 0)
		return wait_for_loop(pid);

	sandbox_common();
#if SYZ_EXECUTOR || SYZ_NET_INJECTION
	initialize_tun(procid);
#endif

	char pwbuf[1024];
	struct passwd *pw, pwres;
	if (getpwnam_r("nobody", &pwres, pwbuf, sizeof(pwbuf), &pw) != 0 || !pw)
		fail("getpwnam_r(\"nobody\") failed");

	if (setgroups(0, NULL))
		fail("failed to setgroups");
	if (setgid(pw->pw_gid))
		fail("failed to setgid");
	if (setuid(pw->pw_uid))
		fail("failed to setuid");

	loop();
	doexit(1);
}
#endif

#elif GOOS_openbsd

#include <unistd.h>

#include <pwd.h>
#include <stdarg.h>
#include <stdbool.h>
#include <string.h>
#include <sys/syscall.h>
#include <dirent.h>
#include <fcntl.h>
#include <poll.h>
#include <sys/event.h>
#include <sys/ioctl.h>
#include <sys/ktrace.h>
#include <sys/mman.h>
#include <sys/msg.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/sysctl.h>
#include <sys/syslog.h>

#define CAST

#if (SYZ_EXECUTOR || __NR_syz_open_pts)
#include <termios.h>
#include <util.h>

static uintptr_t syz_open_pts(void)
{
	int master, slave;

	if (openpty(&master, &slave, NULL, NULL, NULL) == -1)
		return -1;
	if (dup2(master, master + 100) != -1)
		close(master);
	return slave;
}
#endif

#if SYZ_EXECUTOR || SYZ_NET_INJECTION

#include <net/if_tun.h>
#include <sys/types.h>

static int tunfd = -1;

#define MAX_TUN 8
#define TUN_IFACE "tap%d"
#define MAX_TUN_IFACE_SIZE sizeof("tap2147483647")
#define TUN_DEVICE "/dev/tap%d"
#define MAX_TUN_DEVICE_SIZE sizeof("/dev/tap2147483647")

#define LOCAL_MAC "aa:aa:aa:aa:aa:aa"
#define REMOTE_MAC "aa:aa:aa:aa:aa:bb"
#define LOCAL_IPV4 "172.20.%d.170"
#define MAX_LOCAL_IPV4_SIZE sizeof("172.20.255.170")
#define REMOTE_IPV4 "172.20.%d.187"
#define MAX_REMOTE_IPV4_SIZE sizeof("172.20.255.187")
#define LOCAL_IPV6 "fe80::%02xaa"
#define MAX_LOCAL_IPV6_SIZE sizeof("fe80::ffaa")
#define REMOTE_IPV6 "fe80::%02xbb"
#define MAX_REMOTE_IPV6_SIZE sizeof("fe80::ffbb")

static void vsnprintf_check(char* str, size_t size, const char* format, va_list args)
{
	int rv = vsnprintf(str, size, format, args);
	if (rv < 0)
		fail("vsnprintf failed");
	if ((size_t)rv >= size)
		failmsg("vsnprintf: string doesn't fit into buffer", "string='%s'", str);
}

static void snprintf_check(char* str, size_t size, const char* format, ...)
{
	va_list args;

	va_start(args, format);
	vsnprintf_check(str, size, format, args);
	va_end(args);
}

#define COMMAND_MAX_LEN 128
#define PATH_PREFIX "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin "
#define PATH_PREFIX_LEN (sizeof(PATH_PREFIX) - 1)

static void execute_command(bool panic, const char* format, ...)
{
	va_list args;
	va_start(args, format);
	char command[PATH_PREFIX_LEN + COMMAND_MAX_LEN];
	memcpy(command, PATH_PREFIX, PATH_PREFIX_LEN);
	vsnprintf_check(command + PATH_PREFIX_LEN, COMMAND_MAX_LEN, format, args);
	va_end(args);
	int rv = system(command);
	if (rv) {
		if (panic)
			failmsg("command failed", "command=%s: %d", &command[0], rv);
		debug("command '%s': %d\n", &command[0], rv);
	}
}

static void initialize_tun(int tun_id)
{
#if SYZ_EXECUTOR
	if (!flag_net_injection)
		return;
#endif

	if (tun_id < 0 || tun_id >= MAX_TUN)
		failmsg("tun_id out of range", "tun_id=%d", tun_id);

	char tun_device[MAX_TUN_DEVICE_SIZE];
	snprintf_check(tun_device, sizeof(tun_device), TUN_DEVICE, tun_id);

	char tun_iface[MAX_TUN_IFACE_SIZE];
	snprintf_check(tun_iface, sizeof(tun_iface), TUN_IFACE, tun_id);

	execute_command(0, "ifconfig %s destroy", tun_iface);

	tunfd = open(tun_device, O_RDWR | O_NONBLOCK);
	if (tunfd == -1) {
#if SYZ_EXECUTOR
		failmsg("tun: can't open device", "device=%s", tun_device);
#else
		printf("tun: can't open %s: errno=%d\n", tun_device, errno);
		return;
#endif
	}
	const int kTunFd = 200;
	if (dup2(tunfd, kTunFd) < 0)
		fail("dup2(tunfd, kTunFd) failed");
	close(tunfd);
	tunfd = kTunFd;

	char local_mac[sizeof(LOCAL_MAC)];
	snprintf_check(local_mac, sizeof(local_mac), LOCAL_MAC);
	execute_command(1, "ifconfig %s lladdr %s", tun_iface, local_mac);
	char local_ipv4[MAX_LOCAL_IPV4_SIZE];
	snprintf_check(local_ipv4, sizeof(local_ipv4), LOCAL_IPV4, tun_id);
	execute_command(1, "ifconfig %s inet %s netmask 255.255.255.0", tun_iface, local_ipv4);
	char remote_mac[sizeof(REMOTE_MAC)];
	char remote_ipv4[MAX_REMOTE_IPV4_SIZE];
	snprintf_check(remote_mac, sizeof(remote_mac), REMOTE_MAC);
	snprintf_check(remote_ipv4, sizeof(remote_ipv4), REMOTE_IPV4, tun_id);
	execute_command(0, "arp -s %s %s", remote_ipv4, remote_mac);
	char local_ipv6[MAX_LOCAL_IPV6_SIZE];
	snprintf_check(local_ipv6, sizeof(local_ipv6), LOCAL_IPV6, tun_id);
	execute_command(1, "ifconfig %s inet6 %s", tun_iface, local_ipv6);
	char remote_ipv6[MAX_REMOTE_IPV6_SIZE];
	snprintf_check(remote_ipv6, sizeof(remote_ipv6), REMOTE_IPV6, tun_id);
	execute_command(0, "ndp -s %s%%%s %s", remote_ipv6, tun_iface, remote_mac);
}

#endif

#if SYZ_EXECUTOR || __NR_syz_emit_ethernet && SYZ_NET_INJECTION
#include <sys/uio.h>

static long syz_emit_ethernet(volatile long a0, volatile long a1)
{
	if (tunfd < 0)
		return (uintptr_t)-1;

	size_t length = a0;
	const char* data = (char*)a1;
	debug_dump_data(data, length);

	return write(tunfd, data, length);
}
#endif

#if SYZ_EXECUTOR || SYZ_NET_INJECTION && (__NR_syz_extract_tcp_res || SYZ_REPEAT)
#include <errno.h>

static int read_tun(char* data, int size)
{
	if (tunfd < 0)
		return -1;

	int rv = read(tunfd, data, size);
	if (rv < 0) {
		if (errno == EAGAIN)
			return -1;
		fail("tun: read failed");
	}
	return rv;
}
#endif

#if SYZ_EXECUTOR || __NR_syz_extract_tcp_res && SYZ_NET_INJECTION

struct tcp_resources {
	uint32 seq;
	uint32 ack;
};

#include <net/ethertypes.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip6.h>
#include <netinet/tcp.h>
#include <netinet/if_ether.h>

static long syz_extract_tcp_res(volatile long a0, volatile long a1, volatile long a2)
{

	if (tunfd < 0)
		return (uintptr_t)-1;
	char data[1000];
	int rv = read_tun(&data[0], sizeof(data));
	if (rv == -1)
		return (uintptr_t)-1;
	size_t length = rv;
	debug_dump_data(data, length);

	if (length < sizeof(struct ether_header))
		return (uintptr_t)-1;
	struct ether_header* ethhdr = (struct ether_header*)&data[0];

	struct tcphdr* tcphdr = 0;
	if (ethhdr->ether_type == htons(ETHERTYPE_IP)) {
		if (length < sizeof(struct ether_header) + sizeof(struct ip))
			return (uintptr_t)-1;
		struct ip* iphdr = (struct ip*)&data[sizeof(struct ether_header)];
		if (iphdr->ip_p != IPPROTO_TCP)
			return (uintptr_t)-1;
		if (length < sizeof(struct ether_header) + iphdr->ip_hl * 4 + sizeof(struct tcphdr))
			return (uintptr_t)-1;
		tcphdr = (struct tcphdr*)&data[sizeof(struct ether_header) + iphdr->ip_hl * 4];
	} else {
		if (length < sizeof(struct ether_header) + sizeof(struct ip6_hdr))
			return (uintptr_t)-1;
		struct ip6_hdr* ipv6hdr = (struct ip6_hdr*)&data[sizeof(struct ether_header)];
		if (ipv6hdr->ip6_nxt != IPPROTO_TCP)
			return (uintptr_t)-1;
		if (length < sizeof(struct ether_header) + sizeof(struct ip6_hdr) + sizeof(struct tcphdr))
			return (uintptr_t)-1;
		tcphdr = (struct tcphdr*)&data[sizeof(struct ether_header) + sizeof(struct ip6_hdr)];
	}

	struct tcp_resources* res = (struct tcp_resources*)a0;
	res->seq = htonl(ntohl(tcphdr->th_seq) + (uint32)a1);
	res->ack = htonl(ntohl(tcphdr->th_ack) + (uint32)a2);

	debug("extracted seq: %08x\n", res->seq);
	debug("extracted ack: %08x\n", res->ack);

	return 0;
}
#endif

#if SYZ_EXECUTOR || SYZ_SANDBOX_SETUID || SYZ_SANDBOX_NONE

#include <sys/resource.h>

static void sandbox_common()
{
#if !SYZ_THREADED
#if SYZ_EXECUTOR
	if (!flag_threaded)
#endif
		if (setsid() == -1)
			fail("setsid failed");
#endif
	struct rlimit rlim;
	rlim.rlim_cur = rlim.rlim_max = 8 << 20;
	setrlimit(RLIMIT_MEMLOCK, &rlim);
	rlim.rlim_cur = rlim.rlim_max = 1 << 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);
}
#endif

#if SYZ_EXECUTOR || SYZ_SANDBOX_NONE

static void loop();

static int do_sandbox_none(void)
{
	sandbox_common();
#if SYZ_EXECUTOR || SYZ_NET_INJECTION
	initialize_tun(procid);
#endif
	loop();
	return 0;
}
#endif

#if SYZ_EXECUTOR || SYZ_SANDBOX_SETUID

#include <sys/wait.h>

static void loop();

static int wait_for_loop(int pid)
{
	if (pid < 0)
		fail("sandbox fork failed");
	debug("spawned loop pid %d\n", pid);
	int status = 0;
	while (waitpid(-1, &status, WUNTRACED) != pid) {
	}
	return WEXITSTATUS(status);
}

#define SYZ_HAVE_SANDBOX_SETUID 1
static int do_sandbox_setuid(void)
{
	int pid = fork();
	if (pid != 0)
		return wait_for_loop(pid);

	sandbox_common();
#if SYZ_EXECUTOR || SYZ_NET_INJECTION
	initialize_tun(procid);
#endif

	char pwbuf[1024];
	struct passwd *pw, pwres;
	if (getpwnam_r("nobody", &pwres, pwbuf, sizeof(pwbuf), &pw) != 0 || !pw)
		fail("getpwnam_r(\"nobody\") failed");

	if (setgroups(0, NULL))
		fail("failed to setgroups");
	if (setgid(pw->pw_gid))
		fail("failed to setgid");
	if (setuid(pw->pw_uid))
		fail("failed to setuid");

	loop();
	doexit(1);
}
#endif

#elif GOOS_fuchsia

#include <fcntl.h>
#include <lib/fdio/directory.h>
#include <poll.h>
#include <signal.h>
#include <stdlib.h>
#include <sys/file.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <time.h>
#include <unistd.h>
#include <utime.h>
#include <zircon/process.h>
#include <zircon/status.h>
#include <zircon/syscalls.h>

#if SYZ_EXECUTOR || __NR_get_root_resource
#include <lib/ddk/driver.h>
#endif

#if SYZ_EXECUTOR || SYZ_HANDLE_SEGV
#include <pthread.h>
#include <setjmp.h>
#include <zircon/syscalls/debug.h>
#include <zircon/syscalls/exception.h>
#include <zircon/syscalls/object.h>

static __thread int skip_segv;
static __thread jmp_buf segv_env;

static void segv_handler(void)
{
	if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED)) {
		debug("recover: skipping\n");
		longjmp(segv_env, 1);
	}
	debug("recover: exiting\n");
	doexit(SIGSEGV);
}

static zx_status_t update_exception_thread_regs(zx_handle_t exception)
{
	zx_handle_t thread;
	zx_status_t status = zx_exception_get_thread(exception, &thread);
	if (status != ZX_OK) {
		debug("zx_exception_get_thread failed: %s (%d)\n", zx_status_get_string(status), status);
		return status;
	}

	zx_thread_state_general_regs_t regs;
	status = zx_thread_read_state(thread, ZX_THREAD_STATE_GENERAL_REGS,
				      &regs, sizeof(regs));
	if (status != ZX_OK) {
		debug("zx_thread_read_state failed: %d %s (%d)\n",
		      (int)sizeof(regs), zx_status_get_string(status), status);
	} else {
#if GOARCH_amd64
		regs.rip = (uint64)(void*)&segv_handler;
#elif GOARCH_arm64
		regs.pc = (uint64)(void*)&segv_handler;
#else
#error "unsupported arch"
#endif
		status = zx_thread_write_state(thread, ZX_THREAD_STATE_GENERAL_REGS, &regs, sizeof(regs));
		if (status != ZX_OK) {
			debug("zx_thread_write_state failed: %s (%d)\n", zx_status_get_string(status), status);
		}
	}

	zx_handle_close(thread);
	return status;
}

static void* ex_handler(void* arg)
{
	zx_handle_t exception_channel = (zx_handle_t)(long)arg;
	for (int i = 0; i < 10000; i++) {
		zx_status_t status = zx_object_wait_one(exception_channel, ZX_CHANNEL_READABLE, ZX_TIME_INFINITE, NULL);
		if (status != ZX_OK) {
			debug("zx_object_wait_one failed: %s (%d)\n", zx_status_get_string(status), status);
			continue;
		}

		zx_exception_info_t info;
		zx_handle_t exception;
		status = zx_channel_read(exception_channel, 0, &info, &exception, sizeof(info), 1, NULL, NULL);
		if (status != ZX_OK) {
			debug("zx_channel_read failed: %s (%d)\n", zx_status_get_string(status), status);
			continue;
		}

		debug("got exception: type=%d tid=%llu\n", info.type, (unsigned long long)(info.tid));
		status = update_exception_thread_regs(exception);
		if (status != ZX_OK) {
			debug("failed to update exception thread registers: %s (%d)\n", zx_status_get_string(status), status);
		}

		uint32 state = ZX_EXCEPTION_STATE_HANDLED;
		status = zx_object_set_property(exception, ZX_PROP_EXCEPTION_STATE, &state, sizeof(state));
		if (status != ZX_OK) {
			debug("zx_object_set_property(ZX_PROP_EXCEPTION_STATE) failed: %s (%d)\n", zx_status_get_string(status), status);
		}
		zx_handle_close(exception);
	}
	doexit(1);
	return 0;
}

static void install_segv_handler(void)
{
	zx_status_t status;
	zx_handle_t exception_channel;
	if ((status = zx_task_create_exception_channel(zx_process_self(), 0, &exception_channel)) != ZX_OK)
		failmsg("zx_task_create_exception_channel failed",
			"status=%s (%d)", zx_status_get_string(status), status);
	pthread_t th;
	if (pthread_create(&th, 0, ex_handler, (void*)(long)exception_channel))
		fail("pthread_create failed");
}

#define NONFAILING(...)                                              \
	({                                                           \
		int ok = 1;                                          \
		__atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \
		if (sigsetjmp(segv_env, 0) == 0) {                   \
			__VA_ARGS__;                                 \
		} else                                               \
			ok = 0;                                      \
		__atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \
		ok;                                                  \
	})
#endif

#if SYZ_EXECUTOR || SYZ_THREADED
#include <unistd.h>
typedef struct {
	int state;
} event_t;

static void event_init(event_t* ev)
{
	ev->state = 0;
}

static void event_reset(event_t* ev)
{
	ev->state = 0;
}

static void event_set(event_t* ev)
{
	if (ev->state)
		exitf("event already set");
	__atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
}

static void event_wait(event_t* ev)
{
	while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
		usleep(200);
}

static int event_isset(event_t* ev)
{
	return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
}

static int event_timedwait(event_t* ev, uint64 timeout_ms)
{
	uint64 start = current_time_ms();
	for (;;) {
		if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
			return 1;
		if (current_time_ms() - start > timeout_ms)
			return 0;
		usleep(200);
	}
}
#endif

#if SYZ_EXECUTOR || __NR_syz_mmap
long syz_mmap(size_t addr, size_t size)
{
	zx_handle_t root = zx_vmar_root_self();
	zx_info_vmar_t info;
	zx_status_t status = zx_object_get_info(root, ZX_INFO_VMAR, &info, sizeof(info), 0, 0);
	if (status != ZX_OK) {
		debug("zx_object_get_info(ZX_INFO_VMAR) failed: %s (%d)", zx_status_get_string(status), status);
		return status;
	}
	zx_handle_t vmo;
	status = zx_vmo_create(size, 0, &vmo);
	if (status != ZX_OK) {
		debug("zx_vmo_create failed: %s (%d)\n", zx_status_get_string(status), status);
		return status;
	}

	uintptr_t mapped_addr;
	status = zx_vmar_map(root, ZX_VM_FLAG_SPECIFIC_OVERWRITE | ZX_VM_FLAG_PERM_READ | ZX_VM_FLAG_PERM_WRITE,
			     addr - info.base, vmo, 0, size,
			     &mapped_addr);

	zx_status_t close_vmo_status = zx_handle_close(vmo);
	if (close_vmo_status != ZX_OK) {
		debug("zx_handle_close(vmo) failed with: %s (%d)\n", zx_status_get_string(close_vmo_status), close_vmo_status);
	}
	return status;
}
#endif

#if SYZ_EXECUTOR || __NR_syz_process_self
static long syz_process_self(void)
{
	return zx_process_self();
}
#endif

#if SYZ_EXECUTOR || __NR_syz_thread_self
static long syz_thread_self(void)
{
	return zx_thread_self();
}
#endif

#if SYZ_EXECUTOR || __NR_syz_vmar_root_self
static long syz_vmar_root_self(void)
{
	return zx_vmar_root_self();
}
#endif

#if SYZ_EXECUTOR || __NR_syz_job_default
static long syz_job_default(void)
{
	return zx_job_default();
}
#endif

#if SYZ_EXECUTOR || __NR_syz_future_time
static long syz_future_time(volatile long when)
{
	zx_time_t delta_ms = 10000;
	switch (when) {
	case 0:
		delta_ms = 5;
		break;
	case 1:
		delta_ms = 30;
		break;
	}
	zx_time_t now = 0;
	zx_clock_read(ZX_CLOCK_MONOTONIC, &now);
	return now + delta_ms * 1000 * 1000;
}
#endif

#if SYZ_EXECUTOR || SYZ_SANDBOX_NONE
static void loop();
static int do_sandbox_none(void)
{
	loop();
	return 0;
}
#endif
#define CAST(f) ({void* p = (void*)f; p; })

#elif GOOS_linux

#include <stdlib.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>

#if SYZ_EXECUTOR
const int kExtraCoverSize = 256 << 10;
struct cover_t;
static void cover_reset(cover_t* cov);
#endif

#if SYZ_EXECUTOR || SYZ_THREADED
#include <linux/futex.h>
#include <pthread.h>

typedef struct {
	int state;
} event_t;

static void event_init(event_t* ev)
{
	ev->state = 0;
}

static void event_reset(event_t* ev)
{
	ev->state = 0;
}

static void event_set(event_t* ev)
{
	if (ev->state)
		exitf("event already set");
	__atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
	syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1000000);
}

static void event_wait(event_t* ev)
{
	while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
		syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
}

static int event_isset(event_t* ev)
{
	return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
}

static int event_timedwait(event_t* ev, uint64 timeout)
{
	uint64 start = current_time_ms();
	uint64 now = start;
	for (;;) {
		uint64 remain = timeout - (now - start);
		struct timespec ts;
		ts.tv_sec = remain / 1000;
		ts.tv_nsec = (remain % 1000) * 1000 * 1000;
		syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
		if (__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
			return 1;
		now = current_time_ms();
		if (now - start > timeout)
			return 0;
	}
}
#endif

#if SYZ_EXECUTOR || SYZ_REPEAT || SYZ_NET_INJECTION || SYZ_FAULT || SYZ_SANDBOX_NONE || \
    SYZ_SANDBOX_SETUID || SYZ_SANDBOX_NAMESPACE || SYZ_SANDBOX_ANDROID ||               \
    SYZ_FAULT || SYZ_LEAK || SYZ_BINFMT_MISC || SYZ_SYSCTL ||                           \
    ((__NR_syz_usb_connect || __NR_syz_usb_connect_ath9k) && USB_DEBUG) ||              \
    __NR_syz_usbip_server_init
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdbool.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>

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);
		debug("write(%s) failed: %d\n", file, err);
		errno = err;
		return false;
	}
	close(fd);
	return true;
}
#endif

#if SYZ_EXECUTOR || SYZ_NET_DEVICES || SYZ_NET_INJECTION || SYZ_DEVLINK_PCI || SYZ_WIFI || SYZ_802154 || \
    __NR_syz_genetlink_get_family_id || __NR_syz_80211_inject_frame || __NR_syz_80211_join_ibss || SYZ_NIC_VF
#include <arpa/inet.h>
#include <errno.h>
#include <net/if.h>
#include <netinet/in.h>
#include <stdbool.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>

#include <linux/genetlink.h>
#include <linux/if_addr.h>
#include <linux/if_link.h>
#include <linux/in6.h>
#include <linux/neighbour.h>
#include <linux/net.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <linux/veth.h>

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);
}

#if SYZ_EXECUTOR || SYZ_NET_DEVICES || SYZ_802154
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;
}

#if SYZ_EXECUTOR || SYZ_NIC_VF
#include <ifaddrs.h>
#include <linux/ethtool.h>
#include <linux/sockios.h>
#include <sys/ioctl.h>

struct vf_intf {
	char pass_thru_intf[IFNAMSIZ];
	int ppid;
};

static struct vf_intf vf_intf;

static void find_vf_interface(void)
{
#if SYZ_EXECUTOR
	if (!flag_nic_vf)
		return;
#endif
	struct ifaddrs* addresses = NULL;
	int pid = getpid();
	int ret = 0;

	memset(&vf_intf, 0, sizeof(struct vf_intf));

	debug("Checking for VF pass-thru interface.\n");
	if (getifaddrs(&addresses) == -1) {
		debug("%s: getifaddrs() failed.\n", __func__);
		return;
	}

	int fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);

	if (fd < 0) {
		debug("%s: socket() failed.\n", __func__);
		return;
	}
	struct ifreq ifr;
	struct ethtool_drvinfo drvinfo;
	struct ifaddrs* address = addresses;

	while (address) {
		debug("ifa_name: %s\n", address->ifa_name);
		memset(&ifr, 0, sizeof(struct ifreq));
		strcpy(ifr.ifr_name, address->ifa_name);
		memset(&drvinfo, 0, sizeof(struct ethtool_drvinfo));
		drvinfo.cmd = ETHTOOL_GDRVINFO;
		ifr.ifr_data = (caddr_t)&drvinfo;
		ret = ioctl(fd, SIOCETHTOOL, &ifr);

		if (ret < 0) {
			debug("%s: ioctl() failed.\n", __func__);
		} else if (strlen(drvinfo.bus_info)) {
			debug("bus_info: %s, strlen(drvinfo.bus_info)=%zu\n",
			      drvinfo.bus_info, strlen(drvinfo.bus_info));
			if (strcmp(drvinfo.bus_info, "0000:00:11.0") == 0) {
				if (strlen(address->ifa_name) < IFNAMSIZ) {
					strncpy(vf_intf.pass_thru_intf,
						address->ifa_name, IFNAMSIZ);
					vf_intf.ppid = pid;
				} else {
					debug("%s: %d strlen(%s) >= IFNAMSIZ.\n",
					      __func__, pid, address->ifa_name);
				}
				break;
			}
		}
		address = address->ifa_next;
	}
	freeifaddrs(addresses);
	if (!vf_intf.ppid) {
		memset(&vf_intf, 0, sizeof(struct vf_intf));
		debug("%s: %d could not find VF pass-thru interface.\n", __func__, pid);
		return;
	}
	debug("%s: %d found VF pass-thru interface %s\n",
	      __func__, pid, vf_intf.pass_thru_intf);
}
#endif

#endif

static int netlink_send_ext(struct nlmsg* nlmsg, int sock,
			    uint16 reply_type, int* reply_len, bool dofail)
{
	if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
		fail("nlmsg overflow/bad nesting");
	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)
			failmsg("netlink_send_ext: short netlink write", "wrote=%zd, want=%d", n, hdr->nlmsg_len);
		debug("netlink_send_ext: short netlink write: %zd/%d errno=%d\n", n, hdr->nlmsg_len, errno);
		return -1;
	}
	n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
	if (reply_len)
		*reply_len = 0;
	if (n < 0) {
		if (dofail)
			fail("netlink_send_ext: netlink read failed");
		debug("netlink_send_ext: netlink read failed: errno=%d\n", errno);
		return -1;
	}
	if (n < (ssize_t)sizeof(struct nlmsghdr)) {
		errno = EINVAL;
		if (dofail)
			failmsg("netlink_send_ext: short netlink read", "read=%zd", n);
		debug("netlink_send_ext: short netlink read: %zd\n", n);
		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)
			failmsg("netlink_send_ext: short netlink read", "read=%zd", n);
		debug("netlink_send_ext: short netlink read: %zd\n", n);
		return -1;
	}
	if (hdr->nlmsg_type != NLMSG_ERROR) {
		errno = EINVAL;
		if (dofail)
			failmsg("netlink_send_ext: bad netlink ack type", "type=%d", hdr->nlmsg_type);
		debug("netlink_send_ext: short netlink ack: %d\n", hdr->nlmsg_type);
		return -1;
	}
	errno = -((struct nlmsgerr*)(hdr + 1))->error;
	return -errno;
}

#if SYZ_EXECUTOR || SYZ_NET_DEVICES || SYZ_NET_INJECTION || SYZ_DEVLINK_PCI || SYZ_WIFI || SYZ_802154 || \
    __NR_syz_80211_join_ibss || __NR_syz_80211_inject_frame
static int netlink_send(struct nlmsg* nlmsg, int sock)
{
	return netlink_send_ext(nlmsg, sock, 0, NULL, true);
}
#endif

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) {
		debug("netlink: failed to get family id for %.*s: %s\n", GENL_NAMSIZ, family_name, strerror(errno));
		return -1;
	}
	uint16 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*)(attr + 1);
			break;
		}
	}
	if (!id) {
		debug("netlink: failed to parse family id for %.*s\n", GENL_NAMSIZ, family_name);
		errno = EINVAL;
		return -1;
	}
	recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);

	return id;
}

#if SYZ_EXECUTOR || SYZ_NET_DEVICES || SYZ_DEVLINK_PCI
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;
}
#endif

#if SYZ_EXECUTOR || SYZ_NET_DEVICES || SYZ_802154
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));
}
#endif

#if SYZ_EXECUTOR || SYZ_NET_DEVICES
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) {
		debug("netlink: adding device %s type %s: %s\n", name, type, strerror(errno));
	}
}

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) {
		debug("netlink: adding device %s type veth peer %s: %s\n", name, peer, strerror(errno));
	}
}

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) {
		debug("netlink: adding device %s type xfrm if_id %d: %s\n", name, if_id, strerror(errno));
	}
}

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) {
		debug("netlink: adding device %s type hsr slave1 %s slave2 %s: %s\n", name, slave1, slave2, strerror(errno));
	}
}

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) {
		debug("netlink: adding device %s type %s link %s: %s\n", name, type, link, strerror(errno));
	}
}

static void netlink_add_vlan(struct nlmsg* nlmsg, int sock, const char* name, const char* link, uint16 id, uint16 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) {
		debug("netlink: add %s type vlan link %s id %d: %s\n", name, link, id, strerror(errno));
	}
}

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 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) {
		debug("netlink: add %s type macvlan link %s mode %d: %s\n", name, link, mode, strerror(errno));
	}
}

static void netlink_add_geneve(struct nlmsg* nlmsg, int sock, const char* name, uint32 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) {
		debug("netlink: add %s type geneve vni %u: %s\n", name, vni, strerror(errno));
	}
}

#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 mode, uint16 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) {
		debug("netlink: add %s type ipvlan link %s mode %d: %s\n", name, link, mode, strerror(errno));
	}
}
#endif

#if SYZ_EXECUTOR || SYZ_NET_DEVICES || SYZ_NET_INJECTION || SYZ_DEVLINK_PCI || SYZ_802154
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) {
		debug("netlink: device %s up master %s: %s\n", name, master ? master : "NULL", strerror(errno));
	}
}
#endif

#if SYZ_EXECUTOR || SYZ_NET_DEVICES || SYZ_NET_INJECTION
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) {
		debug("netlink: add addr %s dev %s: %s\n", addr, dev, strerror(errno));
	}
}

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) {
		debug("netlink: add addr %s dev %s: %s\n", addr, dev, strerror(errno));
	}
}
#endif

#if SYZ_EXECUTOR || SYZ_NET_INJECTION
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) {
		debug("netlink: add neigh %s addr %d lladdr %d: %s\n", name, addrsize, macsize, strerror(errno));
	}
}
#endif
#endif

#if SYZ_EXECUTOR || SYZ_NET_DEVICES || SYZ_NET_INJECTION || SYZ_DEVLINK_PCI || SYZ_WIFI || SYZ_802154
static struct nlmsg nlmsg;
#endif

#if SYZ_EXECUTOR || SYZ_NET_INJECTION
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <stdarg.h>
#include <stdbool.h>
#include <sys/ioctl.h>
#include <sys/stat.h>

#include <linux/if_ether.h>
#include <linux/if_tun.h>
#include <linux/ip.h>
#include <linux/tcp.h>

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"

#ifndef IFF_NAPI
#define IFF_NAPI 0x0010
#endif
#if ENABLE_NAPI_FRAGS
static int tun_frags_enabled;
#ifndef IFF_NAPI_FRAGS
#define IFF_NAPI_FRAGS 0x0020
#endif
#endif

static void initialize_tun(void)
{
#if SYZ_EXECUTOR
	if (!flag_net_injection)
		return;
#endif
	tunfd = open("/dev/net/tun", O_RDWR | O_NONBLOCK);
	if (tunfd == -1) {
#if SYZ_EXECUTOR
		fail("tun: can't open /dev/net/tun");
#else
		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;
#endif
	}
	const int kTunFd = 200;
	if (dup2(tunfd, kTunFd) < 0)
		fail("dup2(tunfd, kTunFd) failed");
	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 ENABLE_NAPI_FRAGS
	ifr.ifr_flags |= IFF_NAPI | IFF_NAPI_FRAGS;
#endif
	if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0) {
#if ENABLE_NAPI_FRAGS
		ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
		if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0)
#endif
			fail("tun: ioctl(TUNSETIFF) failed");
	}
#if ENABLE_NAPI_FRAGS
	if (ioctl(tunfd, TUNGETIFF, (void*)&ifr) < 0)
		fail("tun: ioctl(TUNGETIFF) failed");
	tun_frags_enabled = (ifr.ifr_flags & IFF_NAPI_FRAGS) != 0;
	debug("tun_frags_enabled=%d\n", tun_frags_enabled);
#endif
	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)
		fail("socket(AF_NETLINK) failed");

	netlink_add_addr4(&nlmsg, sock, TUN_IFACE, LOCAL_IPV4);
	netlink_add_addr6(&nlmsg, sock, TUN_IFACE, LOCAL_IPV6);
	uint64 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);
}
#endif

#if SYZ_EXECUTOR || __NR_syz_init_net_socket || SYZ_DEVLINK_PCI
const int kInitNetNsFd = 201;
#endif

#if SYZ_EXECUTOR || SYZ_DEVLINK_PCI || SYZ_NET_DEVICES

#include <linux/genetlink.h>
#include <stdbool.h>

#define DEVLINK_FAMILY_NAME "devlink"

#define DEVLINK_CMD_PORT_GET 5
#if SYZ_EXECUTOR || SYZ_DEVLINK_PCI
#define DEVLINK_CMD_RELOAD 37
#endif
#define DEVLINK_ATTR_BUS_NAME 1
#define DEVLINK_ATTR_DEV_NAME 2
#define DEVLINK_ATTR_NETDEV_NAME 7
#if SYZ_EXECUTOR || SYZ_DEVLINK_PCI
#define DEVLINK_ATTR_NETNS_FD 138
#endif

#if SYZ_EXECUTOR || SYZ_DEVLINK_PCI
static void netlink_devlink_netns_move(const char* bus_name, const char* dev_name, int netns_fd)
{
	struct genlmsghdr genlhdr;
	int sock;
	int id, err;

	sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
	if (sock == -1)
		fail("socket(AF_NETLINK) failed");

	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_RELOAD;
	netlink_init(&nlmsg, id, 0, &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);
	netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
	err = netlink_send(&nlmsg, sock);
	if (err < 0) {
		debug("netlink: failed to move devlink instance %s/%s into network namespace: %s\n",
		      bus_name, dev_name, strerror(errno));
	}
error:
	close(sock);
}
#endif

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

	int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
	if (sock == -1)
		fail("socket(AF_NETLINK) failed");

	int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
	if (rtsock == -1)
		fail("socket(AF_NETLINK) failed");

	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) {
		debug("netlink: failed to get port get reply: %s\n", strerror(errno));
		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);
}

#if SYZ_EXECUTOR || SYZ_DEVLINK_PCI
#include <fcntl.h>
#include <sched.h>

static void initialize_devlink_pci(void)
{
#if SYZ_EXECUTOR
	if (!flag_devlink_pci)
		return;
#endif
	int netns = open("/proc/self/ns/net", O_RDONLY);
	if (netns == -1)
		fail("open(/proc/self/ns/net) failed");
	int ret = setns(kInitNetNsFd, 0);
	if (ret == -1)
		fail("set_ns(init_netns_fd) failed");
	netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
	ret = setns(netns, 0);
	if (ret == -1)
		fail("set_ns(this_netns_fd) failed");
	close(netns);

	initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
}
#endif
#endif

#if SYZ_EXECUTOR || SYZ_WIFI || __NR_syz_80211_inject_frame || __NR_syz_80211_join_ibss

#define WIFI_INITIAL_DEVICE_COUNT 2
#define WIFI_MAC_BASE                              \
	{                                          \
		0x08, 0x02, 0x11, 0x00, 0x00, 0x00 \
	}
#define WIFI_IBSS_BSSID                            \
	{                                          \
		0x50, 0x50, 0x50, 0x50, 0x50, 0x50 \
	}
#define WIFI_IBSS_SSID                             \
	{                                          \
		0x10, 0x10, 0x10, 0x10, 0x10, 0x10 \
	}
#define WIFI_DEFAULT_FREQUENCY 2412
#define WIFI_DEFAULT_SIGNAL 0
#define WIFI_DEFAULT_RX_RATE 1
#define HWSIM_CMD_REGISTER 1
#define HWSIM_CMD_FRAME 2
#define HWSIM_CMD_NEW_RADIO 4
#define HWSIM_ATTR_SUPPORT_P2P_DEVICE 14
#define HWSIM_ATTR_PERM_ADDR 22

#endif

#if SYZ_EXECUTOR || SYZ_WIFI || __NR_syz_80211_join_ibss
#include <linux/genetlink.h>
#include <linux/if_ether.h>
#include <linux/nl80211.h>
#include <linux/rtnetlink.h>
#include <net/if.h>
#include <stdbool.h>
#include <sys/ioctl.h>
#define IF_OPER_UP 6
struct join_ibss_props {
	int wiphy_freq;
	bool wiphy_freq_fixed;
	uint8* mac;
	uint8* ssid;
	int ssid_len;
};

static int set_interface_state(const char* interface_name, int on)
{
	struct ifreq ifr;
	int sock = socket(AF_INET, SOCK_DGRAM, 0);
	if (sock < 0) {
		debug("set_interface_state: failed to open socket, errno %d\n", errno);
		return -1;
	}

	memset(&ifr, 0, sizeof(ifr));
	strcpy(ifr.ifr_name, interface_name);
	int ret = ioctl(sock, SIOCGIFFLAGS, &ifr);
	if (ret < 0) {
		debug("set_interface_state: failed to execute SIOCGIFFLAGS, ret %d\n", ret);
		close(sock);
		return -1;
	}

	if (on)
		ifr.ifr_flags |= IFF_UP;
	else
		ifr.ifr_flags &= ~IFF_UP;

	ret = ioctl(sock, SIOCSIFFLAGS, &ifr);
	close(sock);
	if (ret < 0) {
		debug("set_interface_state: failed to execute SIOCSIFFLAGS, ret %d\n", ret);
		return -1;
	}
	return 0;
}

static int nl80211_set_interface(struct nlmsg* nlmsg, int sock, int nl80211_family, uint32 ifindex, uint32 iftype)
{
	struct genlmsghdr genlhdr;

	memset(&genlhdr, 0, sizeof(genlhdr));
	genlhdr.cmd = NL80211_CMD_SET_INTERFACE;
	netlink_init(nlmsg, nl80211_family, 0, &genlhdr, sizeof(genlhdr));
	netlink_attr(nlmsg, NL80211_ATTR_IFINDEX, &ifindex, sizeof(ifindex));
	netlink_attr(nlmsg, NL80211_ATTR_IFTYPE, &iftype, sizeof(iftype));
	int err = netlink_send(nlmsg, sock);
	if (err < 0) {
		debug("nl80211_set_interface failed: %s\n", strerror(errno));
	}
	return err;
}

static int nl80211_join_ibss(struct nlmsg* nlmsg, int sock, int nl80211_family, uint32 ifindex, struct join_ibss_props* props)
{
	struct genlmsghdr genlhdr;

	memset(&genlhdr, 0, sizeof(genlhdr));
	genlhdr.cmd = NL80211_CMD_JOIN_IBSS;
	netlink_init(nlmsg, nl80211_family, 0, &genlhdr, sizeof(genlhdr));
	netlink_attr(nlmsg, NL80211_ATTR_IFINDEX, &ifindex, sizeof(ifindex));
	netlink_attr(nlmsg, NL80211_ATTR_SSID, props->ssid, props->ssid_len);
	netlink_attr(nlmsg, NL80211_ATTR_WIPHY_FREQ, &(props->wiphy_freq), sizeof(props->wiphy_freq));
	if (props->mac)
		netlink_attr(nlmsg, NL80211_ATTR_MAC, props->mac, ETH_ALEN);
	if (props->wiphy_freq_fixed)
		netlink_attr(nlmsg, NL80211_ATTR_FREQ_FIXED, NULL, 0);
	int err = netlink_send(nlmsg, sock);
	if (err < 0) {
		debug("nl80211_join_ibss failed: %s\n", strerror(errno));
	}
	return err;
}

static int get_ifla_operstate(struct nlmsg* nlmsg, int ifindex)
{
	struct ifinfomsg info;
	memset(&info, 0, sizeof(info));
	info.ifi_family = AF_UNSPEC;
	info.ifi_index = ifindex;

	int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
	if (sock == -1) {
		debug("get_ifla_operstate: socket failed: %d\n", errno);
		return -1;
	}

	netlink_init(nlmsg, RTM_GETLINK, 0, &info, sizeof(info));
	int n;
	int err = netlink_send_ext(nlmsg, sock, RTM_NEWLINK, &n, true);
	close(sock);

	if (err) {
		debug("get_ifla_operstate: failed to query: %s\n", strerror(errno));
		return -1;
	}

	struct rtattr* attr = IFLA_RTA(NLMSG_DATA(nlmsg->buf));
	for (; RTA_OK(attr, n); attr = RTA_NEXT(attr, n)) {
		if (attr->rta_type == IFLA_OPERSTATE)
			return *((int32_t*)RTA_DATA(attr));
	}

	return -1;
}

static int await_ifla_operstate(struct nlmsg* nlmsg, char* interface, int operstate)
{
	int ifindex = if_nametoindex(interface);
	while (true) {
		usleep(1000);
		int ret = get_ifla_operstate(nlmsg, ifindex);
		if (ret < 0)
			return ret;
		if (ret == operstate)
			return 0;
	}
	return 0;
}

static int nl80211_setup_ibss_interface(struct nlmsg* nlmsg, int sock, int nl80211_family_id, char* interface, struct join_ibss_props* ibss_props)
{
	int ifindex = if_nametoindex(interface);
	if (ifindex == 0) {
		debug("nl80211_setup_ibss_interface: if_nametoindex failed for %.32s, ret 0\n", interface);
		return -1;
	}

	int ret = nl80211_set_interface(nlmsg, sock, nl80211_family_id, ifindex, NL80211_IFTYPE_ADHOC);
	if (ret < 0) {
		debug("nl80211_setup_ibss_interface: nl80211_set_interface failed for %.32s, ret %d\n", interface, ret);
		return -1;
	}

	ret = set_interface_state(interface, 1);
	if (ret < 0) {
		debug("nl80211_setup_ibss_interface: set_interface_state failed for %.32s, ret %d\n", interface, ret);
		return -1;
	}

	ret = nl80211_join_ibss(nlmsg, sock, nl80211_family_id, ifindex, ibss_props);
	if (ret < 0) {
		debug("nl80211_setup_ibss_interface: nl80211_join_ibss failed for %.32s, ret %d\n", interface, ret);
		return -1;
	}

	return 0;
}
#endif

#if SYZ_EXECUTOR || SYZ_WIFI
#include <fcntl.h>
#include <linux/rfkill.h>
#include <sys/stat.h>
#include <sys/types.h>

static int hwsim80211_create_device(struct nlmsg* nlmsg, int sock, int hwsim_family, uint8 mac_addr[ETH_ALEN])
{
	struct genlmsghdr genlhdr;
	memset(&genlhdr, 0, sizeof(genlhdr));
	genlhdr.cmd = HWSIM_CMD_NEW_RADIO;
	netlink_init(nlmsg, hwsim_family, 0, &genlhdr, sizeof(genlhdr));
	netlink_attr(nlmsg, HWSIM_ATTR_SUPPORT_P2P_DEVICE, NULL, 0);
	netlink_attr(nlmsg, HWSIM_ATTR_PERM_ADDR, mac_addr, ETH_ALEN);
	int err = netlink_send(nlmsg, sock);
	if (err < 0) {
		debug("hwsim80211_create_device failed: %s\n", strerror(errno));
	}
	return err;
}

static void initialize_wifi_devices(void)
{

#if SYZ_EXECUTOR
	if (!flag_wifi)
		return;
#endif
	int rfkill = open("/dev/rfkill", O_RDWR);
	if (rfkill == -1) {
		if (errno != ENOENT && errno != EACCES)
			fail("open(/dev/rfkill) failed");
	} else {
		struct rfkill_event event = {0};
		event.type = RFKILL_TYPE_ALL;
		event.op = RFKILL_OP_CHANGE_ALL;
		if (write(rfkill, &event, sizeof(event)) != (ssize_t)(sizeof(event)))
			fail("write(/dev/rfkill) failed");
		close(rfkill);
	}

	uint8 mac_addr[6] = WIFI_MAC_BASE;
	int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
	if (sock < 0) {
		debug("initialize_wifi_devices: failed to create socket (%d)\n", errno);
		return;
	}

	int hwsim_family_id = netlink_query_family_id(&nlmsg, sock, "MAC80211_HWSIM", true);
	int nl80211_family_id = netlink_query_family_id(&nlmsg, sock, "nl80211", true);
	uint8 ssid[] = WIFI_IBSS_SSID;
	uint8 bssid[] = WIFI_IBSS_BSSID;
	struct join_ibss_props ibss_props = {
	    .wiphy_freq = WIFI_DEFAULT_FREQUENCY, .wiphy_freq_fixed = true, .mac = bssid, .ssid = ssid, .ssid_len = sizeof(ssid)};

	for (int device_id = 0; device_id < WIFI_INITIAL_DEVICE_COUNT; device_id++) {
		mac_addr[5] = device_id;
		int ret = hwsim80211_create_device(&nlmsg, sock, hwsim_family_id, mac_addr);
		if (ret < 0)
			failmsg("initialize_wifi_devices: failed to create device", "device=%d", device_id);
		char interface[6] = "wlan0";
		interface[4] += device_id;

		if (nl80211_setup_ibss_interface(&nlmsg, sock, nl80211_family_id, interface, &ibss_props) < 0)
			failmsg("initialize_wifi_devices: failed set up IBSS network", "device=%d", device_id);
	}
	for (int device_id = 0; device_id < WIFI_INITIAL_DEVICE_COUNT; device_id++) {
		char interface[6] = "wlan0";
		interface[4] += device_id;
		int ret = await_ifla_operstate(&nlmsg, interface, IF_OPER_UP);
		if (ret < 0)
			failmsg("initialize_wifi_devices: get_ifla_operstate failed",
				"device=%d, ret=%d", device_id, ret);
	}

	close(sock);
}
#endif

#if SYZ_EXECUTOR || (SYZ_NET_DEVICES && SYZ_NIC_VF) || SYZ_SWAP
static int runcmdline(char* cmdline)
{
	debug("%s\n", cmdline);
	int ret = system(cmdline);
	if (ret) {
		debug("FAIL: %s\n", cmdline);
	}
	return ret;
}
#endif

#if SYZ_EXECUTOR || SYZ_NET_DEVICES
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <stdarg.h>
#include <stdbool.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/uio.h>

#include <linux/if_ether.h>
#include <linux/if_tun.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#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 listen_a = 20001;
	const uint16 listen_b = 20002;
	const uint16 listen_c = 20003;
	const uint16 af_inet = AF_INET;
	const uint16 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)htonl(128 << 24)};
	const struct in6_addr first_half_v6 = {{{0}}};
	const struct in6_addr second_half_v6 = {{{0x80}}};
	const uint8 half_cidr = 1;
	const uint16 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) {
		debug("socket(AF_NETLINK) failed: %s\n", strerror(errno));
		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) {
		debug("netlink: failed to setup wireguard instance: %s\n", strerror(errno));
	}

	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) {
		debug("netlink: failed to setup wireguard instance: %s\n", strerror(errno));
	}

	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) {
		debug("netlink: failed to setup wireguard instance: %s\n", strerror(errno));
	}

error:
	close(sock);
}

#if SYZ_EXECUTOR || SYZ_NIC_VF

static void netlink_nicvf_setup(void)
{
	char cmdline[256];

#if SYZ_EXECUTOR
	if (!flag_nic_vf)
		return;
#endif
	if (!vf_intf.ppid)
		return;

	debug("ppid = %d, vf_intf.pass_thru_intf: %s\n",
	      vf_intf.ppid, vf_intf.pass_thru_intf);

	sprintf(cmdline, "nsenter -t 1 -n ip link set %s netns %d",
		vf_intf.pass_thru_intf, getpid());
	if (runcmdline(cmdline))
		return;

	sprintf(cmdline, "ip a s %s", vf_intf.pass_thru_intf);
	if (runcmdline(cmdline))
		return;

	sprintf(cmdline, "ip link set %s down", vf_intf.pass_thru_intf);
	if (runcmdline(cmdline))
		return;

	sprintf(cmdline, "ip link set %s name nicvf0", vf_intf.pass_thru_intf);
	if (runcmdline(cmdline))
		return;

	debug("nicvf0 VF pass-through setup complete.\n");
}
#endif
static void initialize_netdevices(void)
{
#if SYZ_EXECUTOR
	if (!flag_net_devices)
		return;
#endif
	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"},
#if SYZ_EXECUTOR || SYZ_NIC_VF
		{"nicvf", "nicvf0"},
#endif
		{"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},
#if SYZ_EXECUTOR || SYZ_NIC_VF
		{"nicvf0", 0, true},
#endif
		{"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)
		fail("socket(AF_NETLINK) failed");
	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)
		fail("geneve0 inet_pton failed");
	struct in6_addr geneve_addr6;
	if (inet_pton(AF_INET6, "fc00::01", &geneve_addr6) <= 0)
		fail("geneve1 inet_pton failed");
	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();

#if SYZ_EXECUTOR || SYZ_NIC_VF
	netlink_nicvf_setup();
#endif

	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 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)
{
#if SYZ_EXECUTOR
	if (!flag_net_devices)
		return;
#endif
	int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
	if (sock == -1)
		fail("socket(AF_NETLINK) failed");
	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 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);

#if SYZ_EXECUTOR || SYZ_NIC_VF
	find_vf_interface();
#endif
}
#endif

#if SYZ_EXECUTOR || SYZ_NET_INJECTION && (__NR_syz_extract_tcp_res || SYZ_REPEAT)
#include <errno.h>

static int read_tun(char* data, int size)
{
	if (tunfd < 0)
		return -1;

	int rv = read(tunfd, data, size);
	if (rv < 0) {
		if (errno == EAGAIN || errno == EBADFD)
			return -1;
		fail("tun read failed");
	}
	return rv;
}
#endif

#if SYZ_EXECUTOR || __NR_syz_emit_ethernet && SYZ_NET_INJECTION
#include <stdbool.h>
#include <sys/uio.h>

#if ENABLE_NAPI_FRAGS
#define MAX_FRAGS 4
struct vnet_fragmentation {
	uint32 full;
	uint32 count;
	uint32 frags[MAX_FRAGS];
};
#endif

static long syz_emit_ethernet(volatile long a0, volatile long a1, volatile long a2)
{
	if (tunfd < 0)
		return (uintptr_t)-1;

	uint32 length = a0;
	char* data = (char*)a1;
	debug_dump_data(data, length);

#if ENABLE_NAPI_FRAGS
	struct vnet_fragmentation* frags = (struct vnet_fragmentation*)a2;
	struct iovec vecs[MAX_FRAGS + 1];
	uint32 nfrags = 0;
	if (!tun_frags_enabled || frags == NULL) {
		vecs[nfrags].iov_base = data;
		vecs[nfrags].iov_len = length;
		nfrags++;
	} else {
		bool full = frags->full;
		uint32 count = frags->count;
		if (count > MAX_FRAGS)
			count = MAX_FRAGS;
		uint32 i;
		for (i = 0; i < count && length != 0; i++) {
			uint32 size = frags->frags[i];
			if (size > length)
				size = length;
			vecs[nfrags].iov_base = data;
			vecs[nfrags].iov_len = size;
			nfrags++;
			data += size;
			length -= size;
		}
		if (length != 0 && (full || nfrags == 0)) {
			vecs[nfrags].iov_base = data;
			vecs[nfrags].iov_len = length;
			nfrags++;
		}
	}
	return writev(tunfd, vecs, nfrags);
#else
	return write(tunfd, data, length);
#endif
}
#endif

#if SYZ_EXECUTOR || __NR_syz_io_uring_submit || __NR_syz_io_uring_complete || __NR_syz_io_uring_setup

#define SIZEOF_IO_URING_SQE 64
#define SIZEOF_IO_URING_CQE 16
#define SQ_HEAD_OFFSET 0
#define SQ_TAIL_OFFSET 64
#define SQ_RING_MASK_OFFSET 256
#define SQ_RING_ENTRIES_OFFSET 264
#define SQ_FLAGS_OFFSET 276
#define SQ_DROPPED_OFFSET 272
#define CQ_HEAD_OFFSET 128
#define CQ_TAIL_OFFSET 192
#define CQ_RING_MASK_OFFSET 260
#define CQ_RING_ENTRIES_OFFSET 268
#define CQ_RING_OVERFLOW_OFFSET 284
#define CQ_FLAGS_OFFSET 280
#define CQ_CQES_OFFSET 320

#if SYZ_EXECUTOR || __NR_syz_io_uring_complete
struct io_uring_cqe {
	uint64 user_data;
	uint32 res;
	uint32 flags;
};

static long syz_io_uring_complete(volatile long a0)
{
	char* ring_ptr = (char*)a0;
	uint32 cq_ring_mask = *(uint32*)(ring_ptr + CQ_RING_MASK_OFFSET);
	uint32* cq_head_ptr = (uint32*)(ring_ptr + CQ_HEAD_OFFSET);
	uint32 cq_head = *cq_head_ptr & cq_ring_mask;
	uint32 cq_head_next = *cq_head_ptr + 1;
	char* cqe_src = ring_ptr + CQ_CQES_OFFSET + cq_head * SIZEOF_IO_URING_CQE;
	struct io_uring_cqe cqe;
	memcpy(&cqe, cqe_src, sizeof(cqe));
	__atomic_store_n(cq_head_ptr, cq_head_next, __ATOMIC_RELEASE);
	return (cqe.user_data == 0x12345 || cqe.user_data == 0x23456) ? (long)cqe.res : (long)-1;
}

#endif

#if SYZ_EXECUTOR || __NR_syz_io_uring_setup

struct io_sqring_offsets {
	uint32 head;
	uint32 tail;
	uint32 ring_mask;
	uint32 ring_entries;
	uint32 flags;
	uint32 dropped;
	uint32 array;
	uint32 resv1;
	uint64 resv2;
};

struct io_cqring_offsets {
	uint32 head;
	uint32 tail;
	uint32 ring_mask;
	uint32 ring_entries;
	uint32 overflow;
	uint32 cqes;
	uint64 resv[2];
};

struct io_uring_params {
	uint32 sq_entries;
	uint32 cq_entries;
	uint32 flags;
	uint32 sq_thread_cpu;
	uint32 sq_thread_idle;
	uint32 features;
	uint32 resv[4];
	struct io_sqring_offsets sq_off;
	struct io_cqring_offsets cq_off;
};

#define IORING_OFF_SQ_RING 0
#define IORING_OFF_SQES 0x10000000ULL

#include <sys/mman.h>
#include <unistd.h>
static long syz_io_uring_setup(volatile long a0, volatile long a1, volatile long a2, volatile long a3, volatile long a4, volatile long a5)
{
	uint32 entries = (uint32)a0;
	struct io_uring_params* setup_params = (struct io_uring_params*)a1;
	void* vma1 = (void*)a2;
	void* vma2 = (void*)a3;
	void** ring_ptr_out = (void**)a4;
	void** sqes_ptr_out = (void**)a5;

	uint32 fd_io_uring = syscall(__NR_io_uring_setup, entries, setup_params);
	uint32 sq_ring_sz = setup_params->sq_off.array + setup_params->sq_entries * sizeof(uint32);
	uint32 cq_ring_sz = setup_params->cq_off.cqes + setup_params->cq_entries * SIZEOF_IO_URING_CQE;
	uint32 ring_sz = sq_ring_sz > cq_ring_sz ? sq_ring_sz : cq_ring_sz;
	*ring_ptr_out = mmap(vma1, ring_sz, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE | MAP_FIXED, fd_io_uring, IORING_OFF_SQ_RING);

	uint32 sqes_sz = setup_params->sq_entries * SIZEOF_IO_URING_SQE;
	*sqes_ptr_out = mmap(vma2, sqes_sz, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE | MAP_FIXED, fd_io_uring, IORING_OFF_SQES);

	return fd_io_uring;
}

#endif

#if SYZ_EXECUTOR || __NR_syz_io_uring_submit

static long syz_io_uring_submit(volatile long a0, volatile long a1, volatile long a2, volatile long a3)
{
	char* ring_ptr = (char*)a0;
	char* sqes_ptr = (char*)a1;
	char* sqe = (char*)a2;
	uint32 sqes_index = (uint32)a3;

	uint32 sq_ring_entries = *(uint32*)(ring_ptr + SQ_RING_ENTRIES_OFFSET);
	uint32 cq_ring_entries = *(uint32*)(ring_ptr + CQ_RING_ENTRIES_OFFSET);
	uint32 sq_array_off = (CQ_CQES_OFFSET + cq_ring_entries * SIZEOF_IO_URING_CQE + 63) & ~63;
	if (sq_ring_entries)
		sqes_index %= sq_ring_entries;
	char* sqe_dest = sqes_ptr + sqes_index * SIZEOF_IO_URING_SQE;
	memcpy(sqe_dest, sqe, SIZEOF_IO_URING_SQE);
	uint32 sq_ring_mask = *(uint32*)(ring_ptr + SQ_RING_MASK_OFFSET);
	uint32* sq_tail_ptr = (uint32*)(ring_ptr + SQ_TAIL_OFFSET);
	uint32 sq_tail = *sq_tail_ptr & sq_ring_mask;
	uint32 sq_tail_next = *sq_tail_ptr + 1;
	uint32* sq_array = (uint32*)(ring_ptr + sq_array_off);
	*(sq_array + sq_tail) = sqes_index;
	__atomic_store_n(sq_tail_ptr, sq_tail_next, __ATOMIC_RELEASE);
	return 0;
}

#endif

#endif

#if SYZ_EXECUTOR || __NR_syz_usbip_server_init

#include <errno.h>
#include <fcntl.h>
#include <linux/usb/ch9.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#define VHCI_HC_PORTS 8
#define VHCI_PORTS (VHCI_HC_PORTS * 2)

static long syz_usbip_server_init(volatile long a0)
{
	static int port_alloc[2];

	int speed = (int)a0;
	bool usb3 = (speed == USB_SPEED_SUPER);

	int socket_pair[2];
	if (socketpair(AF_UNIX, SOCK_STREAM, 0, socket_pair))
		fail("syz_usbip_server_init: socketpair failed");

	int client_fd = socket_pair[0];
	int server_fd = socket_pair[1];

	int available_port_num = __atomic_fetch_add(&port_alloc[usb3], 1, __ATOMIC_RELAXED);
	if (available_port_num > VHCI_HC_PORTS) {
		debug("syz_usbip_server_init : no more available port for : %d\n", available_port_num);
		return -1;
	}
	int port_num = procid * VHCI_PORTS + usb3 * VHCI_HC_PORTS + available_port_num;
	char buffer[100];
	sprintf(buffer, "%d %d %s %d", port_num, client_fd, "0", speed);

	write_file("/sys/devices/platform/vhci_hcd.0/attach", buffer);
	return server_fd;
}

#endif

#if SYZ_EXECUTOR || __NR_syz_btf_id_by_name

#include <errno.h>
#include <fcntl.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#define BTF_MAGIC 0xeB9F

struct btf_header {
	__u16 magic;
	__u8 version;
	__u8 flags;
	__u32 hdr_len;
	__u32 type_off;
	__u32 type_len;
	__u32 str_off;
	__u32 str_len;
};

#define BTF_INFO_KIND(info) (((info) >> 24) & 0x0f)
#define BTF_INFO_VLEN(info) ((info)&0xffff)

#define BTF_KIND_INT 1
#define BTF_KIND_ARRAY 3
#define BTF_KIND_STRUCT 4
#define BTF_KIND_UNION 5
#define BTF_KIND_ENUM 6
#define BTF_KIND_FUNC_PROTO 13
#define BTF_KIND_VAR 14
#define BTF_KIND_DATASEC 15

struct btf_type {
	__u32 name_off;
	__u32 info;
	union {
		__u32 size;
		__u32 type;
	};
};

struct btf_enum {
	__u32 name_off;
	__s32 val;
};

struct btf_array {
	__u32 type;
	__u32 index_type;
	__u32 nelems;
};

struct btf_member {
	__u32 name_off;
	__u32 type;
	__u32 offset;
};

struct btf_param {
	__u32 name_off;
	__u32 type;
};

struct btf_var {
	__u32 linkage;
};

struct btf_var_secinfo {
	__u32 type;
	__u32 offset;
	__u32 size;
};
#define VMLINUX_MAX_SUPPORT_SIZE (10 * 1024 * 1024)
static char* read_btf_vmlinux()
{
	static bool is_read = false;
	static char buf[VMLINUX_MAX_SUPPORT_SIZE];
	if (is_read)
		return buf;

	int fd = open("/sys/kernel/btf/vmlinux", O_RDONLY);
	if (fd < 0)
		return NULL;

	unsigned long bytes_read = 0;
	for (;;) {
		ssize_t ret = read(fd, buf + bytes_read,
				   VMLINUX_MAX_SUPPORT_SIZE - bytes_read);

		if (ret < 0 || bytes_read + ret == VMLINUX_MAX_SUPPORT_SIZE)
			return NULL;

		if (ret == 0)
			break;

		bytes_read += ret;
	}

	is_read = true;
	return buf;
}
static long syz_btf_id_by_name(volatile long a0)
{
	char* target = (char*)a0;

	char* vmlinux = read_btf_vmlinux();
	if (vmlinux == NULL)
		return -1;

	struct btf_header* btf_header = (struct btf_header*)vmlinux;
	if (btf_header->magic != BTF_MAGIC)
		return -1;
	char* btf_type_sec = vmlinux + btf_header->hdr_len + btf_header->type_off;
	char* btf_str_sec = vmlinux + btf_header->hdr_len + btf_header->str_off;
	unsigned int bytes_parsed = 0;
	long idx = 1;
	while (bytes_parsed < btf_header->type_len) {
		struct btf_type* btf_type = (struct btf_type*)(btf_type_sec + bytes_parsed);
		uint32 kind = BTF_INFO_KIND(btf_type->info);
		uint32 vlen = BTF_INFO_VLEN(btf_type->info);
		char* name = btf_str_sec + btf_type->name_off;

		if (strcmp(name, target) == 0)
			return idx;
		size_t skip;
		switch (kind) {
		case BTF_KIND_INT:
			skip = sizeof(uint32);
			break;
		case BTF_KIND_ENUM:
			skip = sizeof(struct btf_enum) * vlen;
			break;
		case BTF_KIND_ARRAY:
			skip = sizeof(struct btf_array);
			break;
		case BTF_KIND_STRUCT:
		case BTF_KIND_UNION:
			skip = sizeof(struct btf_member) * vlen;
			break;
		case BTF_KIND_FUNC_PROTO:
			skip = sizeof(struct btf_param) * vlen;
			break;
		case BTF_KIND_VAR:
			skip = sizeof(struct btf_var);
			break;
		case BTF_KIND_DATASEC:
			skip = sizeof(struct btf_var_secinfo) * vlen;
			break;
		default:
			skip = 0;
		}

		bytes_parsed += sizeof(struct btf_type) + skip;
		idx++;
	}

	return -1;
}

#endif
#if SYZ_EXECUTOR || __NR_syz_memcpy_off
static long syz_memcpy_off(volatile long a0, volatile long a1, volatile long a2, volatile long a3, volatile long a4)
{
	char* dest = (char*)a0;
	uint32 dest_off = (uint32)a1;
	char* src = (char*)a2;
	uint32 src_off = (uint32)a3;
	size_t n = (size_t)a4;

	return (long)memcpy(dest + dest_off, src + src_off, n);
}
#endif

#if (SYZ_EXECUTOR || SYZ_REPEAT && SYZ_NET_INJECTION) && SYZ_EXECUTOR_USES_FORK_SERVER
static void flush_tun()
{
#if SYZ_EXECUTOR
	if (!flag_net_injection)
		return;
#endif
	char data[1000];
	while (read_tun(&data[0], sizeof(data)) != -1) {
	}
}
#endif

#if SYZ_EXECUTOR || __NR_syz_extract_tcp_res && SYZ_NET_INJECTION
#ifndef __ANDROID__
struct ipv6hdr {
	__u8 priority : 4,
	    version : 4;
	__u8 flow_lbl[3];

	__be16 payload_len;
	__u8 nexthdr;
	__u8 hop_limit;

	struct in6_addr saddr;
	struct in6_addr daddr;
};
#endif

struct tcp_resources {
	uint32 seq;
	uint32 ack;
};

static long syz_extract_tcp_res(volatile long a0, volatile long a1, volatile long a2)
{

	if (tunfd < 0)
		return (uintptr_t)-1;
	char data[1000];
	int rv = read_tun(&data[0], sizeof(data));
	if (rv == -1)
		return (uintptr_t)-1;
	size_t length = rv;
	debug_dump_data(data, length);

	if (length < sizeof(struct ethhdr))
		return (uintptr_t)-1;
	struct ethhdr* ethhdr = (struct ethhdr*)&data[0];

	struct tcphdr* tcphdr = 0;
	if (ethhdr->h_proto == htons(ETH_P_IP)) {
		if (length < sizeof(struct ethhdr) + sizeof(struct iphdr))
			return (uintptr_t)-1;
		struct iphdr* iphdr = (struct iphdr*)&data[sizeof(struct ethhdr)];
		if (iphdr->protocol != IPPROTO_TCP)
			return (uintptr_t)-1;
		if (length < sizeof(struct ethhdr) + iphdr->ihl * 4 + sizeof(struct tcphdr))
			return (uintptr_t)-1;
		tcphdr = (struct tcphdr*)&data[sizeof(struct ethhdr) + iphdr->ihl * 4];
	} else {
		if (length < sizeof(struct ethhdr) + sizeof(struct ipv6hdr))
			return (uintptr_t)-1;
		struct ipv6hdr* ipv6hdr = (struct ipv6hdr*)&data[sizeof(struct ethhdr)];
		if (ipv6hdr->nexthdr != IPPROTO_TCP)
			return (uintptr_t)-1;
		if (length < sizeof(struct ethhdr) + sizeof(struct ipv6hdr) + sizeof(struct tcphdr))
			return (uintptr_t)-1;
		tcphdr = (struct tcphdr*)&data[sizeof(struct ethhdr) + sizeof(struct ipv6hdr)];
	}

	struct tcp_resources* res = (struct tcp_resources*)a0;
	res->seq = htonl((ntohl(tcphdr->seq) + (uint32)a1));
	res->ack = htonl((ntohl(tcphdr->ack_seq) + (uint32)a2));

	debug("extracted seq: %08x\n", res->seq);
	debug("extracted ack: %08x\n", res->ack);

	return 0;
}
#endif

#if SYZ_EXECUTOR || SYZ_CLOSE_FDS || __NR_syz_usb_connect || __NR_syz_usb_connect_ath9k
#define MAX_FDS 30
#endif

#if SYZ_EXECUTOR || __NR_syz_usb_connect || __NR_syz_usb_connect_ath9k ||       \
    __NR_syz_usb_ep_write || __NR_syz_usb_ep_read || __NR_syz_usb_control_io || \
    __NR_syz_usb_disconnect
#include <errno.h>
#include <fcntl.h>
#include <linux/usb/ch9.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/types.h>

#define USB_MAX_IFACE_NUM 4
#define USB_MAX_EP_NUM 32
#define USB_MAX_FDS 6

struct usb_endpoint_index {
	struct usb_endpoint_descriptor desc;
	int handle;
};

struct usb_iface_index {
	struct usb_interface_descriptor* iface;
	uint8 bInterfaceNumber;
	uint8 bAlternateSetting;
	uint8 bInterfaceClass;
	struct usb_endpoint_index eps[USB_MAX_EP_NUM];
	int eps_num;
};

struct usb_device_index {
	struct usb_device_descriptor* dev;
	struct usb_config_descriptor* config;
	uint8 bDeviceClass;
	uint8 bMaxPower;
	int config_length;
	struct usb_iface_index ifaces[USB_MAX_IFACE_NUM];
	int ifaces_num;
	int iface_cur;
};

struct usb_info {
	int fd;
	struct usb_device_index index;
};

#if SYZ_EXECUTOR || __NR_syz_usb_connect || __NR_syz_usb_connect_ath9k || \
    __NR_syz_usb_control_io || __NR_syz_usb_ep_read || __NR_syz_usb_ep_write
static struct usb_info usb_devices[USB_MAX_FDS];

static struct usb_device_index* lookup_usb_index(int fd)
{
	for (int i = 0; i < USB_MAX_FDS; i++) {
		if (__atomic_load_n(&usb_devices[i].fd, __ATOMIC_ACQUIRE) == fd)
			return &usb_devices[i].index;
	}
	return NULL;
}
#endif

#if SYZ_EXECUTOR || __NR_syz_usb_connect || __NR_syz_usb_connect_ath9k
static int usb_devices_num;

static bool parse_usb_descriptor(const char* buffer, size_t length, struct usb_device_index* index)
{
	if (length < sizeof(*index->dev) + sizeof(*index->config))
		return false;

	memset(index, 0, sizeof(*index));

	index->dev = (struct usb_device_descriptor*)buffer;
	index->config = (struct usb_config_descriptor*)(buffer + sizeof(*index->dev));
	index->bDeviceClass = index->dev->bDeviceClass;
	index->bMaxPower = index->config->bMaxPower;
	index->config_length = length - sizeof(*index->dev);
	index->iface_cur = -1;
	size_t offset = 0;

	while (true) {
		if (offset + 1 >= length)
			break;
		uint8 desc_length = buffer[offset];
		uint8 desc_type = buffer[offset + 1];
		if (desc_length <= 2)
			break;
		if (offset + desc_length > length)
			break;
		if (desc_type == USB_DT_INTERFACE && index->ifaces_num < USB_MAX_IFACE_NUM) {
			struct usb_interface_descriptor* iface = (struct usb_interface_descriptor*)(buffer + offset);
			debug("parse_usb_descriptor: found interface #%u (%d, %d) at %p\n",
			      index->ifaces_num, iface->bInterfaceNumber, iface->bAlternateSetting, iface);
			index->ifaces[index->ifaces_num].iface = iface;
			index->ifaces[index->ifaces_num].bInterfaceNumber = iface->bInterfaceNumber;
			index->ifaces[index->ifaces_num].bAlternateSetting = iface->bAlternateSetting;
			index->ifaces[index->ifaces_num].bInterfaceClass = iface->bInterfaceClass;
			index->ifaces_num++;
		}
		if (desc_type == USB_DT_ENDPOINT && index->ifaces_num > 0) {
			struct usb_iface_index* iface = &index->ifaces[index->ifaces_num - 1];
			debug("parse_usb_descriptor: found endpoint #%u at %p\n", iface->eps_num, buffer + offset);
			if (iface->eps_num < USB_MAX_EP_NUM) {
				memcpy(&iface->eps[iface->eps_num].desc, buffer + offset, sizeof(iface->eps[iface->eps_num].desc));
				iface->eps_num++;
			}
		}
		offset += desc_length;
	}

	return true;
}

static struct usb_device_index* add_usb_index(int fd, const char* dev, size_t dev_len)
{
	int i = __atomic_fetch_add(&usb_devices_num, 1, __ATOMIC_RELAXED);
	if (i >= USB_MAX_FDS)
		return NULL;

	if (!parse_usb_descriptor(dev, dev_len, &usb_devices[i].index))
		return NULL;

	__atomic_store_n(&usb_devices[i].fd, fd, __ATOMIC_RELEASE);
	return &usb_devices[i].index;
}

#endif

#if USB_DEBUG

#include <linux/hid.h>
#include <linux/usb/audio.h>
#include <linux/usb/cdc.h>
#include <linux/usb/ch11.h>
#include <linux/usb/ch9.h>
#define USBLP_REQ_GET_ID 0x00
#define USBLP_REQ_GET_STATUS 0x01
#define USBLP_REQ_RESET 0x02

const char* usb_class_to_string(unsigned value)
{
	switch (value) {
	case USB_CLASS_PER_INTERFACE:
		return "USB_CLASS_PER_INTERFACE";
	case USB_CLASS_AUDIO:
		return "USB_CLASS_AUDIO";
	case USB_CLASS_COMM:
		return "USB_CLASS_COMM";
	case USB_CLASS_HID:
		return "USB_CLASS_HID";
	case USB_CLASS_PHYSICAL:
		return "USB_CLASS_PHYSICAL";
	case USB_CLASS_STILL_IMAGE:
		return "USB_CLASS_STILL_IMAGE";
	case USB_CLASS_PRINTER:
		return "USB_CLASS_PRINTER";
	case USB_CLASS_MASS_STORAGE:
		return "USB_CLASS_MASS_STORAGE";
	case USB_CLASS_HUB:
		return "USB_CLASS_HUB";
	case USB_CLASS_CDC_DATA:
		return "USB_CLASS_CDC_DATA";
	case USB_CLASS_CSCID:
		return "USB_CLASS_CSCID";
	case USB_CLASS_CONTENT_SEC:
		return "USB_CLASS_CONTENT_SEC";
	case USB_CLASS_VIDEO:
		return "USB_CLASS_VIDEO";
	case USB_CLASS_WIRELESS_CONTROLLER:
		return "USB_CLASS_WIRELESS_CONTROLLER";
	case USB_CLASS_MISC:
		return "USB_CLASS_MISC";
	case USB_CLASS_APP_SPEC:
		return "USB_CLASS_APP_SPEC";
	case USB_CLASS_VENDOR_SPEC:
		return "USB_CLASS_VENDOR_SPEC";
	}
	return "unknown";
}
static void analyze_usb_device(struct usb_device_index* index)
{
	debug("analyze_usb_device: idVendor = %04x\n", (unsigned)index->dev->idVendor);
	debug("analyze_usb_device: idProduct = %04x\n", (unsigned)index->dev->idProduct);

	debug("analyze_usb_device: bDeviceClass = %x (%s)\n", (unsigned)index->dev->bDeviceClass,
	      usb_class_to_string(index->dev->bDeviceClass));
	debug("analyze_usb_device: bDeviceSubClass = %x\n", (unsigned)index->dev->bDeviceSubClass);
	debug("analyze_usb_device: bDeviceProtocol = %x\n", (unsigned)index->dev->bDeviceProtocol);

	for (int i = 0; i < index->ifaces_num; i++) {
		struct usb_interface_descriptor* iface = index->ifaces[i].iface;
		debug("analyze_usb_device: interface #%d:\n", i);
		debug("analyze_usb_device: bInterfaceClass = %x (%s)\n", (unsigned)iface->bInterfaceClass,
		      usb_class_to_string(iface->bInterfaceClass));
		debug("analyze_usb_device: bInterfaceSubClass = %x\n", (unsigned)iface->bInterfaceSubClass);
		debug("analyze_usb_device: bInterfaceProtocol = %x\n", (unsigned)iface->bInterfaceProtocol);
	}
}

static bool analyze_control_request_standard(struct usb_device_index* index, struct usb_ctrlrequest* ctrl)
{
	uint8 bDeviceClass = index->bDeviceClass;
	uint8 bInterfaceClass = index->ifaces[index->iface_cur].bInterfaceClass;
	if (bDeviceClass == USB_CLASS_HID || bInterfaceClass == USB_CLASS_HID) {
		switch (ctrl->bRequest) {
		case USB_REQ_GET_DESCRIPTOR:
			debug("analyze_control_request: req = USB_REQ_GET_DESCRIPTOR\n");
			switch (ctrl->wValue >> 8) {
			case HID_DT_HID:
				debug("analyze_control_request: desc = HID_DT_HID\n");
				return true;
			case HID_DT_REPORT:
				debug("analyze_control_request: desc = HID_DT_REPORT\n");
				return true;
			case HID_DT_PHYSICAL:
				debug("analyze_control_request: desc = HID_DT_PHYSICAL\n");
				return false;
			}
		}
	}

	switch (ctrl->bRequest) {
	case USB_REQ_GET_DESCRIPTOR:
		debug("analyze_control_request: req = USB_REQ_GET_DESCRIPTOR\n");
		switch (ctrl->wValue >> 8) {
		case USB_DT_DEVICE:
			debug("analyze_control_request: desc = USB_DT_DEVICE\n");
			return true;
		case USB_DT_CONFIG:
			debug("analyze_control_request: desc = USB_DT_CONFIG, index = %d\n", (int)(ctrl->wValue & 0xff));
			return true;
		case USB_DT_STRING:
			debug("analyze_control_request: desc = USB_DT_STRING\n");
			return true;
		case USB_DT_INTERFACE:
			debug("analyze_control_request: desc = USB_DT_INTERFACE\n");
			break;
		case USB_DT_ENDPOINT:
			debug("analyze_control_request: desc = USB_DT_ENDPOINT\n");
			break;
		case USB_DT_DEVICE_QUALIFIER:
			debug("analyze_control_request: desc = USB_DT_DEVICE_QUALIFIER\n");
			return true;
		case USB_DT_OTHER_SPEED_CONFIG:
			debug("analyze_control_request: desc = USB_DT_OTHER_SPEED_CONFIG\n");
			break;
		case USB_DT_INTERFACE_POWER:
			debug("analyze_control_request: desc = USB_DT_INTERFACE_POWER\n");
			break;
		case USB_DT_OTG:
			debug("analyze_control_request: desc = USB_DT_OTG\n");
			break;
		case USB_DT_DEBUG:
			debug("analyze_control_request: desc = USB_DT_DEBUG\n");
			break;
		case USB_DT_INTERFACE_ASSOCIATION:
			debug("analyze_control_request: desc = USB_DT_INTERFACE_ASSOCIATION\n");
			break;
		case USB_DT_SECURITY:
			debug("analyze_control_request: desc = USB_DT_SECURITY\n");
			break;
		case USB_DT_KEY:
			debug("analyze_control_request: desc = USB_DT_KEY\n");
			break;
		case USB_DT_ENCRYPTION_TYPE:
			debug("analyze_control_request: desc = USB_DT_ENCRYPTION_TYPE\n");
			break;
		case USB_DT_BOS:
			debug("analyze_control_request: desc = USB_DT_BOS\n");
			return true;
		case USB_DT_DEVICE_CAPABILITY:
			debug("analyze_control_request: desc = USB_DT_DEVICE_CAPABILITY\n");
			break;
		case USB_DT_WIRELESS_ENDPOINT_COMP:
			debug("analyze_control_request: desc = USB_DT_WIRELESS_ENDPOINT_COMP\n");
			break;
		case USB_DT_WIRE_ADAPTER:
			debug("analyze_control_request: desc = USB_DT_WIRE_ADAPTER\n");
			break;
		case USB_DT_RPIPE:
			debug("analyze_control_request: desc = USB_DT_RPIPE\n");
			break;
		case USB_DT_CS_RADIO_CONTROL:
			debug("analyze_control_request: desc = USB_DT_CS_RADIO_CONTROL\n");
			break;
		case USB_DT_PIPE_USAGE:
			debug("analyze_control_request: desc = USB_DT_PIPE_USAGE\n");
			break;
		case USB_DT_SS_ENDPOINT_COMP:
			debug("analyze_control_request: desc = USB_DT_SS_ENDPOINT_COMP\n");
			break;
		case USB_DT_SSP_ISOC_ENDPOINT_COMP:
			debug("analyze_control_request: desc = USB_DT_SSP_ISOC_ENDPOINT_COMP\n");
			break;
		default:
			debug("analyze_control_request: desc = unknown = 0x%x\n", (int)(ctrl->wValue >> 8));
			break;
		}
		break;
	case USB_REQ_GET_STATUS:
		debug("analyze_control_request: req = USB_REQ_GET_STATUS\n");
		break;
	case USB_REQ_CLEAR_FEATURE:
		debug("analyze_control_request: req = USB_REQ_CLEAR_FEATURE\n");
		break;
	case USB_REQ_SET_FEATURE:
		debug("analyze_control_request: req = USB_REQ_SET_FEATURE\n");
		break;
	case USB_REQ_GET_CONFIGURATION:
		debug("analyze_control_request: req = USB_REQ_GET_CONFIGURATION\n");
		return true;
	case USB_REQ_SET_CONFIGURATION:
		debug("analyze_control_request: req = USB_REQ_SET_CONFIGURATION\n");
		break;
	case USB_REQ_GET_INTERFACE:
		debug("analyze_control_request: req = USB_REQ_GET_INTERFACE\n");
		return true;
	case USB_REQ_SET_INTERFACE:
		debug("analyze_control_request: req = USB_REQ_SET_INTERFACE\n");
		break;
	default:
		debug("analyze_control_request: req = unknown = 0x%x\n", (int)ctrl->bRequest);
		break;
	}

	return false;
}

static bool analyze_control_request_class(struct usb_device_index* index, struct usb_ctrlrequest* ctrl)
{
	uint8 bDeviceClass = index->bDeviceClass;
	uint8 bInterfaceClass = index->ifaces[index->iface_cur].bInterfaceClass;

	if (bDeviceClass == USB_CLASS_HID || bInterfaceClass == USB_CLASS_HID) {
		switch (ctrl->bRequest) {
		case HID_REQ_GET_REPORT:
			debug("analyze_control_request: req = HID_REQ_GET_REPORT\n");
			return true;
		case HID_REQ_GET_IDLE:
			debug("analyze_control_request: req = HID_REQ_GET_IDLE\n");
			break;
		case HID_REQ_GET_PROTOCOL:
			debug("analyze_control_request: req = HID_REQ_GET_PROTOCOL\n");
			return true;
		case HID_REQ_SET_REPORT:
			debug("analyze_control_request: req = HID_REQ_SET_REPORT\n");
			break;
		case HID_REQ_SET_IDLE:
			debug("analyze_control_request: req = HID_REQ_SET_IDLE\n");
			break;
		case HID_REQ_SET_PROTOCOL:
			debug("analyze_control_request: req = HID_REQ_SET_PROTOCOL\n");
			break;
		}
	}

	if (bDeviceClass == USB_CLASS_AUDIO || bInterfaceClass == USB_CLASS_AUDIO) {
		switch (ctrl->bRequest) {
		case UAC_SET_CUR:
			debug("analyze_control_request: req = UAC_SET_CUR\n");
			break;
		case UAC_GET_CUR:
			debug("analyze_control_request: req = UAC_GET_CUR\n");
			return true;
		case UAC_SET_MIN:
			debug("analyze_control_request: req = UAC_SET_MIN\n");
			break;
		case UAC_GET_MIN:
			debug("analyze_control_request: req = UAC_GET_MIN\n");
			return true;
		case UAC_SET_MAX:
			debug("analyze_control_request: req = UAC_SET_MAX\n");
			break;
		case UAC_GET_MAX:
			debug("analyze_control_request: req = UAC_GET_MAX\n");
			return true;
		case UAC_SET_RES:
			debug("analyze_control_request: req = UAC_SET_RES\n");
			break;
		case UAC_GET_RES:
			debug("analyze_control_request: req = UAC_GET_RES\n");
			return true;
		case UAC_SET_MEM:
			debug("analyze_control_request: req = UAC_SET_MEM\n");
			break;
		case UAC_GET_MEM:
			debug("analyze_control_request: req = UAC_GET_MEM\n");
			return true;
		}
	}

	if (bDeviceClass == USB_CLASS_PRINTER || bInterfaceClass == USB_CLASS_PRINTER) {
		switch (ctrl->bRequest) {
		case USBLP_REQ_GET_ID:
			debug("analyze_control_request: req = USBLP_REQ_GET_ID\n");
			return true;
		case USBLP_REQ_GET_STATUS:
			debug("analyze_control_request: req = USBLP_REQ_GET_STATUS\n");
			return true;
		case USBLP_REQ_RESET:
			debug("analyze_control_request: req = USBLP_REQ_RESET\n");
			break;
		}
	}

	if (bDeviceClass == USB_CLASS_HUB || bInterfaceClass == USB_CLASS_HUB) {
		switch (ctrl->bRequest) {
		case USB_REQ_GET_DESCRIPTOR:
			switch (ctrl->wValue >> 8) {
			case USB_DT_HUB:
				debug("analyze_control_request: desc = USB_DT_HUB\n");
				return true;
			case USB_DT_SS_HUB:
				debug("analyze_control_request: desc = USB_DT_SS_HUB\n");
				return true;
			}
		case USB_REQ_GET_STATUS:
			debug("analyze_control_request: req = USB_REQ_GET_STATUS\n");
			return true;
		case HUB_SET_DEPTH:
			debug("analyze_control_request: req = HUB_SET_DEPTH\n");
			break;
		}
	}

	if (bInterfaceClass == USB_CLASS_COMM) {
		switch (ctrl->bRequest) {
		case USB_CDC_SEND_ENCAPSULATED_COMMAND:
			debug("analyze_control_request: req = USB_CDC_SEND_ENCAPSULATED_COMMAND\n");
			break;
		case USB_CDC_GET_ENCAPSULATED_RESPONSE:
			debug("analyze_control_request: req = USB_CDC_GET_ENCAPSULATED_RESPONSE\n");
			break;
		case USB_CDC_REQ_SET_LINE_CODING:
			debug("analyze_control_request: req = USB_CDC_REQ_SET_LINE_CODING\n");
			break;
		case USB_CDC_REQ_GET_LINE_CODING:
			debug("analyze_control_request: req = USB_CDC_REQ_GET_LINE_CODING\n");
			break;
		case USB_CDC_REQ_SET_CONTROL_LINE_STATE:
			debug("analyze_control_request: req = USB_CDC_REQ_SET_CONTROL_LINE_STATE\n");
			break;
		case USB_CDC_REQ_SEND_BREAK:
			debug("analyze_control_request: req = USB_CDC_REQ_SEND_BREAK\n");
			break;
		case USB_CDC_SET_ETHERNET_MULTICAST_FILTERS:
			debug("analyze_control_request: req = USB_CDC_SET_ETHERNET_MULTICAST_FILTERS\n");
			break;
		case USB_CDC_SET_ETHERNET_PM_PATTERN_FILTER:
			debug("analyze_control_request: req = USB_CDC_SET_ETHERNET_PM_PATTERN_FILTER\n");
			break;
		case USB_CDC_GET_ETHERNET_PM_PATTERN_FILTER:
			debug("analyze_control_request: req = USB_CDC_GET_ETHERNET_PM_PATTERN_FILTER\n");
			break;
		case USB_CDC_SET_ETHERNET_PACKET_FILTER:
			debug("analyze_control_request: req = USB_CDC_SET_ETHERNET_PACKET_FILTER\n");
			break;
		case USB_CDC_GET_ETHERNET_STATISTIC:
			debug("analyze_control_request: req = USB_CDC_GET_ETHERNET_STATISTIC\n");
			break;
		case USB_CDC_GET_NTB_PARAMETERS:
			debug("analyze_control_request: req = USB_CDC_GET_NTB_PARAMETERS\n");
			return true;
		case USB_CDC_GET_NET_ADDRESS:
			debug("analyze_control_request: req = USB_CDC_GET_NET_ADDRESS\n");
			break;
		case USB_CDC_SET_NET_ADDRESS:
			debug("analyze_control_request: req = USB_CDC_SET_NET_ADDRESS\n");
			break;
		case USB_CDC_GET_NTB_FORMAT:
			debug("analyze_control_request: req = USB_CDC_GET_NTB_FORMAT\n");
			return true;
		case USB_CDC_SET_NTB_FORMAT:
			debug("analyze_control_request: req = USB_CDC_SET_NTB_FORMAT\n");
			break;
		case USB_CDC_GET_NTB_INPUT_SIZE:
			debug("analyze_control_request: req = USB_CDC_GET_NTB_INPUT_SIZE\n");
			return true;
		case USB_CDC_SET_NTB_INPUT_SIZE:
			debug("analyze_control_request: req = USB_CDC_SET_NTB_INPUT_SIZE\n");
			break;
		case USB_CDC_GET_MAX_DATAGRAM_SIZE:
			debug("analyze_control_request: req = USB_CDC_GET_MAX_DATAGRAM_SIZE\n");
			return true;
		case USB_CDC_SET_MAX_DATAGRAM_SIZE:
			debug("analyze_control_request: req = USB_CDC_SET_MAX_DATAGRAM_SIZE\n");
			break;
		case USB_CDC_GET_CRC_MODE:
			debug("analyze_control_request: req = USB_CDC_GET_CRC_MODE\n");
			return true;
		case USB_CDC_SET_CRC_MODE:
			debug("analyze_control_request: req = USB_CDC_SET_CRC_MODE\n");
			break;
		}
	}

	return false;
}

static bool analyze_control_request_vendor(struct usb_device_index* index, struct usb_ctrlrequest* ctrl)
{
	return true;
}
static void analyze_control_request(int fd, struct usb_ctrlrequest* ctrl)
{
	struct usb_device_index* index = lookup_usb_index(fd);

	if (!index)
		return;

	switch (ctrl->bRequestType & USB_TYPE_MASK) {
	case USB_TYPE_STANDARD:
		debug("analyze_control_request: type = USB_TYPE_STANDARD\n");
		if (analyze_control_request_standard(index, ctrl))
			return;
		break;
	case USB_TYPE_CLASS:
		debug("analyze_control_request: type = USB_TYPE_CLASS\n");
		if (analyze_control_request_class(index, ctrl))
			return;
		break;
	case USB_TYPE_VENDOR:
		debug("analyze_control_request: type = USB_TYPE_VENDOR\n");
		if (analyze_control_request_vendor(index, ctrl))
			return;
		break;
	}

	if (ctrl->bRequestType & USB_DIR_IN) {
		char message[128];
		debug("analyze_control_request: unknown control request\n");
		snprintf(&message[0], sizeof(message), "BUG: unknown control request (0x%x, 0x%x, 0x%x, 0x%x, %d)",
			 ctrl->bRequestType, ctrl->bRequest, ctrl->wValue, ctrl->wIndex, ctrl->wLength);
		write_file("/dev/kmsg", &message[0]);
	}
}

#endif

struct vusb_connect_string_descriptor {
	uint32 len;
	char* str;
} __attribute__((packed));

struct vusb_connect_descriptors {
	uint32 qual_len;
	char* qual;
	uint32 bos_len;
	char* bos;
	uint32 strs_len;
	struct vusb_connect_string_descriptor strs[0];
} __attribute__((packed));

#if SYZ_EXECUTOR || __NR_syz_usb_connect || __NR_syz_usb_connect_ath9k

static const char default_string[] = {
    8, USB_DT_STRING,
    's', 0, 'y', 0, 'z', 0
};

static const char default_lang_id[] = {
    4, USB_DT_STRING,
    0x09, 0x04
};

static bool lookup_connect_response_in(int fd, const struct vusb_connect_descriptors* descs,
				       const struct usb_ctrlrequest* ctrl,
				       struct usb_qualifier_descriptor* qual,
				       char** response_data, uint32* response_length)
{
	struct usb_device_index* index = lookup_usb_index(fd);
	uint8 str_idx;

	if (!index)
		return false;

	switch (ctrl->bRequestType & USB_TYPE_MASK) {
	case USB_TYPE_STANDARD:
		switch (ctrl->bRequest) {
		case USB_REQ_GET_DESCRIPTOR:
			switch (ctrl->wValue >> 8) {
			case USB_DT_DEVICE:
				*response_data = (char*)index->dev;
				*response_length = sizeof(*index->dev);
				return true;
			case USB_DT_CONFIG:
				*response_data = (char*)index->config;
				*response_length = index->config_length;
				return true;
			case USB_DT_STRING:
				str_idx = (uint8)ctrl->wValue;
				if (descs && str_idx < descs->strs_len) {
					*response_data = descs->strs[str_idx].str;
					*response_length = descs->strs[str_idx].len;
					return true;
				}
				if (str_idx == 0) {
					*response_data = (char*)&default_lang_id[0];
					*response_length = default_lang_id[0];
					return true;
				}
				*response_data = (char*)&default_string[0];
				*response_length = default_string[0];
				return true;
			case USB_DT_BOS:
				*response_data = descs->bos;
				*response_length = descs->bos_len;
				return true;
			case USB_DT_DEVICE_QUALIFIER:
				if (!descs->qual) {
					qual->bLength = sizeof(*qual);
					qual->bDescriptorType = USB_DT_DEVICE_QUALIFIER;
					qual->bcdUSB = index->dev->bcdUSB;
					qual->bDeviceClass = index->dev->bDeviceClass;
					qual->bDeviceSubClass = index->dev->bDeviceSubClass;
					qual->bDeviceProtocol = index->dev->bDeviceProtocol;
					qual->bMaxPacketSize0 = index->dev->bMaxPacketSize0;
					qual->bNumConfigurations = index->dev->bNumConfigurations;
					qual->bRESERVED = 0;
					*response_data = (char*)qual;
					*response_length = sizeof(*qual);
					return true;
				}
				*response_data = descs->qual;
				*response_length = descs->qual_len;
				return true;
			default:
				break;
			}
			break;
		default:
			break;
		}
		break;
	default:
		break;
	}

	debug("lookup_connect_response_in: unknown request");
	return false;
}

#endif

typedef bool (*lookup_connect_out_response_t)(int fd, const struct vusb_connect_descriptors* descs,
					      const struct usb_ctrlrequest* ctrl, bool* done);

#if SYZ_EXECUTOR || __NR_syz_usb_connect
static bool lookup_connect_response_out_generic(int fd, const struct vusb_connect_descriptors* descs,
						const struct usb_ctrlrequest* ctrl, bool* done)
{
	switch (ctrl->bRequestType & USB_TYPE_MASK) {
	case USB_TYPE_STANDARD:
		switch (ctrl->bRequest) {
		case USB_REQ_SET_CONFIGURATION:
			*done = true;
			return true;
		default:
			break;
		}
		break;
	}

	debug("lookup_connect_response_out: unknown request");
	return false;
}
#endif

#if GOOS_linux && (SYZ_EXECUTOR || __NR_syz_usb_connect_ath9k)
#define ATH9K_FIRMWARE_DOWNLOAD 0x30
#define ATH9K_FIRMWARE_DOWNLOAD_COMP 0x31

static bool lookup_connect_response_out_ath9k(int fd, const struct vusb_connect_descriptors* descs,
					      const struct usb_ctrlrequest* ctrl, bool* done)
{
	switch (ctrl->bRequestType & USB_TYPE_MASK) {
	case USB_TYPE_STANDARD:
		switch (ctrl->bRequest) {
		case USB_REQ_SET_CONFIGURATION:
			return true;
		default:
			break;
		}
		break;
	case USB_TYPE_VENDOR:
		switch (ctrl->bRequest) {
		case ATH9K_FIRMWARE_DOWNLOAD:
			return true;
		case ATH9K_FIRMWARE_DOWNLOAD_COMP:
			*done = true;
			return true;
		default:
			break;
		}
		break;
	}

	debug("lookup_connect_response_out_ath9k: unknown request");
	return false;
}

#endif

#if GOOS_linux && (SYZ_EXECUTOR || __NR_syz_usb_control_io)

struct vusb_descriptor {
	uint8 req_type;
	uint8 desc_type;
	uint32 len;
	char data[0];
} __attribute__((packed));

struct vusb_descriptors {
	uint32 len;
	struct vusb_descriptor* generic;
	struct vusb_descriptor* descs[0];
} __attribute__((packed));

struct vusb_response {
	uint8 type;
	uint8 req;
	uint32 len;
	char data[0];
} __attribute__((packed));

struct vusb_responses {
	uint32 len;
	struct vusb_response* generic;
	struct vusb_response* resps[0];
} __attribute__((packed));

static bool lookup_control_response(const struct vusb_descriptors* descs, const struct vusb_responses* resps,
				    struct usb_ctrlrequest* ctrl, char** response_data, uint32* response_length)
{
	int descs_num = 0;
	int resps_num = 0;

	if (descs)
		descs_num = (descs->len - offsetof(struct vusb_descriptors, descs)) / sizeof(descs->descs[0]);
	if (resps)
		resps_num = (resps->len - offsetof(struct vusb_responses, resps)) / sizeof(resps->resps[0]);

	uint8 req = ctrl->bRequest;
	uint8 req_type = ctrl->bRequestType & USB_TYPE_MASK;
	uint8 desc_type = ctrl->wValue >> 8;

	if (req == USB_REQ_GET_DESCRIPTOR) {
		int i;

		for (i = 0; i < descs_num; i++) {
			struct vusb_descriptor* desc = descs->descs[i];
			if (!desc)
				continue;
			if (desc->req_type == req_type && desc->desc_type == desc_type) {
				*response_length = desc->len;
				if (*response_length != 0)
					*response_data = &desc->data[0];
				else
					*response_data = NULL;
				return true;
			}
		}

		if (descs && descs->generic) {
			*response_data = &descs->generic->data[0];
			*response_length = descs->generic->len;
			return true;
		}
	} else {
		int i;

		for (i = 0; i < resps_num; i++) {
			struct vusb_response* resp = resps->resps[i];
			if (!resp)
				continue;
			if (resp->type == req_type && resp->req == req) {
				*response_length = resp->len;
				if (*response_length != 0)
					*response_data = &resp->data[0];
				else
					*response_data = NULL;
				return true;
			}
		}

		if (resps && resps->generic) {
			*response_data = &resps->generic->data[0];
			*response_length = resps->generic->len;
			return true;
		}
	}

	return false;
}

#endif


#define UDC_NAME_LENGTH_MAX 128

struct usb_raw_init {
	__u8 driver_name[UDC_NAME_LENGTH_MAX];
	__u8 device_name[UDC_NAME_LENGTH_MAX];
	__u8 speed;
};

enum usb_raw_event_type {
	USB_RAW_EVENT_INVALID = 0,
	USB_RAW_EVENT_CONNECT = 1,
	USB_RAW_EVENT_CONTROL = 2,
};

struct usb_raw_event {
	__u32 type;
	__u32 length;
	__u8 data[0];
};

struct usb_raw_ep_io {
	__u16 ep;
	__u16 flags;
	__u32 length;
	__u8 data[0];
};

#define USB_RAW_EPS_NUM_MAX 30
#define USB_RAW_EP_NAME_MAX 16
#define USB_RAW_EP_ADDR_ANY 0xff

struct usb_raw_ep_caps {
	__u32 type_control : 1;
	__u32 type_iso : 1;
	__u32 type_bulk : 1;
	__u32 type_int : 1;
	__u32 dir_in : 1;
	__u32 dir_out : 1;
};

struct usb_raw_ep_limits {
	__u16 maxpacket_limit;
	__u16 max_streams;
	__u32 reserved;
};

struct usb_raw_ep_info {
	__u8 name[USB_RAW_EP_NAME_MAX];
	__u32 addr;
	struct usb_raw_ep_caps caps;
	struct usb_raw_ep_limits limits;
};

struct usb_raw_eps_info {
	struct usb_raw_ep_info eps[USB_RAW_EPS_NUM_MAX];
};

#define USB_RAW_IOCTL_INIT _IOW('U', 0, struct usb_raw_init)
#define USB_RAW_IOCTL_RUN _IO('U', 1)
#define USB_RAW_IOCTL_EVENT_FETCH _IOR('U', 2, struct usb_raw_event)
#define USB_RAW_IOCTL_EP0_WRITE _IOW('U', 3, struct usb_raw_ep_io)
#define USB_RAW_IOCTL_EP0_READ _IOWR('U', 4, struct usb_raw_ep_io)
#define USB_RAW_IOCTL_EP_ENABLE _IOW('U', 5, struct usb_endpoint_descriptor)
#define USB_RAW_IOCTL_EP_DISABLE _IOW('U', 6, __u32)
#define USB_RAW_IOCTL_EP_WRITE _IOW('U', 7, struct usb_raw_ep_io)
#define USB_RAW_IOCTL_EP_READ _IOWR('U', 8, struct usb_raw_ep_io)
#define USB_RAW_IOCTL_CONFIGURE _IO('U', 9)
#define USB_RAW_IOCTL_VBUS_DRAW _IOW('U', 10, __u32)
#define USB_RAW_IOCTL_EPS_INFO _IOR('U', 11, struct usb_raw_eps_info)
#define USB_RAW_IOCTL_EP0_STALL _IO('U', 12)
#define USB_RAW_IOCTL_EP_SET_HALT _IOW('U', 13, __u32)
#define USB_RAW_IOCTL_EP_CLEAR_HALT _IOW('U', 14, __u32)
#define USB_RAW_IOCTL_EP_SET_WEDGE _IOW('U', 15, __u32)

#if SYZ_EXECUTOR || __NR_syz_usb_connect || __NR_syz_usb_connect_ath9k
static int usb_raw_open()
{
	return open("/dev/raw-gadget", O_RDWR);
}

static int usb_raw_init(int fd, uint32 speed, const char* driver, const char* device)
{
	struct usb_raw_init arg;
	strncpy((char*)&arg.driver_name[0], driver, sizeof(arg.driver_name));
	strncpy((char*)&arg.device_name[0], device, sizeof(arg.device_name));
	arg.speed = speed;
	return ioctl(fd, USB_RAW_IOCTL_INIT, &arg);
}

static int usb_raw_run(int fd)
{
	return ioctl(fd, USB_RAW_IOCTL_RUN, 0);
}
#endif

#if SYZ_EXECUTOR || __NR_syz_usb_ep_write
static int usb_raw_ep_write(int fd, struct usb_raw_ep_io* io)
{
	return ioctl(fd, USB_RAW_IOCTL_EP_WRITE, io);
}
#endif

#if SYZ_EXECUTOR || __NR_syz_usb_ep_read
static int usb_raw_ep_read(int fd, struct usb_raw_ep_io* io)
{
	return ioctl(fd, USB_RAW_IOCTL_EP_READ, io);
}
#endif

#if SYZ_EXECUTOR || __NR_syz_usb_connect || __NR_syz_usb_connect_ath9k

static int usb_raw_configure(int fd)
{
	return ioctl(fd, USB_RAW_IOCTL_CONFIGURE, 0);
}

static int usb_raw_vbus_draw(int fd, uint32 power)
{
	return ioctl(fd, USB_RAW_IOCTL_VBUS_DRAW, power);
}

#endif

#if SYZ_EXECUTOR || __NR_syz_usb_connect || __NR_syz_usb_connect_ath9k || __NR_syz_usb_control_io
static int usb_raw_ep0_write(int fd, struct usb_raw_ep_io* io)
{
	return ioctl(fd, USB_RAW_IOCTL_EP0_WRITE, io);
}

static int usb_raw_ep0_read(int fd, struct usb_raw_ep_io* io)
{
	return ioctl(fd, USB_RAW_IOCTL_EP0_READ, io);
}

static int usb_raw_event_fetch(int fd, struct usb_raw_event* event)
{
	return ioctl(fd, USB_RAW_IOCTL_EVENT_FETCH, event);
}

static int usb_raw_ep_enable(int fd, struct usb_endpoint_descriptor* desc)
{
	return ioctl(fd, USB_RAW_IOCTL_EP_ENABLE, desc);
}

static int usb_raw_ep_disable(int fd, int ep)
{
	return ioctl(fd, USB_RAW_IOCTL_EP_DISABLE, ep);
}

static int usb_raw_ep0_stall(int fd)
{
	return ioctl(fd, USB_RAW_IOCTL_EP0_STALL, 0);
}
#endif

#if SYZ_EXECUTOR || __NR_syz_usb_control_io
static int lookup_interface(int fd, uint8 bInterfaceNumber, uint8 bAlternateSetting)
{
	struct usb_device_index* index = lookup_usb_index(fd);
	if (!index)
		return -1;

	for (int i = 0; i < index->ifaces_num; i++) {
		if (index->ifaces[i].bInterfaceNumber == bInterfaceNumber &&
		    index->ifaces[i].bAlternateSetting == bAlternateSetting)
			return i;
	}
	return -1;
}
#endif

#if SYZ_EXECUTOR || __NR_syz_usb_ep_write || __NR_syz_usb_ep_read
static int lookup_endpoint(int fd, uint8 bEndpointAddress)
{
	struct usb_device_index* index = lookup_usb_index(fd);
	if (!index)
		return -1;
	if (index->iface_cur < 0)
		return -1;

	for (int ep = 0; ep < index->ifaces[index->iface_cur].eps_num; ep++)
		if (index->ifaces[index->iface_cur].eps[ep].desc.bEndpointAddress == bEndpointAddress)
			return index->ifaces[index->iface_cur].eps[ep].handle;
	return -1;
}
#endif

#define USB_MAX_PACKET_SIZE 4096

struct usb_raw_control_event {
	struct usb_raw_event inner;
	struct usb_ctrlrequest ctrl;
	char data[USB_MAX_PACKET_SIZE];
};

struct usb_raw_ep_io_data {
	struct usb_raw_ep_io inner;
	char data[USB_MAX_PACKET_SIZE];
};

#if SYZ_EXECUTOR || __NR_syz_usb_connect || __NR_syz_usb_connect_ath9k || __NR_syz_usb_control_io
static void set_interface(int fd, int n)
{
	struct usb_device_index* index = lookup_usb_index(fd);
	if (!index)
		return;

	if (index->iface_cur >= 0 && index->iface_cur < index->ifaces_num) {
		for (int ep = 0; ep < index->ifaces[index->iface_cur].eps_num; ep++) {
			int rv = usb_raw_ep_disable(fd, index->ifaces[index->iface_cur].eps[ep].handle);
			if (rv < 0) {
				debug("set_interface: failed to disable endpoint 0x%02x\n",
				      index->ifaces[index->iface_cur].eps[ep].desc.bEndpointAddress);
			} else {
				debug("set_interface: endpoint 0x%02x disabled\n",
				      index->ifaces[index->iface_cur].eps[ep].desc.bEndpointAddress);
			}
		}
	}
	if (n >= 0 && n < index->ifaces_num) {
		for (int ep = 0; ep < index->ifaces[n].eps_num; ep++) {
			int rv = usb_raw_ep_enable(fd, &index->ifaces[n].eps[ep].desc);
			if (rv < 0) {
				debug("set_interface: failed to enable endpoint 0x%02x\n",
				      index->ifaces[n].eps[ep].desc.bEndpointAddress);
			} else {
				debug("set_interface: endpoint 0x%02x enabled as %d\n",
				      index->ifaces[n].eps[ep].desc.bEndpointAddress, rv);
				index->ifaces[n].eps[ep].handle = rv;
			}
		}
		index->iface_cur = n;
	}
}
#endif

#if SYZ_EXECUTOR || __NR_syz_usb_connect || __NR_syz_usb_connect_ath9k
static int configure_device(int fd)
{
	struct usb_device_index* index = lookup_usb_index(fd);

	if (!index)
		return -1;

	int rv = usb_raw_vbus_draw(fd, index->bMaxPower);
	if (rv < 0) {
		debug("configure_device: usb_raw_vbus_draw failed with %d\n", rv);
		return rv;
	}
	rv = usb_raw_configure(fd);
	if (rv < 0) {
		debug("configure_device: usb_raw_configure failed with %d\n", rv);
		return rv;
	}
	set_interface(fd, 0);
	return 0;
}

static volatile long syz_usb_connect_impl(uint64 speed, uint64 dev_len, const char* dev,
					  const struct vusb_connect_descriptors* descs,
					  lookup_connect_out_response_t lookup_connect_response_out)
{
	debug("syz_usb_connect: dev: %p\n", dev);
	if (!dev) {
		debug("syz_usb_connect: dev is null\n");
		return -1;
	}

	debug("syz_usb_connect: device data:\n");
	debug_dump_data(dev, dev_len);

	int fd = usb_raw_open();
	if (fd < 0) {
		debug("syz_usb_connect: usb_raw_open failed with %d\n", fd);
		return fd;
	}
	if (fd >= MAX_FDS) {
		close(fd);
		debug("syz_usb_connect: too many open fds\n");
		return -1;
	}
	debug("syz_usb_connect: usb_raw_open success\n");

	struct usb_device_index* index = add_usb_index(fd, dev, dev_len);
	if (!index) {
		debug("syz_usb_connect: add_usb_index failed\n");
		return -1;
	}
	debug("syz_usb_connect: add_usb_index success\n");

#if USB_DEBUG
	analyze_usb_device(index);
#endif
	char device[32];
	sprintf(&device[0], "dummy_udc.%llu", procid);
	int rv = usb_raw_init(fd, speed, "dummy_udc", &device[0]);
	if (rv < 0) {
		debug("syz_usb_connect: usb_raw_init failed with %d\n", rv);
		return rv;
	}
	debug("syz_usb_connect: usb_raw_init success\n");

	rv = usb_raw_run(fd);
	if (rv < 0) {
		debug("syz_usb_connect: usb_raw_run failed with %d\n", rv);
		return rv;
	}
	debug("syz_usb_connect: usb_raw_run success\n");

	bool done = false;
	while (!done) {
		struct usb_raw_control_event event;
		event.inner.type = 0;
		event.inner.length = sizeof(event.ctrl);
		rv = usb_raw_event_fetch(fd, (struct usb_raw_event*)&event);
		if (rv < 0) {
			debug("syz_usb_connect: usb_raw_event_fetch failed with %d\n", rv);
			return rv;
		}
		if (event.inner.type != USB_RAW_EVENT_CONTROL)
			continue;

		debug("syz_usb_connect: bReqType: 0x%x (%s), bReq: 0x%x, wVal: 0x%x, wIdx: 0x%x, wLen: %d\n",
		      event.ctrl.bRequestType, (event.ctrl.bRequestType & USB_DIR_IN) ? "IN" : "OUT",
		      event.ctrl.bRequest, event.ctrl.wValue, event.ctrl.wIndex, event.ctrl.wLength);

#if USB_DEBUG
		analyze_control_request(fd, &event.ctrl);
#endif

		char* response_data = NULL;
		uint32 response_length = 0;
		struct usb_qualifier_descriptor qual;

		if (event.ctrl.bRequestType & USB_DIR_IN) {
			if (!lookup_connect_response_in(fd, descs, &event.ctrl, &qual, &response_data, &response_length)) {
				debug("syz_usb_connect: unknown request, stalling\n");
				usb_raw_ep0_stall(fd);
				continue;
			}
		} else {
			if (!lookup_connect_response_out(fd, descs, &event.ctrl, &done)) {
				debug("syz_usb_connect: unknown request, stalling\n");
				usb_raw_ep0_stall(fd);
				continue;
			}
			response_data = NULL;
			response_length = event.ctrl.wLength;
		}

		if ((event.ctrl.bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD &&
		    event.ctrl.bRequest == USB_REQ_SET_CONFIGURATION) {
			rv = configure_device(fd);
			if (rv < 0) {
				debug("syz_usb_connect: configure_device failed with %d\n", rv);
				return rv;
			}
		}

		struct usb_raw_ep_io_data response;
		response.inner.ep = 0;
		response.inner.flags = 0;
		if (response_length > sizeof(response.data))
			response_length = 0;
		if (event.ctrl.wLength < response_length)
			response_length = event.ctrl.wLength;
		response.inner.length = response_length;
		if (response_data)
			memcpy(&response.data[0], response_data, response_length);
		else
			memset(&response.data[0], 0, response_length);

		if (event.ctrl.bRequestType & USB_DIR_IN) {
			debug("syz_usb_connect: writing %d bytes\n", response.inner.length);
			rv = usb_raw_ep0_write(fd, (struct usb_raw_ep_io*)&response);
		} else {
			rv = usb_raw_ep0_read(fd, (struct usb_raw_ep_io*)&response);
			debug("syz_usb_connect: read %d bytes\n", response.inner.length);
			debug_dump_data(&event.data[0], response.inner.length);
		}
		if (rv < 0) {
			debug("syz_usb_connect: usb_raw_ep0_read/write failed with %d\n", rv);
			return rv;
		}
	}

	sleep_ms(200);

	debug("syz_usb_connect: configured\n");

	return fd;
}

#endif

#if SYZ_EXECUTOR || __NR_syz_usb_connect
static volatile long syz_usb_connect(volatile long a0, volatile long a1, volatile long a2, volatile long a3)
{
	uint64 speed = a0;
	uint64 dev_len = a1;
	const char* dev = (const char*)a2;
	const struct vusb_connect_descriptors* descs = (const struct vusb_connect_descriptors*)a3;

	return syz_usb_connect_impl(speed, dev_len, dev, descs, &lookup_connect_response_out_generic);
}
#endif

#if SYZ_EXECUTOR || __NR_syz_usb_connect_ath9k
static volatile long syz_usb_connect_ath9k(volatile long a0, volatile long a1, volatile long a2, volatile long a3)
{
	uint64 speed = a0;
	uint64 dev_len = a1;
	const char* dev = (const char*)a2;
	const struct vusb_connect_descriptors* descs = (const struct vusb_connect_descriptors*)a3;

	return syz_usb_connect_impl(speed, dev_len, dev, descs, &lookup_connect_response_out_ath9k);
}
#endif

#if SYZ_EXECUTOR || __NR_syz_usb_control_io
static volatile long syz_usb_control_io(volatile long a0, volatile long a1, volatile long a2)
{
	int fd = a0;
	const struct vusb_descriptors* descs = (const struct vusb_descriptors*)a1;
	const struct vusb_responses* resps = (const struct vusb_responses*)a2;

	struct usb_raw_control_event event;
	event.inner.type = 0;
	event.inner.length = USB_MAX_PACKET_SIZE;
	int rv = usb_raw_event_fetch(fd, (struct usb_raw_event*)&event);
	if (rv < 0) {
		debug("syz_usb_control_io: usb_raw_ep0_read failed with %d\n", rv);
		return rv;
	}
	if (event.inner.type != USB_RAW_EVENT_CONTROL) {
		debug("syz_usb_control_io: wrong event type: %d\n", (int)event.inner.type);
		return -1;
	}

	debug("syz_usb_control_io: bReqType: 0x%x (%s), bReq: 0x%x, wVal: 0x%x, wIdx: 0x%x, wLen: %d\n",
	      event.ctrl.bRequestType, (event.ctrl.bRequestType & USB_DIR_IN) ? "IN" : "OUT",
	      event.ctrl.bRequest, event.ctrl.wValue, event.ctrl.wIndex, event.ctrl.wLength);

#if USB_DEBUG
	analyze_control_request(fd, &event.ctrl);
#endif

	char* response_data = NULL;
	uint32 response_length = 0;

	if ((event.ctrl.bRequestType & USB_DIR_IN) && event.ctrl.wLength) {
		if (!lookup_control_response(descs, resps, &event.ctrl, &response_data, &response_length)) {
			debug("syz_usb_connect: unknown request, stalling\n");
			usb_raw_ep0_stall(fd);
			return -1;
		}
	} else {
		if ((event.ctrl.bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD ||
		    event.ctrl.bRequest == USB_REQ_SET_INTERFACE) {
			int iface_num = event.ctrl.wIndex;
			int alt_set = event.ctrl.wValue;
			debug("syz_usb_control_io: setting interface (%d, %d)\n", iface_num, alt_set);
			int iface_index = lookup_interface(fd, iface_num, alt_set);
			if (iface_index < 0) {
				debug("syz_usb_control_io: interface (%d, %d) not found\n", iface_num, alt_set);
			} else {
				set_interface(fd, iface_index);
				debug("syz_usb_control_io: interface (%d, %d) set\n", iface_num, alt_set);
			}
		}

		response_length = event.ctrl.wLength;
	}

	struct usb_raw_ep_io_data response;
	response.inner.ep = 0;
	response.inner.flags = 0;
	if (response_length > sizeof(response.data))
		response_length = 0;
	if (event.ctrl.wLength < response_length)
		response_length = event.ctrl.wLength;
	if ((event.ctrl.bRequestType & USB_DIR_IN) && !event.ctrl.wLength) {
		response_length = USB_MAX_PACKET_SIZE;
	}
	response.inner.length = response_length;
	if (response_data)
		memcpy(&response.data[0], response_data, response_length);
	else
		memset(&response.data[0], 0, response_length);

	if ((event.ctrl.bRequestType & USB_DIR_IN) && event.ctrl.wLength) {
		debug("syz_usb_control_io: writing %d bytes\n", response.inner.length);
		debug_dump_data(&response.data[0], response.inner.length);
		rv = usb_raw_ep0_write(fd, (struct usb_raw_ep_io*)&response);
	} else {
		rv = usb_raw_ep0_read(fd, (struct usb_raw_ep_io*)&response);
		debug("syz_usb_control_io: read %d bytes\n", response.inner.length);
		debug_dump_data(&response.data[0], response.inner.length);
	}
	if (rv < 0) {
		debug("syz_usb_control_io: usb_raw_ep0_read/write failed with %d\n", rv);
		return rv;
	}

	sleep_ms(200);

	return 0;
}
#endif

#if SYZ_EXECUTOR || __NR_syz_usb_ep_write
static volatile long syz_usb_ep_write(volatile long a0, volatile long a1, volatile long a2, volatile long a3)
{
	int fd = a0;
	uint8 ep = a1;
	uint32 len = a2;
	char* data = (char*)a3;

	int ep_handle = lookup_endpoint(fd, ep);
	if (ep_handle < 0) {
		debug("syz_usb_ep_write: endpoint not found\n");
		return -1;
	}
	debug("syz_usb_ep_write: endpoint handle: %d\n", ep_handle);

	struct usb_raw_ep_io_data io_data;
	io_data.inner.ep = ep_handle;
	io_data.inner.flags = 0;
	if (len > sizeof(io_data.data))
		len = sizeof(io_data.data);
	io_data.inner.length = len;
	memcpy(&io_data.data[0], data, len);

	int rv = usb_raw_ep_write(fd, (struct usb_raw_ep_io*)&io_data);
	if (rv < 0) {
		debug("syz_usb_ep_write: usb_raw_ep_write failed with %d\n", rv);
		return rv;
	}

	sleep_ms(200);

	return 0;
}
#endif

#if SYZ_EXECUTOR || __NR_syz_usb_ep_read
static volatile long syz_usb_ep_read(volatile long a0, volatile long a1, volatile long a2, volatile long a3)
{
	int fd = a0;
	uint8 ep = a1;
	uint32 len = a2;
	char* data = (char*)a3;

	int ep_handle = lookup_endpoint(fd, ep);
	if (ep_handle < 0) {
		debug("syz_usb_ep_read: endpoint not found\n");
		return -1;
	}
	debug("syz_usb_ep_read: endpoint handle: %d\n", ep_handle);

	struct usb_raw_ep_io_data io_data;
	io_data.inner.ep = ep_handle;
	io_data.inner.flags = 0;
	if (len > sizeof(io_data.data))
		len = sizeof(io_data.data);
	io_data.inner.length = len;

	int rv = usb_raw_ep_read(fd, (struct usb_raw_ep_io*)&io_data);
	if (rv < 0) {
		debug("syz_usb_ep_read: usb_raw_ep_read failed with %d\n", rv);
		return rv;
	}

	memcpy(&data[0], &io_data.data[0], io_data.inner.length);

	debug("syz_usb_ep_read: received data:\n");
	debug_dump_data(&io_data.data[0], io_data.inner.length);

	sleep_ms(200);

	return 0;
}
#endif

#if SYZ_EXECUTOR || __NR_syz_usb_disconnect
static volatile long syz_usb_disconnect(volatile long a0)
{
	int fd = a0;

	int rv = close(fd);

	sleep_ms(200);

	return rv;
}
#endif

#endif

#if SYZ_EXECUTOR || __NR_syz_open_dev
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>

static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
{
	if (a0 == 0xc || a0 == 0xb) {
		char buf[128];
		sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8)a1, (uint8)a2);
		return open(buf, O_RDWR, 0);
	} else {
		char buf[1024];
		char* hash;
		strncpy(buf, (char*)a0, sizeof(buf) - 1);
		buf[sizeof(buf) - 1] = 0;
		while ((hash = strchr(buf, '#'))) {
			*hash = '0' + (char)(a1 % 10);
			a1 /= 10;
		}
		return open(buf, a2, 0);
	}
}
#endif

#if SYZ_EXECUTOR || __NR_syz_open_procfs
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>

static long syz_open_procfs(volatile long a0, volatile long a1)
{

	char buf[128];
	memset(buf, 0, sizeof(buf));
	if (a0 == 0) {
		snprintf(buf, sizeof(buf), "/proc/self/%s", (char*)a1);
	} else if (a0 == -1) {
		snprintf(buf, sizeof(buf), "/proc/thread-self/%s", (char*)a1);
	} else {
		snprintf(buf, sizeof(buf), "/proc/self/task/%d/%s", (int)a0, (char*)a1);
	}
	int fd = open(buf, O_RDWR);
	if (fd == -1)
		fd = open(buf, O_RDONLY);
	return fd;
}
#endif

#if SYZ_EXECUTOR || __NR_syz_open_pts
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>

static long syz_open_pts(volatile long a0, volatile long a1)
{
	int ptyno = 0;
	if (ioctl(a0, TIOCGPTN, &ptyno))
		return -1;
	char buf[128];
	sprintf(buf, "/dev/pts/%d", ptyno);
	return open(buf, a1, 0);
}
#endif

#if SYZ_EXECUTOR || __NR_syz_init_net_socket
#if SYZ_EXECUTOR || SYZ_SANDBOX_NONE || SYZ_SANDBOX_SETUID || SYZ_SANDBOX_NAMESPACE || SYZ_SANDBOX_ANDROID
#include <fcntl.h>
#include <sched.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
static long syz_init_net_socket(volatile long domain, volatile long type, volatile long proto)
{
	int netns = open("/proc/self/ns/net", O_RDONLY);
	if (netns == -1)
		return netns;
	if (setns(kInitNetNsFd, 0))
		return -1;
	int sock = syscall(__NR_socket, domain, type, proto);
	int err = errno;
	if (setns(netns, 0))
		fail("setns(netns) failed");
	close(netns);
	errno = err;
	return sock;
}
#else
static long syz_init_net_socket(volatile long domain, volatile long type, volatile long proto)
{
	return syscall(__NR_socket, domain, type, proto);
}
#endif
#endif

#if SYZ_EXECUTOR || SYZ_VHCI_INJECTION
#include <errno.h>
#include <fcntl.h>
#include <linux/rfkill.h>
#include <pthread.h>
#include <sys/epoll.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/uio.h>

#define BTPROTO_HCI 1
#define ACL_LINK 1
#define SCAN_PAGE 2

typedef struct {
	uint8 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 opcode;
	uint8 plen;
} __attribute__((packed));

struct hci_event_hdr {
	uint8 evt;
	uint8 plen;
} __attribute__((packed));

#define HCI_EV_CONN_COMPLETE 0x03
struct hci_ev_conn_complete {
	uint8 status;
	uint16 handle;
	bdaddr_t bdaddr;
	uint8 link_type;
	uint8 encr_mode;
} __attribute__((packed));

#define HCI_EV_CONN_REQUEST 0x04
struct hci_ev_conn_request {
	bdaddr_t bdaddr;
	uint8 dev_class[3];
	uint8 link_type;
} __attribute__((packed));

#define HCI_EV_REMOTE_FEATURES 0x0b
struct hci_ev_remote_features {
	uint8 status;
	uint16 handle;
	uint8 features[8];
} __attribute__((packed));

#define HCI_EV_CMD_COMPLETE 0x0e
struct hci_ev_cmd_complete {
	uint8 ncmd;
	uint16 opcode;
} __attribute__((packed));

#define HCI_OP_WRITE_SCAN_ENABLE 0x0c1a

#define HCI_OP_READ_BUFFER_SIZE 0x1005
struct hci_rp_read_buffer_size {
	uint8 status;
	uint16 acl_mtu;
	uint8 sco_mtu;
	uint16 acl_max_pkt;
	uint16 sco_max_pkt;
} __attribute__((packed));

#define HCI_OP_READ_BD_ADDR 0x1009
struct hci_rp_read_bd_addr {
	uint8 status;
	bdaddr_t bdaddr;
} __attribute__((packed));

#define HCI_EV_LE_META 0x3e
struct hci_ev_le_meta {
	uint8 subevent;
} __attribute__((packed));

#define HCI_EV_LE_CONN_COMPLETE 0x01
struct hci_ev_le_conn_complete {
	uint8 status;
	uint16 handle;
	uint8 role;
	uint8 bdaddr_type;
	bdaddr_t bdaddr;
	uint16 interval;
	uint16 latency;
	uint16 supervision_timeout;
	uint8 clk_accurancy;
} __attribute__((packed));

struct hci_dev_req {
	uint16 dev_id;
	uint32 dev_opt;
};

struct vhci_vendor_pkt_request {
	uint8 type;
	uint8 opcode;
} __attribute__((packed));

struct vhci_pkt {
	uint8 type;
	union {
		struct {
			uint8 opcode;
			uint16 id;
		} __attribute__((packed)) vendor_pkt;
		struct hci_command_hdr command_hdr;
	};
} __attribute__((packed));

#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)
		fail("open /dev/rfkill failed");
	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)
		fail("write rfkill event failed");
	close(fd);
}

static void hci_send_event_packet(int fd, uint8 evt, void* data, size_t data_len)
{
	struct iovec iv[3];

	struct hci_event_hdr hdr;
	hdr.evt = evt;
	hdr.plen = data_len;

	uint8 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)
		fail("writev failed");
}

static void hci_send_event_cmd_complete(int fd, uint16 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 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)
		fail("writev failed");
}

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))
		failmsg("process_command_pkt: invalid size", "suze=%zx", buf_size);

	switch (hdr->opcode) {
	case HCI_OP_WRITE_SCAN_ENABLE: {
		uint8 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)
			fail("read failed");
		debug_dump_data(buf, buf_size);
		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

#define HCI_PRIMARY 0
#define HCI_OP_RESET 0x0c03

static void initialize_vhci()
{
#if SYZ_EXECUTOR
	if (!flag_vhci_injection)
		return;
#endif

	int hci_sock = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
	if (hci_sock < 0)
		fail("socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI) failed");

	vhci_fd = open("/dev/vhci", O_RDWR);
	if (vhci_fd == -1)
		fail("open /dev/vhci failed");
	const int kVhciFd = 202;
	if (dup2(vhci_fd, kVhciFd) < 0)
		fail("dup2(vhci_fd, kVhciFd) failed");
	close(vhci_fd);
	vhci_fd = kVhciFd;

	struct vhci_vendor_pkt_request vendor_pkt_req = {HCI_VENDOR_PKT, HCI_PRIMARY};
	if (write(vhci_fd, &vendor_pkt_req, sizeof(vendor_pkt_req)) != sizeof(vendor_pkt_req))
		fail("vendor_pkt_req write failed");

	struct vhci_pkt vhci_pkt;
	if (read(vhci_fd, &vhci_pkt, sizeof(vhci_pkt)) != sizeof(vhci_pkt))
		fail("vhci_pkt read failed");

	if (vhci_pkt.type == HCI_COMMAND_PKT && vhci_pkt.command_hdr.opcode == HCI_OP_RESET) {
		char response[1] = {0};
		hci_send_event_cmd_complete(vhci_fd, HCI_OP_RESET, response, sizeof(response));

		if (read(vhci_fd, &vhci_pkt, sizeof(vhci_pkt)) != sizeof(vhci_pkt))
			fail("vhci_pkt read failed");
	}

	if (vhci_pkt.type != HCI_VENDOR_PKT)
		fail("wrong response packet");

	int dev_id = vhci_pkt.vendor_pkt.id;
	debug("hci dev id: %x\n", dev_id);

	pthread_t th;
	if (pthread_create(&th, NULL, event_thread, NULL))
		fail("pthread_create failed");
	int ret = ioctl(hci_sock, HCIDEVUP, dev_id);
	if (ret) {
		if (errno == ERFKILL) {
			rfkill_unblock_all();
			ret = ioctl(hci_sock, HCIDEVUP, dev_id);
		}

		if (ret && errno != EALREADY)
			fail("ioctl(HCIDEVUP) failed");
	}
	struct hci_dev_req dr = {0};
	dr.dev_id = dev_id;
	dr.dev_opt = SCAN_PAGE;
	if (ioctl(hci_sock, HCISETSCAN, &dr))
		fail("ioctl(HCISETSCAN) failed");
	struct hci_ev_conn_request request;
	memset(&request, 0, sizeof(request));
	memset(&request.bdaddr, 0xaa, 6);
	*(uint8*)&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*)&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*)&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);
}
#endif

#if SYZ_EXECUTOR || __NR_syz_emit_vhci && SYZ_VHCI_INJECTION
static long syz_emit_vhci(volatile long a0, volatile long a1)
{
	if (vhci_fd < 0)
		return (uintptr_t)-1;

	char* data = (char*)a0;
	uint32 length = a1;

	return write(vhci_fd, data, length);
}
#endif

#if SYZ_EXECUTOR || __NR_syz_genetlink_get_family_id
#include <errno.h>
#include <sys/socket.h>

static long syz_genetlink_get_family_id(volatile long name, volatile long sock_arg)
{
	debug("syz_genetlink_get_family_id(%s, %d)\n", (char*)name, (int)sock_arg);
	int fd = sock_arg;
	if (fd < 0) {
		fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
		if (fd == -1) {
			debug("syz_genetlink_get_family_id: socket failed: %d\n", errno);
			return -1;
		}
	}
	struct nlmsg nlmsg_tmp;
	int ret = netlink_query_family_id(&nlmsg_tmp, fd, (char*)name, false);
	if ((int)sock_arg < 0)
		close(fd);
	if (ret < 0) {
		debug("syz_genetlink_get_family_id: netlink_query_family_id failed: %d\n", ret);
		return -1;
	}

	return ret;
}
#endif

#if SYZ_EXECUTOR || __NR_syz_mount_image || __NR_syz_read_part_table

//% This code is derived from puff.{c,h}, found in the zlib development. The
//% original files come with the following copyright notice:

//% Copyright (C) 2002-2013 Mark Adler, all rights reserved
//% version 2.3, 21 Jan 2013
//% This software is provided 'as-is', without any express or implied
//% warranty.  In no event will the author be held liable for any damages
//% arising from the use of this software.
//% Permission is granted to anyone to use this software for any purpose,
//% including commercial applications, and to alter it and redistribute it
//% freely, subject to the following restrictions:
//% 1. The origin of this software must not be misrepresented; you must not
//%    claim that you wrote the original software. If you use this software
//%    in a product, an acknowledgment in the product documentation would be
//%    appreciated but is not required.
//% 2. Altered source versions must be plainly marked as such, and must not be
//%    misrepresented as being the original software.
//% 3. This notice may not be removed or altered from any source distribution.
//% Mark Adler    madler@alumni.caltech.edu

//% BEGIN CODE DERIVED FROM puff.{c,h}

#include <setjmp.h>
#define MAXBITS 15
#define MAXLCODES 286
#define MAXDCODES 30
#define MAXCODES (MAXLCODES + MAXDCODES)
#define FIXLCODES 288

struct puff_state {
	unsigned char* out;
	unsigned long outlen;
	unsigned long outcnt;
	const unsigned char* in;
	unsigned long inlen;
	unsigned long incnt;
	int bitbuf;
	int bitcnt;
	jmp_buf env;
};
static int puff_bits(struct puff_state* s, int need)
{
	long val = s->bitbuf;
	while (s->bitcnt < need) {
		if (s->incnt == s->inlen)
			longjmp(s->env, 1);
		val |= (long)(s->in[s->incnt++]) << s->bitcnt;
		s->bitcnt += 8;
	}
	s->bitbuf = (int)(val >> need);
	s->bitcnt -= need;
	return (int)(val & ((1L << need) - 1));
}
static int puff_stored(struct puff_state* s)
{
	s->bitbuf = 0;
	s->bitcnt = 0;
	if (s->incnt + 4 > s->inlen)
		return 2;
	unsigned len = s->in[s->incnt++];
	len |= s->in[s->incnt++] << 8;
	if (s->in[s->incnt++] != (~len & 0xff) ||
	    s->in[s->incnt++] != ((~len >> 8) & 0xff))
		return -2;
	if (s->incnt + len > s->inlen)
		return 2;
	if (s->outcnt + len > s->outlen)
		return 1;
	for (; len--; s->outcnt++, s->incnt++) {
		if (s->in[s->incnt])
			s->out[s->outcnt] = s->in[s->incnt];
	}
	return 0;
}
struct puff_huffman {
	short* count;
	short* symbol;
};
static int puff_decode(struct puff_state* s, const struct puff_huffman* h)
{
	int first = 0;
	int index = 0;
	int bitbuf = s->bitbuf;
	int left = s->bitcnt;
	int code = first = index = 0;
	int len = 1;
	short* next = h->count + 1;
	while (1) {
		while (left--) {
			code |= bitbuf & 1;
			bitbuf >>= 1;
			int count = *next++;
			if (code - count < first) {
				s->bitbuf = bitbuf;
				s->bitcnt = (s->bitcnt - len) & 7;
				return h->symbol[index + (code - first)];
			}
			index += count;
			first += count;
			first <<= 1;
			code <<= 1;
			len++;
		}
		left = (MAXBITS + 1) - len;
		if (left == 0)
			break;
		if (s->incnt == s->inlen)
			longjmp(s->env, 1);
		bitbuf = s->in[s->incnt++];
		if (left > 8)
			left = 8;
	}
	return -10;
}
static int puff_construct(struct puff_huffman* h, const short* length, int n)
{
	int len;
	for (len = 0; len <= MAXBITS; len++)
		h->count[len] = 0;
	int symbol;
	for (symbol = 0; symbol < n; symbol++)
		(h->count[length[symbol]])++;
	if (h->count[0] == n)
		return 0;
	int left = 1;
	for (len = 1; len <= MAXBITS; len++) {
		left <<= 1;
		left -= h->count[len];
		if (left < 0)
			return left;
	}
	short offs[MAXBITS + 1];
	offs[1] = 0;
	for (len = 1; len < MAXBITS; len++)
		offs[len + 1] = offs[len] + h->count[len];
	for (symbol = 0; symbol < n; symbol++)
		if (length[symbol] != 0)
			h->symbol[offs[length[symbol]]++] = symbol;
	return left;
}
static int puff_codes(struct puff_state* s,
		      const struct puff_huffman* lencode,
		      const struct puff_huffman* distcode)
{
	static const short lens[29] = {
				       3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
				       35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258};
	static const short lext[29] = {
				       0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
				       3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0};
	static const short dists[30] = {
					1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
					257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
					8193, 12289, 16385, 24577};
	static const short dext[30] = {
				       0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
				       7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
				       12, 12, 13, 13};
	int symbol;
	do {
		symbol = puff_decode(s, lencode);
		if (symbol < 0)
			return symbol;
		if (symbol < 256) {
			if (s->outcnt == s->outlen)
				return 1;
			if (symbol)
				s->out[s->outcnt] = symbol;
			s->outcnt++;
		} else if (symbol > 256) {
			symbol -= 257;
			if (symbol >= 29)
				return -10;
			int len = lens[symbol] + puff_bits(s, lext[symbol]);
			symbol = puff_decode(s, distcode);
			if (symbol < 0)
				return symbol;
			unsigned dist = dists[symbol] + puff_bits(s, dext[symbol]);
			if (dist > s->outcnt)
				return -11;
			if (s->outcnt + len > s->outlen)
				return 1;
			while (len--) {
				if (dist <= s->outcnt && s->out[s->outcnt - dist])
					s->out[s->outcnt] = s->out[s->outcnt - dist];
				s->outcnt++;
			}
		}
	} while (symbol != 256);
	return 0;
}
static int puff_fixed(struct puff_state* s)
{
	static int virgin = 1;
	static short lencnt[MAXBITS + 1], lensym[FIXLCODES];
	static short distcnt[MAXBITS + 1], distsym[MAXDCODES];
	static struct puff_huffman lencode, distcode;
	if (virgin) {
		lencode.count = lencnt;
		lencode.symbol = lensym;
		distcode.count = distcnt;
		distcode.symbol = distsym;
		short lengths[FIXLCODES];
		int symbol;
		for (symbol = 0; symbol < 144; symbol++)
			lengths[symbol] = 8;
		for (; symbol < 256; symbol++)
			lengths[symbol] = 9;
		for (; symbol < 280; symbol++)
			lengths[symbol] = 7;
		for (; symbol < FIXLCODES; symbol++)
			lengths[symbol] = 8;
		puff_construct(&lencode, lengths, FIXLCODES);
		for (symbol = 0; symbol < MAXDCODES; symbol++)
			lengths[symbol] = 5;
		puff_construct(&distcode, lengths, MAXDCODES);
		virgin = 0;
	}
	return puff_codes(s, &lencode, &distcode);
}
static int puff_dynamic(struct puff_state* s)
{
	static const short order[19] =
	    {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
	int nlen = puff_bits(s, 5) + 257;
	int ndist = puff_bits(s, 5) + 1;
	int ncode = puff_bits(s, 4) + 4;
	if (nlen > MAXLCODES || ndist > MAXDCODES)
		return -3;
	short lengths[MAXCODES];
	int index;
	for (index = 0; index < ncode; index++)
		lengths[order[index]] = puff_bits(s, 3);
	for (; index < 19; index++)
		lengths[order[index]] = 0;
	short lencnt[MAXBITS + 1], lensym[MAXLCODES];
	struct puff_huffman lencode = {lencnt, lensym};
	int err = puff_construct(&lencode, lengths, 19);
	if (err != 0)
		return -4;
	index = 0;
	while (index < nlen + ndist) {
		int symbol;
		int len;

		symbol = puff_decode(s, &lencode);
		if (symbol < 0)
			return symbol;
		if (symbol < 16)
			lengths[index++] = symbol;
		else {
			len = 0;
			if (symbol == 16) {
				if (index == 0)
					return -5;
				len = lengths[index - 1];
				symbol = 3 + puff_bits(s, 2);
			} else if (symbol == 17)
				symbol = 3 + puff_bits(s, 3);
			else
				symbol = 11 + puff_bits(s, 7);
			if (index + symbol > nlen + ndist)
				return -6;
			while (symbol--)
				lengths[index++] = len;
		}
	}
	if (lengths[256] == 0)
		return -9;
	err = puff_construct(&lencode, lengths, nlen);
	if (err && (err < 0 || nlen != lencode.count[0] + lencode.count[1]))
		return -7;
	short distcnt[MAXBITS + 1], distsym[MAXDCODES];
	struct puff_huffman distcode = {distcnt, distsym};
	err = puff_construct(&distcode, lengths + nlen, ndist);
	if (err && (err < 0 || ndist != distcode.count[0] + distcode.count[1]))
		return -8;
	return puff_codes(s, &lencode, &distcode);
}
static int puff(
    unsigned char* dest,
    unsigned long* destlen,
    const unsigned char* source,
    unsigned long sourcelen)
{
	struct puff_state s = {
	    .out = dest,
	    .outlen = *destlen,
	    .outcnt = 0,
	    .in = source,
	    .inlen = sourcelen,
	    .incnt = 0,
	    .bitbuf = 0,
	    .bitcnt = 0,
	};
	int err;
	if (setjmp(s.env) != 0)
		err = 2;
	else {
		int last;
		do {
			last = puff_bits(&s, 1);
			int type = puff_bits(&s, 2);
			err = type == 0 ? puff_stored(&s) : (type == 1 ? puff_fixed(&s) : (type == 2 ? puff_dynamic(&s) : -1));
			if (err != 0)
				break;
		} while (!last);
	}

	*destlen = s.outcnt;
	return err;
}

//% END CODE DERIVED FROM puff.{c,h}

#include <errno.h>
#include <sys/mman.h>
#define ZLIB_HEADER_WIDTH 2

static int puff_zlib_to_file(const unsigned char* source, unsigned long sourcelen, int dest_fd)
{
	if (sourcelen < ZLIB_HEADER_WIDTH)
		return 0;
	source += ZLIB_HEADER_WIDTH;
	sourcelen -= ZLIB_HEADER_WIDTH;
	const unsigned long max_destlen = 132 << 20;
	void* ret = mmap(0, max_destlen, PROT_WRITE | PROT_READ, MAP_PRIVATE | MAP_ANON, -1, 0);
	if (ret == MAP_FAILED)
		return -1;
	unsigned char* dest = (unsigned char*)ret;
	unsigned long destlen = max_destlen;
	int err = puff(dest, &destlen, source, sourcelen);
	if (err) {
		munmap(dest, max_destlen);
		errno = -err;
		return -1;
	}
	if (write(dest_fd, dest, destlen) != (ssize_t)destlen) {
		munmap(dest, max_destlen);
		return -1;
	}
	return munmap(dest, destlen);
}

#include <errno.h>
#include <fcntl.h>
#include <linux/loop.h>
#include <stdbool.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
static int setup_loop_device(unsigned char* data, unsigned long size, const char* loopname, int* loopfd_p)
{
	int err = 0, loopfd = -1;
	int memfd = syscall(__NR_memfd_create, "syzkaller", 0);
	if (memfd == -1) {
		err = errno;
		goto error;
	}
	if (puff_zlib_to_file(data, size, memfd)) {
		err = errno;
		debug("setup_loop_device: could not decompress data: %d\n", errno);
		goto error_close_memfd;
	}

	loopfd = open(loopname, O_RDWR);
	if (loopfd == -1) {
		err = errno;
		goto error_close_memfd;
	}
	if (ioctl(loopfd, LOOP_SET_FD, memfd)) {
		if (errno != EBUSY) {
			err = errno;
			goto error_close_loop;
		}
		ioctl(loopfd, LOOP_CLR_FD, 0);
		usleep(1000);
		if (ioctl(loopfd, LOOP_SET_FD, memfd)) {
			err = errno;
			goto error_close_loop;
		}
	}

	close(memfd);
	*loopfd_p = loopfd;
	return 0;

error_close_loop:
	close(loopfd);
error_close_memfd:
	close(memfd);
error:
	errno = err;
	return -1;
}
#endif

#if SYZ_EXECUTOR || __NR_syz_read_part_table
static long syz_read_part_table(volatile unsigned long size, volatile long image)
{
	unsigned char* data = (unsigned char*)image;
	int err = 0, res = -1, loopfd = -1;
	char loopname[64];

	snprintf(loopname, sizeof(loopname), "/dev/loop%llu", procid);
	if (setup_loop_device(data, size, loopname, &loopfd) == -1)
		return -1;

	struct loop_info64 info;
	if (ioctl(loopfd, LOOP_GET_STATUS64, &info)) {
		err = errno;
		goto error_clear_loop;
	}
#if SYZ_EXECUTOR
	cover_reset(0);
#endif
	info.lo_flags |= LO_FLAGS_PARTSCAN;
	if (ioctl(loopfd, LOOP_SET_STATUS64, &info)) {
		err = errno;
		goto error_clear_loop;
	}
	res = 0;
	for (unsigned long i = 1, j = 0; i < 8; i++) {
		snprintf(loopname, sizeof(loopname), "/dev/loop%llup%d", procid, (int)i);
		struct stat statbuf;
		if (stat(loopname, &statbuf) == 0) {
			char linkname[64];
			snprintf(linkname, sizeof(linkname), "./file%d", (int)j++);
			if (symlink(loopname, linkname)) {
				debug("syz_read_part_table: symlink(%s, %s) failed: %d\n", loopname, linkname, errno);
			}
		}
	}
error_clear_loop:
	if (res)
		ioctl(loopfd, LOOP_CLR_FD, 0);
	close(loopfd);
	errno = err;
	return res;
}
#endif

#if SYZ_EXECUTOR || __NR_syz_mount_image
#include <stddef.h>
#include <string.h>
#include <sys/mount.h>
static long syz_mount_image(
    volatile long fsarg,
    volatile long dir,
    volatile long flags,
    volatile long optsarg,
    volatile long change_dir,
    volatile unsigned long size,
    volatile long image)
{
	unsigned char* data = (unsigned char*)image;
	int res = -1, err = 0, loopfd = -1, need_loop_device = !!size;
	char* mount_opts = (char*)optsarg;
	char* target = (char*)dir;
	char* fs = (char*)fsarg;
	char* source = NULL;
	char loopname[64];

	if (need_loop_device) {
		memset(loopname, 0, sizeof(loopname));
		snprintf(loopname, sizeof(loopname), "/dev/loop%llu", procid);
		if (setup_loop_device(data, size, loopname, &loopfd) == -1)
			return -1;
		source = loopname;
	}

	mkdir(target, 0777);
	char opts[256];
	memset(opts, 0, sizeof(opts));
	if (strlen(mount_opts) > (sizeof(opts) - 32)) {
		debug("ERROR: syz_mount_image parameter optsarg bigger than internal opts\n");
	}
	strncpy(opts, mount_opts, sizeof(opts) - 32);
	if (strcmp(fs, "iso9660") == 0) {
		flags |= MS_RDONLY;
	} else if (strncmp(fs, "ext", 3) == 0) {
		bool has_remount_ro = false;
		char* remount_ro_start = strstr(opts, "errors=remount-ro");
		if (remount_ro_start != NULL) {
			char after = *(remount_ro_start + strlen("errors=remount-ro"));
			char before = remount_ro_start == opts ? '\0' : *(remount_ro_start - 1);
			has_remount_ro = ((before == '\0' || before == ',') && (after == '\0' || after == ','));
		}
		if (strstr(opts, "errors=panic") || !has_remount_ro)
			strcat(opts, ",errors=continue");
	} else if (strcmp(fs, "xfs") == 0) {
		strcat(opts, ",nouuid");
	}
	debug("syz_mount_image: size=%llu loop='%s' dir='%s' fs='%s' flags=%llu opts='%s'\n", (uint64)size, loopname, target, fs, (uint64)flags, opts);
#if SYZ_EXECUTOR
	cover_reset(0);
#endif
	res = mount(source, target, fs, flags, opts);
	if (res == -1) {
		debug("syz_mount_image > mount error: %d\n", errno);
		err = errno;
		goto error_clear_loop;
	}
	res = open(target, O_RDONLY | O_DIRECTORY);
	if (res == -1) {
		debug("syz_mount_image > open error: %d\n", errno);
		err = errno;
		goto error_clear_loop;
	}
	if (change_dir) {
		res = chdir(target);
		if (res == -1) {
			debug("syz_mount_image > chdir error: %d\n", errno);
			err = errno;
		}
	}

error_clear_loop:
	if (need_loop_device) {
		ioctl(loopfd, LOOP_CLR_FD, 0);
		close(loopfd);
	}
	errno = err;
	return res;
}
#endif

#if SYZ_EXECUTOR || __NR_syz_kvm_setup_cpu
#if !GOARCH_riscv64 && !GOARCH_arm
#include <errno.h>
#include <fcntl.h>
#include <linux/kvm.h>
#include <stdarg.h>
#include <stddef.h>
#include <sys/ioctl.h>
#include <sys/stat.h>

#if GOARCH_amd64

#define ADDR_TEXT 0x0000
#define ADDR_GDT 0x1000
#define ADDR_LDT 0x1800
#define ADDR_PML4 0x2000
#define ADDR_PDP 0x3000
#define ADDR_PD 0x4000
#define ADDR_STACK0 0x0f80
#define ADDR_VAR_HLT 0x2800
#define ADDR_VAR_SYSRET 0x2808
#define ADDR_VAR_SYSEXIT 0x2810
#define ADDR_VAR_IDT 0x3800
#define ADDR_VAR_TSS64 0x3a00
#define ADDR_VAR_TSS64_CPL3 0x3c00
#define ADDR_VAR_TSS16 0x3d00
#define ADDR_VAR_TSS16_2 0x3e00
#define ADDR_VAR_TSS16_CPL3 0x3f00
#define ADDR_VAR_TSS32 0x4800
#define ADDR_VAR_TSS32_2 0x4a00
#define ADDR_VAR_TSS32_CPL3 0x4c00
#define ADDR_VAR_TSS32_VM86 0x4e00
#define ADDR_VAR_VMXON_PTR 0x5f00
#define ADDR_VAR_VMCS_PTR 0x5f08
#define ADDR_VAR_VMEXIT_PTR 0x5f10
#define ADDR_VAR_VMWRITE_FLD 0x5f18
#define ADDR_VAR_VMWRITE_VAL 0x5f20
#define ADDR_VAR_VMXON 0x6000
#define ADDR_VAR_VMCS 0x7000
#define ADDR_VAR_VMEXIT_CODE 0x9000
#define ADDR_VAR_USER_CODE 0x9100
#define ADDR_VAR_USER_CODE2 0x9120

#define SEL_LDT (1 << 3)
#define SEL_CS16 (2 << 3)
#define SEL_DS16 (3 << 3)
#define SEL_CS16_CPL3 ((4 << 3) + 3)
#define SEL_DS16_CPL3 ((5 << 3) + 3)
#define SEL_CS32 (6 << 3)
#define SEL_DS32 (7 << 3)
#define SEL_CS32_CPL3 ((8 << 3) + 3)
#define SEL_DS32_CPL3 ((9 << 3) + 3)
#define SEL_CS64 (10 << 3)
#define SEL_DS64 (11 << 3)
#define SEL_CS64_CPL3 ((12 << 3) + 3)
#define SEL_DS64_CPL3 ((13 << 3) + 3)
#define SEL_CGATE16 (14 << 3)
#define SEL_TGATE16 (15 << 3)
#define SEL_CGATE32 (16 << 3)
#define SEL_TGATE32 (17 << 3)
#define SEL_CGATE64 (18 << 3)
#define SEL_CGATE64_HI (19 << 3)
#define SEL_TSS16 (20 << 3)
#define SEL_TSS16_2 (21 << 3)
#define SEL_TSS16_CPL3 ((22 << 3) + 3)
#define SEL_TSS32 (23 << 3)
#define SEL_TSS32_2 (24 << 3)
#define SEL_TSS32_CPL3 ((25 << 3) + 3)
#define SEL_TSS32_VM86 (26 << 3)
#define SEL_TSS64 (27 << 3)
#define SEL_TSS64_HI (28 << 3)
#define SEL_TSS64_CPL3 ((29 << 3) + 3)
#define SEL_TSS64_CPL3_HI (30 << 3)

#define MSR_IA32_FEATURE_CONTROL 0x3a
#define MSR_IA32_VMX_BASIC 0x480
#define MSR_IA32_SMBASE 0x9e
#define MSR_IA32_SYSENTER_CS 0x174
#define MSR_IA32_SYSENTER_ESP 0x175
#define MSR_IA32_SYSENTER_EIP 0x176
#define MSR_IA32_STAR 0xC0000081
#define MSR_IA32_LSTAR 0xC0000082
#define MSR_IA32_VMX_PROCBASED_CTLS2 0x48B

#define NEXT_INSN $0xbadc0de
#define PREFIX_SIZE 0xba1d
const char kvm_asm16_cpl3[] = "\x0f\x20\xc0\x66\x83\xc8\x01\x0f\x22\xc0\xb8\xa0\x00\x0f\x00\xd8\xb8\x2b\x00\x8e\xd8\x8e\xc0\x8e\xe0\x8e\xe8\xbc\x00\x01\xc7\x06\x00\x01\x1d\xba\xc7\x06\x02\x01\x23\x00\xc7\x06\x04\x01\x00\x01\xc7\x06\x06\x01\x2b\x00\xcb";
const char kvm_asm32_paged[] = "\x0f\x20\xc0\x0d\x00\x00\x00\x80\x0f\x22\xc0";
const char kvm_asm32_vm86[] = "\x66\xb8\xb8\x00\x0f\x00\xd8\xea\x00\x00\x00\x00\xd0\x00";
const char kvm_asm32_paged_vm86[] = "\x0f\x20\xc0\x0d\x00\x00\x00\x80\x0f\x22\xc0\x66\xb8\xb8\x00\x0f\x00\xd8\xea\x00\x00\x00\x00\xd0\x00";
const char kvm_asm64_enable_long[] = "\x0f\x20\xc0\x0d\x00\x00\x00\x80\x0f\x22\xc0\xea\xde\xc0\xad\x0b\x50\x00\x48\xc7\xc0\xd8\x00\x00\x00\x0f\x00\xd8";
const char kvm_asm64_init_vm[] = "\x0f\x20\xc0\x0d\x00\x00\x00\x80\x0f\x22\xc0\xea\xde\xc0\xad\x0b\x50\x00\x48\xc7\xc0\xd8\x00\x00\x00\x0f\x00\xd8\x48\xc7\xc1\x3a\x00\x00\x00\x0f\x32\x48\x83\xc8\x05\x0f\x30\x0f\x20\xe0\x48\x0d\x00\x20\x00\x00\x0f\x22\xe0\x48\xc7\xc1\x80\x04\x00\x00\x0f\x32\x48\xc7\xc2\x00\x60\x00\x00\x89\x02\x48\xc7\xc2\x00\x70\x00\x00\x89\x02\x48\xc7\xc0\x00\x5f\x00\x00\xf3\x0f\xc7\x30\x48\xc7\xc0\x08\x5f\x00\x00\x66\x0f\xc7\x30\x0f\xc7\x30\x48\xc7\xc1\x81\x04\x00\x00\x0f\x32\x48\x83\xc8\x00\x48\x21\xd0\x48\xc7\xc2\x00\x40\x00\x00\x0f\x79\xd0\x48\xc7\xc1\x82\x04\x00\x00\x0f\x32\x48\x83\xc8\x00\x48\x21\xd0\x48\xc7\xc2\x02\x40\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x1e\x40\x00\x00\x48\xc7\xc0\x81\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc1\x83\x04\x00\x00\x0f\x32\x48\x0d\xff\x6f\x03\x00\x48\x21\xd0\x48\xc7\xc2\x0c\x40\x00\x00\x0f\x79\xd0\x48\xc7\xc1\x84\x04\x00\x00\x0f\x32\x48\x0d\xff\x17\x00\x00\x48\x21\xd0\x48\xc7\xc2\x12\x40\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x04\x2c\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x00\x28\x00\x00\x48\xc7\xc0\xff\xff\xff\xff\x0f\x79\xd0\x48\xc7\xc2\x02\x0c\x00\x00\x48\xc7\xc0\x50\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc0\x58\x00\x00\x00\x48\xc7\xc2\x00\x0c\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x04\x0c\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x06\x0c\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x08\x0c\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x0a\x0c\x00\x00\x0f\x79\xd0\x48\xc7\xc0\xd8\x00\x00\x00\x48\xc7\xc2\x0c\x0c\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x02\x2c\x00\x00\x48\xc7\xc0\x00\x05\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x00\x4c\x00\x00\x48\xc7\xc0\x50\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x10\x6c\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x12\x6c\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x0f\x20\xc0\x48\xc7\xc2\x00\x6c\x00\x00\x48\x89\xc0\x0f\x79\xd0\x0f\x20\xd8\x48\xc7\xc2\x02\x6c\x00\x00\x48\x89\xc0\x0f\x79\xd0\x0f\x20\xe0\x48\xc7\xc2\x04\x6c\x00\x00\x48\x89\xc0\x0f\x79\xd0\x48\xc7\xc2\x06\x6c\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x08\x6c\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x0a\x6c\x00\x00\x48\xc7\xc0\x00\x3a\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x0c\x6c\x00\x00\x48\xc7\xc0\x00\x10\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x0e\x6c\x00\x00\x48\xc7\xc0\x00\x38\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x14\x6c\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x16\x6c\x00\x00\x48\x8b\x04\x25\x10\x5f\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x00\x00\x00\x00\x48\xc7\xc0\x01\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x02\x00\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x00\x20\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x02\x20\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x04\x20\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x06\x20\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc1\x77\x02\x00\x00\x0f\x32\x48\xc1\xe2\x20\x48\x09\xd0\x48\xc7\xc2\x00\x2c\x00\x00\x48\x89\xc0\x0f\x79\xd0\x48\xc7\xc2\x04\x40\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x0a\x40\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x0e\x40\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x10\x40\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x16\x40\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x14\x40\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x00\x60\x00\x00\x48\xc7\xc0\xff\xff\xff\xff\x0f\x79\xd0\x48\xc7\xc2\x02\x60\x00\x00\x48\xc7\xc0\xff\xff\xff\xff\x0f\x79\xd0\x48\xc7\xc2\x1c\x20\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x1e\x20\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x20\x20\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x22\x20\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x00\x08\x00\x00\x48\xc7\xc0\x58\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x02\x08\x00\x00\x48\xc7\xc0\x50\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x04\x08\x00\x00\x48\xc7\xc0\x58\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x06\x08\x00\x00\x48\xc7\xc0\x58\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x08\x08\x00\x00\x48\xc7\xc0\x58\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x0a\x08\x00\x00\x48\xc7\xc0\x58\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x0c\x08\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x0e\x08\x00\x00\x48\xc7\xc0\xd8\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x12\x68\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x14\x68\x00\x00\x48\xc7\xc0\x00\x3a\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x16\x68\x00\x00\x48\xc7\xc0\x00\x10\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x18\x68\x00\x00\x48\xc7\xc0\x00\x38\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x00\x48\x00\x00\x48\xc7\xc0\xff\xff\x0f\x00\x0f\x79\xd0\x48\xc7\xc2\x02\x48\x00\x00\x48\xc7\xc0\xff\xff\x0f\x00\x0f\x79\xd0\x48\xc7\xc2\x04\x48\x00\x00\x48\xc7\xc0\xff\xff\x0f\x00\x0f\x79\xd0\x48\xc7\xc2\x06\x48\x00\x00\x48\xc7\xc0\xff\xff\x0f\x00\x0f\x79\xd0\x48\xc7\xc2\x08\x48\x00\x00\x48\xc7\xc0\xff\xff\x0f\x00\x0f\x79\xd0\x48\xc7\xc2\x0a\x48\x00\x00\x48\xc7\xc0\xff\xff\x0f\x00\x0f\x79\xd0\x48\xc7\xc2\x0c\x48\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x0e\x48\x00\x00\x48\xc7\xc0\xff\x1f\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x10\x48\x00\x00\x48\xc7\xc0\xff\x1f\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x12\x48\x00\x00\x48\xc7\xc0\xff\x1f\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x14\x48\x00\x00\x48\xc7\xc0\x93\x40\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x16\x48\x00\x00\x48\xc7\xc0\x9b\x20\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x18\x48\x00\x00\x48\xc7\xc0\x93\x40\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x1a\x48\x00\x00\x48\xc7\xc0\x93\x40\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x1c\x48\x00\x00\x48\xc7\xc0\x93\x40\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x1e\x48\x00\x00\x48\xc7\xc0\x93\x40\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x20\x48\x00\x00\x48\xc7\xc0\x82\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x22\x48\x00\x00\x48\xc7\xc0\x8b\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x1c\x68\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x1e\x68\x00\x00\x48\xc7\xc0\x00\x91\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x20\x68\x00\x00\x48\xc7\xc0\x02\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x06\x28\x00\x00\x48\xc7\xc0\x00\x05\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x0a\x28\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x0c\x28\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x0e\x28\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x10\x28\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x0f\x20\xc0\x48\xc7\xc2\x00\x68\x00\x00\x48\x89\xc0\x0f\x79\xd0\x0f\x20\xd8\x48\xc7\xc2\x02\x68\x00\x00\x48\x89\xc0\x0f\x79\xd0\x0f\x20\xe0\x48\xc7\xc2\x04\x68\x00\x00\x48\x89\xc0\x0f\x79\xd0\x48\xc7\xc0\x18\x5f\x00\x00\x48\x8b\x10\x48\xc7\xc0\x20\x5f\x00\x00\x48\x8b\x08\x48\x31\xc0\x0f\x78\xd0\x48\x31\xc8\x0f\x79\xd0\x0f\x01\xc2\x48\xc7\xc2\x00\x44\x00\x00\x0f\x78\xd0\xf4";
const char kvm_asm64_vm_exit[] = "\x48\xc7\xc3\x00\x44\x00\x00\x0f\x78\xda\x48\xc7\xc3\x02\x44\x00\x00\x0f\x78\xd9\x48\xc7\xc0\x00\x64\x00\x00\x0f\x78\xc0\x48\xc7\xc3\x1e\x68\x00\x00\x0f\x78\xdb\xf4";
const char kvm_asm64_cpl3[] = "\x0f\x20\xc0\x0d\x00\x00\x00\x80\x0f\x22\xc0\xea\xde\xc0\xad\x0b\x50\x00\x48\xc7\xc0\xd8\x00\x00\x00\x0f\x00\xd8\x48\xc7\xc0\x6b\x00\x00\x00\x8e\xd8\x8e\xc0\x8e\xe0\x8e\xe8\x48\xc7\xc4\x80\x0f\x00\x00\x48\xc7\x04\x24\x1d\xba\x00\x00\x48\xc7\x44\x24\x04\x63\x00\x00\x00\x48\xc7\x44\x24\x08\x80\x0f\x00\x00\x48\xc7\x44\x24\x0c\x6b\x00\x00\x00\xcb";


#ifndef KVM_SMI
#define KVM_SMI _IO(KVMIO, 0xb7)
#endif

#define CR0_PE 1
#define CR0_MP (1 << 1)
#define CR0_EM (1 << 2)
#define CR0_TS (1 << 3)
#define CR0_ET (1 << 4)
#define CR0_NE (1 << 5)
#define CR0_WP (1 << 16)
#define CR0_AM (1 << 18)
#define CR0_NW (1 << 29)
#define CR0_CD (1 << 30)
#define CR0_PG (1 << 31)

#define CR4_VME 1
#define CR4_PVI (1 << 1)
#define CR4_TSD (1 << 2)
#define CR4_DE (1 << 3)
#define CR4_PSE (1 << 4)
#define CR4_PAE (1 << 5)
#define CR4_MCE (1 << 6)
#define CR4_PGE (1 << 7)
#define CR4_PCE (1 << 8)
#define CR4_OSFXSR (1 << 8)
#define CR4_OSXMMEXCPT (1 << 10)
#define CR4_UMIP (1 << 11)
#define CR4_VMXE (1 << 13)
#define CR4_SMXE (1 << 14)
#define CR4_FSGSBASE (1 << 16)
#define CR4_PCIDE (1 << 17)
#define CR4_OSXSAVE (1 << 18)
#define CR4_SMEP (1 << 20)
#define CR4_SMAP (1 << 21)
#define CR4_PKE (1 << 22)

#define EFER_SCE 1
#define EFER_LME (1 << 8)
#define EFER_LMA (1 << 10)
#define EFER_NXE (1 << 11)
#define EFER_SVME (1 << 12)
#define EFER_LMSLE (1 << 13)
#define EFER_FFXSR (1 << 14)
#define EFER_TCE (1 << 15)
#define PDE32_PRESENT 1
#define PDE32_RW (1 << 1)
#define PDE32_USER (1 << 2)
#define PDE32_PS (1 << 7)
#define PDE64_PRESENT 1
#define PDE64_RW (1 << 1)
#define PDE64_USER (1 << 2)
#define PDE64_ACCESSED (1 << 5)
#define PDE64_DIRTY (1 << 6)
#define PDE64_PS (1 << 7)
#define PDE64_G (1 << 8)

struct tss16 {
	uint16 prev;
	uint16 sp0;
	uint16 ss0;
	uint16 sp1;
	uint16 ss1;
	uint16 sp2;
	uint16 ss2;
	uint16 ip;
	uint16 flags;
	uint16 ax;
	uint16 cx;
	uint16 dx;
	uint16 bx;
	uint16 sp;
	uint16 bp;
	uint16 si;
	uint16 di;
	uint16 es;
	uint16 cs;
	uint16 ss;
	uint16 ds;
	uint16 ldt;
} __attribute__((packed));

struct tss32 {
	uint16 prev, prevh;
	uint32 sp0;
	uint16 ss0, ss0h;
	uint32 sp1;
	uint16 ss1, ss1h;
	uint32 sp2;
	uint16 ss2, ss2h;
	uint32 cr3;
	uint32 ip;
	uint32 flags;
	uint32 ax;
	uint32 cx;
	uint32 dx;
	uint32 bx;
	uint32 sp;
	uint32 bp;
	uint32 si;
	uint32 di;
	uint16 es, esh;
	uint16 cs, csh;
	uint16 ss, ssh;
	uint16 ds, dsh;
	uint16 fs, fsh;
	uint16 gs, gsh;
	uint16 ldt, ldth;
	uint16 trace;
	uint16 io_bitmap;
} __attribute__((packed));

struct tss64 {
	uint32 reserved0;
	uint64 rsp[3];
	uint64 reserved1;
	uint64 ist[7];
	uint64 reserved2;
	uint32 reserved3;
	uint32 io_bitmap;
} __attribute__((packed));

static void fill_segment_descriptor(uint64* dt, uint64* lt, struct kvm_segment* seg)
{
	uint16 index = seg->selector >> 3;
	uint64 limit = seg->g ? seg->limit >> 12 : seg->limit;
	uint64 sd = (limit & 0xffff) | (seg->base & 0xffffff) << 16 | (uint64)seg->type << 40 | (uint64)seg->s << 44 | (uint64)seg->dpl << 45 | (uint64)seg->present << 47 | (limit & 0xf0000ULL) << 48 | (uint64)seg->avl << 52 | (uint64)seg->l << 53 | (uint64)seg->db << 54 | (uint64)seg->g << 55 | (seg->base & 0xff000000ULL) << 56;
	dt[index] = sd;
	lt[index] = sd;
}

static void fill_segment_descriptor_dword(uint64* dt, uint64* lt, struct kvm_segment* seg)
{
	fill_segment_descriptor(dt, lt, seg);
	uint16 index = seg->selector >> 3;
	dt[index + 1] = 0;
	lt[index + 1] = 0;
}

static void setup_syscall_msrs(int cpufd, uint16 sel_cs, uint16 sel_cs_cpl3)
{
	char buf[sizeof(struct kvm_msrs) + 5 * sizeof(struct kvm_msr_entry)];
	memset(buf, 0, sizeof(buf));
	struct kvm_msrs* msrs = (struct kvm_msrs*)buf;
	struct kvm_msr_entry* entries = msrs->entries;
	msrs->nmsrs = 5;
	entries[0].index = MSR_IA32_SYSENTER_CS;
	entries[0].data = sel_cs;
	entries[1].index = MSR_IA32_SYSENTER_ESP;
	entries[1].data = ADDR_STACK0;
	entries[2].index = MSR_IA32_SYSENTER_EIP;
	entries[2].data = ADDR_VAR_SYSEXIT;
	entries[3].index = MSR_IA32_STAR;
	entries[3].data = ((uint64)sel_cs << 32) | ((uint64)sel_cs_cpl3 << 48);
	entries[4].index = MSR_IA32_LSTAR;
	entries[4].data = ADDR_VAR_SYSRET;
	ioctl(cpufd, KVM_SET_MSRS, msrs);
}

static void setup_32bit_idt(struct kvm_sregs* sregs, char* host_mem, uintptr_t guest_mem)
{
	sregs->idt.base = guest_mem + ADDR_VAR_IDT;
	sregs->idt.limit = 0x1ff;
	uint64* idt = (uint64*)(host_mem + sregs->idt.base);
	for (int i = 0; i < 32; i++) {
		struct kvm_segment gate;
		gate.selector = i << 3;
		switch (i % 6) {
		case 0:
			gate.type = 6;
			gate.base = SEL_CS16;
			break;
		case 1:
			gate.type = 7;
			gate.base = SEL_CS16;
			break;
		case 2:
			gate.type = 3;
			gate.base = SEL_TGATE16;
			break;
		case 3:
			gate.type = 14;
			gate.base = SEL_CS32;
			break;
		case 4:
			gate.type = 15;
			gate.base = SEL_CS32;
			break;
		case 5:
			gate.type = 11;
			gate.base = SEL_TGATE32;
			break;
		}
		gate.limit = guest_mem + ADDR_VAR_USER_CODE2;
		gate.present = 1;
		gate.dpl = 0;
		gate.s = 0;
		gate.g = 0;
		gate.db = 0;
		gate.l = 0;
		gate.avl = 0;
		fill_segment_descriptor(idt, idt, &gate);
	}
}

static void setup_64bit_idt(struct kvm_sregs* sregs, char* host_mem, uintptr_t guest_mem)
{
	sregs->idt.base = guest_mem + ADDR_VAR_IDT;
	sregs->idt.limit = 0x1ff;
	uint64* idt = (uint64*)(host_mem + sregs->idt.base);
	for (int i = 0; i < 32; i++) {
		struct kvm_segment gate;
		gate.selector = (i * 2) << 3;
		gate.type = (i & 1) ? 14 : 15;
		gate.base = SEL_CS64;
		gate.limit = guest_mem + ADDR_VAR_USER_CODE2;
		gate.present = 1;
		gate.dpl = 0;
		gate.s = 0;
		gate.g = 0;
		gate.db = 0;
		gate.l = 0;
		gate.avl = 0;
		fill_segment_descriptor_dword(idt, idt, &gate);
	}
}

struct kvm_text {
	uintptr_t typ;
	const void* text;
	uintptr_t size;
};

struct kvm_opt {
	uint64 typ;
	uint64 val;
};

#define KVM_SETUP_PAGING (1 << 0)
#define KVM_SETUP_PAE (1 << 1)
#define KVM_SETUP_PROTECTED (1 << 2)
#define KVM_SETUP_CPL3 (1 << 3)
#define KVM_SETUP_VIRT86 (1 << 4)
#define KVM_SETUP_SMM (1 << 5)
#define KVM_SETUP_VM (1 << 6)
static volatile long syz_kvm_setup_cpu(volatile long a0, volatile long a1, volatile long a2, volatile long a3, volatile long a4, volatile long a5, volatile long a6, volatile long a7)
{
	const int vmfd = a0;
	const int cpufd = a1;
	char* const host_mem = (char*)a2;
	const struct kvm_text* const text_array_ptr = (struct kvm_text*)a3;
	const uintptr_t text_count = a4;
	const uintptr_t flags = a5;
	const struct kvm_opt* const opt_array_ptr = (struct kvm_opt*)a6;
	uintptr_t opt_count = a7;

	const uintptr_t page_size = 4 << 10;
	const uintptr_t ioapic_page = 10;
	const uintptr_t guest_mem_size = 24 * page_size;
	const uintptr_t guest_mem = 0;

	(void)text_count;
	int text_type = text_array_ptr[0].typ;
	const void* text = text_array_ptr[0].text;
	uintptr_t text_size = text_array_ptr[0].size;

	for (uintptr_t i = 0; i < guest_mem_size / page_size; i++) {
		struct kvm_userspace_memory_region memreg;
		memreg.slot = i;
		memreg.flags = 0;
		memreg.guest_phys_addr = guest_mem + i * page_size;
		if (i == ioapic_page)
			memreg.guest_phys_addr = 0xfec00000;
		memreg.memory_size = page_size;
		memreg.userspace_addr = (uintptr_t)host_mem + i * page_size;
		ioctl(vmfd, KVM_SET_USER_MEMORY_REGION, &memreg);
	}
	struct kvm_userspace_memory_region memreg;
	memreg.slot = 1 + (1 << 16);
	memreg.flags = 0;
	memreg.guest_phys_addr = 0x30000;
	memreg.memory_size = 64 << 10;
	memreg.userspace_addr = (uintptr_t)host_mem;
	ioctl(vmfd, KVM_SET_USER_MEMORY_REGION, &memreg);

	struct kvm_sregs sregs;
	if (ioctl(cpufd, KVM_GET_SREGS, &sregs))
		return -1;

	struct kvm_regs regs;
	memset(&regs, 0, sizeof(regs));
	regs.rip = guest_mem + ADDR_TEXT;
	regs.rsp = ADDR_STACK0;

	sregs.gdt.base = guest_mem + ADDR_GDT;
	sregs.gdt.limit = 256 * sizeof(uint64) - 1;
	uint64* gdt = (uint64*)(host_mem + sregs.gdt.base);

	struct kvm_segment seg_ldt;
	seg_ldt.selector = SEL_LDT;
	seg_ldt.type = 2;
	seg_ldt.base = guest_mem + ADDR_LDT;
	seg_ldt.limit = 256 * sizeof(uint64) - 1;
	seg_ldt.present = 1;
	seg_ldt.dpl = 0;
	seg_ldt.s = 0;
	seg_ldt.g = 0;
	seg_ldt.db = 1;
	seg_ldt.l = 0;
	sregs.ldt = seg_ldt;
	uint64* ldt = (uint64*)(host_mem + sregs.ldt.base);

	struct kvm_segment seg_cs16;
	seg_cs16.selector = SEL_CS16;
	seg_cs16.type = 11;
	seg_cs16.base = 0;
	seg_cs16.limit = 0xfffff;
	seg_cs16.present = 1;
	seg_cs16.dpl = 0;
	seg_cs16.s = 1;
	seg_cs16.g = 0;
	seg_cs16.db = 0;
	seg_cs16.l = 0;

	struct kvm_segment seg_ds16 = seg_cs16;
	seg_ds16.selector = SEL_DS16;
	seg_ds16.type = 3;

	struct kvm_segment seg_cs16_cpl3 = seg_cs16;
	seg_cs16_cpl3.selector = SEL_CS16_CPL3;
	seg_cs16_cpl3.dpl = 3;

	struct kvm_segment seg_ds16_cpl3 = seg_ds16;
	seg_ds16_cpl3.selector = SEL_DS16_CPL3;
	seg_ds16_cpl3.dpl = 3;

	struct kvm_segment seg_cs32 = seg_cs16;
	seg_cs32.selector = SEL_CS32;
	seg_cs32.db = 1;

	struct kvm_segment seg_ds32 = seg_ds16;
	seg_ds32.selector = SEL_DS32;
	seg_ds32.db = 1;

	struct kvm_segment seg_cs32_cpl3 = seg_cs32;
	seg_cs32_cpl3.selector = SEL_CS32_CPL3;
	seg_cs32_cpl3.dpl = 3;

	struct kvm_segment seg_ds32_cpl3 = seg_ds32;
	seg_ds32_cpl3.selector = SEL_DS32_CPL3;
	seg_ds32_cpl3.dpl = 3;

	struct kvm_segment seg_cs64 = seg_cs16;
	seg_cs64.selector = SEL_CS64;
	seg_cs64.l = 1;

	struct kvm_segment seg_ds64 = seg_ds32;
	seg_ds64.selector = SEL_DS64;

	struct kvm_segment seg_cs64_cpl3 = seg_cs64;
	seg_cs64_cpl3.selector = SEL_CS64_CPL3;
	seg_cs64_cpl3.dpl = 3;

	struct kvm_segment seg_ds64_cpl3 = seg_ds64;
	seg_ds64_cpl3.selector = SEL_DS64_CPL3;
	seg_ds64_cpl3.dpl = 3;

	struct kvm_segment seg_tss32;
	seg_tss32.selector = SEL_TSS32;
	seg_tss32.type = 9;
	seg_tss32.base = ADDR_VAR_TSS32;
	seg_tss32.limit = 0x1ff;
	seg_tss32.present = 1;
	seg_tss32.dpl = 0;
	seg_tss32.s = 0;
	seg_tss32.g = 0;
	seg_tss32.db = 0;
	seg_tss32.l = 0;

	struct kvm_segment seg_tss32_2 = seg_tss32;
	seg_tss32_2.selector = SEL_TSS32_2;
	seg_tss32_2.base = ADDR_VAR_TSS32_2;

	struct kvm_segment seg_tss32_cpl3 = seg_tss32;
	seg_tss32_cpl3.selector = SEL_TSS32_CPL3;
	seg_tss32_cpl3.base = ADDR_VAR_TSS32_CPL3;

	struct kvm_segment seg_tss32_vm86 = seg_tss32;
	seg_tss32_vm86.selector = SEL_TSS32_VM86;
	seg_tss32_vm86.base = ADDR_VAR_TSS32_VM86;

	struct kvm_segment seg_tss16 = seg_tss32;
	seg_tss16.selector = SEL_TSS16;
	seg_tss16.base = ADDR_VAR_TSS16;
	seg_tss16.limit = 0xff;
	seg_tss16.type = 1;

	struct kvm_segment seg_tss16_2 = seg_tss16;
	seg_tss16_2.selector = SEL_TSS16_2;
	seg_tss16_2.base = ADDR_VAR_TSS16_2;
	seg_tss16_2.dpl = 0;

	struct kvm_segment seg_tss16_cpl3 = seg_tss16;
	seg_tss16_cpl3.selector = SEL_TSS16_CPL3;
	seg_tss16_cpl3.base = ADDR_VAR_TSS16_CPL3;
	seg_tss16_cpl3.dpl = 3;

	struct kvm_segment seg_tss64 = seg_tss32;
	seg_tss64.selector = SEL_TSS64;
	seg_tss64.base = ADDR_VAR_TSS64;
	seg_tss64.limit = 0x1ff;

	struct kvm_segment seg_tss64_cpl3 = seg_tss64;
	seg_tss64_cpl3.selector = SEL_TSS64_CPL3;
	seg_tss64_cpl3.base = ADDR_VAR_TSS64_CPL3;
	seg_tss64_cpl3.dpl = 3;

	struct kvm_segment seg_cgate16;
	seg_cgate16.selector = SEL_CGATE16;
	seg_cgate16.type = 4;
	seg_cgate16.base = SEL_CS16 | (2 << 16);
	seg_cgate16.limit = ADDR_VAR_USER_CODE2;
	seg_cgate16.present = 1;
	seg_cgate16.dpl = 0;
	seg_cgate16.s = 0;
	seg_cgate16.g = 0;
	seg_cgate16.db = 0;
	seg_cgate16.l = 0;
	seg_cgate16.avl = 0;

	struct kvm_segment seg_tgate16 = seg_cgate16;
	seg_tgate16.selector = SEL_TGATE16;
	seg_tgate16.type = 3;
	seg_cgate16.base = SEL_TSS16_2;
	seg_tgate16.limit = 0;

	struct kvm_segment seg_cgate32 = seg_cgate16;
	seg_cgate32.selector = SEL_CGATE32;
	seg_cgate32.type = 12;
	seg_cgate32.base = SEL_CS32 | (2 << 16);

	struct kvm_segment seg_tgate32 = seg_cgate32;
	seg_tgate32.selector = SEL_TGATE32;
	seg_tgate32.type = 11;
	seg_tgate32.base = SEL_TSS32_2;
	seg_tgate32.limit = 0;

	struct kvm_segment seg_cgate64 = seg_cgate16;
	seg_cgate64.selector = SEL_CGATE64;
	seg_cgate64.type = 12;
	seg_cgate64.base = SEL_CS64;

	int kvmfd = open("/dev/kvm", O_RDWR);
	char buf[sizeof(struct kvm_cpuid2) + 128 * sizeof(struct kvm_cpuid_entry2)];
	memset(buf, 0, sizeof(buf));
	struct kvm_cpuid2* cpuid = (struct kvm_cpuid2*)buf;
	cpuid->nent = 128;
	ioctl(kvmfd, KVM_GET_SUPPORTED_CPUID, cpuid);
	ioctl(cpufd, KVM_SET_CPUID2, cpuid);
	close(kvmfd);

	const char* text_prefix = 0;
	int text_prefix_size = 0;
	char* host_text = host_mem + ADDR_TEXT;

	if (text_type == 8) {
		if (flags & KVM_SETUP_SMM) {
			if (flags & KVM_SETUP_PROTECTED) {
				sregs.cs = seg_cs16;
				sregs.ds = sregs.es = sregs.fs = sregs.gs = sregs.ss = seg_ds16;
				sregs.cr0 |= CR0_PE;
			} else {
				sregs.cs.selector = 0;
				sregs.cs.base = 0;
			}

			*(host_mem + ADDR_TEXT) = 0xf4;
			host_text = host_mem + 0x8000;

			ioctl(cpufd, KVM_SMI, 0);
		} else if (flags & KVM_SETUP_VIRT86) {
			sregs.cs = seg_cs32;
			sregs.ds = sregs.es = sregs.fs = sregs.gs = sregs.ss = seg_ds32;
			sregs.cr0 |= CR0_PE;
			sregs.efer |= EFER_SCE;

			setup_syscall_msrs(cpufd, SEL_CS32, SEL_CS32_CPL3);
			setup_32bit_idt(&sregs, host_mem, guest_mem);

			if (flags & KVM_SETUP_PAGING) {
				uint64 pd_addr = guest_mem + ADDR_PD;
				uint64* pd = (uint64*)(host_mem + ADDR_PD);
				pd[0] = PDE32_PRESENT | PDE32_RW | PDE32_USER | PDE32_PS;
				sregs.cr3 = pd_addr;
				sregs.cr4 |= CR4_PSE;

				text_prefix = kvm_asm32_paged_vm86;
				text_prefix_size = sizeof(kvm_asm32_paged_vm86) - 1;
			} else {
				text_prefix = kvm_asm32_vm86;
				text_prefix_size = sizeof(kvm_asm32_vm86) - 1;
			}
		} else {
			sregs.cs.selector = 0;
			sregs.cs.base = 0;
		}
	} else if (text_type == 16) {
		if (flags & KVM_SETUP_CPL3) {
			sregs.cs = seg_cs16;
			sregs.ds = sregs.es = sregs.fs = sregs.gs = sregs.ss = seg_ds16;

			text_prefix = kvm_asm16_cpl3;
			text_prefix_size = sizeof(kvm_asm16_cpl3) - 1;
		} else {
			sregs.cr0 |= CR0_PE;
			sregs.cs = seg_cs16;
			sregs.ds = sregs.es = sregs.fs = sregs.gs = sregs.ss = seg_ds16;
		}
	} else if (text_type == 32) {
		sregs.cr0 |= CR0_PE;
		sregs.efer |= EFER_SCE;

		setup_syscall_msrs(cpufd, SEL_CS32, SEL_CS32_CPL3);
		setup_32bit_idt(&sregs, host_mem, guest_mem);

		if (flags & KVM_SETUP_SMM) {
			sregs.cs = seg_cs32;
			sregs.ds = sregs.es = sregs.fs = sregs.gs = sregs.ss = seg_ds32;

			*(host_mem + ADDR_TEXT) = 0xf4;
			host_text = host_mem + 0x8000;

			ioctl(cpufd, KVM_SMI, 0);
		} else if (flags & KVM_SETUP_PAGING) {
			sregs.cs = seg_cs32;
			sregs.ds = sregs.es = sregs.fs = sregs.gs = sregs.ss = seg_ds32;

			uint64 pd_addr = guest_mem + ADDR_PD;
			uint64* pd = (uint64*)(host_mem + ADDR_PD);
			pd[0] = PDE32_PRESENT | PDE32_RW | PDE32_USER | PDE32_PS;
			sregs.cr3 = pd_addr;
			sregs.cr4 |= CR4_PSE;

			text_prefix = kvm_asm32_paged;
			text_prefix_size = sizeof(kvm_asm32_paged) - 1;
		} else if (flags & KVM_SETUP_CPL3) {
			sregs.cs = seg_cs32_cpl3;
			sregs.ds = sregs.es = sregs.fs = sregs.gs = sregs.ss = seg_ds32_cpl3;
		} else {
			sregs.cs = seg_cs32;
			sregs.ds = sregs.es = sregs.fs = sregs.gs = sregs.ss = seg_ds32;
		}
	} else {
		sregs.efer |= EFER_LME | EFER_SCE;
		sregs.cr0 |= CR0_PE;

		setup_syscall_msrs(cpufd, SEL_CS64, SEL_CS64_CPL3);
		setup_64bit_idt(&sregs, host_mem, guest_mem);

		sregs.cs = seg_cs32;
		sregs.ds = sregs.es = sregs.fs = sregs.gs = sregs.ss = seg_ds32;

		uint64 pml4_addr = guest_mem + ADDR_PML4;
		uint64* pml4 = (uint64*)(host_mem + ADDR_PML4);
		uint64 pdpt_addr = guest_mem + ADDR_PDP;
		uint64* pdpt = (uint64*)(host_mem + ADDR_PDP);
		uint64 pd_addr = guest_mem + ADDR_PD;
		uint64* pd = (uint64*)(host_mem + ADDR_PD);
		pml4[0] = PDE64_PRESENT | PDE64_RW | PDE64_USER | pdpt_addr;
		pdpt[0] = PDE64_PRESENT | PDE64_RW | PDE64_USER | pd_addr;
		pd[0] = PDE64_PRESENT | PDE64_RW | PDE64_USER | PDE64_PS;
		sregs.cr3 = pml4_addr;
		sregs.cr4 |= CR4_PAE;

		if (flags & KVM_SETUP_VM) {
			sregs.cr0 |= CR0_NE;

			*((uint64*)(host_mem + ADDR_VAR_VMXON_PTR)) = ADDR_VAR_VMXON;
			*((uint64*)(host_mem + ADDR_VAR_VMCS_PTR)) = ADDR_VAR_VMCS;
			memcpy(host_mem + ADDR_VAR_VMEXIT_CODE, kvm_asm64_vm_exit, sizeof(kvm_asm64_vm_exit) - 1);
			*((uint64*)(host_mem + ADDR_VAR_VMEXIT_PTR)) = ADDR_VAR_VMEXIT_CODE;

			text_prefix = kvm_asm64_init_vm;
			text_prefix_size = sizeof(kvm_asm64_init_vm) - 1;
		} else if (flags & KVM_SETUP_CPL3) {
			text_prefix = kvm_asm64_cpl3;
			text_prefix_size = sizeof(kvm_asm64_cpl3) - 1;
		} else {
			text_prefix = kvm_asm64_enable_long;
			text_prefix_size = sizeof(kvm_asm64_enable_long) - 1;
		}
	}

	struct tss16 tss16;
	memset(&tss16, 0, sizeof(tss16));
	tss16.ss0 = tss16.ss1 = tss16.ss2 = SEL_DS16;
	tss16.sp0 = tss16.sp1 = tss16.sp2 = ADDR_STACK0;
	tss16.ip = ADDR_VAR_USER_CODE2;
	tss16.flags = (1 << 1);
	tss16.cs = SEL_CS16;
	tss16.es = tss16.ds = tss16.ss = SEL_DS16;
	tss16.ldt = SEL_LDT;
	struct tss16* tss16_addr = (struct tss16*)(host_mem + seg_tss16_2.base);
	memcpy(tss16_addr, &tss16, sizeof(tss16));

	memset(&tss16, 0, sizeof(tss16));
	tss16.ss0 = tss16.ss1 = tss16.ss2 = SEL_DS16;
	tss16.sp0 = tss16.sp1 = tss16.sp2 = ADDR_STACK0;
	tss16.ip = ADDR_VAR_USER_CODE2;
	tss16.flags = (1 << 1);
	tss16.cs = SEL_CS16_CPL3;
	tss16.es = tss16.ds = tss16.ss = SEL_DS16_CPL3;
	tss16.ldt = SEL_LDT;
	struct tss16* tss16_cpl3_addr = (struct tss16*)(host_mem + seg_tss16_cpl3.base);
	memcpy(tss16_cpl3_addr, &tss16, sizeof(tss16));

	struct tss32 tss32;
	memset(&tss32, 0, sizeof(tss32));
	tss32.ss0 = tss32.ss1 = tss32.ss2 = SEL_DS32;
	tss32.sp0 = tss32.sp1 = tss32.sp2 = ADDR_STACK0;
	tss32.ip = ADDR_VAR_USER_CODE;
	tss32.flags = (1 << 1) | (1 << 17);
	tss32.ldt = SEL_LDT;
	tss32.cr3 = sregs.cr3;
	tss32.io_bitmap = offsetof(struct tss32, io_bitmap);
	struct tss32* tss32_addr = (struct tss32*)(host_mem + seg_tss32_vm86.base);
	memcpy(tss32_addr, &tss32, sizeof(tss32));

	memset(&tss32, 0, sizeof(tss32));
	tss32.ss0 = tss32.ss1 = tss32.ss2 = SEL_DS32;
	tss32.sp0 = tss32.sp1 = tss32.sp2 = ADDR_STACK0;
	tss32.ip = ADDR_VAR_USER_CODE;
	tss32.flags = (1 << 1);
	tss32.cr3 = sregs.cr3;
	tss32.es = tss32.ds = tss32.ss = tss32.gs = tss32.fs = SEL_DS32;
	tss32.cs = SEL_CS32;
	tss32.ldt = SEL_LDT;
	tss32.cr3 = sregs.cr3;
	tss32.io_bitmap = offsetof(struct tss32, io_bitmap);
	struct tss32* tss32_cpl3_addr = (struct tss32*)(host_mem + seg_tss32_2.base);
	memcpy(tss32_cpl3_addr, &tss32, sizeof(tss32));

	struct tss64 tss64;
	memset(&tss64, 0, sizeof(tss64));
	tss64.rsp[0] = ADDR_STACK0;
	tss64.rsp[1] = ADDR_STACK0;
	tss64.rsp[2] = ADDR_STACK0;
	tss64.io_bitmap = offsetof(struct tss64, io_bitmap);
	struct tss64* tss64_addr = (struct tss64*)(host_mem + seg_tss64.base);
	memcpy(tss64_addr, &tss64, sizeof(tss64));

	memset(&tss64, 0, sizeof(tss64));
	tss64.rsp[0] = ADDR_STACK0;
	tss64.rsp[1] = ADDR_STACK0;
	tss64.rsp[2] = ADDR_STACK0;
	tss64.io_bitmap = offsetof(struct tss64, io_bitmap);
	struct tss64* tss64_cpl3_addr = (struct tss64*)(host_mem + seg_tss64_cpl3.base);
	memcpy(tss64_cpl3_addr, &tss64, sizeof(tss64));

	if (text_size > 1000)
		text_size = 1000;
	if (text_prefix) {
		memcpy(host_text, text_prefix, text_prefix_size);
		void* patch = memmem(host_text, text_prefix_size, "\xde\xc0\xad\x0b", 4);
		if (patch)
			*((uint32*)patch) = guest_mem + ADDR_TEXT + ((char*)patch - host_text) + 6;
		uint16 magic = PREFIX_SIZE;
		patch = memmem(host_text, text_prefix_size, &magic, sizeof(magic));
		if (patch)
			*((uint16*)patch) = guest_mem + ADDR_TEXT + text_prefix_size;
	}
	memcpy((void*)(host_text + text_prefix_size), text, text_size);
	*(host_text + text_prefix_size + text_size) = 0xf4;

	memcpy(host_mem + ADDR_VAR_USER_CODE, text, text_size);
	*(host_mem + ADDR_VAR_USER_CODE + text_size) = 0xf4;

	*(host_mem + ADDR_VAR_HLT) = 0xf4;
	memcpy(host_mem + ADDR_VAR_SYSRET, "\x0f\x07\xf4", 3);
	memcpy(host_mem + ADDR_VAR_SYSEXIT, "\x0f\x35\xf4", 3);

	*(uint64*)(host_mem + ADDR_VAR_VMWRITE_FLD) = 0;
	*(uint64*)(host_mem + ADDR_VAR_VMWRITE_VAL) = 0;

	if (opt_count > 2)
		opt_count = 2;
	for (uintptr_t i = 0; i < opt_count; i++) {
		uint64 typ = opt_array_ptr[i].typ;
		uint64 val = opt_array_ptr[i].val;
		switch (typ % 9) {
		case 0:
			sregs.cr0 ^= val & (CR0_MP | CR0_EM | CR0_ET | CR0_NE | CR0_WP | CR0_AM | CR0_NW | CR0_CD);
			break;
		case 1:
			sregs.cr4 ^= val & (CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_MCE | CR4_PGE | CR4_PCE |
					    CR4_OSFXSR | CR4_OSXMMEXCPT | CR4_UMIP | CR4_VMXE | CR4_SMXE | CR4_FSGSBASE | CR4_PCIDE |
					    CR4_OSXSAVE | CR4_SMEP | CR4_SMAP | CR4_PKE);
			break;
		case 2:
			sregs.efer ^= val & (EFER_SCE | EFER_NXE | EFER_SVME | EFER_LMSLE | EFER_FFXSR | EFER_TCE);
			break;
		case 3:
			val &= ((1 << 8) | (1 << 9) | (1 << 10) | (1 << 12) | (1 << 13) | (1 << 14) |
				(1 << 15) | (1 << 18) | (1 << 19) | (1 << 20) | (1 << 21));
			regs.rflags ^= val;
			tss16_addr->flags ^= val;
			tss16_cpl3_addr->flags ^= val;
			tss32_addr->flags ^= val;
			tss32_cpl3_addr->flags ^= val;
			break;
		case 4:
			seg_cs16.type = val & 0xf;
			seg_cs32.type = val & 0xf;
			seg_cs64.type = val & 0xf;
			break;
		case 5:
			seg_cs16_cpl3.type = val & 0xf;
			seg_cs32_cpl3.type = val & 0xf;
			seg_cs64_cpl3.type = val & 0xf;
			break;
		case 6:
			seg_ds16.type = val & 0xf;
			seg_ds32.type = val & 0xf;
			seg_ds64.type = val & 0xf;
			break;
		case 7:
			seg_ds16_cpl3.type = val & 0xf;
			seg_ds32_cpl3.type = val & 0xf;
			seg_ds64_cpl3.type = val & 0xf;
			break;
		case 8:
			*(uint64*)(host_mem + ADDR_VAR_VMWRITE_FLD) = (val & 0xffff);
			*(uint64*)(host_mem + ADDR_VAR_VMWRITE_VAL) = (val >> 16);
			break;
		default:
			fail("bad kvm setup opt");
		}
	}
	regs.rflags |= 2;

	fill_segment_descriptor(gdt, ldt, &seg_ldt);
	fill_segment_descriptor(gdt, ldt, &seg_cs16);
	fill_segment_descriptor(gdt, ldt, &seg_ds16);
	fill_segment_descriptor(gdt, ldt, &seg_cs16_cpl3);
	fill_segment_descriptor(gdt, ldt, &seg_ds16_cpl3);
	fill_segment_descriptor(gdt, ldt, &seg_cs32);
	fill_segment_descriptor(gdt, ldt, &seg_ds32);
	fill_segment_descriptor(gdt, ldt, &seg_cs32_cpl3);
	fill_segment_descriptor(gdt, ldt, &seg_ds32_cpl3);
	fill_segment_descriptor(gdt, ldt, &seg_cs64);
	fill_segment_descriptor(gdt, ldt, &seg_ds64);
	fill_segment_descriptor(gdt, ldt, &seg_cs64_cpl3);
	fill_segment_descriptor(gdt, ldt, &seg_ds64_cpl3);
	fill_segment_descriptor(gdt, ldt, &seg_tss32);
	fill_segment_descriptor(gdt, ldt, &seg_tss32_2);
	fill_segment_descriptor(gdt, ldt, &seg_tss32_cpl3);
	fill_segment_descriptor(gdt, ldt, &seg_tss32_vm86);
	fill_segment_descriptor(gdt, ldt, &seg_tss16);
	fill_segment_descriptor(gdt, ldt, &seg_tss16_2);
	fill_segment_descriptor(gdt, ldt, &seg_tss16_cpl3);
	fill_segment_descriptor_dword(gdt, ldt, &seg_tss64);
	fill_segment_descriptor_dword(gdt, ldt, &seg_tss64_cpl3);
	fill_segment_descriptor(gdt, ldt, &seg_cgate16);
	fill_segment_descriptor(gdt, ldt, &seg_tgate16);
	fill_segment_descriptor(gdt, ldt, &seg_cgate32);
	fill_segment_descriptor(gdt, ldt, &seg_tgate32);
	fill_segment_descriptor_dword(gdt, ldt, &seg_cgate64);

	if (ioctl(cpufd, KVM_SET_SREGS, &sregs))
		return -1;
	if (ioctl(cpufd, KVM_SET_REGS, &regs))
		return -1;
	return 0;
}

#elif GOARCH_arm64

struct kvm_text {
	uintptr_t typ;
	const void* text;
	uintptr_t size;
};

struct kvm_opt {
	uint64 typ;
	uint64 val;
};
static volatile long syz_kvm_setup_cpu(volatile long a0, volatile long a1, volatile long a2, volatile long a3, volatile long a4, volatile long a5, volatile long a6, volatile long a7)
{
	const int vmfd = a0;
	const int cpufd = a1;
	char* const host_mem = (char*)a2;
	const struct kvm_text* const text_array_ptr = (struct kvm_text*)a3;
	const uintptr_t text_count = a4;
	const uintptr_t flags = a5;
	const struct kvm_opt* const opt_array_ptr = (struct kvm_opt*)a6;
	uintptr_t opt_count = a7;

	(void)flags;
	(void)opt_count;

	const uintptr_t page_size = 4 << 10;
	const uintptr_t guest_mem = 0;
	const uintptr_t guest_mem_size = 24 * page_size;

	(void)text_count;
	int text_type = text_array_ptr[0].typ;
	const void* text = text_array_ptr[0].text;
	int text_size = text_array_ptr[0].size;
	(void)text_type;
	(void)opt_array_ptr;

	uint32 features = 0;
	if (opt_count > 1)
		opt_count = 1;
	for (uintptr_t i = 0; i < opt_count; i++) {
		uint64 typ = opt_array_ptr[i].typ;
		uint64 val = opt_array_ptr[i].val;
		switch (typ) {
		case 1:
			features = val;
			break;
		}
	}

	for (uintptr_t i = 0; i < guest_mem_size / page_size; i++) {
		struct kvm_userspace_memory_region memreg;
		memreg.slot = i;
		memreg.flags = 0;
		memreg.guest_phys_addr = guest_mem + i * page_size;
		memreg.memory_size = page_size;
		memreg.userspace_addr = (uintptr_t)host_mem + i * page_size;
		ioctl(vmfd, KVM_SET_USER_MEMORY_REGION, &memreg);
	}

	struct kvm_vcpu_init init;
	ioctl(cpufd, KVM_ARM_PREFERRED_TARGET, &init);
	init.features[0] = features;
	ioctl(cpufd, KVM_ARM_VCPU_INIT, &init);

	if (text_size > 1000)
		text_size = 1000;
	memcpy(host_mem, text, text_size);

	return 0;
}

#elif GOARCH_ppc64 || GOARCH_ppc64le
const char kvm_ppc64_mr[] = "\x00\x00\xa0\x3c\x00\x00\xa5\x60\xc6\x07\xa5\x78\xad\x0b\xa5\x64\xde\xc0\xa5\x60\x78\x2b\xa4\x7c\x78\x23\x83\x7c";
const char kvm_ppc64_ld[] = "\x00\x00\xe0\x3d\x00\x00\xef\x61\xc6\x07\xef\x79\xad\x0b\xef\x65\xde\xc0\xef\x61\x00\x00\x20\x3f\x00\x00\x39\x63\xc6\x07\x39\x7b\x17\x00\x39\x67\xf8\xff\x39\x63\x00\x00\xf9\xf9\x00\x00\x79\xe8";
const char kvm_ppc64_recharge_dec[] = "\x00\x00\x80\x3e\x00\x00\x94\x62\xc6\x07\x94\x7a\xff\x07\x94\x66\xff\xff\x94\x62\xa6\x03\x96\x7e\x24\x00\x00\x4c";


#define BOOK3S_INTERRUPT_SYSTEM_RESET 0x100
#define BOOK3S_INTERRUPT_MACHINE_CHECK 0x200
#define BOOK3S_INTERRUPT_DATA_STORAGE 0x300
#define BOOK3S_INTERRUPT_DATA_SEGMENT 0x380
#define BOOK3S_INTERRUPT_INST_STORAGE 0x400
#define BOOK3S_INTERRUPT_INST_SEGMENT 0x480
#define BOOK3S_INTERRUPT_EXTERNAL 0x500
#define BOOK3S_INTERRUPT_EXTERNAL_HV 0x502
#define BOOK3S_INTERRUPT_ALIGNMENT 0x600
#define BOOK3S_INTERRUPT_PROGRAM 0x700
#define BOOK3S_INTERRUPT_FP_UNAVAIL 0x800
#define BOOK3S_INTERRUPT_DECREMENTER 0x900
#define BOOK3S_INTERRUPT_HV_DECREMENTER 0x980
#define BOOK3S_INTERRUPT_DOORBELL 0xa00
#define BOOK3S_INTERRUPT_SYSCALL 0xc00
#define BOOK3S_INTERRUPT_TRACE 0xd00
#define BOOK3S_INTERRUPT_H_DATA_STORAGE 0xe00
#define BOOK3S_INTERRUPT_H_INST_STORAGE 0xe20
#define BOOK3S_INTERRUPT_H_EMUL_ASSIST 0xe40
#define BOOK3S_INTERRUPT_HMI 0xe60
#define BOOK3S_INTERRUPT_H_DOORBELL 0xe80
#define BOOK3S_INTERRUPT_H_VIRT 0xea0
#define BOOK3S_INTERRUPT_PERFMON 0xf00
#define BOOK3S_INTERRUPT_ALTIVEC 0xf20
#define BOOK3S_INTERRUPT_VSX 0xf40
#define BOOK3S_INTERRUPT_FAC_UNAVAIL 0xf60
#define BOOK3S_INTERRUPT_H_FAC_UNAVAIL 0xf80

#define BITS_PER_LONG 64
#define PPC_BITLSHIFT(be) (BITS_PER_LONG - 1 - (be))
#define PPC_BIT(bit) (1ULL << PPC_BITLSHIFT(bit))
#define PPC_BITMASK(bs, be) ((PPC_BIT(bs) - PPC_BIT(be)) | PPC_BIT(bs))

#define RADIX_PTE_INDEX_SIZE 5
#define RADIX_PMD_INDEX_SIZE 9
#define RADIX_PUD_INDEX_SIZE 9
#define RADIX_PGD_INDEX_SIZE 13

#define cpu_to_be32(x) __builtin_bswap32(x)
#define cpu_to_be64(x) __builtin_bswap64(x)
#define be64_to_cpu(x) __builtin_bswap64(x)

#define LPCR_ILE PPC_BIT(38)
#define LPCR_UPRT PPC_BIT(41)
#define LPCR_EVIRT PPC_BIT(42)
#define LPCR_HR PPC_BIT(43)
#ifndef KVM_REG_PPC_LPCR_64
#define KVM_REG_PPC_LPCR_64 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xb5)
#endif

#define PRTB_SIZE_SHIFT 12
#define PATB_GR (1UL << 63)
#define PATB_HR (1UL << 63)
#define PRTB_MASK 0x0ffffffffffff000UL

#define ALIGNUP(p, q) ((void*)(((unsigned long)(p) + (q)-1) & ~((q)-1)))
#define MAX(a, b) (((a) > (b)) ? (a) : (b))

#ifndef KVM_REG_PPC_DEC_EXPIRY
#define KVM_REG_PPC_DEC_EXPIRY (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xbe)
#endif

#ifndef KVM_PPC_CONFIGURE_V3_MMU
#define KVM_PPC_CONFIGURE_V3_MMU _IOW(KVMIO, 0xaf, struct kvm_ppc_mmuv3_cfg)
struct kvm_ppc_mmuv3_cfg {
	__u64 flags;
	__u64 process_table;
};
#define KVM_PPC_MMUV3_RADIX 1
#define KVM_PPC_MMUV3_GTSE 2
#endif

#ifndef KVM_CAP_PPC_NESTED_HV
#define KVM_CAP_PPC_NESTED_HV 160
#endif

struct kvm_text {
	uintptr_t typ;
	const void* text;
	uintptr_t size;
};

static int kvmppc_define_rtas_kernel_token(int vmfd, unsigned token, const char* func)
{
	struct kvm_rtas_token_args args;

	args.token = token;
	strncpy(args.name, func, sizeof(args.name) - 1);

	return ioctl(vmfd, KVM_PPC_RTAS_DEFINE_TOKEN, &args);
}

static int kvmppc_get_one_reg(int cpufd, uint64 id, void* target)
{
	struct kvm_one_reg reg = {.id = id, .addr = (uintptr_t)target};

	return ioctl(cpufd, KVM_GET_ONE_REG, &reg);
}

static int kvmppc_set_one_reg(int cpufd, uint64 id, void* target)
{
	struct kvm_one_reg reg = {.id = id, .addr = (uintptr_t)target};

	return ioctl(cpufd, KVM_SET_ONE_REG, &reg);
}

static int kvm_vcpu_enable_cap(int cpufd, uint32 capability)
{
	struct kvm_enable_cap cap = {
	    .cap = capability,
	};
	return ioctl(cpufd, KVM_ENABLE_CAP, &cap);
}

static int kvm_vm_enable_cap(int vmfd, uint32 capability, uint64 p1, uint64 p2)
{
	struct kvm_enable_cap cap = {
	    .cap = capability,
	    .flags = 0,
	    .args = {p1, p2},
	};
	return ioctl(vmfd, KVM_ENABLE_CAP, &cap);
}

static void dump_text(const char* mem, unsigned start, unsigned cw, uint32 debug_inst_opcode)
{
#ifdef DEBUG
	printf("Text @%x: ", start);

	for (unsigned i = 0; i < cw; ++i) {
		uint32 w = ((uint32*)(mem + start))[i];

		printf(" %08x", w);
		if (debug_inst_opcode && debug_inst_opcode == w)
			break;
	}

	printf("\n");
#endif
}
#define KVM_SETUP_PPC64_LE (1 << 0)
#define KVM_SETUP_PPC64_IR (1 << 1)
#define KVM_SETUP_PPC64_DR (1 << 2)
#define KVM_SETUP_PPC64_PR (1 << 3)
#define KVM_SETUP_PPC64_PID1 (1 << 4)
static volatile long syz_kvm_setup_cpu(volatile long a0, volatile long a1, volatile long a2, volatile long a3, volatile long a4, volatile long a5, volatile long a6, volatile long a7)
{
	const int vmfd = a0;
	const int cpufd = a1;
	char* const host_mem = (char*)a2;
	const struct kvm_text* const text_array_ptr = (struct kvm_text*)a3;
	const uintptr_t text_count = a4;
	uintptr_t flags = a5;
	const uintptr_t page_size = 0x10000;
	const uintptr_t guest_mem_size = 24 * page_size;
	unsigned long gpa_off = 0;
	uint32 debug_inst_opcode = 0;

	(void)text_count;
	const void* text = 0;
	uintptr_t text_size = 0;
	uint64 pid = 0;
	uint64 lpcr = 0;
	NONFAILING(text = text_array_ptr[0].text);
	NONFAILING(text_size = text_array_ptr[0].size);

	if (kvm_vcpu_enable_cap(cpufd, KVM_CAP_PPC_PAPR))
		return -1;

	if (kvm_vm_enable_cap(vmfd, KVM_CAP_PPC_NESTED_HV, true, 0))
		return -1;

	for (uintptr_t i = 0; i < guest_mem_size / page_size; i++) {
		struct kvm_userspace_memory_region memreg;
		memreg.slot = i;
		memreg.flags = 0;
		memreg.guest_phys_addr = i * page_size;
		memreg.memory_size = page_size;
		memreg.userspace_addr = (uintptr_t)host_mem + i * page_size;
		if (ioctl(vmfd, KVM_SET_USER_MEMORY_REGION, &memreg))
			return -1;
	}

	struct kvm_regs regs;
	struct kvm_sregs sregs;
	if (ioctl(cpufd, KVM_GET_SREGS, &sregs))
		return -1;
	if (ioctl(cpufd, KVM_GET_REGS, &regs))
		return -1;

	regs.msr = PPC_BIT(0);
	if (flags & KVM_SETUP_PPC64_LE)
		regs.msr |= PPC_BIT(63);
	if (flags & KVM_SETUP_PPC64_PR) {
		regs.msr |= PPC_BIT(49);
		flags |= KVM_SETUP_PPC64_IR | KVM_SETUP_PPC64_DR | KVM_SETUP_PPC64_PID1;
	}

	if (flags & KVM_SETUP_PPC64_IR)
		regs.msr |= PPC_BIT(58);
	if (flags & KVM_SETUP_PPC64_DR)
		regs.msr |= PPC_BIT(59);
	if (flags & KVM_SETUP_PPC64_PID1)
		pid = 1;
	if (kvmppc_get_one_reg(cpufd, KVM_REG_PPC_DEBUG_INST, &debug_inst_opcode))
		return -1;

#define VEC(x) (*((uint32*)(host_mem + (x))))
	VEC(BOOK3S_INTERRUPT_SYSTEM_RESET) = debug_inst_opcode;
	VEC(BOOK3S_INTERRUPT_MACHINE_CHECK) = debug_inst_opcode;
	VEC(BOOK3S_INTERRUPT_DATA_STORAGE) = debug_inst_opcode;
	VEC(BOOK3S_INTERRUPT_DATA_SEGMENT) = debug_inst_opcode;
	VEC(BOOK3S_INTERRUPT_INST_STORAGE) = debug_inst_opcode;
	VEC(BOOK3S_INTERRUPT_INST_SEGMENT) = debug_inst_opcode;
	VEC(BOOK3S_INTERRUPT_EXTERNAL) = debug_inst_opcode;
	VEC(BOOK3S_INTERRUPT_EXTERNAL_HV) = debug_inst_opcode;
	VEC(BOOK3S_INTERRUPT_ALIGNMENT) = debug_inst_opcode;
	VEC(BOOK3S_INTERRUPT_PROGRAM) = debug_inst_opcode;
	VEC(BOOK3S_INTERRUPT_FP_UNAVAIL) = debug_inst_opcode;
	memcpy(host_mem + BOOK3S_INTERRUPT_DECREMENTER, kvm_ppc64_recharge_dec, sizeof(kvm_ppc64_recharge_dec) - 1);
	VEC(BOOK3S_INTERRUPT_DECREMENTER + sizeof(kvm_ppc64_recharge_dec) - 1) = debug_inst_opcode;
	VEC(BOOK3S_INTERRUPT_HV_DECREMENTER) = debug_inst_opcode;
	VEC(BOOK3S_INTERRUPT_DOORBELL) = debug_inst_opcode;
	VEC(BOOK3S_INTERRUPT_SYSCALL) = debug_inst_opcode;
	VEC(BOOK3S_INTERRUPT_TRACE) = debug_inst_opcode;
	VEC(BOOK3S_INTERRUPT_H_DATA_STORAGE) = debug_inst_opcode;
	VEC(BOOK3S_INTERRUPT_H_INST_STORAGE) = debug_inst_opcode;
	VEC(BOOK3S_INTERRUPT_H_EMUL_ASSIST) = debug_inst_opcode;
	VEC(BOOK3S_INTERRUPT_HMI) = debug_inst_opcode;
	VEC(BOOK3S_INTERRUPT_H_DOORBELL) = debug_inst_opcode;
	VEC(BOOK3S_INTERRUPT_H_VIRT) = debug_inst_opcode;
	VEC(BOOK3S_INTERRUPT_PERFMON) = debug_inst_opcode;
	VEC(BOOK3S_INTERRUPT_ALTIVEC) = debug_inst_opcode;
	VEC(BOOK3S_INTERRUPT_VSX) = debug_inst_opcode;
	VEC(BOOK3S_INTERRUPT_FAC_UNAVAIL) = debug_inst_opcode;
	VEC(BOOK3S_INTERRUPT_H_FAC_UNAVAIL) = debug_inst_opcode;

	struct kvm_guest_debug dbg = {0};
	dbg.control = KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP;

	if (ioctl(cpufd, KVM_SET_GUEST_DEBUG, &dbg))
		return -1;
	gpa_off = 128 << 10;
	if (flags & (KVM_SETUP_PPC64_IR | KVM_SETUP_PPC64_DR)) {
		uintptr_t process_tb_off = gpa_off;
		unsigned long process_tb_size = 1UL << (PRTB_SIZE_SHIFT + 4);
		struct prtb_entry {
			__be64 prtb0;
			__be64 prtb1;
		}* process_tb = (struct prtb_entry*)(host_mem + gpa_off);

		memset(process_tb, 0xcc, process_tb_size);
		gpa_off += process_tb_size;

		unsigned long *pgd, *pud, *pmd, *pte, i;
		uintptr_t pgd_off = gpa_off;
		pgd = (unsigned long*)(host_mem + pgd_off);
		gpa_off += page_size;
		uintptr_t pud_off = gpa_off;
		pud = (unsigned long*)(host_mem + pud_off);
		gpa_off += page_size;
		uintptr_t pmd_off = gpa_off;
		pmd = (unsigned long*)(host_mem + pmd_off);
		gpa_off += page_size;
		uintptr_t pte_off = gpa_off;
		pte = (unsigned long*)(host_mem + pte_off);
		gpa_off += page_size;

		memset(pgd, 0, page_size);
		memset(pud, 0, page_size);
		memset(pmd, 0, page_size);
		memset(pte, 0, page_size);
		pgd[0] = cpu_to_be64(PPC_BIT(0) |
				     (pud_off & PPC_BITMASK(4, 55)) |
				     RADIX_PUD_INDEX_SIZE);
		pud[0] = cpu_to_be64(PPC_BIT(0) |
				     (pmd_off & PPC_BITMASK(4, 55)) |
				     RADIX_PMD_INDEX_SIZE);
		pmd[0] = cpu_to_be64(PPC_BIT(0) |
				     (pte_off & PPC_BITMASK(4, 55)) |
				     RADIX_PTE_INDEX_SIZE);
		for (i = 0; i < 24; ++i)
			pte[i] = cpu_to_be64(PPC_BIT(0) |
					     PPC_BIT(1) |
					     ((i * page_size) & PPC_BITMASK(7, 51)) |
					     PPC_BIT(55) |
					     PPC_BIT(56) |
					     PPC_BIT(61) |
					     PPC_BIT(62) |
					     PPC_BIT(63));

		const long max_shift = 52;
		const unsigned long rts = (max_shift - 31) & 0x1f;
		const unsigned long rts1 = (rts >> 3) << PPC_BITLSHIFT(2);
		const unsigned long rts2 = (rts & 7) << PPC_BITLSHIFT(58);

		process_tb[0].prtb0 = cpu_to_be64(PATB_HR | rts1 | pgd_off | rts2 | RADIX_PGD_INDEX_SIZE);
		if (pid)
			process_tb[pid].prtb0 = cpu_to_be64(PATB_HR | rts1 | pgd_off | rts2 | RADIX_PGD_INDEX_SIZE);
		struct kvm_ppc_mmuv3_cfg cfg = {
		    .flags = KVM_PPC_MMUV3_RADIX | KVM_PPC_MMUV3_GTSE,
		    .process_table = (process_tb_off & PRTB_MASK) | (PRTB_SIZE_SHIFT - 12) | PATB_GR,
		};
		if (ioctl(vmfd, KVM_PPC_CONFIGURE_V3_MMU, &cfg))
			return -1;

		lpcr |= LPCR_UPRT | LPCR_HR;
#ifdef DEBUG
		printf("MMUv3: flags=%lx %016lx\n", cfg.flags, cfg.process_table);
		printf("PTRB0=%016lx PGD0=%016lx PUD0=%016lx PMD0=%016lx\n",
		       be64_to_cpu((unsigned long)process_tb[0].prtb0), be64_to_cpu((unsigned long)pgd[0]),
		       be64_to_cpu((unsigned long)pud[0]), be64_to_cpu((unsigned long)pmd[0]));
		printf("PTEs @%lx:\n  %016lx %016lx %016lx %016lx\n  %016lx %016lx %016lx %016lx\n",
		       pte_off,
		       be64_to_cpu((unsigned long)pte[0]), be64_to_cpu((unsigned long)pte[1]),
		       be64_to_cpu((unsigned long)pte[2]), be64_to_cpu((unsigned long)pte[3]),
		       be64_to_cpu((unsigned long)pte[4]), be64_to_cpu((unsigned long)pte[5]),
		       be64_to_cpu((unsigned long)pte[6]), be64_to_cpu((unsigned long)pte[7]));
#endif
	}

	memcpy(host_mem + gpa_off, text, text_size);
	regs.pc = gpa_off;

	uintptr_t end_of_text = gpa_off + ((text_size + 3) & ~3);
	memcpy(host_mem + end_of_text, &debug_inst_opcode, sizeof(debug_inst_opcode));
	if (!(flags & KVM_SETUP_PPC64_LE)) {
		uint32* p = (uint32*)(host_mem + gpa_off);
		for (unsigned long i = 0; i < text_size / sizeof(*p); ++i)
			p[i] = cpu_to_be32(p[i]);

		p = (uint32*)(host_mem + BOOK3S_INTERRUPT_DECREMENTER);
		for (unsigned long i = 0; i < sizeof(kvm_ppc64_recharge_dec) / sizeof(*p); ++i)
			p[i] = cpu_to_be32(p[i]);
	} else {
		lpcr |= LPCR_ILE;
	}

	if (ioctl(cpufd, KVM_SET_SREGS, &sregs))
		return -1;
	if (ioctl(cpufd, KVM_SET_REGS, &regs))
		return -1;
	if (kvmppc_set_one_reg(cpufd, KVM_REG_PPC_LPCR_64, &lpcr))
		return -1;
	if (kvmppc_set_one_reg(cpufd, KVM_REG_PPC_PID, &pid))
		return -1;
#define MAX_HCALL 0x450
	for (unsigned hcall = 4; hcall < MAX_HCALL; hcall += 4)
		kvm_vm_enable_cap(vmfd, KVM_CAP_PPC_ENABLE_HCALL, hcall, 1);

	for (unsigned hcall = 0xf000; hcall < 0xf810; hcall += 4)
		kvm_vm_enable_cap(vmfd, KVM_CAP_PPC_ENABLE_HCALL, hcall, 1);

	for (unsigned hcall = 0xef00; hcall < 0xef20; hcall += 4)
		kvm_vm_enable_cap(vmfd, KVM_CAP_PPC_ENABLE_HCALL, hcall, 1);
	kvmppc_define_rtas_kernel_token(vmfd, 1, "ibm,set-xive");
	kvmppc_define_rtas_kernel_token(vmfd, 2, "ibm,get-xive");
	kvmppc_define_rtas_kernel_token(vmfd, 3, "ibm,int-on");
	kvmppc_define_rtas_kernel_token(vmfd, 4, "ibm,int-off");

	dump_text(host_mem, regs.pc, 8, debug_inst_opcode);
	dump_text(host_mem, BOOK3S_INTERRUPT_DECREMENTER, 16, debug_inst_opcode);

	uint64 decr = 0x7fffffff;
	if (kvmppc_set_one_reg(cpufd, KVM_REG_PPC_DEC_EXPIRY, &decr))
		return -1;

	return 0;
}

#elif !GOARCH_arm
static volatile long syz_kvm_setup_cpu(volatile long a0, volatile long a1, volatile long a2, volatile long a3, volatile long a4, volatile long a5, volatile long a6, volatile long a7)
{
	return 0;
}
#endif
#endif
#endif

#if (SYZ_EXECUTOR || SYZ_NET_RESET) && SYZ_EXECUTOR_USES_FORK_SERVER
#include <errno.h>
#include <net/if.h>
#include <netinet/in.h>
#include <string.h>
#include <sys/socket.h>

#include <linux/net.h>
#define XT_TABLE_SIZE 1536
#define XT_MAX_ENTRIES 10

struct xt_counters {
	uint64 pcnt, bcnt;
};

struct ipt_getinfo {
	char name[32];
	unsigned int valid_hooks;
	unsigned int hook_entry[5];
	unsigned int underflow[5];
	unsigned int num_entries;
	unsigned int size;
};

struct ipt_get_entries {
	char name[32];
	unsigned int size;
	uint64 entrytable[XT_TABLE_SIZE / sizeof(uint64)];
};

struct ipt_replace {
	char name[32];
	unsigned int valid_hooks;
	unsigned int num_entries;
	unsigned int size;
	unsigned int hook_entry[5];
	unsigned int underflow[5];
	unsigned int num_counters;
	struct xt_counters* counters;
	uint64 entrytable[XT_TABLE_SIZE / sizeof(uint64)];
};

struct ipt_table_desc {
	const char* name;
	struct ipt_getinfo info;
	struct ipt_replace replace;
};

static struct ipt_table_desc ipv4_tables[] = {
    {.name = "filter"},
    {.name = "nat"},
    {.name = "mangle"},
    {.name = "raw"},
    {.name = "security"},
};

static struct ipt_table_desc ipv6_tables[] = {
    {.name = "filter"},
    {.name = "nat"},
    {.name = "mangle"},
    {.name = "raw"},
    {.name = "security"},
};

#define IPT_BASE_CTL 64
#define IPT_SO_SET_REPLACE (IPT_BASE_CTL)
#define IPT_SO_GET_INFO (IPT_BASE_CTL)
#define IPT_SO_GET_ENTRIES (IPT_BASE_CTL + 1)

struct arpt_getinfo {
	char name[32];
	unsigned int valid_hooks;
	unsigned int hook_entry[3];
	unsigned int underflow[3];
	unsigned int num_entries;
	unsigned int size;
};

struct arpt_get_entries {
	char name[32];
	unsigned int size;
	uint64 entrytable[XT_TABLE_SIZE / sizeof(uint64)];
};

struct arpt_replace {
	char name[32];
	unsigned int valid_hooks;
	unsigned int num_entries;
	unsigned int size;
	unsigned int hook_entry[3];
	unsigned int underflow[3];
	unsigned int num_counters;
	struct xt_counters* counters;
	uint64 entrytable[XT_TABLE_SIZE / sizeof(uint64)];
};

struct arpt_table_desc {
	const char* name;
	struct arpt_getinfo info;
	struct arpt_replace replace;
};

static struct arpt_table_desc arpt_tables[] = {
    {.name = "filter"},
};

#define ARPT_BASE_CTL 96
#define ARPT_SO_SET_REPLACE (ARPT_BASE_CTL)
#define ARPT_SO_GET_INFO (ARPT_BASE_CTL)
#define ARPT_SO_GET_ENTRIES (ARPT_BASE_CTL + 1)

static void checkpoint_iptables(struct ipt_table_desc* tables, int num_tables, int family, int level)
{
	int fd = socket(family, SOCK_STREAM, IPPROTO_TCP);
	if (fd == -1) {
		switch (errno) {
		case EAFNOSUPPORT:
		case ENOPROTOOPT:
			return;
		}
		failmsg("iptable checkpoint: socket(SOCK_STREAM, IPPROTO_TCP) failed", "family=%d", family);
	}
	for (int i = 0; i < num_tables; i++) {
		struct ipt_table_desc* table = &tables[i];
		strcpy(table->info.name, table->name);
		strcpy(table->replace.name, table->name);
		socklen_t optlen = sizeof(table->info);
		if (getsockopt(fd, level, IPT_SO_GET_INFO, &table->info, &optlen)) {
			switch (errno) {
			case EPERM:
			case ENOENT:
			case ENOPROTOOPT:
				continue;
			}
			failmsg("iptable checkpoint: getsockopt(IPT_SO_GET_INFO) failed",
				"table=%s, family=%d", table->name, family);
		}
		debug("iptable checkpoint %s/%d: checkpoint entries=%d hooks=%x size=%d\n",
		      table->name, family, table->info.num_entries,
		      table->info.valid_hooks, table->info.size);
		if (table->info.size > sizeof(table->replace.entrytable))
			failmsg("iptable checkpoint: table size is too large", "table=%s, family=%d, size=%u",
				table->name, family, table->info.size);
		if (table->info.num_entries > XT_MAX_ENTRIES)
			failmsg("iptable checkpoint: too many counters", "table=%s, family=%d, counters=%d",
				table->name, family, table->info.num_entries);
		struct ipt_get_entries entries;
		memset(&entries, 0, sizeof(entries));
		strcpy(entries.name, table->name);
		entries.size = table->info.size;
		optlen = sizeof(entries) - sizeof(entries.entrytable) + table->info.size;
		if (getsockopt(fd, level, IPT_SO_GET_ENTRIES, &entries, &optlen))
			failmsg("iptable checkpoint: getsockopt(IPT_SO_GET_ENTRIES) failed",
				"table=%s, family=%d", table->name, family);
		table->replace.valid_hooks = table->info.valid_hooks;
		table->replace.num_entries = table->info.num_entries;
		table->replace.size = table->info.size;
		memcpy(table->replace.hook_entry, table->info.hook_entry, sizeof(table->replace.hook_entry));
		memcpy(table->replace.underflow, table->info.underflow, sizeof(table->replace.underflow));
		memcpy(table->replace.entrytable, entries.entrytable, table->info.size);
	}
	close(fd);
}

static void reset_iptables(struct ipt_table_desc* tables, int num_tables, int family, int level)
{
	int fd = socket(family, SOCK_STREAM, IPPROTO_TCP);
	if (fd == -1) {
		switch (errno) {
		case EAFNOSUPPORT:
		case ENOPROTOOPT:
			return;
		}
		failmsg("iptable: socket(SOCK_STREAM, IPPROTO_TCP) failed", "family=%d", family);
	}
	for (int i = 0; i < num_tables; i++) {
		struct ipt_table_desc* table = &tables[i];
		if (table->info.valid_hooks == 0)
			continue;
		struct ipt_getinfo info;
		memset(&info, 0, sizeof(info));
		strcpy(info.name, table->name);
		socklen_t optlen = sizeof(info);
		if (getsockopt(fd, level, IPT_SO_GET_INFO, &info, &optlen))
			failmsg("iptable: getsockopt(IPT_SO_GET_INFO) failed",
				"table=%s, family=%d", table->name, family);
		if (memcmp(&table->info, &info, sizeof(table->info)) == 0) {
			struct ipt_get_entries entries;
			memset(&entries, 0, sizeof(entries));
			strcpy(entries.name, table->name);
			entries.size = table->info.size;
			optlen = sizeof(entries) - sizeof(entries.entrytable) + entries.size;
			if (getsockopt(fd, level, IPT_SO_GET_ENTRIES, &entries, &optlen))
				failmsg("iptable: getsockopt(IPT_SO_GET_ENTRIES) failed",
					"table=%s, family=%d", table->name, family);
			if (memcmp(table->replace.entrytable, entries.entrytable, table->info.size) == 0)
				continue;
		}
		debug("iptable %s/%d: resetting\n", table->name, family);
		struct xt_counters counters[XT_MAX_ENTRIES];
		table->replace.num_counters = info.num_entries;
		table->replace.counters = counters;
		optlen = sizeof(table->replace) - sizeof(table->replace.entrytable) + table->replace.size;
		if (setsockopt(fd, level, IPT_SO_SET_REPLACE, &table->replace, optlen))
			failmsg("iptable: setsockopt(IPT_SO_SET_REPLACE) failed",
				"table=%s, family=%d", table->name, family);
	}
	close(fd);
}

static void checkpoint_arptables(void)
{
	int fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (fd == -1) {
		switch (errno) {
		case EAFNOSUPPORT:
		case ENOPROTOOPT:
			return;
		}
		fail("arptable checkpoint: socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) failed");
	}
	for (unsigned i = 0; i < sizeof(arpt_tables) / sizeof(arpt_tables[0]); i++) {
		struct arpt_table_desc* table = &arpt_tables[i];
		strcpy(table->info.name, table->name);
		strcpy(table->replace.name, table->name);
		socklen_t optlen = sizeof(table->info);
		if (getsockopt(fd, SOL_IP, ARPT_SO_GET_INFO, &table->info, &optlen)) {
			switch (errno) {
			case EPERM:
			case ENOENT:
			case ENOPROTOOPT:
				continue;
			}
			failmsg("arptable checkpoint: getsockopt(ARPT_SO_GET_INFO) failed", "table=%s", table->name);
		}
		debug("arptable checkpoint %s: entries=%d hooks=%x size=%d\n",
		      table->name, table->info.num_entries, table->info.valid_hooks, table->info.size);
		if (table->info.size > sizeof(table->replace.entrytable))
			failmsg("arptable checkpoint: table size is too large",
				"table=%s, size=%u", table->name, table->info.size);
		if (table->info.num_entries > XT_MAX_ENTRIES)
			failmsg("arptable checkpoint: too many counters",
				"table=%s, counters=%u", table->name, table->info.num_entries);
		struct arpt_get_entries entries;
		memset(&entries, 0, sizeof(entries));
		strcpy(entries.name, table->name);
		entries.size = table->info.size;
		optlen = sizeof(entries) - sizeof(entries.entrytable) + table->info.size;
		if (getsockopt(fd, SOL_IP, ARPT_SO_GET_ENTRIES, &entries, &optlen))
			failmsg("arptable checkpoint: getsockopt(ARPT_SO_GET_ENTRIES) failed", "table=%s", table->name);
		table->replace.valid_hooks = table->info.valid_hooks;
		table->replace.num_entries = table->info.num_entries;
		table->replace.size = table->info.size;
		memcpy(table->replace.hook_entry, table->info.hook_entry, sizeof(table->replace.hook_entry));
		memcpy(table->replace.underflow, table->info.underflow, sizeof(table->replace.underflow));
		memcpy(table->replace.entrytable, entries.entrytable, table->info.size);
	}
	close(fd);
}

static void reset_arptables()
{
	int fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (fd == -1) {
		switch (errno) {
		case EAFNOSUPPORT:
		case ENOPROTOOPT:
			return;
		}
		fail("arptable: socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)");
	}
	for (unsigned i = 0; i < sizeof(arpt_tables) / sizeof(arpt_tables[0]); i++) {
		struct arpt_table_desc* table = &arpt_tables[i];
		if (table->info.valid_hooks == 0)
			continue;
		struct arpt_getinfo info;
		memset(&info, 0, sizeof(info));
		strcpy(info.name, table->name);
		socklen_t optlen = sizeof(info);
		if (getsockopt(fd, SOL_IP, ARPT_SO_GET_INFO, &info, &optlen))
			failmsg("arptable: getsockopt(ARPT_SO_GET_INFO) failed", "table=%s", table->name);
		if (memcmp(&table->info, &info, sizeof(table->info)) == 0) {
			struct arpt_get_entries entries;
			memset(&entries, 0, sizeof(entries));
			strcpy(entries.name, table->name);
			entries.size = table->info.size;
			optlen = sizeof(entries) - sizeof(entries.entrytable) + entries.size;
			if (getsockopt(fd, SOL_IP, ARPT_SO_GET_ENTRIES, &entries, &optlen))
				failmsg("arptable: getsockopt(ARPT_SO_GET_ENTRIES) failed", "table=%s", table->name);
			if (memcmp(table->replace.entrytable, entries.entrytable, table->info.size) == 0)
				continue;
			debug("arptable %s: data changed\n", table->name);
		} else {
			debug("arptable %s: header changed\n", table->name);
		}
		debug("arptable %s: resetting\n", table->name);
		struct xt_counters counters[XT_MAX_ENTRIES];
		table->replace.num_counters = info.num_entries;
		table->replace.counters = counters;
		optlen = sizeof(table->replace) - sizeof(table->replace.entrytable) + table->replace.size;
		if (setsockopt(fd, SOL_IP, ARPT_SO_SET_REPLACE, &table->replace, optlen))
			failmsg("arptable: setsockopt(ARPT_SO_SET_REPLACE) failed",
				"table=%s", table->name);
	}
	close(fd);
}

#define NF_BR_NUMHOOKS 6
#define EBT_TABLE_MAXNAMELEN 32
#define EBT_CHAIN_MAXNAMELEN 32
#define EBT_BASE_CTL 128
#define EBT_SO_SET_ENTRIES (EBT_BASE_CTL)
#define EBT_SO_GET_INFO (EBT_BASE_CTL)
#define EBT_SO_GET_ENTRIES (EBT_SO_GET_INFO + 1)
#define EBT_SO_GET_INIT_INFO (EBT_SO_GET_ENTRIES + 1)
#define EBT_SO_GET_INIT_ENTRIES (EBT_SO_GET_INIT_INFO + 1)

struct ebt_replace {
	char name[EBT_TABLE_MAXNAMELEN];
	unsigned int valid_hooks;
	unsigned int nentries;
	unsigned int entries_size;
	struct ebt_entries* hook_entry[NF_BR_NUMHOOKS];
	unsigned int num_counters;
	struct ebt_counter* counters;
	char* entries;
};

struct ebt_entries {
	unsigned int distinguisher;
	char name[EBT_CHAIN_MAXNAMELEN];
	unsigned int counter_offset;
	int policy;
	unsigned int nentries;
	char data[0] __attribute__((aligned(__alignof__(struct ebt_replace))));
};

struct ebt_table_desc {
	const char* name;
	struct ebt_replace replace;
	char entrytable[XT_TABLE_SIZE];
};

static struct ebt_table_desc ebt_tables[] = {
    {.name = "filter"},
    {.name = "nat"},
    {.name = "broute"},
};

static void checkpoint_ebtables(void)
{
	int fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (fd == -1) {
		switch (errno) {
		case EAFNOSUPPORT:
		case ENOPROTOOPT:
			return;
		}
		fail("ebtable checkpoint: socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)");
	}
	for (size_t i = 0; i < sizeof(ebt_tables) / sizeof(ebt_tables[0]); i++) {
		struct ebt_table_desc* table = &ebt_tables[i];
		strcpy(table->replace.name, table->name);
		socklen_t optlen = sizeof(table->replace);
		if (getsockopt(fd, SOL_IP, EBT_SO_GET_INIT_INFO, &table->replace, &optlen)) {
			switch (errno) {
			case EPERM:
			case ENOENT:
			case ENOPROTOOPT:
				continue;
			}
			failmsg("ebtable checkpoint: getsockopt(EBT_SO_GET_INIT_INFO) failed",
				"table=%s", table->name);
		}
		debug("ebtable checkpoint %s: entries=%d hooks=%x size=%d\n",
		      table->name, table->replace.nentries, table->replace.valid_hooks,
		      table->replace.entries_size);
		if (table->replace.entries_size > sizeof(table->entrytable))
			failmsg("ebtable checkpoint: table size is too large", "table=%s, size=%u",
				table->name, table->replace.entries_size);
		table->replace.num_counters = 0;
		table->replace.entries = table->entrytable;
		optlen = sizeof(table->replace) + table->replace.entries_size;
		if (getsockopt(fd, SOL_IP, EBT_SO_GET_INIT_ENTRIES, &table->replace, &optlen))
			failmsg("ebtable checkpoint: getsockopt(EBT_SO_GET_INIT_ENTRIES) failed",
				"table=%s", table->name);
	}
	close(fd);
}

static void reset_ebtables()
{
	int fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (fd == -1) {
		switch (errno) {
		case EAFNOSUPPORT:
		case ENOPROTOOPT:
			return;
		}
		fail("ebtable: socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)");
	}
	for (unsigned i = 0; i < sizeof(ebt_tables) / sizeof(ebt_tables[0]); i++) {
		struct ebt_table_desc* table = &ebt_tables[i];
		if (table->replace.valid_hooks == 0)
			continue;
		struct ebt_replace replace;
		memset(&replace, 0, sizeof(replace));
		strcpy(replace.name, table->name);
		socklen_t optlen = sizeof(replace);
		if (getsockopt(fd, SOL_IP, EBT_SO_GET_INFO, &replace, &optlen))
			failmsg("ebtable: getsockopt(EBT_SO_GET_INFO)", "table=%s", table->name);
		replace.num_counters = 0;
		table->replace.entries = 0;
		for (unsigned h = 0; h < NF_BR_NUMHOOKS; h++)
			table->replace.hook_entry[h] = 0;
		if (memcmp(&table->replace, &replace, sizeof(table->replace)) == 0) {
			char entrytable[XT_TABLE_SIZE];
			memset(&entrytable, 0, sizeof(entrytable));
			replace.entries = entrytable;
			optlen = sizeof(replace) + replace.entries_size;
			if (getsockopt(fd, SOL_IP, EBT_SO_GET_ENTRIES, &replace, &optlen))
				failmsg("ebtable: getsockopt(EBT_SO_GET_ENTRIES) failed", "table=%s", table->name);
			if (memcmp(table->entrytable, entrytable, replace.entries_size) == 0)
				continue;
		}
		debug("ebtable %s: resetting\n", table->name);
		for (unsigned j = 0, h = 0; h < NF_BR_NUMHOOKS; h++) {
			if (table->replace.valid_hooks & (1 << h)) {
				table->replace.hook_entry[h] = (struct ebt_entries*)table->entrytable + j;
				j++;
			}
		}
		table->replace.entries = table->entrytable;
		optlen = sizeof(table->replace) + table->replace.entries_size;
		if (setsockopt(fd, SOL_IP, EBT_SO_SET_ENTRIES, &table->replace, optlen))
			failmsg("ebtable: setsockopt(EBT_SO_SET_ENTRIES) failed", "table=%s", table->name);
	}
	close(fd);
}

static void checkpoint_net_namespace(void)
{
#if SYZ_EXECUTOR
	if (!flag_net_reset || flag_sandbox_setuid)
		return;
#endif
	checkpoint_ebtables();
	checkpoint_arptables();
	checkpoint_iptables(ipv4_tables, sizeof(ipv4_tables) / sizeof(ipv4_tables[0]), AF_INET, SOL_IP);
	checkpoint_iptables(ipv6_tables, sizeof(ipv6_tables) / sizeof(ipv6_tables[0]), AF_INET6, SOL_IPV6);
}

static void reset_net_namespace(void)
{
#if SYZ_EXECUTOR
	if (!flag_net_reset || flag_sandbox_setuid)
		return;
#endif
	reset_ebtables();
	reset_arptables();
	reset_iptables(ipv4_tables, sizeof(ipv4_tables) / sizeof(ipv4_tables[0]), AF_INET, SOL_IP);
	reset_iptables(ipv6_tables, sizeof(ipv6_tables) / sizeof(ipv6_tables[0]), AF_INET6, SOL_IPV6);
}
#endif

#if SYZ_EXECUTOR || (SYZ_CGROUPS && (SYZ_SANDBOX_NONE || SYZ_SANDBOX_SETUID || SYZ_SANDBOX_NAMESPACE || SYZ_SANDBOX_ANDROID))
#include <fcntl.h>
#include <string.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/types.h>

static void mount_cgroups(const char* dir, const char** controllers, int count)
{
	if (mkdir(dir, 0777)) {
		debug("mkdir(%s) failed: %d\n", dir, errno);
		return;
	}
	char enabled[128] = {0};
	int i = 0;
	for (; i < count; i++) {
		if (mount("none", dir, "cgroup", 0, controllers[i])) {
			debug("mount(%s, %s) failed: %d\n", dir, controllers[i], errno);
			continue;
		}
		umount(dir);
		strcat(enabled, ",");
		strcat(enabled, controllers[i]);
	}
	if (enabled[0] == 0) {
		if (rmdir(dir) && errno != EBUSY)
			failmsg("rmdir failed", "dir=%s", dir);
		return;
	}
	if (mount("none", dir, "cgroup", 0, enabled + 1)) {
		debug("mount(%s, %s) failed: %d\n", dir, enabled + 1, errno);
		if (rmdir(dir) && errno != EBUSY)
			failmsg("rmdir failed", "dir=%s enabled=%s", dir, enabled);
	}
	if (chmod(dir, 0777)) {
		debug("chmod(%s) failed: %d\n", dir, errno);
	}
}

static void mount_cgroups2(const char** controllers, int count)
{
	if (mkdir("/syzcgroup/unified", 0777)) {
		debug("mkdir(/syzcgroup/unified) failed: %d\n", errno);
		return;
	}
	if (mount("none", "/syzcgroup/unified", "cgroup2", 0, NULL)) {
		debug("mount(cgroup2) failed: %d\n", errno);
		if (rmdir("/syzcgroup/unified") && errno != EBUSY)
			fail("rmdir(/syzcgroup/unified) failed");
		return;
	}
	if (chmod("/syzcgroup/unified", 0777)) {
		debug("chmod(/syzcgroup/unified) failed: %d\n", errno);
	}
	int control = open("/syzcgroup/unified/cgroup.subtree_control", O_WRONLY);
	if (control == -1)
		return;
	int i;
	for (i = 0; i < count; i++)
		if (write(control, controllers[i], strlen(controllers[i])) < 0) {
			debug("write(cgroup.subtree_control, %s) failed: %d\n", controllers[i], errno);
		}
	close(control);
}

static void setup_cgroups()
{
	const char* unified_controllers[] = {"+cpu", "+io", "+pids"};
	const char* net_controllers[] = {"net", "net_prio", "devices", "blkio", "freezer"};
	const char* cpu_controllers[] = {"cpuset", "cpuacct", "hugetlb", "rlimit", "memory"};
	if (mkdir("/syzcgroup", 0777)) {
		debug("mkdir(/syzcgroup) failed: %d\n", errno);
		return;
	}
	mount_cgroups2(unified_controllers, sizeof(unified_controllers) / sizeof(unified_controllers[0]));
	mount_cgroups("/syzcgroup/net", net_controllers, sizeof(net_controllers) / sizeof(net_controllers[0]));
	mount_cgroups("/syzcgroup/cpu", cpu_controllers, sizeof(cpu_controllers) / sizeof(cpu_controllers[0]));
	write_file("/syzcgroup/cpu/cgroup.clone_children", "1");
	write_file("/syzcgroup/cpu/cpuset.memory_pressure_enabled", "1");
}

#if (SYZ_EXECUTOR || SYZ_REPEAT) && SYZ_EXECUTOR_USES_FORK_SERVER
static void setup_cgroups_loop()
{
#if SYZ_EXECUTOR
	if (!flag_cgroups)
		return;
#endif
	int pid = getpid();
	char file[128];
	char cgroupdir[64];
	snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/unified/syz%llu", procid);
	if (mkdir(cgroupdir, 0777)) {
		debug("mkdir(%s) failed: %d\n", cgroupdir, errno);
	}
	snprintf(file, sizeof(file), "%s/pids.max", cgroupdir);
	write_file(file, "32");
	snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
	write_file(file, "%d", pid);
	snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/cpu/syz%llu", procid);
	if (mkdir(cgroupdir, 0777)) {
		debug("mkdir(%s) failed: %d\n", cgroupdir, errno);
	}
	snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
	write_file(file, "%d", pid);
	snprintf(file, sizeof(file), "%s/memory.soft_limit_in_bytes", cgroupdir);
	write_file(file, "%d", 299 << 20);
	snprintf(file, sizeof(file), "%s/memory.limit_in_bytes", cgroupdir);
	write_file(file, "%d", 300 << 20);
	snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/net/syz%llu", procid);
	if (mkdir(cgroupdir, 0777)) {
		debug("mkdir(%s) failed: %d\n", cgroupdir, errno);
	}
	snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
	write_file(file, "%d", pid);
}

static void setup_cgroups_test()
{
#if SYZ_EXECUTOR
	if (!flag_cgroups)
		return;
#endif
	char cgroupdir[64];
	snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/unified/syz%llu", procid);
	if (symlink(cgroupdir, "./cgroup")) {
		debug("symlink(%s, ./cgroup) failed: %d\n", cgroupdir, errno);
	}
	snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/cpu/syz%llu", procid);
	if (symlink(cgroupdir, "./cgroup.cpu")) {
		debug("symlink(%s, ./cgroup.cpu) failed: %d\n", cgroupdir, errno);
	}
	snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/net/syz%llu", procid);
	if (symlink(cgroupdir, "./cgroup.net")) {
		debug("symlink(%s, ./cgroup.net) failed: %d\n", cgroupdir, errno);
	}
}
#endif

#if SYZ_EXECUTOR || SYZ_SANDBOX_NAMESPACE
static void initialize_cgroups()
{
#if SYZ_EXECUTOR
	if (!flag_cgroups)
		return;
#endif
	if (mkdir("./syz-tmp/newroot/syzcgroup", 0700))
		fail("mkdir failed");
	if (mkdir("./syz-tmp/newroot/syzcgroup/unified", 0700))
		fail("mkdir failed");
	if (mkdir("./syz-tmp/newroot/syzcgroup/cpu", 0700))
		fail("mkdir failed");
	if (mkdir("./syz-tmp/newroot/syzcgroup/net", 0700))
		fail("mkdir failed");
	unsigned bind_mount_flags = MS_BIND | MS_REC | MS_PRIVATE;
	if (mount("/syzcgroup/unified", "./syz-tmp/newroot/syzcgroup/unified", NULL, bind_mount_flags, NULL)) {
		debug("mount(cgroup2, MS_BIND) failed: %d\n", errno);
	}
	if (mount("/syzcgroup/cpu", "./syz-tmp/newroot/syzcgroup/cpu", NULL, bind_mount_flags, NULL)) {
		debug("mount(cgroup/cpu, MS_BIND) failed: %d\n", errno);
	}
	if (mount("/syzcgroup/net", "./syz-tmp/newroot/syzcgroup/net", NULL, bind_mount_flags, NULL)) {
		debug("mount(cgroup/net, MS_BIND) failed: %d\n", errno);
	}
}
#endif
#endif

#if SYZ_EXECUTOR || SYZ_SANDBOX_NONE || SYZ_SANDBOX_SETUID || SYZ_SANDBOX_NAMESPACE || SYZ_SANDBOX_ANDROID
#include <errno.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <unistd.h>

static void setup_common()
{
	if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
		debug("mount(fusectl) failed: %d\n", errno);
	}
}

static void setup_binderfs()
{
	if (mkdir("/dev/binderfs", 0777)) {
		debug("mkdir(/dev/binderfs) failed: %d\n", errno);
	}

	if (mount("binder", "/dev/binderfs", "binder", 0, NULL)) {
		debug("mount of binder at /dev/binderfs failed: %d\n", errno);
	}
#if !SYZ_EXECUTOR && !SYZ_USE_TMP_DIR
	if (symlink("/dev/binderfs", "./binderfs")) {
		debug("symlink(/dev/binderfs, ./binderfs) failed: %d\n", errno);
	}
#endif
}

#include <sched.h>
#include <sys/prctl.h>
#include <sys/resource.h>
#include <sys/time.h>
#include <sys/wait.h>

static void loop();

static void sandbox_common()
{
	prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
	setsid();

#if SYZ_EXECUTOR || __NR_syz_init_net_socket || SYZ_DEVLINK_PCI
	int netns = open("/proc/self/ns/net", O_RDONLY);
	if (netns == -1)
		fail("open(/proc/self/ns/net) failed");
	if (dup2(netns, kInitNetNsFd) < 0)
		fail("dup2(netns, kInitNetNsFd) failed");
	close(netns);
#endif

	struct rlimit rlim;
#if SYZ_EXECUTOR
	rlim.rlim_cur = rlim.rlim_max = (200 << 20) +
					(kMaxThreads * kCoverSize + kExtraCoverSize) * sizeof(void*);
#else
	rlim.rlim_cur = rlim.rlim_max = (200 << 20);
#endif
	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)) {
		debug("unshare(CLONE_NEWNS): %d\n", errno);
	}
	if (mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, NULL)) {
		debug("mount(\"/\", MS_REC | MS_PRIVATE): %d\n", errno);
	}
	if (unshare(CLONE_NEWIPC)) {
		debug("unshare(CLONE_NEWIPC): %d\n", errno);
	}
	if (unshare(0x02000000)) {
		debug("unshare(CLONE_NEWCGROUP): %d\n", errno);
	}
	if (unshare(CLONE_NEWUTS)) {
		debug("unshare(CLONE_NEWUTS): %d\n", errno);
	}
	if (unshare(CLONE_SYSVSEM)) {
		debug("unshare(CLONE_SYSVSEM): %d\n", errno);
	}
	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);
}
#endif

#if SYZ_EXECUTOR || SYZ_SANDBOX_NONE || SYZ_SANDBOX_SETUID || SYZ_SANDBOX_NAMESPACE
static int wait_for_loop(int pid)
{
	if (pid < 0)
		fail("sandbox fork failed");
	debug("spawned loop pid %d\n", pid);
	int status = 0;
	while (waitpid(-1, &status, __WALL) != pid) {
	}
	return WEXITSTATUS(status);
}
#endif

#if SYZ_EXECUTOR || SYZ_SANDBOX_NONE || SYZ_SANDBOX_NAMESPACE || SYZ_SANDBOX_ANDROID
#include <linux/capability.h>

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))
		fail("capget failed");
	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))
		fail("capset failed");
}
#endif

#if SYZ_EXECUTOR || SYZ_SANDBOX_NONE
#include <sched.h>
#include <sys/types.h>

static int do_sandbox_none(void)
{
	if (unshare(CLONE_NEWPID)) {
		debug("unshare(CLONE_NEWPID): %d\n", errno);
	}
	int pid = fork();
	if (pid != 0)
		return wait_for_loop(pid);

	setup_common();
#if SYZ_EXECUTOR || SYZ_VHCI_INJECTION
	initialize_vhci();
#endif
	sandbox_common();
	drop_caps();
#if SYZ_EXECUTOR || SYZ_NET_DEVICES
	initialize_netdevices_init();
#endif
	if (unshare(CLONE_NEWNET)) {
		debug("unshare(CLONE_NEWNET): %d\n", errno);
	}
	write_file("/proc/sys/net/ipv4/ping_group_range", "0 65535");
#if SYZ_EXECUTOR || SYZ_DEVLINK_PCI
	initialize_devlink_pci();
#endif
#if SYZ_EXECUTOR || SYZ_NET_INJECTION
	initialize_tun();
#endif
#if SYZ_EXECUTOR || SYZ_NET_DEVICES
	initialize_netdevices();
#endif
#if SYZ_EXECUTOR || SYZ_WIFI
	initialize_wifi_devices();
#endif
	setup_binderfs();
	loop();
	doexit(1);
}
#endif

#if SYZ_EXECUTOR || SYZ_SANDBOX_SETUID
#include <grp.h>
#include <sched.h>
#include <sys/prctl.h>

#define SYZ_HAVE_SANDBOX_SETUID 1
static int do_sandbox_setuid(void)
{
	if (unshare(CLONE_NEWPID)) {
		debug("unshare(CLONE_NEWPID): %d\n", errno);
	}
	int pid = fork();
	if (pid != 0)
		return wait_for_loop(pid);

	setup_common();
#if SYZ_EXECUTOR || SYZ_VHCI_INJECTION
	initialize_vhci();
#endif
	sandbox_common();
#if SYZ_EXECUTOR || SYZ_NET_DEVICES
	initialize_netdevices_init();
#endif
	if (unshare(CLONE_NEWNET)) {
		debug("unshare(CLONE_NEWNET): %d\n", errno);
	}
#if SYZ_EXECUTOR || SYZ_DEVLINK_PCI
	initialize_devlink_pci();
#endif
#if SYZ_EXECUTOR || SYZ_NET_INJECTION
	initialize_tun();
#endif
#if SYZ_EXECUTOR || SYZ_NET_DEVICES
	initialize_netdevices();
#endif
#if SYZ_EXECUTOR || SYZ_WIFI
	initialize_wifi_devices();
#endif
	setup_binderfs();

	const int nobody = 65534;
	if (setgroups(0, NULL))
		fail("failed to setgroups");
	if (syscall(SYS_setresgid, nobody, nobody, nobody))
		fail("failed to setresgid");
	if (syscall(SYS_setresuid, nobody, nobody, nobody))
		fail("failed to setresuid");
	prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
	prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);

	loop();
	doexit(1);
}
#endif

#if SYZ_EXECUTOR || SYZ_SANDBOX_NAMESPACE
#include <sched.h>
#include <sys/mman.h>
#include <sys/mount.h>

static int real_uid;
static int real_gid;
__attribute__((aligned(64 << 10))) static char sandbox_stack[1 << 20];

static int namespace_sandbox_proc(void* arg)
{
	sandbox_common();
	write_file("/proc/self/setgroups", "deny");
	if (!write_file("/proc/self/uid_map", "0 %d 1\n", real_uid))
		fail("write of /proc/self/uid_map failed");
	if (!write_file("/proc/self/gid_map", "0 %d 1\n", real_gid))
		fail("write of /proc/self/gid_map failed");

#if SYZ_EXECUTOR || SYZ_NET_DEVICES
	initialize_netdevices_init();
#endif
	if (unshare(CLONE_NEWNET))
		fail("unshare(CLONE_NEWNET)");
	write_file("/proc/sys/net/ipv4/ping_group_range", "0 65535");
#if SYZ_EXECUTOR || SYZ_DEVLINK_PCI
	initialize_devlink_pci();
#endif
#if SYZ_EXECUTOR || SYZ_NET_INJECTION
	initialize_tun();
#endif
#if SYZ_EXECUTOR || SYZ_NET_DEVICES
	initialize_netdevices();
#endif
#if SYZ_EXECUTOR || SYZ_WIFI
	initialize_wifi_devices();
#endif

	if (mkdir("./syz-tmp", 0777))
		fail("mkdir(syz-tmp) failed");
	if (mount("", "./syz-tmp", "tmpfs", 0, NULL))
		fail("mount(tmpfs) failed");
	if (mkdir("./syz-tmp/newroot", 0777))
		fail("mkdir failed");
	if (mkdir("./syz-tmp/newroot/dev", 0700))
		fail("mkdir failed");
	unsigned bind_mount_flags = MS_BIND | MS_REC | MS_PRIVATE;
	if (mount("/dev", "./syz-tmp/newroot/dev", NULL, bind_mount_flags, NULL))
		fail("mount(dev) failed");
	if (mkdir("./syz-tmp/newroot/proc", 0700))
		fail("mkdir failed");
	if (mount(NULL, "./syz-tmp/newroot/proc", "proc", 0, NULL))
		fail("mount(proc) failed");
	if (mkdir("./syz-tmp/newroot/selinux", 0700))
		fail("mkdir failed");
	const char* selinux_path = "./syz-tmp/newroot/selinux";
	if (mount("/selinux", selinux_path, NULL, bind_mount_flags, NULL)) {
		if (errno != ENOENT)
			fail("mount(/selinux) failed");
		if (mount("/sys/fs/selinux", selinux_path, NULL, bind_mount_flags, NULL) && errno != ENOENT)
			fail("mount(/sys/fs/selinux) failed");
	}
	if (mkdir("./syz-tmp/newroot/sys", 0700))
		fail("mkdir failed");
	if (mount("/sys", "./syz-tmp/newroot/sys", 0, bind_mount_flags, NULL))
		fail("mount(sysfs) failed");
#if SYZ_EXECUTOR || SYZ_CGROUPS
	initialize_cgroups();
#endif
	if (mkdir("./syz-tmp/pivot", 0777))
		fail("mkdir failed");
	if (syscall(SYS_pivot_root, "./syz-tmp", "./syz-tmp/pivot")) {
		debug("pivot_root failed\n");
		if (chdir("./syz-tmp"))
			fail("chdir failed");
	} else {
		debug("pivot_root OK\n");
		if (chdir("/"))
			fail("chdir failed");
		if (umount2("./pivot", MNT_DETACH))
			fail("umount failed");
	}
	if (chroot("./newroot"))
		fail("chroot failed");
	if (chdir("/"))
		fail("chdir failed");
	setup_binderfs();
	drop_caps();

	loop();
	doexit(1);
}

#define SYZ_HAVE_SANDBOX_NAMESPACE 1
static int do_sandbox_namespace(void)
{
	setup_common();
#if SYZ_EXECUTOR || SYZ_VHCI_INJECTION
	initialize_vhci();
#endif
	real_uid = getuid();
	real_gid = getgid();
	mprotect(sandbox_stack, 4096, PROT_NONE);
	int pid = clone(namespace_sandbox_proc, &sandbox_stack[sizeof(sandbox_stack) - 64],
			CLONE_NEWUSER | CLONE_NEWPID, 0);
	return wait_for_loop(pid);
}
#endif

#if SYZ_EXECUTOR || SYZ_SANDBOX_ANDROID
#if GOARCH_arm || GOARCH_arm64 || GOARCH_386 || GOARCH_amd64
#include <assert.h>
#include <errno.h>
#include <linux/audit.h>
#include <linux/filter.h>
#include <linux/seccomp.h>
#include <stddef.h>
#include <stdlib.h>
#include <sys/prctl.h>
#include <sys/syscall.h>
#if GOARCH_arm64
#define PRIMARY_ARCH AUDIT_ARCH_AARCH64

const struct sock_filter arm64_app_filter[] = {
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 0, 0, 68),
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 98, 66, 0),
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 29, 65, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 163, 33, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 101, 17, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 52, 9, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 41, 5, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 30, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 19, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 18, 59, 58),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 29, 58, 57),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 40, 57, 56),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 43, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 42, 55, 54),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 51, 54, 53),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 90, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 59, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 58, 51, 50),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 89, 50, 49),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 99, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 98, 48, 47),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 100, 47, 46),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 147, 7, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 113, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 107, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 104, 43, 42),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 112, 42, 41),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 117, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 116, 40, 39),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 142, 39, 38),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 153, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 150, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 149, 36, 35),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 151, 35, 34),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 160, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 159, 33, 32),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 161, 32, 31),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 267, 15, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 220, 7, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 198, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 172, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 170, 27, 26),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 180, 26, 25),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 203, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 202, 24, 23),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 217, 23, 22),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 240, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 226, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 224, 20, 19),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 234, 19, 18),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 260, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 244, 17, 16),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 262, 16, 15),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 434, 7, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 291, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 274, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 272, 12, 11),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 288, 11, 10),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 424, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 292, 9, 8),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 425, 8, 7),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 438, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 436, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 435, 5, 4),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 437, 4, 3),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 440, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 439, 2, 1),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 441, 1, 0),
BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
};

#define arm64_app_filter_size (sizeof(arm64_app_filter) / sizeof(struct sock_filter))

static const struct sock_filter* primary_app_filter = arm64_app_filter;
static const size_t primary_app_filter_size = arm64_app_filter_size;

const struct sock_filter arm64_system_filter[] = {
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 0, 0, 46),
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 98, 44, 0),
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 29, 43, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 226, 21, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 101, 11, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 43, 5, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 30, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 19, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 18, 38, 37),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 29, 37, 36),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 42, 36, 35),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 99, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 59, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 58, 33, 32),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 98, 32, 31),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 100, 31, 30),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 203, 5, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 198, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 105, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 104, 27, 26),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 180, 26, 25),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 202, 25, 24),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 220, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 217, 23, 22),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 224, 22, 21),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 424, 11, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 266, 5, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 260, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 240, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 234, 17, 16),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 244, 16, 15),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 262, 15, 14),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 291, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 274, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 272, 12, 11),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 288, 11, 10),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 292, 10, 9),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 438, 5, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 436, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 434, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 425, 6, 5),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 435, 5, 4),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 437, 4, 3),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 440, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 439, 2, 1),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 441, 1, 0),
BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
};

#define arm64_system_filter_size (sizeof(arm64_system_filter) / sizeof(struct sock_filter))

static const struct sock_filter* system_filter = arm64_system_filter;
static const size_t system_filter_size = arm64_system_filter_size;
#define kFilterMaxSize (arm64_app_filter_size + 3 + 1 + 4 + 2)

#elif GOARCH_arm
#define PRIMARY_ARCH AUDIT_ARCH_ARM

const struct sock_filter arm_app_filter[] = {
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 0, 0, 146),
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 240, 144, 0),
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 54, 143, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 199, 71, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 85, 35, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 45, 17, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 26, 9, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 19, 5, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 10, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 8, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 7, 136, 135),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 9, 135, 134),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 13, 134, 133),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 24, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 21, 132, 131),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 25, 131, 130),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 36, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 33, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 27, 128, 127),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 34, 127, 126),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 41, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 40, 125, 124),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 44, 124, 123),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 63, 9, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 57, 5, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 55, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 52, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 46, 119, 118),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 53, 118, 117),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 56, 117, 116),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 60, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 58, 115, 114),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 61, 114, 113),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 75, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 66, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 65, 111, 110),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 68, 110, 109),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 77, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 76, 108, 107),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 79, 107, 106),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 125, 17, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 114, 9, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 96, 5, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 94, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 91, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 86, 101, 100),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 93, 100, 99),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 95, 99, 98),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 104, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 98, 97, 96),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 107, 96, 95),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 118, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 116, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 115, 93, 92),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 117, 92, 91),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 122, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 121, 90, 89),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 123, 89, 88),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 168, 9, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 140, 5, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 136, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 131, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 126, 84, 83),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 134, 83, 82),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 137, 82, 81),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 150, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 149, 80, 79),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 164, 79, 78),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 183, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 172, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 169, 76, 75),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 182, 75, 74),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 190, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 188, 73, 72),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 198, 72, 71),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 327, 35, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 256, 17, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 219, 9, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 211, 5, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 207, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 205, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 203, 65, 64),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 206, 64, 63),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 210, 63, 62),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 217, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 212, 61, 60),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 218, 60, 59),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 241, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 224, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 222, 57, 56),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 240, 56, 55),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 250, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 249, 54, 53),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 254, 53, 52),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 290, 9, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 280, 5, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 270, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 263, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 262, 48, 47),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 269, 47, 46),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 271, 46, 45),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 286, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 285, 44, 43),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 289, 43, 42),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 316, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 292, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 291, 40, 39),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 298, 39, 38),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 322, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 319, 37, 36),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 326, 36, 35),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 403, 17, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 369, 9, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 348, 5, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 345, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 340, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 339, 30, 29),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 344, 29, 28),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 347, 28, 27),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 350, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 349, 26, 25),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 367, 25, 24),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 380, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 373, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 370, 22, 21),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 378, 21, 20),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 397, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 394, 19, 18),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 398, 18, 17),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 438, 9, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 434, 5, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 420, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 417, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 415, 13, 12),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 418, 12, 11),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 425, 11, 10),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 436, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 435, 9, 8),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 437, 8, 7),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 983042, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 440, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 439, 5, 4),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 441, 4, 3),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 983045, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 983043, 2, 1),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 983046, 1, 0),
BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
};

#define arm_app_filter_size (sizeof(arm_app_filter) / sizeof(struct sock_filter))

static const struct sock_filter* primary_app_filter = arm_app_filter;
static const size_t primary_app_filter_size = arm_app_filter_size;

const struct sock_filter arm_system_filter[] = {
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 0, 0, 142),
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 240, 140, 0),
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 54, 139, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 197, 69, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 91, 35, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 51, 17, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 36, 9, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 19, 5, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 11, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 3, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 2, 132, 131),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 7, 131, 130),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 13, 130, 129),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 26, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 22, 128, 127),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 27, 127, 126),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 43, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 41, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 38, 124, 123),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 42, 123, 122),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 45, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 44, 121, 120),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 46, 120, 119),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 74, 9, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 64, 5, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 60, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 57, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 53, 115, 114),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 58, 114, 113),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 62, 113, 112),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 66, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 65, 111, 110),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 68, 110, 109),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 85, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 77, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 76, 107, 106),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 80, 106, 105),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 88, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 86, 104, 103),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 89, 103, 102),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 131, 17, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 116, 9, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 103, 5, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 96, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 94, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 93, 97, 96),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 95, 96, 95),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 98, 95, 94),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 114, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 107, 93, 92),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 115, 92, 91),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 124, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 118, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 117, 89, 88),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 123, 88, 87),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 128, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 126, 86, 85),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 130, 85, 84),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 150, 7, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 138, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 136, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 134, 81, 80),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 137, 80, 79),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 143, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 141, 78, 77),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 149, 77, 76),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 183, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 172, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 164, 74, 73),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 182, 73, 72),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 190, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 188, 71, 70),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 196, 70, 69),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 345, 35, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 270, 17, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 224, 9, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 217, 5, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 213, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 199, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 198, 63, 62),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 212, 62, 61),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 215, 61, 60),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 219, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 218, 59, 58),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 222, 58, 57),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 251, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 241, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 240, 55, 54),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 249, 54, 53),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 256, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 252, 52, 51),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 269, 51, 50),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 317, 9, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 290, 5, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 286, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 280, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 271, 46, 45),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 285, 45, 44),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 289, 44, 43),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 292, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 291, 42, 41),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 298, 41, 40),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 327, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 322, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 319, 38, 37),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 326, 37, 36),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 340, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 339, 35, 34),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 344, 34, 33),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 417, 17, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 372, 9, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 352, 5, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 350, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 348, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 347, 28, 27),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 349, 27, 26),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 351, 26, 25),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 369, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 367, 24, 23),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 370, 23, 22),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 397, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 380, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 378, 20, 19),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 394, 19, 18),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 403, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 398, 17, 16),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 415, 16, 15),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 438, 7, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 434, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 420, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 418, 12, 11),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 425, 11, 10),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 436, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 435, 9, 8),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 437, 8, 7),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 983042, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 440, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 439, 5, 4),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 441, 4, 3),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 983045, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 983043, 2, 1),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 983046, 1, 0),
BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
};

#define arm_system_filter_size (sizeof(arm_system_filter) / sizeof(struct sock_filter))

static const struct sock_filter* system_filter = arm_system_filter;
static const size_t system_filter_size = arm_system_filter_size;
#define kFilterMaxSize (arm_app_filter_size + 3 + 1 + 4 + 2)

#elif GOARCH_amd64
#define PRIMARY_ARCH AUDIT_ARCH_X86_64

const struct sock_filter x86_64_app_filter[] = {
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 0, 0, 114),
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 202, 112, 0),
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 16, 111, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 166, 55, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 104, 27, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 44, 13, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 32, 7, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 17, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 8, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 6, 105, 104),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 16, 104, 103),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 24, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 21, 102, 101),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 29, 101, 100),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 38, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 35, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 33, 98, 97),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 37, 97, 96),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 43, 96, 95),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 91, 7, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 72, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 58, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 57, 92, 91),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 64, 91, 90),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 89, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 82, 89, 88),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 90, 88, 87),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 95, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 93, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 92, 85, 84),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 94, 84, 83),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 103, 83, 82),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 135, 13, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 117, 7, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 112, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 107, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 105, 78, 77),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 111, 77, 76),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 115, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 113, 75, 74),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 116, 74, 73),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 124, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 120, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 119, 71, 70),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 122, 70, 69),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 132, 69, 68),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 157, 7, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 140, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 137, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 136, 65, 64),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 139, 64, 63),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 155, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 153, 62, 61),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 156, 61, 60),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 162, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 160, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 159, 58, 57),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 161, 57, 56),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 163, 56, 55),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 275, 27, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 228, 13, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 206, 7, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 186, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 179, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 167, 50, 49),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 180, 49, 48),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 203, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 201, 47, 46),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 205, 46, 45),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 221, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 217, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 211, 43, 42),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 220, 42, 41),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 227, 41, 40),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 254, 7, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 247, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 233, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 232, 37, 36),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 235, 36, 35),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 251, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 248, 34, 33),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 253, 33, 32),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 262, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 257, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 256, 30, 29),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 261, 29, 28),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 274, 28, 27),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 321, 13, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 302, 7, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 283, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 280, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 279, 23, 22),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 282, 22, 21),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 285, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 284, 20, 19),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 300, 19, 18),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 314, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 306, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 303, 16, 15),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 312, 15, 14),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 320, 14, 13),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 436, 7, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 424, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 332, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 329, 10, 9),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 333, 9, 8),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 434, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 425, 7, 6),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 435, 6, 5),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 440, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 438, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 437, 3, 2),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 439, 2, 1),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 441, 1, 0),
BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
};

#define x86_64_app_filter_size (sizeof(x86_64_app_filter) / sizeof(struct sock_filter))

static const struct sock_filter* primary_app_filter = x86_64_app_filter;
static const size_t primary_app_filter_size = x86_64_app_filter_size;

const struct sock_filter x86_64_system_filter[] = {
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 0, 0, 100),
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 202, 98, 0),
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 16, 97, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 203, 49, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 93, 25, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 44, 13, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 32, 7, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 17, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 8, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 6, 91, 90),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 16, 90, 89),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 24, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 21, 88, 87),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 29, 87, 86),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 38, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 35, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 33, 84, 83),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 37, 83, 82),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 43, 82, 81),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 79, 5, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 72, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 58, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 57, 78, 77),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 64, 77, 76),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 78, 76, 75),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 91, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 89, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 82, 73, 72),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 90, 72, 71),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 92, 71, 70),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 155, 11, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 135, 5, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 112, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 95, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 94, 66, 65),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 111, 65, 64),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 132, 64, 63),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 140, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 137, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 136, 61, 60),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 139, 60, 59),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 153, 59, 58),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 175, 5, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 169, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 157, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 156, 55, 54),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 167, 54, 53),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 172, 53, 52),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 186, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 179, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 177, 50, 49),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 180, 49, 48),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 201, 48, 47),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 283, 23, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 251, 11, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 221, 5, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 217, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 206, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 205, 42, 41),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 211, 41, 40),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 220, 40, 39),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 247, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 233, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 232, 37, 36),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 235, 36, 35),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 248, 35, 34),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 262, 5, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 257, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 254, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 253, 31, 30),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 256, 30, 29),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 261, 29, 28),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 280, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 275, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 274, 26, 25),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 279, 25, 24),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 282, 24, 23),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 332, 11, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 305, 5, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 302, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 285, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 284, 19, 18),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 300, 18, 17),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 303, 17, 16),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 321, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 314, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 312, 14, 13),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 320, 13, 12),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 329, 12, 11),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 436, 5, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 434, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 424, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 333, 8, 7),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 425, 7, 6),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 435, 6, 5),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 440, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 438, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 437, 3, 2),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 439, 2, 1),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 441, 1, 0),
BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
};

#define x86_64_system_filter_size (sizeof(x86_64_system_filter) / sizeof(struct sock_filter))

static const struct sock_filter* system_filter = x86_64_system_filter;
static const size_t system_filter_size = x86_64_system_filter_size;
#define kFilterMaxSize (x86_64_app_filter_size + 3 + 1 + 4 + 2)

#elif GOARCH_386
#define PRIMARY_ARCH AUDIT_ARCH_I386

const struct sock_filter x86_app_filter[] = {
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 0, 0, 140),
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 240, 138, 0),
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 54, 137, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 183, 69, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 85, 35, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 45, 17, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 26, 9, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 19, 5, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 10, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 8, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 7, 130, 129),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 9, 129, 128),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 13, 128, 127),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 24, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 21, 126, 125),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 25, 125, 124),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 36, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 33, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 27, 122, 121),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 34, 121, 120),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 41, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 40, 119, 118),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 44, 118, 117),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 63, 9, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 57, 5, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 55, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 52, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 46, 113, 112),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 53, 112, 111),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 56, 111, 110),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 60, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 58, 109, 108),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 61, 108, 107),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 75, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 66, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 65, 105, 104),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 68, 104, 103),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 77, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 76, 102, 101),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 79, 101, 100),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 122, 17, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 104, 9, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 96, 5, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 94, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 90, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 86, 95, 94),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 93, 94, 93),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 95, 93, 92),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 102, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 98, 91, 90),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 103, 90, 89),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 116, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 114, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 107, 87, 86),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 115, 86, 85),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 118, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 117, 84, 83),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 121, 83, 82),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 140, 7, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 131, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 125, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 123, 79, 78),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 126, 78, 77),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 136, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 134, 76, 75),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 137, 75, 74),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 168, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 150, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 149, 72, 71),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 164, 71, 70),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 172, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 169, 69, 68),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 182, 68, 67),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 300, 33, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 245, 17, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 211, 9, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 205, 5, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 199, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 190, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 188, 61, 60),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 198, 60, 59),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 203, 59, 58),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 207, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 206, 57, 56),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 210, 56, 55),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 224, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 218, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 212, 53, 52),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 222, 52, 51),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 241, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 240, 50, 49),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 244, 49, 48),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 272, 7, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 254, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 252, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 250, 45, 44),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 253, 44, 43),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 265, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 264, 42, 41),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 271, 41, 40),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 291, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 284, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 273, 38, 37),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 285, 37, 36),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 295, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 294, 35, 34),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 299, 34, 33),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 383, 17, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 344, 9, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 322, 5, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 318, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 313, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 312, 28, 27),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 317, 27, 26),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 321, 26, 25),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 340, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 337, 24, 23),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 341, 23, 22),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 351, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 346, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 345, 20, 19),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 349, 19, 18),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 374, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 359, 17, 16),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 380, 16, 15),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 434, 7, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 417, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 403, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 384, 12, 11),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 415, 11, 10),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 420, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 418, 9, 8),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 425, 8, 7),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 438, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 436, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 435, 5, 4),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 437, 4, 3),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 440, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 439, 2, 1),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 441, 1, 0),
BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
};

#define x86_app_filter_size (sizeof(x86_app_filter) / sizeof(struct sock_filter))

static const struct sock_filter* primary_app_filter = x86_app_filter;
static const size_t primary_app_filter_size = x86_app_filter_size;

const struct sock_filter x86_system_filter[] = {
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 0, 0, 136),
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 240, 134, 0),
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 54, 133, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 190, 67, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 88, 33, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 51, 17, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 36, 9, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 19, 5, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 11, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 3, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 2, 126, 125),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 7, 125, 124),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 13, 124, 123),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 26, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 22, 122, 121),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 27, 121, 120),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 43, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 41, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 38, 118, 117),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 42, 117, 116),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 45, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 44, 115, 114),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 46, 114, 113),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 66, 7, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 60, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 57, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 53, 110, 109),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 58, 109, 108),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 64, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 62, 107, 106),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 65, 106, 105),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 77, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 74, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 68, 103, 102),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 76, 102, 101),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 85, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 80, 100, 99),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 86, 99, 98),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 128, 17, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 114, 9, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 96, 5, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 94, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 91, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 89, 93, 92),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 93, 92, 91),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 95, 91, 90),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 102, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 98, 89, 88),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 107, 88, 87),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 118, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 116, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 115, 85, 84),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 117, 84, 83),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 124, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 123, 82, 81),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 126, 81, 80),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 143, 7, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 136, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 131, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 130, 77, 76),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 134, 76, 75),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 138, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 137, 74, 73),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 141, 73, 72),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 172, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 150, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 149, 70, 69),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 164, 69, 68),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 183, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 182, 67, 66),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 188, 66, 65),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 318, 33, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 255, 17, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 224, 9, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 213, 5, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 199, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 197, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 196, 59, 58),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 198, 58, 57),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 212, 57, 56),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 218, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 215, 55, 54),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 222, 54, 53),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 245, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 241, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 240, 51, 50),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 244, 50, 49),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 252, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 250, 48, 47),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 253, 47, 46),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 292, 7, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 272, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 258, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 256, 43, 42),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 271, 42, 41),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 284, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 273, 40, 39),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 285, 39, 38),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 300, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 295, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 294, 36, 35),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 299, 35, 34),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 313, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 312, 33, 32),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 317, 32, 31),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 383, 15, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 343, 7, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 324, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 322, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 321, 27, 26),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 323, 26, 25),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 340, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 337, 24, 23),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 341, 23, 22),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 351, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 346, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 345, 20, 19),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 349, 19, 18),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 374, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 359, 17, 16),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 380, 16, 15),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 434, 7, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 417, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 403, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 384, 12, 11),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 415, 11, 10),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 420, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 418, 9, 8),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 425, 8, 7),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 438, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 436, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 435, 5, 4),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 437, 4, 3),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 440, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 439, 2, 1),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 441, 1, 0),
BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
};

#define x86_system_filter_size (sizeof(x86_system_filter) / sizeof(struct sock_filter))

static const struct sock_filter* system_filter = x86_system_filter;
static const size_t system_filter_size = x86_system_filter_size;
#define kFilterMaxSize (x86_app_filter_size + 3 + 1 + 4 + 2)

#else
#error No architecture was defined!
#endif

#define syscall_nr (offsetof(struct seccomp_data, nr))
#define arch_nr (offsetof(struct seccomp_data, arch))

typedef struct Filter_t {
	struct sock_filter data[kFilterMaxSize];
	size_t count;
} Filter;

static void push_back(Filter* filter_array, struct sock_filter filter)
{
	if (filter_array->count == kFilterMaxSize)
		failmsg("can't add another syscall to seccomp filter", "count=%zu", filter_array->count);
	filter_array->data[filter_array->count++] = filter;
}

static void Disallow(Filter* f)
{
	struct sock_filter filter = BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_TRAP);
	push_back(f, filter);
}

static void ExamineSyscall(Filter* f)
{
	struct sock_filter filter = BPF_STMT(BPF_LD | BPF_W | BPF_ABS, syscall_nr);
	push_back(f, filter);
}

static void ValidateArchitecture(Filter* f)
{
	struct sock_filter filter1 = BPF_STMT(BPF_LD | BPF_W | BPF_ABS, arch_nr);
	struct sock_filter filter2 = BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, PRIMARY_ARCH, 1, 0);
	push_back(f, filter1);
	push_back(f, filter2);
	Disallow(f);
}
static void install_filter(const Filter* f)
{
	struct sock_fprog prog = {
	    (unsigned short)f->count,
	    (struct sock_filter*)&f->data[0],
	};
	if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) < 0)
		failmsg("could not set seccomp filter", "size=%zu", f->count);
}
static void set_seccomp_filter(const struct sock_filter* filter, size_t size)
{
	Filter f;
	f.count = 0;
	ValidateArchitecture(&f);
	ExamineSyscall(&f);

	for (size_t i = 0; i < size; ++i)
		push_back(&f, filter[i]);
	Disallow(&f);
	install_filter(&f);
}

enum {
	SCFS_RestrictedApp,
	SCFS_SystemAccount
};

static void set_app_seccomp_filter(int account)
{
	if (account == SCFS_SystemAccount) {
		set_seccomp_filter(system_filter, system_filter_size);
	} else {
		set_seccomp_filter(primary_app_filter, primary_app_filter_size);
	}
}


#if GOARCH_amd64 || GOARCH_386
inline int mkdir(const char* path, mode_t mode)
{
	return mkdirat(AT_FDCWD, path, mode);
}

inline int rmdir(const char* path)
{
	return unlinkat(AT_FDCWD, path, AT_REMOVEDIR);
}

inline int symlink(const char* old_path, const char* new_path)
{
	return symlinkat(old_path, AT_FDCWD, new_path);
}
#endif

#endif
#include <fcntl.h>
#include <grp.h>
#include <sys/xattr.h>

#define AID_NET_BT_ADMIN 3001
#define AID_NET_BT 3002
#define AID_INET 3003
#define AID_EVERYBODY 9997
#define AID_APP 10000

#define UNTRUSTED_APP_UID (AID_APP + 999)
#define UNTRUSTED_APP_GID (AID_APP + 999)

#define SYSTEM_UID 1000
#define SYSTEM_GID 1000

const char* const SELINUX_CONTEXT_UNTRUSTED_APP = "u:r:untrusted_app:s0:c512,c768";
const char* const SELINUX_LABEL_APP_DATA_FILE = "u:object_r:app_data_file:s0:c512,c768";
const char* const SELINUX_CONTEXT_FILE = "/proc/thread-self/attr/current";
const char* const SELINUX_XATTR_NAME = "security.selinux";

const gid_t UNTRUSTED_APP_GROUPS[] = {UNTRUSTED_APP_GID, AID_NET_BT_ADMIN, AID_NET_BT, AID_INET, AID_EVERYBODY};
const size_t UNTRUSTED_APP_NUM_GROUPS = sizeof(UNTRUSTED_APP_GROUPS) / sizeof(UNTRUSTED_APP_GROUPS[0]);

const gid_t SYSTEM_GROUPS[] = {SYSTEM_GID, AID_NET_BT_ADMIN, AID_NET_BT, AID_INET, AID_EVERYBODY};
const size_t SYSTEM_NUM_GROUPS = sizeof(SYSTEM_GROUPS) / sizeof(SYSTEM_GROUPS[0]);
static void getcon(char* context, size_t context_size)
{
	int fd = open(SELINUX_CONTEXT_FILE, O_RDONLY);
	if (fd < 0)
		fail("getcon: couldn't open context file");

	ssize_t nread = read(fd, context, context_size);

	close(fd);

	if (nread <= 0)
		fail("getcon: failed to read context file");
	if (context[nread - 1] == '\n')
		context[nread - 1] = '\0';
}
static void setcon(const char* context)
{
	char new_context[512];
	int fd = open(SELINUX_CONTEXT_FILE, O_WRONLY);

	if (fd < 0)
		fail("setcon: could not open context file");

	ssize_t bytes_written = write(fd, context, strlen(context));
	close(fd);

	if (bytes_written != (ssize_t)strlen(context))
		failmsg("setcon: could not write entire context", "wrote=%zi, expected=%zu", bytes_written, strlen(context));
	getcon(new_context, sizeof(new_context));

	if (strcmp(context, new_context) != 0)
		failmsg("setcon: failed to change", "want=%s, context=%s", context, new_context);
}
static void setfilecon(const char* path, const char* context)
{
	char new_context[512];

	if (setxattr(path, SELINUX_XATTR_NAME, context, strlen(context) + 1, 0) != 0)
		fail("setfilecon: setxattr failed");
	if (getxattr(path, SELINUX_XATTR_NAME, new_context, sizeof(new_context)) < 0)
		fail("setfilecon: getxattr failed");
	if (strcmp(context, new_context) != 0)
		failmsg("setfilecon: could not set context", "want=%s, got=%s", context, new_context);
}

#define SYZ_HAVE_SANDBOX_ANDROID 1

static int do_sandbox_android(uint64 sandbox_arg)
{
	setup_common();
#if SYZ_EXECUTOR || SYZ_VHCI_INJECTION
	initialize_vhci();
#endif
	sandbox_common();
	drop_caps();

#if SYZ_EXECUTOR || SYZ_NET_DEVICES
	initialize_netdevices_init();
#endif
	if (unshare(CLONE_NEWNET)) {
		debug("unshare(CLONE_NEWNET): %d\n", errno);
	}
	write_file("/proc/sys/net/ipv4/ping_group_range", "0 65535");
#if SYZ_EXECUTOR || SYZ_DEVLINK_PCI
	initialize_devlink_pci();
#endif
#if SYZ_EXECUTOR || SYZ_NET_INJECTION
	initialize_tun();
#endif
#if SYZ_EXECUTOR || SYZ_NET_DEVICES
	initialize_netdevices();
#endif
	uid_t uid = UNTRUSTED_APP_UID;
	size_t num_groups = UNTRUSTED_APP_NUM_GROUPS;
	const gid_t* groups = UNTRUSTED_APP_GROUPS;
	gid_t gid = UNTRUSTED_APP_GID;
	debug("executor received sandbox_arg=%llu\n", sandbox_arg);
	if (sandbox_arg == 1) {
		uid = SYSTEM_UID;
		num_groups = SYSTEM_NUM_GROUPS;
		groups = SYSTEM_GROUPS;
		gid = SYSTEM_GID;

		debug("fuzzing under SYSTEM account\n");
	}
	if (chown(".", uid, uid) != 0)
		failmsg("do_sandbox_android: chmod failed", "sandbox_arg=%llu", sandbox_arg);

	if (setgroups(num_groups, groups) != 0)
		failmsg("do_sandbox_android: setgroups failed", "sandbox_arg=%llu", sandbox_arg);

	if (setresgid(gid, gid, gid) != 0)
		failmsg("do_sandbox_android: setresgid failed", "sandbox_arg=%llu", sandbox_arg);

	setup_binderfs();

#if GOARCH_arm || GOARCH_arm64 || GOARCH_386 || GOARCH_amd64
	int account = SCFS_RestrictedApp;
	if (sandbox_arg == 1)
		account = SCFS_SystemAccount;
	set_app_seccomp_filter(account);
#endif

	if (setresuid(uid, uid, uid) != 0)
		failmsg("do_sandbox_android: setresuid failed", "sandbox_arg=%llu", sandbox_arg);
	prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);

	setfilecon(".", SELINUX_LABEL_APP_DATA_FILE);
	if (uid == UNTRUSTED_APP_UID)
		setcon(SELINUX_CONTEXT_UNTRUSTED_APP);

	loop();
	doexit(1);
}
#endif

#if SYZ_EXECUTOR || SYZ_REPEAT && SYZ_USE_TMP_DIR
#include <dirent.h>
#include <errno.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mount.h>

#define FS_IOC_SETFLAGS _IOW('f', 2, long)
static void remove_dir(const char* dir)
{
	int iter = 0;
	DIR* dp = 0;
retry:
#if SYZ_EXECUTOR || !SYZ_SANDBOX_ANDROID
#if SYZ_EXECUTOR
	if (!flag_sandbox_android)
#endif
		while (umount2(dir, MNT_DETACH | UMOUNT_NOFOLLOW) == 0) {
			debug("umount(%s)\n", dir);
		}
#endif
	dp = opendir(dir);
	if (dp == NULL) {
		if (errno == EMFILE) {
			exitf("opendir(%s) failed due to NOFILE, exiting", dir);
		}
		exitf("opendir(%s) failed", dir);
	}
	struct dirent* ep = 0;
	while ((ep = readdir(dp))) {
		if (strcmp(ep->d_name, ".") == 0 || strcmp(ep->d_name, "..") == 0)
			continue;
		char filename[FILENAME_MAX];
		snprintf(filename, sizeof(filename), "%s/%s", dir, ep->d_name);
#if SYZ_EXECUTOR || !SYZ_SANDBOX_ANDROID
#if SYZ_EXECUTOR
		if (!flag_sandbox_android)
#endif
			while (umount2(filename, MNT_DETACH | UMOUNT_NOFOLLOW) == 0) {
				debug("umount(%s)\n", filename);
			}
#endif
		struct stat st;
		if (lstat(filename, &st))
			exitf("lstat(%s) failed", filename);
		if (S_ISDIR(st.st_mode)) {
			remove_dir(filename);
			continue;
		}
		int i;
		for (i = 0;; i++) {
			if (unlink(filename) == 0)
				break;
			if (errno == EPERM) {
				int fd = open(filename, O_RDONLY);
				if (fd != -1) {
					long flags = 0;
					if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == 0) {
						debug("reset FS_XFLAG_IMMUTABLE\n");
					}
					close(fd);
					continue;
				}
			}
			if (errno == EROFS) {
				debug("ignoring EROFS\n");
				break;
			}
			if (errno != EBUSY || i > 100)
				exitf("unlink(%s) failed", filename);
#if SYZ_EXECUTOR || !SYZ_SANDBOX_ANDROID
#if SYZ_EXECUTOR
			if (!flag_sandbox_android) {
#endif
				debug("umount(%s)\n", filename);
				if (umount2(filename, MNT_DETACH | UMOUNT_NOFOLLOW))
					exitf("umount(%s) failed", filename);
#if SYZ_EXECUTOR
			}
#endif
#endif
		}
	}
	closedir(dp);
	for (int i = 0;; i++) {
		if (rmdir(dir) == 0)
			break;
		if (i < 100) {
			if (errno == EPERM) {
				int fd = open(dir, O_RDONLY);
				if (fd != -1) {
					long flags = 0;
					if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == 0) {
						debug("reset FS_XFLAG_IMMUTABLE\n");
					}
					close(fd);
					continue;
				}
			}
			if (errno == EROFS) {
				debug("ignoring EROFS\n");
				break;
			}
			if (errno == EBUSY) {
#if SYZ_EXECUTOR || !SYZ_SANDBOX_ANDROID
#if SYZ_EXECUTOR
				if (!flag_sandbox_android) {
#endif
					debug("umount(%s)\n", dir);
					if (umount2(dir, MNT_DETACH | UMOUNT_NOFOLLOW))
						exitf("umount(%s) failed", dir);
#if SYZ_EXECUTOR
				}
#endif
#endif
				continue;
			}
			if (errno == ENOTEMPTY) {
				if (iter < 100) {
					iter++;
					goto retry;
				}
			}
		}
		exitf("rmdir(%s) failed", dir);
	}
}
#endif

#if SYZ_EXECUTOR || SYZ_FAULT
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>

static int inject_fault(int nth)
{
	int fd;
	fd = open("/proc/thread-self/fail-nth", O_RDWR);
	if (fd == -1)
		exitf("failed to open /proc/thread-self/fail-nth");
	char buf[16];
	sprintf(buf, "%d", nth);
	if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf))
		exitf("failed to write /proc/thread-self/fail-nth");
	return fd;
}
#endif

#if SYZ_EXECUTOR
static int fault_injected(int fail_fd)
{
	char buf[16];
	int n = read(fail_fd, buf, sizeof(buf) - 1);
	if (n <= 0)
		exitf("failed to read /proc/thread-self/fail-nth");
	int res = n == 2 && buf[0] == '0' && buf[1] == '\n';
	buf[0] = '0';
	if (write(fail_fd, buf, 1) != 1)
		exitf("failed to write /proc/thread-self/fail-nth");
	close(fail_fd);
	return res;
}
#endif

#if (SYZ_EXECUTOR || SYZ_REPEAT) && SYZ_EXECUTOR_USES_FORK_SERVER
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>

static void kill_and_wait(int pid, int* status)
{
	kill(-pid, SIGKILL);
	kill(pid, SIGKILL);
	for (int i = 0; i < 100; i++) {
		if (waitpid(-1, status, WNOHANG | __WALL) == pid)
			return;
		usleep(1000);
	}
	debug("kill is not working\n");
	DIR* dir = opendir("/sys/fs/fuse/connections");
	if (dir) {
		for (;;) {
			struct dirent* ent = readdir(dir);
			if (!ent)
				break;
			if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
				continue;
			char abort[300];
			snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort", ent->d_name);
			int fd = open(abort, O_WRONLY);
			if (fd == -1) {
				debug("failed to open %s: %d\n", abort, errno);
				continue;
			}
			debug("aborting fuse conn %s\n", ent->d_name);
			if (write(fd, abort, 1) < 0) {
				debug("failed to abort: %d\n", errno);
			}
			close(fd);
		}
		closedir(dir);
	} else {
		debug("failed to open /sys/fs/fuse/connections: %d\n", errno);
	}
	while (waitpid(-1, status, __WALL) != pid) {
	}
}
#endif

#if (SYZ_EXECUTOR || SYZ_REPEAT && (SYZ_CGROUPS || SYZ_NET_RESET)) && SYZ_EXECUTOR_USES_FORK_SERVER
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#define SYZ_HAVE_SETUP_LOOP 1
static void setup_loop()
{
#if SYZ_EXECUTOR || SYZ_CGROUPS
	setup_cgroups_loop();
#endif
#if SYZ_EXECUTOR || SYZ_NET_RESET
	checkpoint_net_namespace();
#endif
}
#endif

#if (SYZ_EXECUTOR || SYZ_REPEAT && (SYZ_NET_RESET || __NR_syz_mount_image || __NR_syz_read_part_table)) && SYZ_EXECUTOR_USES_FORK_SERVER
#define SYZ_HAVE_RESET_LOOP 1
static void reset_loop()
{
#if SYZ_EXECUTOR || __NR_syz_mount_image || __NR_syz_read_part_table
	char buf[64];
	snprintf(buf, sizeof(buf), "/dev/loop%llu", procid);
	int loopfd = open(buf, O_RDWR);
	if (loopfd != -1) {
		ioctl(loopfd, LOOP_CLR_FD, 0);
		close(loopfd);
	}
#endif
#if SYZ_EXECUTOR || SYZ_NET_RESET
	reset_net_namespace();
#endif
}
#endif

#if (SYZ_EXECUTOR || SYZ_REPEAT) && SYZ_EXECUTOR_USES_FORK_SERVER
#include <sys/prctl.h>
#include <unistd.h>

#define SYZ_HAVE_SETUP_TEST 1
static void setup_test()
{
	prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
	setpgrp();
#if SYZ_EXECUTOR || SYZ_CGROUPS
	setup_cgroups_test();
#endif
	write_file("/proc/self/oom_score_adj", "1000");
#if SYZ_EXECUTOR || SYZ_NET_INJECTION
	flush_tun();
#endif
#if SYZ_EXECUTOR || SYZ_USE_TMP_DIR
	if (symlink("/dev/binderfs", "./binderfs")) {
		debug("symlink(/dev/binderfs, ./binderfs) failed: %d", errno);
	}
#endif
}
#endif

#if SYZ_EXECUTOR || SYZ_CLOSE_FDS
#define SYZ_HAVE_CLOSE_FDS 1
static void close_fds()
{
#if SYZ_EXECUTOR
	if (!flag_close_fds)
		return;
#endif
	for (int fd = 3; fd < MAX_FDS; fd++)
		close(fd);
}
#endif

#if SYZ_EXECUTOR || SYZ_FAULT
#include <errno.h>

static void setup_fault()
{
	static struct {
		const char* file;
		const char* val;
		bool fatal;
	} files[] = {
	    {"/sys/kernel/debug/failslab/ignore-gfp-wait", "N", true},
	    {"/sys/kernel/debug/fail_futex/ignore-private", "N", false},
	    {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-highmem", "N", false},
	    {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-wait", "N", false},
	    {"/sys/kernel/debug/fail_page_alloc/min-order", "0", false},
	};
	unsigned i;
	for (i = 0; i < sizeof(files) / sizeof(files[0]); i++) {
		if (!write_file(files[i].file, files[i].val)) {
			debug("failed to write %s: %d\n", files[i].file, errno);
			if (files[i].fatal)
				failmsg("failed to write fault injection file", "file=%s", files[i].file);
		}
	}
}
#endif

#if SYZ_EXECUTOR || SYZ_LEAK
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>

#define KMEMLEAK_FILE "/sys/kernel/debug/kmemleak"

static void setup_leak()
{
	if (!write_file(KMEMLEAK_FILE, "scan"))
		fail("failed to write(kmemleak, \"scan\")");
	sleep(5);
	if (!write_file(KMEMLEAK_FILE, "scan"))
		fail("failed to write(kmemleak, \"scan\")");
	if (!write_file(KMEMLEAK_FILE, "clear"))
		fail("failed to write(kmemleak, \"clear\")");
}

#define SYZ_HAVE_LEAK_CHECK 1
#if SYZ_EXECUTOR
static void check_leaks(char** frames, int nframes)
#else
static void check_leaks(void)
#endif
{
	int fd = open(KMEMLEAK_FILE, O_RDWR);
	if (fd == -1)
		fail("failed to open(kmemleak)");
	uint64 start = current_time_ms();
	if (write(fd, "scan", 4) != 4)
		fail("failed to write(kmemleak, \"scan\")");
	sleep(1);
	while (current_time_ms() - start < 4 * 1000)
		sleep(1);
	if (write(fd, "scan", 4) != 4)
		fail("failed to write(kmemleak, \"scan\")");
	static char buf[128 << 10];
	ssize_t n = read(fd, buf, sizeof(buf) - 1);
	if (n < 0)
		fail("failed to read(kmemleak)");
	int nleaks = 0;
	if (n != 0) {
		sleep(1);
		if (write(fd, "scan", 4) != 4)
			fail("failed to write(kmemleak, \"scan\")");
		if (lseek(fd, 0, SEEK_SET) < 0)
			fail("failed to lseek(kmemleak)");
		n = read(fd, buf, sizeof(buf) - 1);
		if (n < 0)
			fail("failed to read(kmemleak)");
		buf[n] = 0;
		char* pos = buf;
		char* end = buf + n;
		while (pos < end) {
			char* next = strstr(pos + 1, "unreferenced object");
			if (!next)
				next = end;
			char prev = *next;
			*next = 0;
#if SYZ_EXECUTOR
			int f;
			for (f = 0; f < nframes; f++) {
				if (strstr(pos, frames[f]))
					break;
			}
			if (f != nframes) {
				*next = prev;
				pos = next;
				continue;
			}
#endif
			fprintf(stderr, "BUG: memory leak\n%s\n", pos);
			*next = prev;
			pos = next;
			nleaks++;
		}
	}
	if (write(fd, "clear", 5) != 5)
		fail("failed to write(kmemleak, \"clear\")");
	close(fd);
	if (nleaks)
		doexit(1);
}
#endif

#if SYZ_EXECUTOR || SYZ_BINFMT_MISC
#include <fcntl.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/types.h>

static void setup_binfmt_misc()
{
	if (mount(0, "/proc/sys/fs/binfmt_misc", "binfmt_misc", 0, 0)) {
		debug("mount(binfmt_misc) failed: %d\n", errno);
	}
	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");
}
#endif

#if SYZ_EXECUTOR || SYZ_KCSAN
#define KCSAN_DEBUGFS_FILE "/sys/kernel/debug/kcsan"

static void setup_kcsan()
{
	if (!write_file(KCSAN_DEBUGFS_FILE, "on"))
		fail("failed to enable KCSAN");
}

#if SYZ_EXECUTOR
static void setup_kcsan_filterlist(char** frames, int nframes, bool suppress)
{
	int fd = open(KCSAN_DEBUGFS_FILE, O_WRONLY);
	if (fd == -1)
		fail("failed to open kcsan debugfs file");

	printf("%s KCSAN reports in functions: ",
	       suppress ? "suppressing" : "only showing");
	if (!suppress)
		dprintf(fd, "whitelist\n");
	for (int i = 0; i < nframes; ++i) {
		printf("'%s' ", frames[i]);
		dprintf(fd, "!%s\n", frames[i]);
	}
	printf("\n");

	close(fd);
}

#define SYZ_HAVE_KCSAN 1
#endif
#endif

#if SYZ_EXECUTOR || SYZ_USB
static void setup_usb()
{
	if (chmod("/dev/raw-gadget", 0666))
		fail("failed to chmod /dev/raw-gadget");
}
#endif

#if SYZ_EXECUTOR || SYZ_SYSCTL
#include <errno.h>
#include <stdio.h>
#include <string.h>

static void setup_sysctl()
{
	char mypid[32];
	snprintf(mypid, sizeof(mypid), "%d", getpid());
	struct {
		const char* name;
		const char* data;
	} files[] = {
#if GOARCH_amd64 || GOARCH_386
		{"/sys/kernel/debug/x86/nmi_longest_ns", "10000000000"},
#endif
		{"/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/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));
	}
}
#endif

#if SYZ_EXECUTOR || SYZ_802154
#include <net/if.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>

#define NL802154_CMD_SET_SHORT_ADDR 11
#define NL802154_ATTR_IFINDEX 3
#define NL802154_ATTR_SHORT_ADDR 10

static void setup_802154()
{
	int sock_route = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
	if (sock_route == -1)
		fail("socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE) failed");
	int sock_generic = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
	if (sock_generic < 0)
		fail("socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC) failed");
	int nl802154_family_id = netlink_query_family_id(&nlmsg, sock_generic, "nl802154", true);
	for (int i = 0; i < 2; i++) {
		char devname[] = "wpan0";
		devname[strlen(devname) - 1] += i;
		uint64 hwaddr = 0xaaaaaaaaaaaa0002 + (i << 8);
		uint16 shortaddr = 0xaaa0 + i;
		int ifindex = if_nametoindex(devname);
		struct genlmsghdr genlhdr;
		memset(&genlhdr, 0, sizeof(genlhdr));
		genlhdr.cmd = NL802154_CMD_SET_SHORT_ADDR;
		netlink_init(&nlmsg, nl802154_family_id, 0, &genlhdr, sizeof(genlhdr));
		netlink_attr(&nlmsg, NL802154_ATTR_IFINDEX, &ifindex, sizeof(ifindex));
		netlink_attr(&nlmsg, NL802154_ATTR_SHORT_ADDR, &shortaddr, sizeof(shortaddr));
		int err = netlink_send(&nlmsg, sock_generic);
		if (err < 0) {
			debug("NL802154_CMD_SET_SHORT_ADDR failed: %s\n", strerror(errno));
		}
		netlink_device_change(&nlmsg, sock_route, devname, true, 0, &hwaddr, sizeof(hwaddr), 0);
		if (i == 0) {
			netlink_add_device_impl(&nlmsg, "lowpan", "lowpan0", false);
			netlink_done(&nlmsg);
			netlink_attr(&nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
			int err = netlink_send(&nlmsg, sock_route);
			if (err < 0) {
				debug("netlink: adding device lowpan0 type lowpan link wpan0: %s\n", strerror(errno));
			}
		}
	}
	close(sock_route);
	close(sock_generic);
}
#endif

#if GOARCH_s390x
#include <sys/mman.h>
#define CAST(f) ({void* p = (void*)f; p; })
#endif

#if SYZ_EXECUTOR || __NR_syz_fuse_handle_req
#include <fcntl.h>
#include <stddef.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#define FUSE_MIN_READ_BUFFER 8192
enum fuse_opcode {
	FUSE_LOOKUP = 1,
	FUSE_FORGET = 2,
	FUSE_GETATTR = 3,
	FUSE_SETATTR = 4,
	FUSE_READLINK = 5,
	FUSE_SYMLINK = 6,
	FUSE_MKNOD = 8,
	FUSE_MKDIR = 9,
	FUSE_UNLINK = 10,
	FUSE_RMDIR = 11,
	FUSE_RENAME = 12,
	FUSE_LINK = 13,
	FUSE_OPEN = 14,
	FUSE_READ = 15,
	FUSE_WRITE = 16,
	FUSE_STATFS = 17,
	FUSE_RELEASE = 18,
	FUSE_FSYNC = 20,
	FUSE_SETXATTR = 21,
	FUSE_GETXATTR = 22,
	FUSE_LISTXATTR = 23,
	FUSE_REMOVEXATTR = 24,
	FUSE_FLUSH = 25,
	FUSE_INIT = 26,
	FUSE_OPENDIR = 27,
	FUSE_READDIR = 28,
	FUSE_RELEASEDIR = 29,
	FUSE_FSYNCDIR = 30,
	FUSE_GETLK = 31,
	FUSE_SETLK = 32,
	FUSE_SETLKW = 33,
	FUSE_ACCESS = 34,
	FUSE_CREATE = 35,
	FUSE_INTERRUPT = 36,
	FUSE_BMAP = 37,
	FUSE_DESTROY = 38,
	FUSE_IOCTL = 39,
	FUSE_POLL = 40,
	FUSE_NOTIFY_REPLY = 41,
	FUSE_BATCH_FORGET = 42,
	FUSE_FALLOCATE = 43,
	FUSE_READDIRPLUS = 44,
	FUSE_RENAME2 = 45,
	FUSE_LSEEK = 46,
	FUSE_COPY_FILE_RANGE = 47,
	FUSE_SETUPMAPPING = 48,
	FUSE_REMOVEMAPPING = 49,
	CUSE_INIT = 4096,
	CUSE_INIT_BSWAP_RESERVED = 1048576,
	FUSE_INIT_BSWAP_RESERVED = 436207616,
};
struct fuse_in_header {
	uint32 len;
	uint32 opcode;
	uint64 unique;
	uint64 nodeid;
	uint32 uid;
	uint32 gid;
	uint32 pid;
	uint32 padding;
};
struct fuse_out_header {
	uint32 len;
	uint32 error;
	uint64 unique;
};
struct syz_fuse_req_out {
	struct fuse_out_header* init;
	struct fuse_out_header* lseek;
	struct fuse_out_header* bmap;
	struct fuse_out_header* poll;
	struct fuse_out_header* getxattr;
	struct fuse_out_header* lk;
	struct fuse_out_header* statfs;
	struct fuse_out_header* write;
	struct fuse_out_header* read;
	struct fuse_out_header* open;
	struct fuse_out_header* attr;
	struct fuse_out_header* entry;
	struct fuse_out_header* dirent;
	struct fuse_out_header* direntplus;
	struct fuse_out_header* create_open;
	struct fuse_out_header* ioctl;
};
static int fuse_send_response(int fd,
			      const struct fuse_in_header* in_hdr,
			      struct fuse_out_header* out_hdr)
{
	if (!out_hdr) {
		debug("fuse_send_response: received a NULL out_hdr\n");
		return -1;
	}

	out_hdr->unique = in_hdr->unique;
	if (write(fd, out_hdr, out_hdr->len) == -1) {
		debug("fuse_send_response > write failed: %d\n", errno);
		return -1;
	}

	return 0;
}
static volatile long syz_fuse_handle_req(volatile long a0,
					 volatile long a1,
					 volatile long a2,
					 volatile long a3)
{
	struct syz_fuse_req_out* req_out = (struct syz_fuse_req_out*)a3;
	struct fuse_out_header* out_hdr = NULL;
	char* buf = (char*)a1;
	int buf_len = (int)a2;
	int fd = (int)a0;

	if (!req_out) {
		debug("syz_fuse_handle_req: received a NULL syz_fuse_req_out\n");
		return -1;
	}
	if (buf_len < FUSE_MIN_READ_BUFFER) {
		debug("FUSE requires the read buffer to be at least %u\n", FUSE_MIN_READ_BUFFER);
		return -1;
	}

	int ret = read(fd, buf, buf_len);
	if (ret == -1) {
		debug("syz_fuse_handle_req > read failed: %d\n", errno);
		return -1;
	}
	if ((size_t)ret < sizeof(struct fuse_in_header)) {
		debug("syz_fuse_handle_req: received a truncated FUSE header\n");
		return -1;
	}

	const struct fuse_in_header* in_hdr = (const struct fuse_in_header*)buf;
	debug("syz_fuse_handle_req: received opcode %d\n", in_hdr->opcode);
	if (in_hdr->len > (uint32)ret) {
		debug("syz_fuse_handle_req: received a truncated message\n");
		return -1;
	}

	switch (in_hdr->opcode) {
	case FUSE_GETATTR:
	case FUSE_SETATTR:
		out_hdr = req_out->attr;
		break;
	case FUSE_LOOKUP:
	case FUSE_SYMLINK:
	case FUSE_LINK:
	case FUSE_MKNOD:
	case FUSE_MKDIR:
		out_hdr = req_out->entry;
		break;
	case FUSE_OPEN:
	case FUSE_OPENDIR:
		out_hdr = req_out->open;
		break;
	case FUSE_STATFS:
		out_hdr = req_out->statfs;
		break;
	case FUSE_RMDIR:
	case FUSE_RENAME:
	case FUSE_RENAME2:
	case FUSE_FALLOCATE:
	case FUSE_SETXATTR:
	case FUSE_REMOVEXATTR:
	case FUSE_FSYNCDIR:
	case FUSE_FSYNC:
	case FUSE_SETLKW:
	case FUSE_SETLK:
	case FUSE_ACCESS:
	case FUSE_FLUSH:
	case FUSE_RELEASE:
	case FUSE_RELEASEDIR:
	case FUSE_UNLINK:
	case FUSE_DESTROY:
		out_hdr = req_out->init;
		if (!out_hdr) {
			debug("syz_fuse_handle_req: received a NULL out_hdr\n");
			return -1;
		}
		out_hdr->len = sizeof(struct fuse_out_header);
		break;
	case FUSE_READ:
		out_hdr = req_out->read;
		break;
	case FUSE_READDIR:
		out_hdr = req_out->dirent;
		break;
	case FUSE_READDIRPLUS:
		out_hdr = req_out->direntplus;
		break;
	case FUSE_INIT:
		out_hdr = req_out->init;
		break;
	case FUSE_LSEEK:
		out_hdr = req_out->lseek;
		break;
	case FUSE_GETLK:
		out_hdr = req_out->lk;
		break;
	case FUSE_BMAP:
		out_hdr = req_out->bmap;
		break;
	case FUSE_POLL:
		out_hdr = req_out->poll;
		break;
	case FUSE_GETXATTR:
	case FUSE_LISTXATTR:
		out_hdr = req_out->getxattr;
		break;
	case FUSE_WRITE:
	case FUSE_COPY_FILE_RANGE:
		out_hdr = req_out->write;
		break;
	case FUSE_FORGET:
	case FUSE_BATCH_FORGET:
		return 0;
	case FUSE_CREATE:
		out_hdr = req_out->create_open;
		break;
	case FUSE_IOCTL:
		out_hdr = req_out->ioctl;
		break;
	default:
		debug("syz_fuse_handle_req: unknown FUSE opcode\n");
		return -1;
	}

	return fuse_send_response(fd, in_hdr, out_hdr);
}
#endif

#if SYZ_EXECUTOR || __NR_syz_80211_inject_frame
#include <errno.h>
#include <linux/genetlink.h>
#include <linux/if_ether.h>
#include <linux/nl80211.h>
#include <net/if.h>
#include <sys/ioctl.h>

#define HWSIM_ATTR_RX_RATE 5
#define HWSIM_ATTR_SIGNAL 6
#define HWSIM_ATTR_ADDR_RECEIVER 1
#define HWSIM_ATTR_FRAME 3

#define WIFI_MAX_INJECT_LEN 2048

static int hwsim_register_socket(struct nlmsg* nlmsg, int sock, int hwsim_family)
{
	struct genlmsghdr genlhdr;
	memset(&genlhdr, 0, sizeof(genlhdr));
	genlhdr.cmd = HWSIM_CMD_REGISTER;
	netlink_init(nlmsg, hwsim_family, 0, &genlhdr, sizeof(genlhdr));
	int err = netlink_send(nlmsg, sock);
	if (err < 0) {
		debug("hwsim_register_device failed: %s\n", strerror(errno));
	}
	return err;
}

static int hwsim_inject_frame(struct nlmsg* nlmsg, int sock, int hwsim_family, uint8* mac_addr, uint8* data, int len)
{
	struct genlmsghdr genlhdr;
	uint32 rx_rate = WIFI_DEFAULT_RX_RATE;
	uint32 signal = WIFI_DEFAULT_SIGNAL;

	memset(&genlhdr, 0, sizeof(genlhdr));
	genlhdr.cmd = HWSIM_CMD_FRAME;
	netlink_init(nlmsg, hwsim_family, 0, &genlhdr, sizeof(genlhdr));
	netlink_attr(nlmsg, HWSIM_ATTR_RX_RATE, &rx_rate, sizeof(rx_rate));
	netlink_attr(nlmsg, HWSIM_ATTR_SIGNAL, &signal, sizeof(signal));
	netlink_attr(nlmsg, HWSIM_ATTR_ADDR_RECEIVER, mac_addr, ETH_ALEN);
	netlink_attr(nlmsg, HWSIM_ATTR_FRAME, data, len);
	int err = netlink_send(nlmsg, sock);
	if (err < 0) {
		debug("hwsim_inject_frame failed: %s\n", strerror(errno));
	}
	return err;
}

static long syz_80211_inject_frame(volatile long a0, volatile long a1, volatile long a2)
{
	uint8* mac_addr = (uint8*)a0;
	uint8* buf = (uint8*)a1;
	int buf_len = (int)a2;
	struct nlmsg tmp_msg;

	if (buf_len < 0 || buf_len > WIFI_MAX_INJECT_LEN) {
		debug("syz_80211_inject_frame: wrong buffer size %d\n", buf_len);
		return -1;
	}

	int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
	if (sock < 0) {
		debug("syz_80211_inject_frame: socket creation failed, errno %d\n", errno);
		return -1;
	}

	int hwsim_family_id = netlink_query_family_id(&tmp_msg, sock, "MAC80211_HWSIM", true);
	int ret = hwsim_register_socket(&tmp_msg, sock, hwsim_family_id);
	if (ret < 0) {
		debug("syz_80211_inject_frame: failed to register socket, ret %d\n", ret);
		close(sock);
		return -1;
	}

	ret = hwsim_inject_frame(&tmp_msg, sock, hwsim_family_id, mac_addr, buf, buf_len);
	close(sock);
	if (ret < 0) {
		debug("syz_80211_inject_frame: failed to inject message, ret %d\n", ret);
		return -1;
	}

	return 0;
}

#endif

#if SYZ_EXECUTOR || __NR_syz_80211_join_ibss

#define WIFI_MAX_SSID_LEN 32

#define WIFI_JOIN_IBSS_NO_SCAN 0
#define WIFI_JOIN_IBSS_BG_SCAN 1
#define WIFI_JOIN_IBSS_BG_NO_SCAN 2

static long syz_80211_join_ibss(volatile long a0, volatile long a1, volatile long a2, volatile long a3)
{
	char* interface = (char*)a0;
	uint8* ssid = (uint8*)a1;
	int ssid_len = (int)a2;
	int mode = (int)a3;

	struct nlmsg tmp_msg;
	uint8 bssid[ETH_ALEN] = WIFI_IBSS_BSSID;

	if (ssid_len < 0 || ssid_len > WIFI_MAX_SSID_LEN) {
		debug("syz_80211_join_ibss: invalid ssid len %d\n", ssid_len);
		return -1;
	}

	if (mode < 0 || mode > WIFI_JOIN_IBSS_BG_NO_SCAN) {
		debug("syz_80211_join_ibss: invalid mode %d\n", mode);
		return -1;
	}

	int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
	if (sock < 0) {
		debug("syz_80211_join_ibss: socket creation failed, errno %d\n", errno);
		return -1;
	}

	int nl80211_family_id = netlink_query_family_id(&tmp_msg, sock, "nl80211", true);
	struct join_ibss_props ibss_props = {
	    .wiphy_freq = WIFI_DEFAULT_FREQUENCY,
	    .wiphy_freq_fixed = (mode == WIFI_JOIN_IBSS_NO_SCAN || mode == WIFI_JOIN_IBSS_BG_NO_SCAN),
	    .mac = bssid,
	    .ssid = ssid,
	    .ssid_len = ssid_len};

	int ret = nl80211_setup_ibss_interface(&tmp_msg, sock, nl80211_family_id, interface, &ibss_props);
	close(sock);
	if (ret < 0) {
		debug("syz_80211_join_ibss: failed set up IBSS network for %.32s\n", interface);
		return -1;
	}

	if (mode == WIFI_JOIN_IBSS_NO_SCAN) {
		ret = await_ifla_operstate(&tmp_msg, interface, IF_OPER_UP);
		if (ret < 0) {
			debug("syz_80211_join_ibss: await_ifla_operstate failed for %.32s, ret %d\n", interface, ret);
			return -1;
		}
	}

	return 0;
}

#endif

#if SYZ_EXECUTOR || __NR_syz_clone || __NR_syz_clone3
#if SYZ_EXECUTOR
#define USLEEP_FORKED_CHILD (3 * syscall_timeout_ms * 1000)
#else
#define USLEEP_FORKED_CHILD (3 * /*{{{BASE_CALL_TIMEOUT_MS}}}*/ *1000)
#endif

static long handle_clone_ret(long ret)
{
	if (ret != 0) {
#if SYZ_EXECUTOR || SYZ_HANDLE_SEGV
		__atomic_store_n(&clone_ongoing, 0, __ATOMIC_RELAXED);
#endif
		return ret;
	}
	usleep(USLEEP_FORKED_CHILD);
	syscall(__NR_exit, 0);
	while (1) {
	}
}
#endif

#if SYZ_EXECUTOR || __NR_syz_clone
#include <sched.h>
static long syz_clone(volatile long flags, volatile long stack, volatile long stack_len,
		      volatile long ptid, volatile long ctid, volatile long tls)
{
	long sp = (stack + stack_len) & ~15;
#if SYZ_EXECUTOR || SYZ_HANDLE_SEGV
	__atomic_store_n(&clone_ongoing, 1, __ATOMIC_RELAXED);
#endif
	long ret = (long)syscall(__NR_clone, flags & ~CLONE_VM, sp, ptid, ctid, tls);
	return handle_clone_ret(ret);
}
#endif

#if SYZ_EXECUTOR || __NR_syz_clone3
#include <linux/sched.h>
#include <sched.h>

#define MAX_CLONE_ARGS_BYTES 256
static long syz_clone3(volatile long a0, volatile long a1)
{
	unsigned long copy_size = a1;
	if (copy_size < sizeof(uint64) || copy_size > MAX_CLONE_ARGS_BYTES)
		return -1;
	char clone_args[MAX_CLONE_ARGS_BYTES];
	memcpy(&clone_args, (void*)a0, copy_size);
	uint64* flags = (uint64*)&clone_args;
	*flags &= ~CLONE_VM;
#if SYZ_EXECUTOR || SYZ_HANDLE_SEGV
	__atomic_store_n(&clone_ongoing, 1, __ATOMIC_RELAXED);
#endif
	return handle_clone_ret((long)syscall(__NR_clone3, &clone_args, copy_size));
}

#endif

#if SYZ_EXECUTOR || __NR_syz_pkey_set
static long syz_pkey_set(volatile long pkey, volatile long val)
{
#if GOARCH_amd64 || GOARCH_386
	uint32 eax = 0;
	uint32 ecx = 0;
	asm volatile("rdpkru"
		     : "=a"(eax)
		     : "c"(ecx)
		     : "edx");
	eax &= ~(3 << ((pkey % 16) * 2));
	eax |= (val & 3) << ((pkey % 16) * 2);
	uint32 edx = 0;
	asm volatile("wrpkru" ::"a"(eax), "c"(ecx), "d"(edx));
#endif
	return 0;
}
#endif

#if SYZ_EXECUTOR || SYZ_SWAP
#include <fcntl.h>
#include <linux/falloc.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/swap.h>
#include <sys/types.h>

#define SWAP_FILE "./swap-file"
#define SWAP_FILE_SIZE (128 * 1000 * 1000)

static void setup_swap()
{
	swapoff(SWAP_FILE);
	unlink(SWAP_FILE);
	int fd = open(SWAP_FILE, O_CREAT | O_WRONLY | O_CLOEXEC, 0600);
	if (fd == -1) {
		failmsg("swap file open failed", "file: %s", SWAP_FILE);
		return;
	}
	fallocate(fd, FALLOC_FL_ZERO_RANGE, 0, SWAP_FILE_SIZE);
	close(fd);
	char cmdline[64];
	sprintf(cmdline, "mkswap %s", SWAP_FILE);
	if (runcmdline(cmdline)) {
		fail("mkswap failed");
		return;
	}
	if (swapon(SWAP_FILE, SWAP_FLAG_PREFER) == 1) {
		failmsg("swapon failed", "file: %s", SWAP_FILE);
		return;
	}
}

#endif

#elif GOOS_test

#include <stdlib.h>
#include <unistd.h>

#if SYZ_EXECUTOR || __NR_syz_mmap
#include <sys/mman.h>
static long syz_mmap(volatile long a0, volatile long a1)
{
	return (long)mmap((void*)a0, a1, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0);
}
#endif

#if SYZ_EXECUTOR || __NR_syz_errno
#include <errno.h>
static long syz_errno(volatile long v)
{
	errno = v;
	return v == 0 ? 0 : -1;
}
#endif

#if SYZ_EXECUTOR || __NR_syz_exit
static long syz_exit(volatile long status)
{
	_exit(status);
	return 0;
}
#endif

#if SYZ_EXECUTOR || __NR_syz_sleep_ms
static long syz_sleep_ms(volatile long ms)
{
	sleep_ms(ms);
	return 0;
}
#endif

#if SYZ_EXECUTOR || __NR_syz_compare
#include <errno.h>
#include <string.h>
static long syz_compare(volatile long want, volatile long want_len, volatile long got, volatile long got_len)
{
	if (want_len != got_len) {
		errno = EBADF;
		goto error;
	}
	if (memcmp((void*)want, (void*)got, want_len)) {
		errno = EINVAL;
		goto error;
	}
	return 0;

error:
	debug("syz_compare: want (%lu):\n", want_len);
	debug_dump_data((char*)want, want_len);
	debug("got (%lu):\n", got_len);
	debug_dump_data((char*)got, got_len);
	return -1;
}
#endif

#if SYZ_EXECUTOR || __NR_syz_compare_int
#include <errno.h>
#include <stdarg.h>
static long syz_compare_int(volatile long n, ...)
{
	va_list args;
	va_start(args, n);
	long v0 = va_arg(args, long);
	long v1 = va_arg(args, long);
	long v2 = va_arg(args, long);
	long v3 = va_arg(args, long);
	va_end(args);
	if (n < 2 || n > 4)
		return errno = E2BIG, -1;
	if (n <= 2 && v2 != 0)
		return errno = EFAULT, -1;
	if (n <= 3 && v3 != 0)
		return errno = EFAULT, -1;
	if (v0 != v1)
		return errno = EINVAL, -1;
	if (n > 2 && v0 != v2)
		return errno = EINVAL, -1;
	if (n > 3 && v0 != v3)
		return errno = EINVAL, -1;
	return 0;
}
#endif

#if SYZ_EXECUTOR || __NR_syz_compare_zlib

//% This code is derived from puff.{c,h}, found in the zlib development. The
//% original files come with the following copyright notice:

//% Copyright (C) 2002-2013 Mark Adler, all rights reserved
//% version 2.3, 21 Jan 2013
//% This software is provided 'as-is', without any express or implied
//% warranty.  In no event will the author be held liable for any damages
//% arising from the use of this software.
//% Permission is granted to anyone to use this software for any purpose,
//% including commercial applications, and to alter it and redistribute it
//% freely, subject to the following restrictions:
//% 1. The origin of this software must not be misrepresented; you must not
//%    claim that you wrote the original software. If you use this software
//%    in a product, an acknowledgment in the product documentation would be
//%    appreciated but is not required.
//% 2. Altered source versions must be plainly marked as such, and must not be
//%    misrepresented as being the original software.
//% 3. This notice may not be removed or altered from any source distribution.
//% Mark Adler    madler@alumni.caltech.edu

//% BEGIN CODE DERIVED FROM puff.{c,h}

#include <setjmp.h>
#define MAXBITS 15
#define MAXLCODES 286
#define MAXDCODES 30
#define MAXCODES (MAXLCODES + MAXDCODES)
#define FIXLCODES 288

struct puff_state {
	unsigned char* out;
	unsigned long outlen;
	unsigned long outcnt;
	const unsigned char* in;
	unsigned long inlen;
	unsigned long incnt;
	int bitbuf;
	int bitcnt;
	jmp_buf env;
};
static int puff_bits(struct puff_state* s, int need)
{
	long val = s->bitbuf;
	while (s->bitcnt < need) {
		if (s->incnt == s->inlen)
			longjmp(s->env, 1);
		val |= (long)(s->in[s->incnt++]) << s->bitcnt;
		s->bitcnt += 8;
	}
	s->bitbuf = (int)(val >> need);
	s->bitcnt -= need;
	return (int)(val & ((1L << need) - 1));
}
static int puff_stored(struct puff_state* s)
{
	s->bitbuf = 0;
	s->bitcnt = 0;
	if (s->incnt + 4 > s->inlen)
		return 2;
	unsigned len = s->in[s->incnt++];
	len |= s->in[s->incnt++] << 8;
	if (s->in[s->incnt++] != (~len & 0xff) ||
	    s->in[s->incnt++] != ((~len >> 8) & 0xff))
		return -2;
	if (s->incnt + len > s->inlen)
		return 2;
	if (s->outcnt + len > s->outlen)
		return 1;
	for (; len--; s->outcnt++, s->incnt++) {
		if (s->in[s->incnt])
			s->out[s->outcnt] = s->in[s->incnt];
	}
	return 0;
}
struct puff_huffman {
	short* count;
	short* symbol;
};
static int puff_decode(struct puff_state* s, const struct puff_huffman* h)
{
	int first = 0;
	int index = 0;
	int bitbuf = s->bitbuf;
	int left = s->bitcnt;
	int code = first = index = 0;
	int len = 1;
	short* next = h->count + 1;
	while (1) {
		while (left--) {
			code |= bitbuf & 1;
			bitbuf >>= 1;
			int count = *next++;
			if (code - count < first) {
				s->bitbuf = bitbuf;
				s->bitcnt = (s->bitcnt - len) & 7;
				return h->symbol[index + (code - first)];
			}
			index += count;
			first += count;
			first <<= 1;
			code <<= 1;
			len++;
		}
		left = (MAXBITS + 1) - len;
		if (left == 0)
			break;
		if (s->incnt == s->inlen)
			longjmp(s->env, 1);
		bitbuf = s->in[s->incnt++];
		if (left > 8)
			left = 8;
	}
	return -10;
}
static int puff_construct(struct puff_huffman* h, const short* length, int n)
{
	int len;
	for (len = 0; len <= MAXBITS; len++)
		h->count[len] = 0;
	int symbol;
	for (symbol = 0; symbol < n; symbol++)
		(h->count[length[symbol]])++;
	if (h->count[0] == n)
		return 0;
	int left = 1;
	for (len = 1; len <= MAXBITS; len++) {
		left <<= 1;
		left -= h->count[len];
		if (left < 0)
			return left;
	}
	short offs[MAXBITS + 1];
	offs[1] = 0;
	for (len = 1; len < MAXBITS; len++)
		offs[len + 1] = offs[len] + h->count[len];
	for (symbol = 0; symbol < n; symbol++)
		if (length[symbol] != 0)
			h->symbol[offs[length[symbol]]++] = symbol;
	return left;
}
static int puff_codes(struct puff_state* s,
		      const struct puff_huffman* lencode,
		      const struct puff_huffman* distcode)
{
	static const short lens[29] = {
				       3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
				       35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258};
	static const short lext[29] = {
				       0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
				       3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0};
	static const short dists[30] = {
					1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
					257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
					8193, 12289, 16385, 24577};
	static const short dext[30] = {
				       0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
				       7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
				       12, 12, 13, 13};
	int symbol;
	do {
		symbol = puff_decode(s, lencode);
		if (symbol < 0)
			return symbol;
		if (symbol < 256) {
			if (s->outcnt == s->outlen)
				return 1;
			if (symbol)
				s->out[s->outcnt] = symbol;
			s->outcnt++;
		} else if (symbol > 256) {
			symbol -= 257;
			if (symbol >= 29)
				return -10;
			int len = lens[symbol] + puff_bits(s, lext[symbol]);
			symbol = puff_decode(s, distcode);
			if (symbol < 0)
				return symbol;
			unsigned dist = dists[symbol] + puff_bits(s, dext[symbol]);
			if (dist > s->outcnt)
				return -11;
			if (s->outcnt + len > s->outlen)
				return 1;
			while (len--) {
				if (dist <= s->outcnt && s->out[s->outcnt - dist])
					s->out[s->outcnt] = s->out[s->outcnt - dist];
				s->outcnt++;
			}
		}
	} while (symbol != 256);
	return 0;
}
static int puff_fixed(struct puff_state* s)
{
	static int virgin = 1;
	static short lencnt[MAXBITS + 1], lensym[FIXLCODES];
	static short distcnt[MAXBITS + 1], distsym[MAXDCODES];
	static struct puff_huffman lencode, distcode;
	if (virgin) {
		lencode.count = lencnt;
		lencode.symbol = lensym;
		distcode.count = distcnt;
		distcode.symbol = distsym;
		short lengths[FIXLCODES];
		int symbol;
		for (symbol = 0; symbol < 144; symbol++)
			lengths[symbol] = 8;
		for (; symbol < 256; symbol++)
			lengths[symbol] = 9;
		for (; symbol < 280; symbol++)
			lengths[symbol] = 7;
		for (; symbol < FIXLCODES; symbol++)
			lengths[symbol] = 8;
		puff_construct(&lencode, lengths, FIXLCODES);
		for (symbol = 0; symbol < MAXDCODES; symbol++)
			lengths[symbol] = 5;
		puff_construct(&distcode, lengths, MAXDCODES);
		virgin = 0;
	}
	return puff_codes(s, &lencode, &distcode);
}
static int puff_dynamic(struct puff_state* s)
{
	static const short order[19] =
	    {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
	int nlen = puff_bits(s, 5) + 257;
	int ndist = puff_bits(s, 5) + 1;
	int ncode = puff_bits(s, 4) + 4;
	if (nlen > MAXLCODES || ndist > MAXDCODES)
		return -3;
	short lengths[MAXCODES];
	int index;
	for (index = 0; index < ncode; index++)
		lengths[order[index]] = puff_bits(s, 3);
	for (; index < 19; index++)
		lengths[order[index]] = 0;
	short lencnt[MAXBITS + 1], lensym[MAXLCODES];
	struct puff_huffman lencode = {lencnt, lensym};
	int err = puff_construct(&lencode, lengths, 19);
	if (err != 0)
		return -4;
	index = 0;
	while (index < nlen + ndist) {
		int symbol;
		int len;

		symbol = puff_decode(s, &lencode);
		if (symbol < 0)
			return symbol;
		if (symbol < 16)
			lengths[index++] = symbol;
		else {
			len = 0;
			if (symbol == 16) {
				if (index == 0)
					return -5;
				len = lengths[index - 1];
				symbol = 3 + puff_bits(s, 2);
			} else if (symbol == 17)
				symbol = 3 + puff_bits(s, 3);
			else
				symbol = 11 + puff_bits(s, 7);
			if (index + symbol > nlen + ndist)
				return -6;
			while (symbol--)
				lengths[index++] = len;
		}
	}
	if (lengths[256] == 0)
		return -9;
	err = puff_construct(&lencode, lengths, nlen);
	if (err && (err < 0 || nlen != lencode.count[0] + lencode.count[1]))
		return -7;
	short distcnt[MAXBITS + 1], distsym[MAXDCODES];
	struct puff_huffman distcode = {distcnt, distsym};
	err = puff_construct(&distcode, lengths + nlen, ndist);
	if (err && (err < 0 || ndist != distcode.count[0] + distcode.count[1]))
		return -8;
	return puff_codes(s, &lencode, &distcode);
}
static int puff(
    unsigned char* dest,
    unsigned long* destlen,
    const unsigned char* source,
    unsigned long sourcelen)
{
	struct puff_state s = {
	    .out = dest,
	    .outlen = *destlen,
	    .outcnt = 0,
	    .in = source,
	    .inlen = sourcelen,
	    .incnt = 0,
	    .bitbuf = 0,
	    .bitcnt = 0,
	};
	int err;
	if (setjmp(s.env) != 0)
		err = 2;
	else {
		int last;
		do {
			last = puff_bits(&s, 1);
			int type = puff_bits(&s, 2);
			err = type == 0 ? puff_stored(&s) : (type == 1 ? puff_fixed(&s) : (type == 2 ? puff_dynamic(&s) : -1));
			if (err != 0)
				break;
		} while (!last);
	}

	*destlen = s.outcnt;
	return err;
}

//% END CODE DERIVED FROM puff.{c,h}

#include <errno.h>
#include <sys/mman.h>
#define ZLIB_HEADER_WIDTH 2

static int puff_zlib_to_file(const unsigned char* source, unsigned long sourcelen, int dest_fd)
{
	if (sourcelen < ZLIB_HEADER_WIDTH)
		return 0;
	source += ZLIB_HEADER_WIDTH;
	sourcelen -= ZLIB_HEADER_WIDTH;
	const unsigned long max_destlen = 132 << 20;
	void* ret = mmap(0, max_destlen, PROT_WRITE | PROT_READ, MAP_PRIVATE | MAP_ANON, -1, 0);
	if (ret == MAP_FAILED)
		return -1;
	unsigned char* dest = (unsigned char*)ret;
	unsigned long destlen = max_destlen;
	int err = puff(dest, &destlen, source, sourcelen);
	if (err) {
		munmap(dest, max_destlen);
		errno = -err;
		return -1;
	}
	if (write(dest_fd, dest, destlen) != (ssize_t)destlen) {
		munmap(dest, max_destlen);
		return -1;
	}
	return munmap(dest, destlen);
}

#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
static long syz_compare_zlib(volatile long data, volatile long size, volatile long zdata, volatile long zsize)
{
	int fd = open("./uncompressed", O_RDWR | O_CREAT | O_EXCL, 0666);
	if (fd == -1)
		return -1;
	if (puff_zlib_to_file((unsigned char*)zdata, zsize, fd))
		return -1;
	struct stat statbuf;
	if (fstat(fd, &statbuf))
		return -1;
	void* uncompressed = mmap(0, statbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
	if (uncompressed == MAP_FAILED)
		return -1;
	return syz_compare(data, size, (long)uncompressed, statbuf.st_size);
}
#endif

#if SYZ_EXECUTOR || SYZ_SANDBOX_NONE
static void loop();
static int do_sandbox_none(void)
{
	loop();
	return 0;
}
#endif

#elif GOOS_windows

#include <direct.h>
#include <io.h>
#include <windows.h>

#if SYZ_EXECUTOR || SYZ_HANDLE_SEGV
static void install_segv_handler()
{
}

#define NONFAILING(...) \
	([&]() { __try { __VA_ARGS__; } __except (EXCEPTION_EXECUTE_HANDLER) { return false; } return true; }())
#endif

#if SYZ_EXECUTOR || SYZ_THREADED || SYZ_REPEAT && SYZ_EXECUTOR_USES_FORK_SERVER
static uint64 current_time_ms()
{
	return GetTickCount64();
}
#endif

#if SYZ_EXECUTOR || SYZ_THREADED || SYZ_REPEAT && SYZ_EXECUTOR_USES_FORK_SERVER
static void sleep_ms(uint64 ms)
{
	Sleep(ms);
}
#endif

#if SYZ_EXECUTOR || SYZ_THREADED
static void thread_start(void* (*fn)(void*), void* arg)
{
	HANDLE th = CreateThread(NULL, 128 << 10, (LPTHREAD_START_ROUTINE)fn, arg, 0, NULL);
	if (th == NULL)
		exitf("CreateThread failed");
}

struct event_t {
	CRITICAL_SECTION cs;
	CONDITION_VARIABLE cv;
	int state;
};

static void event_init(event_t* ev)
{
	InitializeCriticalSection(&ev->cs);
	InitializeConditionVariable(&ev->cv);
	ev->state = 0;
}

static void event_reset(event_t* ev)
{
	ev->state = 0;
}

static void event_set(event_t* ev)
{
	EnterCriticalSection(&ev->cs);
	if (ev->state)
		exitf("event already set");
	ev->state = 1;
	LeaveCriticalSection(&ev->cs);
	WakeAllConditionVariable(&ev->cv);
}

static void event_wait(event_t* ev)
{
	EnterCriticalSection(&ev->cs);
	while (!ev->state)
		SleepConditionVariableCS(&ev->cv, &ev->cs, INFINITE);
	LeaveCriticalSection(&ev->cs);
}

static int event_isset(event_t* ev)
{
	EnterCriticalSection(&ev->cs);
	int res = ev->state;
	LeaveCriticalSection(&ev->cs);
	return res;
}

static int event_timedwait(event_t* ev, uint64 timeout_ms)
{
	EnterCriticalSection(&ev->cs);
	uint64 start = current_time_ms();
	for (;;) {
		if (ev->state)
			break;
		uint64 now = current_time_ms();
		if (now - start > timeout_ms)
			break;
		SleepConditionVariableCS(&ev->cv, &ev->cs, timeout_ms - (now - start));
	}
	int res = ev->state;
	LeaveCriticalSection(&ev->cs);
	return res;
}
#endif

#if SYZ_EXECUTOR || SYZ_SANDBOX_NONE
static void loop();
static int do_sandbox_none(void)
{
	loop();
	return 0;
}
#endif

static void use_temporary_dir(void)
{
	char tmpdir_template[] = "./syzkaller.XXXXXX";
	char* tmpdir = mktemp(tmpdir_template);

	CreateDirectory(tmpdir, NULL);
	_chdir(tmpdir);
}

#else
#error "unknown OS"
#endif

#if SYZ_TEST_COMMON_EXT_EXAMPLE
#include "common_ext_example.h"
#else

#endif

#if SYZ_EXECUTOR || __NR_syz_execute_func
static long syz_execute_func(volatile long text)
{
#if defined(__GNUC__)
	volatile long p[8] = {0};
	(void)p;
#if GOARCH_amd64
	asm volatile("" ::"r"(0l), "r"(1l), "r"(2l), "r"(3l), "r"(4l), "r"(5l), "r"(6l),
		     "r"(7l), "r"(8l), "r"(9l), "r"(10l), "r"(11l), "r"(12l), "r"(13l));
#endif
#endif
	((void (*)(void))(text))();
	return 0;
}
#endif

#if SYZ_THREADED
struct thread_t {
	int created, call;
	event_t ready, done;
};

static struct thread_t threads[16];
static void execute_call(int call);
static int running;

static void* thr(void* arg)
{
	struct thread_t* th = (struct thread_t*)arg;
	for (;;) {
		event_wait(&th->ready);
		event_reset(&th->ready);
		execute_call(th->call);
		__atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
		event_set(&th->done);
	}
	return 0;
}

#if SYZ_REPEAT
static void execute_one(void)
#else
static void loop(void)
#endif
{
#if SYZ_REPRO
	if (write(1, "executing program\n", sizeof("executing program\n") - 1)) {
	}
#endif
#if SYZ_TRACE
	fprintf(stderr, "### start\n");
#endif
	int i, call, thread;
	for (call = 0; call < /*{{{NUM_CALLS}}}*/; call++) {
		for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0])); thread++) {
			struct thread_t* th = &threads[thread];
			if (!th->created) {
				th->created = 1;
				event_init(&th->ready);
				event_init(&th->done);
				event_set(&th->done);
				thread_start(thr, th);
			}
			if (!event_isset(&th->done))
				continue;
			event_reset(&th->done);
			th->call = call;
			__atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
			event_set(&th->ready);
#if SYZ_ASYNC
			if (/*{{{ASYNC_CONDITIONS}}}*/)
				break;
#endif
			event_timedwait(&th->done, /*{{{CALL_TIMEOUT_MS}}}*/);
			break;
		}
	}
	for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
		sleep_ms(1);
#if SYZ_HAVE_CLOSE_FDS
	close_fds();
#endif
}
#endif

#if SYZ_EXECUTOR || SYZ_REPEAT
static void execute_one(void);
#if SYZ_EXECUTOR_USES_FORK_SERVER
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>

#if GOOS_linux
#define WAIT_FLAGS __WALL
#else
#define WAIT_FLAGS 0
#endif

#if SYZ_EXECUTOR
static void reply_handshake();
#endif

static void loop(void)
{
#if SYZ_HAVE_SETUP_LOOP
	setup_loop();
#endif
#if SYZ_EXECUTOR
	reply_handshake();
#endif
#if SYZ_EXECUTOR && GOOS_akaros
	int child_pipe[2];
	if (pipe(child_pipe))
		fail("pipe failed");
#endif
	int iter = 0;
#if SYZ_REPEAT_TIMES
	for (; iter < /*{{{REPEAT_TIMES}}}*/; iter++) {
#else
	for (;; iter++) {
#endif
#if SYZ_EXECUTOR || SYZ_USE_TMP_DIR
		char cwdbuf[32];
		sprintf(cwdbuf, "./%d", iter);
		if (mkdir(cwdbuf, 0777))
			fail("failed to mkdir");
#endif
#if SYZ_HAVE_RESET_LOOP
		reset_loop();
#endif
#if SYZ_EXECUTOR
		receive_execute();
#endif
		int pid = fork();
		if (pid < 0)
			fail("clone failed");
		if (pid == 0) {
#if SYZ_EXECUTOR || SYZ_USE_TMP_DIR
			if (chdir(cwdbuf))
				fail("failed to chdir");
#endif
#if SYZ_HAVE_SETUP_TEST
			setup_test();
#endif
#if SYZ_HAVE_SETUP_EXT_TEST
			setup_ext_test();
#endif
#if GOOS_akaros
#if SYZ_EXECUTOR
			dup2(child_pipe[0], kInPipeFd);
			close(child_pipe[0]);
			close(child_pipe[1]);
#endif
			execl(program_name, program_name, "child", NULL);
			fail("execl failed");
#else
#if SYZ_EXECUTOR
			close(kInPipeFd);
#endif
#if SYZ_EXECUTOR && SYZ_EXECUTOR_USES_SHMEM
			close(kOutPipeFd);
#endif
			execute_one();
#if SYZ_HAVE_CLOSE_FDS && !SYZ_THREADED
			close_fds();
#endif
			doexit(0);
#endif
		}
		debug("spawned worker pid %d\n", pid);

#if SYZ_EXECUTOR && GOOS_akaros
		resend_execute(child_pipe[1]);
#endif
		int status = 0;
		uint64 start = current_time_ms();
#if SYZ_EXECUTOR && SYZ_EXECUTOR_USES_SHMEM
		uint64 last_executed = start;
		uint32 executed_calls = __atomic_load_n(output_data, __ATOMIC_RELAXED);
#endif
		for (;;) {
			if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
				break;
			sleep_ms(1);
#if SYZ_EXECUTOR
#if SYZ_EXECUTOR_USES_SHMEM
			uint64 min_timeout_ms = program_timeout_ms * 3 / 5;
			uint64 inactive_timeout_ms = syscall_timeout_ms * 20;
			uint64 now = current_time_ms();
			uint32 now_executed = __atomic_load_n(output_data, __ATOMIC_RELAXED);
			if (executed_calls != now_executed) {
				executed_calls = now_executed;
				last_executed = now;
			}
			if ((now - start < program_timeout_ms) &&
			    (now - start < min_timeout_ms || now - last_executed < inactive_timeout_ms))
				continue;
#else
			if (current_time_ms() - start < program_timeout_ms)
				continue;
#endif
#else
			if (current_time_ms() - start < /*{{{PROGRAM_TIMEOUT_MS}}}*/)
				continue;
#endif
			debug("killing hanging pid %d\n", pid);
			kill_and_wait(pid, &status);
			break;
		}
#if SYZ_EXECUTOR
		if (WEXITSTATUS(status) == kFailStatus) {
			errno = 0;
			fail("child failed");
		}
		reply_execute(0);
#endif
#if SYZ_EXECUTOR || SYZ_USE_TMP_DIR
		remove_dir(cwdbuf);
#endif
#if SYZ_LEAK
		check_leaks();
#endif
	}
}
#else
static void loop(void)
{
	execute_one();
}
#endif
#endif

#if !SYZ_EXECUTOR

/*{{{RESULTS}}}*/

#if SYZ_THREADED || SYZ_REPEAT || SYZ_SANDBOX_NONE || SYZ_SANDBOX_SETUID || SYZ_SANDBOX_NAMESPACE || SYZ_SANDBOX_ANDROID
#if SYZ_THREADED
void execute_call(int call)
#elif SYZ_REPEAT
void execute_one(void)
#else
void loop(void)
#endif
{
	/*{{{SYSCALLS}}}*/
#if SYZ_HAVE_CLOSE_FDS && !SYZ_THREADED && !SYZ_REPEAT
	close_fds();
#endif
}
#endif
#if GOOS_akaros && SYZ_REPEAT
#include <string.h>

int main(int argc, char** argv)
{
	/*{{{MMAP_DATA}}}*/

	program_name = argv[0];
	if (argc == 2 && strcmp(argv[1], "child") == 0)
		child();
#else
int main(void)
{
	/*{{{MMAP_DATA}}}*/
#endif

#if SYZ_SYSCTL
	setup_sysctl();
#endif
#if SYZ_CGROUPS
	setup_cgroups();
#endif
#if SYZ_BINFMT_MISC
	setup_binfmt_misc();
#endif
#if SYZ_LEAK
	setup_leak();
#endif
#if SYZ_FAULT
	setup_fault();
#endif
#if SYZ_KCSAN
	setup_kcsan();
#endif
#if SYZ_USB
	setup_usb();
#endif
#if SYZ_802154
	setup_802154();
#endif
#if SYZ_SWAP
	setup_swap();
#endif
#if SYZ_HANDLE_SEGV
	install_segv_handler();
#endif
#if SYZ_HAVE_SETUP_EXT
	setup_ext();
#endif
#if SYZ_MULTI_PROC
	for (procid = 0; procid < /*{{{PROCS}}}*/; procid++) {
		if (fork() == 0) {
#endif
#if SYZ_USE_TMP_DIR || SYZ_SANDBOX_ANDROID
			use_temporary_dir();
#endif
			/*{{{SANDBOX_FUNC}}}*/
#if SYZ_HAVE_CLOSE_FDS && !SYZ_THREADED && !SYZ_REPEAT && !SYZ_SANDBOX_NONE && \
    !SYZ_SANDBOX_SETUID && !SYZ_SANDBOX_NAMESPACE && !SYZ_SANDBOX_ANDROID
			close_fds();
#endif
#if SYZ_MULTI_PROC
		}
	}
	sleep(1000000);
#endif
#if !SYZ_MULTI_PROC && !SYZ_REPEAT && SYZ_LEAK
	check_leaks();
#endif
	return 0;
}
#endif
`
