update linux reproducers

Linux reproducers updates from
https://github.com/dvyukov/syzkaller-repros

Signed-off-by: Dmitry Vyukov <dvyukov@google.com>
Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>
diff --git a/syzkaller-repros/linux/.gitignore b/syzkaller-repros/linux/.gitignore
new file mode 100644
index 0000000..a3af5e7
--- /dev/null
+++ b/syzkaller-repros/linux/.gitignore
@@ -0,0 +1,2 @@
+*.norepro
+*.syz
diff --git a/syzkaller-repros/linux/0003deaa9f80de950cb6e0d2cb04c59b4f33a928.c b/syzkaller-repros/linux/0003deaa9f80de950cb6e0d2cb04c59b4f33a928.c
new file mode 100644
index 0000000..05ce3b8
--- /dev/null
+++ b/syzkaller-repros/linux/0003deaa9f80de950cb6e0d2cb04c59b4f33a928.c
@@ -0,0 +1,357 @@
+// INFO: task hung in nbd_ioctl
+// https://syzkaller.appspot.com/bug?id=0003deaa9f80de950cb6e0d2cb04c59b4f33a928
+// status:fixed
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.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>
+
+static __thread int skip_segv;
+static __thread jmp_buf segv_env;
+
+static void segv_handler(int sig, siginfo_t* info, void* ctx)
+{
+  uintptr_t addr = (uintptr_t)info->si_addr;
+  const uintptr_t prog_start = 1 << 20;
+  const uintptr_t prog_end = 100 << 20;
+  if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED) &&
+      (addr < prog_start || addr > prog_end)) {
+    _longjmp(segv_env, 1);
+  }
+  exit(sig);
+}
+
+static void install_segv_handler(void)
+{
+  struct sigaction sa;
+  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);
+  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(...)                                                        \
+  {                                                                            \
+    __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST);                       \
+    if (_setjmp(segv_env) == 0) {                                              \
+      __VA_ARGS__;                                                             \
+    }                                                                          \
+    __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST);                       \
+  }
+
+static void sleep_ms(uint64_t ms)
+{
+  usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+  struct timespec ts;
+  if (clock_gettime(CLOCK_MONOTONIC, &ts))
+    exit(1);
+  return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+  char buf[1024];
+  va_list args;
+  va_start(args, what);
+  vsnprintf(buf, sizeof(buf), what, args);
+  va_end(args);
+  buf[sizeof(buf) - 1] = 0;
+  int len = strlen(buf);
+  int fd = open(file, O_WRONLY | O_CLOEXEC);
+  if (fd == -1)
+    return false;
+  if (write(fd, buf, len) != len) {
+    int err = errno;
+    close(fd);
+    errno = err;
+    return false;
+  }
+  close(fd);
+  return true;
+}
+
+static struct {
+  char* pos;
+  int nesting;
+  struct nlattr* nested[8];
+  char buf[1024];
+} nlmsg;
+
+static void netlink_init(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(int typ, const void* data, int size)
+{
+  struct nlattr* attr = (struct nlattr*)nlmsg.pos;
+  attr->nla_len = sizeof(*attr) + size;
+  attr->nla_type = typ;
+  memcpy(attr + 1, data, size);
+  nlmsg.pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(int sock, uint16_t reply_type, int* reply_len)
+{
+  if (nlmsg.pos > nlmsg.buf + sizeof(nlmsg.buf) || nlmsg.nesting)
+    exit(1);
+  struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg.buf;
+  hdr->nlmsg_len = nlmsg.pos - nlmsg.buf;
+  struct sockaddr_nl addr;
+  memset(&addr, 0, sizeof(addr));
+  addr.nl_family = AF_NETLINK;
+  unsigned n = sendto(sock, nlmsg.buf, hdr->nlmsg_len, 0,
+                      (struct sockaddr*)&addr, sizeof(addr));
+  if (n != hdr->nlmsg_len)
+    exit(1);
+  n = recv(sock, nlmsg.buf, sizeof(nlmsg.buf), 0);
+  if (n < sizeof(struct nlmsghdr))
+    exit(1);
+  if (reply_len && hdr->nlmsg_type == reply_type) {
+    *reply_len = n;
+    return 0;
+  }
+  if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+    exit(1);
+  if (hdr->nlmsg_type != NLMSG_ERROR)
+    exit(1);
+  return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(int sock)
+{
+  return netlink_send_ext(sock, 0, NULL);
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETNS_FD 137
+
+static void netlink_devlink_netns_move(const char* bus_name,
+                                       const char* dev_name, int netns_fd)
+{
+  struct genlmsghdr genlhdr;
+  struct nlattr* attr;
+  int sock, err, n;
+  uint16_t id = 0;
+  sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+  if (sock == -1)
+    exit(1);
+  memset(&genlhdr, 0, sizeof(genlhdr));
+  genlhdr.cmd = CTRL_CMD_GETFAMILY;
+  netlink_init(GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+  netlink_attr(CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+               strlen(DEVLINK_FAMILY_NAME) + 1);
+  err = netlink_send_ext(sock, GENL_ID_CTRL, &n);
+  if (err) {
+    goto error;
+  }
+  attr =
+      (struct nlattr*)(nlmsg.buf + NLMSG_HDRLEN + NLMSG_ALIGN(sizeof(genlhdr)));
+  for (; (char*)attr < nlmsg.buf + n;
+       attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+    if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+      id = *(uint16_t*)(attr + 1);
+      break;
+    }
+  }
+  if (!id) {
+    goto error;
+  }
+  recv(sock, nlmsg.buf, sizeof(nlmsg.buf), 0); /* recv ack */
+  memset(&genlhdr, 0, sizeof(genlhdr));
+  genlhdr.cmd = DEVLINK_CMD_RELOAD;
+  netlink_init(id, 0, &genlhdr, sizeof(genlhdr));
+  netlink_attr(DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+  netlink_attr(DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+  netlink_attr(DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+  netlink_send(sock);
+error:
+  close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+  int netns = open("/proc/self/ns/net", O_RDONLY);
+  if (netns == -1)
+    exit(1);
+  int ret = setns(kInitNetNsFd, 0);
+  if (ret == -1)
+    exit(1);
+  netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+  ret = setns(netns, 0);
+  if (ret == -1)
+    exit(1);
+  close(netns);
+}
+
+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_t)a1,
+            (uint8_t)a2);
+    return open(buf, O_RDWR, 0);
+  } else {
+    char buf[1024];
+    char* hash;
+    NONFAILING(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);
+  }
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+  kill(-pid, SIGKILL);
+  kill(pid, SIGKILL);
+  int i;
+  for (i = 0; i < 100; i++) {
+    if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+      return;
+    usleep(1000);
+  }
+  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) {
+        continue;
+      }
+      if (write(fd, abort, 1) < 0) {
+      }
+      close(fd);
+    }
+    closedir(dir);
+  } else {
+  }
+  while (waitpid(-1, status, __WALL) != pid) {
+  }
+}
+
+static void setup_test()
+{
+  prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+  setpgrp();
+  write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+  int iter;
+  for (iter = 0;; iter++) {
+    int pid = fork();
+    if (pid < 0)
+      exit(1);
+    if (pid == 0) {
+      setup_test();
+      execute_one();
+      exit(0);
+    }
+    int status = 0;
+    uint64_t start = current_time_ms();
+    for (;;) {
+      if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+        break;
+      sleep_ms(1);
+      if (current_time_ms() - start < 5 * 1000)
+        continue;
+      kill_and_wait(pid, &status);
+      break;
+    }
+  }
+}
+
+uint64_t r[3] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_one(void)
+{
+  intptr_t res = 0;
+  res = syscall(__NR_socket, 0x10, 2, 0);
+  if (res != -1)
+    r[0] = res;
+  NONFAILING(memcpy((void*)0x200001c0, "/dev/nbd#\000", 10));
+  res = syz_open_dev(0x200001c0, 0, 0);
+  if (res != -1)
+    r[1] = res;
+  res = syz_open_dev(0, 0, 0);
+  if (res != -1)
+    r[2] = res;
+  syscall(__NR_ioctl, r[1], 0xab00, r[0]);
+  syscall(__NR_ioctl, r[2], 0xab03, 0);
+}
+int main(void)
+{
+  syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+  install_segv_handler();
+  loop();
+  return 0;
+}
diff --git a/syzkaller-repros/linux/001fc3c152ea89d7baa8b1df4c498ee41cb1d973.c b/syzkaller-repros/linux/001fc3c152ea89d7baa8b1df4c498ee41cb1d973.c
new file mode 100644
index 0000000..875f197
--- /dev/null
+++ b/syzkaller-repros/linux/001fc3c152ea89d7baa8b1df4c498ee41cb1d973.c
@@ -0,0 +1,851 @@
+// KMSAN: kernel-infoleak in hidraw_ioctl
+// https://syzkaller.appspot.com/bug?id=001fc3c152ea89d7baa8b1df4c498ee41cb1d973
+// status:invalid
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/usb/ch9.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+  usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+  struct timespec ts;
+  if (clock_gettime(CLOCK_MONOTONIC, &ts))
+    exit(1);
+  return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void use_temporary_dir(void)
+{
+  char tmpdir_template[] = "./syzkaller.XXXXXX";
+  char* tmpdir = mkdtemp(tmpdir_template);
+  if (!tmpdir)
+    exit(1);
+  if (chmod(tmpdir, 0777))
+    exit(1);
+  if (chdir(tmpdir))
+    exit(1);
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+  char buf[1024];
+  va_list args;
+  va_start(args, what);
+  vsnprintf(buf, sizeof(buf), what, args);
+  va_end(args);
+  buf[sizeof(buf) - 1] = 0;
+  int len = strlen(buf);
+  int fd = open(file, O_WRONLY | O_CLOEXEC);
+  if (fd == -1)
+    return false;
+  if (write(fd, buf, len) != len) {
+    int err = errno;
+    close(fd);
+    errno = err;
+    return false;
+  }
+  close(fd);
+  return true;
+}
+
+#define USB_DEBUG 0
+
+#define USB_MAX_IFACE_NUM 4
+#define USB_MAX_EP_NUM 32
+
+struct usb_iface_index {
+  struct usb_interface_descriptor* iface;
+  struct usb_endpoint_descriptor* eps[USB_MAX_EP_NUM];
+  unsigned eps_num;
+};
+
+struct usb_device_index {
+  struct usb_device_descriptor* dev;
+  struct usb_config_descriptor* config;
+  unsigned config_length;
+  struct usb_iface_index ifaces[USB_MAX_IFACE_NUM];
+  unsigned ifaces_num;
+};
+
+static bool parse_usb_descriptor(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->config_length = length - sizeof(*index->dev);
+  size_t offset = 0;
+  while (true) {
+    if (offset + 1 >= length)
+      break;
+    uint8_t desc_length = buffer[offset];
+    uint8_t 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);
+      index->ifaces[index->ifaces_num++].iface = iface;
+    }
+    if (desc_type == USB_DT_ENDPOINT && index->ifaces_num > 0) {
+      struct usb_iface_index* iface = &index->ifaces[index->ifaces_num - 1];
+      if (iface->eps_num < USB_MAX_EP_NUM)
+        iface->eps[iface->eps_num++] =
+            (struct usb_endpoint_descriptor*)(buffer + offset);
+    }
+    offset += desc_length;
+  }
+  return true;
+}
+
+enum usb_fuzzer_event_type {
+  USB_FUZZER_EVENT_INVALID,
+  USB_FUZZER_EVENT_CONNECT,
+  USB_FUZZER_EVENT_DISCONNECT,
+  USB_FUZZER_EVENT_SUSPEND,
+  USB_FUZZER_EVENT_RESUME,
+  USB_FUZZER_EVENT_CONTROL,
+};
+
+struct usb_fuzzer_event {
+  uint32_t type;
+  uint32_t length;
+  char data[0];
+};
+
+struct usb_fuzzer_init {
+  uint64_t speed;
+  const char* driver_name;
+  const char* device_name;
+};
+
+struct usb_fuzzer_ep_io {
+  uint16_t ep;
+  uint16_t flags;
+  uint32_t length;
+  char data[0];
+};
+
+#define USB_FUZZER_IOCTL_INIT _IOW('U', 0, struct usb_fuzzer_init)
+#define USB_FUZZER_IOCTL_RUN _IO('U', 1)
+#define USB_FUZZER_IOCTL_EVENT_FETCH _IOR('U', 2, struct usb_fuzzer_event)
+#define USB_FUZZER_IOCTL_EP0_WRITE _IOW('U', 3, struct usb_fuzzer_ep_io)
+#define USB_FUZZER_IOCTL_EP0_READ _IOWR('U', 4, struct usb_fuzzer_ep_io)
+#define USB_FUZZER_IOCTL_EP_ENABLE _IOW('U', 5, struct usb_endpoint_descriptor)
+#define USB_FUZZER_IOCTL_EP_WRITE _IOW('U', 7, struct usb_fuzzer_ep_io)
+#define USB_FUZZER_IOCTL_EP_READ _IOWR('U', 8, struct usb_fuzzer_ep_io)
+#define USB_FUZZER_IOCTL_CONFIGURE _IO('U', 9)
+#define USB_FUZZER_IOCTL_VBUS_DRAW _IOW('U', 10, uint32_t)
+
+int usb_fuzzer_open()
+{
+  return open("/sys/kernel/debug/usb-fuzzer", O_RDWR);
+}
+
+int usb_fuzzer_init(int fd, uint32_t speed, const char* driver,
+                    const char* device)
+{
+  struct usb_fuzzer_init arg;
+  arg.speed = speed;
+  arg.driver_name = driver;
+  arg.device_name = device;
+  return ioctl(fd, USB_FUZZER_IOCTL_INIT, &arg);
+}
+
+int usb_fuzzer_run(int fd)
+{
+  return ioctl(fd, USB_FUZZER_IOCTL_RUN, 0);
+}
+
+int usb_fuzzer_event_fetch(int fd, struct usb_fuzzer_event* event)
+{
+  return ioctl(fd, USB_FUZZER_IOCTL_EVENT_FETCH, event);
+}
+
+int usb_fuzzer_ep0_write(int fd, struct usb_fuzzer_ep_io* io)
+{
+  return ioctl(fd, USB_FUZZER_IOCTL_EP0_WRITE, io);
+}
+
+int usb_fuzzer_ep0_read(int fd, struct usb_fuzzer_ep_io* io)
+{
+  return ioctl(fd, USB_FUZZER_IOCTL_EP0_READ, io);
+}
+
+int usb_fuzzer_ep_write(int fd, struct usb_fuzzer_ep_io* io)
+{
+  return ioctl(fd, USB_FUZZER_IOCTL_EP_WRITE, io);
+}
+
+int usb_fuzzer_ep_read(int fd, struct usb_fuzzer_ep_io* io)
+{
+  return ioctl(fd, USB_FUZZER_IOCTL_EP_READ, io);
+}
+
+int usb_fuzzer_ep_enable(int fd, struct usb_endpoint_descriptor* desc)
+{
+  return ioctl(fd, USB_FUZZER_IOCTL_EP_ENABLE, desc);
+}
+
+int usb_fuzzer_configure(int fd)
+{
+  return ioctl(fd, USB_FUZZER_IOCTL_CONFIGURE, 0);
+}
+
+int usb_fuzzer_vbus_draw(int fd, uint32_t power)
+{
+  return ioctl(fd, USB_FUZZER_IOCTL_VBUS_DRAW, power);
+}
+
+#define USB_MAX_PACKET_SIZE 1024
+
+struct usb_fuzzer_control_event {
+  struct usb_fuzzer_event inner;
+  struct usb_ctrlrequest ctrl;
+  char data[USB_MAX_PACKET_SIZE];
+};
+
+struct usb_fuzzer_ep_io_data {
+  struct usb_fuzzer_ep_io inner;
+  char data[USB_MAX_PACKET_SIZE];
+};
+
+struct vusb_connect_string_descriptor {
+  uint32_t len;
+  char* str;
+} __attribute__((packed));
+
+struct vusb_connect_descriptors {
+  uint32_t qual_len;
+  char* qual;
+  uint32_t bos_len;
+  char* bos;
+  uint32_t strs_len;
+  struct vusb_connect_string_descriptor strs[0];
+} __attribute__((packed));
+
+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(struct vusb_connect_descriptors* descs,
+                                    struct usb_device_index* index,
+                                    struct usb_ctrlrequest* ctrl,
+                                    char** response_data,
+                                    uint32_t* response_length)
+{
+  uint8_t str_idx;
+  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_t)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) {
+          struct usb_qualifier_descriptor* qual =
+              (struct usb_qualifier_descriptor*)response_data;
+          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_length = sizeof(*qual);
+          return true;
+        }
+        *response_data = descs->qual;
+        *response_length = descs->qual_len;
+        return true;
+      default:
+        exit(1);
+        return false;
+      }
+      break;
+    default:
+      exit(1);
+      return false;
+    }
+    break;
+  default:
+    exit(1);
+    return false;
+  }
+  return false;
+}
+
+static volatile long syz_usb_connect(volatile long a0, volatile long a1,
+                                     volatile long a2, volatile long a3)
+{
+  uint64_t speed = a0;
+  uint64_t dev_len = a1;
+  char* dev = (char*)a2;
+  struct vusb_connect_descriptors* descs = (struct vusb_connect_descriptors*)a3;
+  if (!dev) {
+    return -1;
+  }
+  struct usb_device_index index;
+  memset(&index, 0, sizeof(index));
+  int rv = 0;
+  rv = parse_usb_descriptor(dev, dev_len, &index);
+  if (!rv) {
+    return rv;
+  }
+  int fd = usb_fuzzer_open();
+  if (fd < 0) {
+    return fd;
+  }
+  char device[32];
+  sprintf(&device[0], "dummy_udc.%llu", procid);
+  rv = usb_fuzzer_init(fd, speed, "dummy_udc", &device[0]);
+  if (rv < 0) {
+    return rv;
+  }
+  rv = usb_fuzzer_run(fd);
+  if (rv < 0) {
+    return rv;
+  }
+  bool done = false;
+  while (!done) {
+    struct usb_fuzzer_control_event event;
+    event.inner.type = 0;
+    event.inner.length = sizeof(event.ctrl);
+    rv = usb_fuzzer_event_fetch(fd, (struct usb_fuzzer_event*)&event);
+    if (rv < 0) {
+      return rv;
+    }
+    if (event.inner.type != USB_FUZZER_EVENT_CONTROL)
+      continue;
+    bool response_found = false;
+    char* response_data = NULL;
+    uint32_t response_length = 0;
+    if (event.ctrl.bRequestType & USB_DIR_IN) {
+      response_found = lookup_connect_response(
+          descs, &index, &event.ctrl, &response_data, &response_length);
+      if (!response_found) {
+        return -1;
+      }
+    } else {
+      if ((event.ctrl.bRequestType & USB_TYPE_MASK) != USB_TYPE_STANDARD ||
+          event.ctrl.bRequest != USB_REQ_SET_CONFIGURATION) {
+        exit(1);
+        return -1;
+      }
+      done = true;
+    }
+    if (done) {
+      rv = usb_fuzzer_vbus_draw(fd, index.config->bMaxPower);
+      if (rv < 0) {
+        return rv;
+      }
+      rv = usb_fuzzer_configure(fd);
+      if (rv < 0) {
+        return rv;
+      }
+      unsigned ep;
+      for (ep = 0; ep < index.ifaces[0].eps_num; ep++) {
+        rv = usb_fuzzer_ep_enable(fd, index.ifaces[0].eps[ep]);
+        if (rv < 0) {
+        } else {
+        }
+      }
+    }
+    struct usb_fuzzer_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) {
+      rv = usb_fuzzer_ep0_write(fd, (struct usb_fuzzer_ep_io*)&response);
+    } else {
+      rv = usb_fuzzer_ep0_read(fd, (struct usb_fuzzer_ep_io*)&response);
+    }
+    if (rv < 0) {
+      return rv;
+    }
+  }
+  sleep_ms(200);
+  return fd;
+}
+
+struct vusb_descriptor {
+  uint8_t req_type;
+  uint8_t desc_type;
+  uint32_t len;
+  char data[0];
+} __attribute__((packed));
+
+struct vusb_descriptors {
+  uint32_t len;
+  struct vusb_descriptor* generic;
+  struct vusb_descriptor* descs[0];
+} __attribute__((packed));
+
+struct vusb_response {
+  uint8_t type;
+  uint8_t req;
+  uint32_t len;
+  char data[0];
+} __attribute__((packed));
+
+struct vusb_responses {
+  uint32_t len;
+  struct vusb_response* generic;
+  struct vusb_response* resps[0];
+} __attribute__((packed));
+
+static bool lookup_control_response(struct vusb_descriptors* descs,
+                                    struct vusb_responses* resps,
+                                    struct usb_ctrlrequest* ctrl,
+                                    char** response_data,
+                                    uint32_t* 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_t req = ctrl->bRequest;
+  uint8_t req_type = ctrl->bRequestType & USB_TYPE_MASK;
+  uint8_t 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;
+}
+
+static volatile long syz_usb_control_io(volatile long a0, volatile long a1,
+                                        volatile long a2)
+{
+  int fd = a0;
+  struct vusb_descriptors* descs = (struct vusb_descriptors*)a1;
+  struct vusb_responses* resps = (struct vusb_responses*)a2;
+  struct usb_fuzzer_control_event event;
+  event.inner.type = 0;
+  event.inner.length = USB_MAX_PACKET_SIZE;
+  int rv = usb_fuzzer_event_fetch(fd, (struct usb_fuzzer_event*)&event);
+  if (rv < 0) {
+    return rv;
+  }
+  if (event.inner.type != USB_FUZZER_EVENT_CONTROL) {
+    return -1;
+  }
+  bool response_found = false;
+  char* response_data = NULL;
+  uint32_t response_length = 0;
+  if ((event.ctrl.bRequestType & USB_DIR_IN) && event.ctrl.wLength) {
+    response_found = lookup_control_response(descs, resps, &event.ctrl,
+                                             &response_data, &response_length);
+    if (!response_found) {
+      return -1;
+    }
+  } else {
+    response_length = event.ctrl.wLength;
+  }
+  struct usb_fuzzer_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) {
+    rv = usb_fuzzer_ep0_write(fd, (struct usb_fuzzer_ep_io*)&response);
+  } else {
+    rv = usb_fuzzer_ep0_read(fd, (struct usb_fuzzer_ep_io*)&response);
+  }
+  if (rv < 0) {
+    return rv;
+  }
+  sleep_ms(200);
+  return 0;
+}
+
+static volatile long syz_usb_disconnect(volatile long a0)
+{
+  int fd = a0;
+  int rv = close(fd);
+  sleep_ms(200);
+  return rv;
+}
+
+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_t)a1,
+            (uint8_t)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);
+  }
+}
+
+#define FS_IOC_SETFLAGS _IOW('f', 2, long)
+static void remove_dir(const char* dir)
+{
+  DIR* dp;
+  struct dirent* ep;
+  int iter = 0;
+retry:
+  while (umount2(dir, MNT_DETACH) == 0) {
+  }
+  dp = opendir(dir);
+  if (dp == NULL) {
+    if (errno == EMFILE) {
+      exit(1);
+    }
+    exit(1);
+  }
+  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);
+    while (umount2(filename, MNT_DETACH) == 0) {
+    }
+    struct stat st;
+    if (lstat(filename, &st))
+      exit(1);
+    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)
+            close(fd);
+          continue;
+        }
+      }
+      if (errno == EROFS) {
+        break;
+      }
+      if (errno != EBUSY || i > 100)
+        exit(1);
+      if (umount2(filename, MNT_DETACH))
+        exit(1);
+    }
+  }
+  closedir(dp);
+  int i;
+  for (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)
+            close(fd);
+          continue;
+        }
+      }
+      if (errno == EROFS) {
+        break;
+      }
+      if (errno == EBUSY) {
+        if (umount2(dir, MNT_DETACH))
+          exit(1);
+        continue;
+      }
+      if (errno == ENOTEMPTY) {
+        if (iter < 100) {
+          iter++;
+          goto retry;
+        }
+      }
+    }
+    exit(1);
+  }
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+  kill(-pid, SIGKILL);
+  kill(pid, SIGKILL);
+  int i;
+  for (i = 0; i < 100; i++) {
+    if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+      return;
+    usleep(1000);
+  }
+  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) {
+        continue;
+      }
+      if (write(fd, abort, 1) < 0) {
+      }
+      close(fd);
+    }
+    closedir(dir);
+  } else {
+  }
+  while (waitpid(-1, status, __WALL) != pid) {
+  }
+}
+
+static void setup_test()
+{
+  prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+  setpgrp();
+  write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+  int iter;
+  for (iter = 0;; iter++) {
+    char cwdbuf[32];
+    sprintf(cwdbuf, "./%d", iter);
+    if (mkdir(cwdbuf, 0777))
+      exit(1);
+    int pid = fork();
+    if (pid < 0)
+      exit(1);
+    if (pid == 0) {
+      if (chdir(cwdbuf))
+        exit(1);
+      setup_test();
+      execute_one();
+      exit(0);
+    }
+    int status = 0;
+    uint64_t start = current_time_ms();
+    for (;;) {
+      if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+        break;
+      sleep_ms(1);
+      if (current_time_ms() - start < 5 * 1000)
+        continue;
+      kill_and_wait(pid, &status);
+      break;
+    }
+    remove_dir(cwdbuf);
+  }
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_one(void)
+{
+  intptr_t res = 0;
+  memcpy(
+      (void*)0x20000680,
+      "\x12\x01\x00\x00\x00\xf6\x00\x08\x4c\x05\xd5\x03\x00\x00\x00\x00\x00\x01"
+      "\x09\x02\x24\x00\x01\x00\x00\xa0\x00\x09\x04\x00\xf5\x08\x03\x00\x00\x00"
+      "\x09\x21\x00\x00\x00\x01\x22\x29\x00\x09\x05\x81\x03\x00\x00\x01\x00\x00"
+      "\x7a\x5e\x60\xbc\xeb\x86\xf7\x37\xd8\xdd\x09\xdd\x05\xfa\x6e\xef\x8d\x5c"
+      "\xff\x4f\xf8\x05\x03\x6d\x2f\xd9\x53\x00\xfa\xc8\x79\xcf\x41\x6e\x82\x2f"
+      "\x58\x17\x66\x92\x5a\xbe\x7d\xf1\x3b\x31\x05\xe2\x95\x86\xe6\x92\x96\xb4"
+      "\x9e\x87\x6c\x47\x37\x35\x37\xe3\x32\xd5\x05\x1b\x11\xe9\x62\xb2\x6a\x1d"
+      "\x63\xfd\xeb\xd1\x0e\x98\xe5\xee\x57\x9d\xf5\x27\xa2\x3f\x11\xa2\x80\x5d"
+      "\x7a\x50\x28\xa4\xd2\xbf\x56\xc8\x87\xa4\xe6\xa6\x63\x4e\xf4\xb7\xb3\x6f"
+      "\x65\x0f\xa5\x4f\xcd\x2f\xb5\x0b\x5e\x42\xde\x7f\x73\x72\x29\xcb\x87\x16"
+      "\x52\x60\x25\xba\x06\x05\x18\x66\xec\xda\xdc\xe3\x0e\xc2\x34\x1d\x39\x9a"
+      "\x47\x2d\x27\x6c\x61\x16\x98\x64\x6d\x07\x6f\x60\x32\xaf\x22\x4f\x09\xb9"
+      "\x26\xe2\x09\x34\x2a\xb2\xb0\xfa\xc7\x03\xb8\xa2\xf2\x75\xc6\x21\x37\xd8"
+      "\x0b\x74\xae\x40\xaf\x65\xa8\x78\x38\xbc\x0e\xf7\x8a\x2c\xdd\x33\xe3\x70"
+      "\x67\xf4\xc9\x95\x68\x04\x53\xf3\x11\xe9\x06\x4b\x3b\x5a\xff\xc7\xa8\xe0"
+      "\xc5\xe3\x6f\x8c\x54\x69\x28\x60\x5c\x8d\xbd\xee\xbd\x9b\x52\xfb\x29\x1d"
+      "\x2b\xec\xf4\xf0\xa0\x7f\xc6\xf1\x2a\x72\x8a\xe4\x2e\x30\x52\x0c\x1c\xd1"
+      "\xce\x05\x26\xb5\x76\x3a\xb6\x1b\x1e\xd0\x8a\x98\xc8\x0b\xcc\x1f\x07\x94"
+      "\x4e\x0b\xc0\x5b\xd7\xfe\x90\x71\x78\xc9\xe8\x0a\xef\x73\x10\xa6\x7e\x90"
+      "\xa7\xa6\x9c\x4b\x9a\x8a\xe5\xba\x9a\x8a\x6b\x8c\x90\x3a\xf5\x61\x68\xe9"
+      "\x9e\x7e\xe6\x7a\xf9\x54\xd2\x30\x03\x52\xca\x84\xcd\x9d\x48\xee\x18\xfc"
+      "\xd2\x24\x51\x0b\xc7\xc1\x05\xe4\x0d\x18\x9e\x1a\x27\x42",
+      392);
+  res = syz_usb_connect(0, 0x36, 0x20000680, 0);
+  if (res != -1)
+    r[0] = res;
+  *(uint32_t*)0x20000300 = 0x2e;
+  *(uint64_t*)0x20000304 = 0;
+  *(uint64_t*)0x2000030c = 0;
+  *(uint64_t*)0x20000314 = 0;
+  *(uint64_t*)0x2000031c = 0x20000180;
+  *(uint8_t*)0x20000180 = 0;
+  *(uint8_t*)0x20000181 = 0x22;
+  *(uint32_t*)0x20000182 = 0x29;
+  *(uint8_t*)0x20000186 = 0;
+  *(uint8_t*)0x20000187 = 0x21;
+  *(uint16_t*)0x20000188 = 0;
+  *(uint8_t*)0x2000018a = 0;
+  *(uint8_t*)0x2000018b = 1;
+  *(uint8_t*)0x2000018c = 0x22;
+  *(uint16_t*)0x2000018d = 0;
+  *(uint32_t*)0x20000fc0 = 0x7349f68b;
+  *(uint64_t*)0x20000fc4 = 0;
+  *(uint64_t*)0x20000fcc = 0;
+  *(uint64_t*)0x20000fd4 = 0;
+  *(uint64_t*)0x20000fdc = 0;
+  *(uint64_t*)0x20000fe4 = 0;
+  syz_usb_control_io(r[0], 0x20000300, 0x20000fc0);
+  memcpy((void*)0x20000b00, "/dev/hidraw#\000", 13);
+  res = syz_open_dev(0x20000b00, 0, 0);
+  if (res != -1)
+    r[1] = res;
+  syz_usb_disconnect(r[0]);
+  syscall(__NR_ioctl, r[1], 0x80084803, 0x200000c0);
+}
+int main(void)
+{
+  syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+  for (procid = 0; procid < 6; procid++) {
+    if (fork() == 0) {
+      use_temporary_dir();
+      loop();
+    }
+  }
+  sleep(1000000);
+  return 0;
+}
diff --git a/syzkaller-repros/linux/0038087ef1d84bbfc785228a26b2fd914d7d32d0.c b/syzkaller-repros/linux/0038087ef1d84bbfc785228a26b2fd914d7d32d0.c
new file mode 100644
index 0000000..91d6188
--- /dev/null
+++ b/syzkaller-repros/linux/0038087ef1d84bbfc785228a26b2fd914d7d32d0.c
@@ -0,0 +1,1836 @@
+// KASAN: use-after-free Read in hci_cmd_timeout
+// https://syzkaller.appspot.com/bug?id=0038087ef1d84bbfc785228a26b2fd914d7d32d0
+// status:open
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <sched.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+#include <linux/futex.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static __thread int skip_segv;
+static __thread jmp_buf segv_env;
+
+static void segv_handler(int sig, siginfo_t* info, void* ctx)
+{
+  uintptr_t addr = (uintptr_t)info->si_addr;
+  const uintptr_t prog_start = 1 << 20;
+  const uintptr_t prog_end = 100 << 20;
+  if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED) &&
+      (addr < prog_start || addr > prog_end)) {
+    _longjmp(segv_env, 1);
+  }
+  exit(sig);
+}
+
+static void install_segv_handler(void)
+{
+  struct sigaction sa;
+  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);
+  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(...)                                                        \
+  {                                                                            \
+    __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST);                       \
+    if (_setjmp(segv_env) == 0) {                                              \
+      __VA_ARGS__;                                                             \
+    }                                                                          \
+    __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST);                       \
+  }
+
+static void sleep_ms(uint64_t ms)
+{
+  usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+  struct timespec ts;
+  if (clock_gettime(CLOCK_MONOTONIC, &ts))
+    exit(1);
+  return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void use_temporary_dir(void)
+{
+  char tmpdir_template[] = "./syzkaller.XXXXXX";
+  char* tmpdir = mkdtemp(tmpdir_template);
+  if (!tmpdir)
+    exit(1);
+  if (chmod(tmpdir, 0777))
+    exit(1);
+  if (chdir(tmpdir))
+    exit(1);
+}
+
+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;
+  for (i = 0; i < 100; i++) {
+    if (pthread_create(&th, &attr, fn, arg) == 0) {
+      pthread_attr_destroy(&attr);
+      return;
+    }
+    if (errno == EAGAIN) {
+      usleep(50);
+      continue;
+    }
+    break;
+  }
+  exit(1);
+}
+
+#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))))
+
+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)
+    exit(1);
+  __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+  syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG);
+}
+
+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_t timeout)
+{
+  uint64_t start = current_time_ms();
+  uint64_t now = start;
+  for (;;) {
+    uint64_t 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_RELAXED))
+      return 1;
+    now = current_time_ms();
+    if (now - start > timeout)
+      return 0;
+  }
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+  char buf[1024];
+  va_list args;
+  va_start(args, what);
+  vsnprintf(buf, sizeof(buf), what, args);
+  va_end(args);
+  buf[sizeof(buf) - 1] = 0;
+  int len = strlen(buf);
+  int fd = open(file, O_WRONLY | O_CLOEXEC);
+  if (fd == -1)
+    return false;
+  if (write(fd, buf, len) != len) {
+    int err = errno;
+    close(fd);
+    errno = err;
+    return false;
+  }
+  close(fd);
+  return true;
+}
+
+struct nlmsg {
+  char* pos;
+  int nesting;
+  struct nlattr* nested[8];
+  char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+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;
+  memcpy(attr + 1, data, size);
+  nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static void netlink_nest(struct nlmsg* nlmsg, int typ)
+{
+  struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+  attr->nla_type = typ;
+  nlmsg->pos += sizeof(*attr);
+  nlmsg->nested[nlmsg->nesting++] = attr;
+}
+
+static void netlink_done(struct nlmsg* nlmsg)
+{
+  struct nlattr* attr = nlmsg->nested[--nlmsg->nesting];
+  attr->nla_len = nlmsg->pos - (char*)attr;
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+                            int* reply_len)
+{
+  if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+    exit(1);
+  struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+  hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+  struct sockaddr_nl addr;
+  memset(&addr, 0, sizeof(addr));
+  addr.nl_family = AF_NETLINK;
+  unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+                      (struct sockaddr*)&addr, sizeof(addr));
+  if (n != hdr->nlmsg_len)
+    exit(1);
+  n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+  if (hdr->nlmsg_type == NLMSG_DONE) {
+    *reply_len = 0;
+    return 0;
+  }
+  if (n < sizeof(struct nlmsghdr))
+    exit(1);
+  if (reply_len && hdr->nlmsg_type == reply_type) {
+    *reply_len = n;
+    return 0;
+  }
+  if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+    exit(1);
+  if (hdr->nlmsg_type != NLMSG_ERROR)
+    exit(1);
+  return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+  return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+                            unsigned int total_len)
+{
+  struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+  if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+    return -1;
+  return hdr->nlmsg_len;
+}
+
+static void netlink_add_device_impl(struct nlmsg* nlmsg, const char* type,
+                                    const char* name)
+{
+  struct ifinfomsg hdr;
+  memset(&hdr, 0, sizeof(hdr));
+  netlink_init(nlmsg, RTM_NEWLINK, NLM_F_EXCL | NLM_F_CREATE, &hdr,
+               sizeof(hdr));
+  if (name)
+    netlink_attr(nlmsg, IFLA_IFNAME, name, strlen(name));
+  netlink_nest(nlmsg, IFLA_LINKINFO);
+  netlink_attr(nlmsg, IFLA_INFO_KIND, type, strlen(type));
+}
+
+static void netlink_add_device(struct nlmsg* nlmsg, int sock, const char* type,
+                               const char* name)
+{
+  netlink_add_device_impl(nlmsg, type, name);
+  netlink_done(nlmsg);
+  int err = netlink_send(nlmsg, sock);
+  (void)err;
+}
+
+static void netlink_add_veth(struct nlmsg* nlmsg, int sock, const char* name,
+                             const char* peer)
+{
+  netlink_add_device_impl(nlmsg, "veth", name);
+  netlink_nest(nlmsg, IFLA_INFO_DATA);
+  netlink_nest(nlmsg, VETH_INFO_PEER);
+  nlmsg->pos += sizeof(struct ifinfomsg);
+  netlink_attr(nlmsg, IFLA_IFNAME, peer, strlen(peer));
+  netlink_done(nlmsg);
+  netlink_done(nlmsg);
+  netlink_done(nlmsg);
+  int err = netlink_send(nlmsg, sock);
+  (void)err;
+}
+
+static void netlink_add_hsr(struct nlmsg* nlmsg, int sock, const char* name,
+                            const char* slave1, const char* slave2)
+{
+  netlink_add_device_impl(nlmsg, "hsr", name);
+  netlink_nest(nlmsg, IFLA_INFO_DATA);
+  int ifindex1 = if_nametoindex(slave1);
+  netlink_attr(nlmsg, IFLA_HSR_SLAVE1, &ifindex1, sizeof(ifindex1));
+  int ifindex2 = if_nametoindex(slave2);
+  netlink_attr(nlmsg, IFLA_HSR_SLAVE2, &ifindex2, sizeof(ifindex2));
+  netlink_done(nlmsg);
+  netlink_done(nlmsg);
+  int err = netlink_send(nlmsg, sock);
+  (void)err;
+}
+
+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);
+  (void)err;
+}
+
+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));
+  (void)err;
+}
+
+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));
+  (void)err;
+}
+
+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);
+  (void)err;
+}
+
+static int tunfd = -1;
+static int tun_frags_enabled;
+
+#define TUN_IFACE "syz_tun"
+
+#define LOCAL_MAC 0xaaaaaaaaaaaa
+#define REMOTE_MAC 0xaaaaaaaaaabb
+
+#define LOCAL_IPV4 "172.20.20.170"
+#define REMOTE_IPV4 "172.20.20.187"
+
+#define LOCAL_IPV6 "fe80::aa"
+#define REMOTE_IPV6 "fe80::bb"
+
+#define IFF_NAPI 0x0010
+#define IFF_NAPI_FRAGS 0x0020
+
+static void initialize_tun(void)
+{
+  tunfd = open("/dev/net/tun", O_RDWR | O_NONBLOCK);
+  if (tunfd == -1) {
+    printf("tun: can't open /dev/net/tun: please enable CONFIG_TUN=y\n");
+    printf("otherwise fuzzing or reproducing might not work as intended\n");
+    return;
+  }
+  const int kTunFd = 240;
+  if (dup2(tunfd, kTunFd) < 0)
+    exit(1);
+  close(tunfd);
+  tunfd = kTunFd;
+  struct ifreq ifr;
+  memset(&ifr, 0, sizeof(ifr));
+  strncpy(ifr.ifr_name, TUN_IFACE, IFNAMSIZ);
+  ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_NAPI | IFF_NAPI_FRAGS;
+  if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0) {
+    ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+    if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0)
+      exit(1);
+  }
+  if (ioctl(tunfd, TUNGETIFF, (void*)&ifr) < 0)
+    exit(1);
+  tun_frags_enabled = (ifr.ifr_flags & IFF_NAPI_FRAGS) != 0;
+  char sysctl[64];
+  sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/accept_dad", TUN_IFACE);
+  write_file(sysctl, "0");
+  sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/router_solicitations", TUN_IFACE);
+  write_file(sysctl, "0");
+  int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+  if (sock == -1)
+    exit(1);
+  netlink_add_addr4(&nlmsg, sock, TUN_IFACE, LOCAL_IPV4);
+  netlink_add_addr6(&nlmsg, sock, TUN_IFACE, LOCAL_IPV6);
+  uint64_t macaddr = REMOTE_MAC;
+  struct in_addr in_addr;
+  inet_pton(AF_INET, REMOTE_IPV4, &in_addr);
+  netlink_add_neigh(&nlmsg, sock, TUN_IFACE, &in_addr, sizeof(in_addr),
+                    &macaddr, ETH_ALEN);
+  struct in6_addr in6_addr;
+  inet_pton(AF_INET6, REMOTE_IPV6, &in6_addr);
+  netlink_add_neigh(&nlmsg, sock, TUN_IFACE, &in6_addr, sizeof(in6_addr),
+                    &macaddr, ETH_ALEN);
+  macaddr = LOCAL_MAC;
+  netlink_device_change(&nlmsg, sock, TUN_IFACE, true, 0, &macaddr, ETH_ALEN,
+                        NULL);
+  close(sock);
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+  struct genlmsghdr genlhdr;
+  struct nlattr* attr;
+  int err, n;
+  uint16_t id = 0;
+  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, DEVLINK_FAMILY_NAME,
+               strlen(DEVLINK_FAMILY_NAME) + 1);
+  err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+  if (err) {
+    return -1;
+  }
+  attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+                          NLMSG_ALIGN(sizeof(genlhdr)));
+  for (; (char*)attr < nlmsg->buf + n;
+       attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+    if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+      id = *(uint16_t*)(attr + 1);
+      break;
+    }
+  }
+  if (!id) {
+    return -1;
+  }
+  recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+  return id;
+}
+
+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)
+    exit(1);
+  id = netlink_devlink_id_get(&nlmsg, sock);
+  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) {
+  }
+error:
+  close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+                                     const char* netdev_prefix)
+{
+  struct genlmsghdr genlhdr;
+  int len, total_len, id, err, offset;
+  uint16_t netdev_index;
+  int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+  if (sock == -1)
+    exit(1);
+  int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+  if (rtsock == -1)
+    exit(1);
+  id = netlink_devlink_id_get(&nlmsg, sock);
+  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);
+  if (err) {
+    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);
+}
+
+static void initialize_devlink_pci(void)
+{
+  int netns = open("/proc/self/ns/net", O_RDONLY);
+  if (netns == -1)
+    exit(1);
+  int ret = setns(kInitNetNsFd, 0);
+  if (ret == -1)
+    exit(1);
+  netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+  ret = setns(netns, 0);
+  if (ret == -1)
+    exit(1);
+  close(netns);
+  initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+#define DEV_IPV4 "172.20.20.%d"
+#define DEV_IPV6 "fe80::%02x"
+#define DEV_MAC 0x00aaaaaaaaaa
+
+static void netdevsim_add(unsigned int addr, unsigned int port_count)
+{
+  char buf[16];
+  sprintf(buf, "%u %u", addr, port_count);
+  if (write_file("/sys/bus/netdevsim/new_device", buf)) {
+    snprintf(buf, sizeof(buf), "netdevsim%d", addr);
+    initialize_devlink_ports("netdevsim", buf, "netdevsim");
+  }
+}
+static void initialize_netdevices(void)
+{
+  char netdevsim[16];
+  sprintf(netdevsim, "netdevsim%d", (int)procid);
+  struct {
+    const char* type;
+    const char* dev;
+  } devtypes[] = {
+      {"ip6gretap", "ip6gretap0"}, {"bridge", "bridge0"},
+      {"vcan", "vcan0"},           {"bond", "bond0"},
+      {"team", "team0"},           {"dummy", "dummy0"},
+      {"nlmon", "nlmon0"},         {"caif", "caif0"},
+      {"batadv", "batadv0"},       {"vxcan", "vxcan1"},
+      {"netdevsim", netdevsim},    {"veth", 0},
+  };
+  const char* devmasters[] = {"bridge", "bond", "team"};
+  struct {
+    const char* name;
+    int macsize;
+    bool noipv6;
+  } devices[] = {
+      {"lo", ETH_ALEN},
+      {"sit0", 0},
+      {"bridge0", ETH_ALEN},
+      {"vcan0", 0, true},
+      {"tunl0", 0},
+      {"gre0", 0},
+      {"gretap0", ETH_ALEN},
+      {"ip_vti0", 0},
+      {"ip6_vti0", 0},
+      {"ip6tnl0", 0},
+      {"ip6gre0", 0},
+      {"ip6gretap0", ETH_ALEN},
+      {"erspan0", ETH_ALEN},
+      {"bond0", ETH_ALEN},
+      {"veth0", ETH_ALEN},
+      {"veth1", ETH_ALEN},
+      {"team0", ETH_ALEN},
+      {"veth0_to_bridge", ETH_ALEN},
+      {"veth1_to_bridge", ETH_ALEN},
+      {"veth0_to_bond", ETH_ALEN},
+      {"veth1_to_bond", ETH_ALEN},
+      {"veth0_to_team", ETH_ALEN},
+      {"veth1_to_team", ETH_ALEN},
+      {"veth0_to_hsr", ETH_ALEN},
+      {"veth1_to_hsr", ETH_ALEN},
+      {"hsr0", 0},
+      {"dummy0", ETH_ALEN},
+      {"nlmon0", 0},
+      {"vxcan0", 0, true},
+      {"vxcan1", 0, true},
+      {"caif0", ETH_ALEN},
+      {"batadv0", ETH_ALEN},
+      {netdevsim, ETH_ALEN},
+  };
+  int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+  if (sock == -1)
+    exit(1);
+  unsigned i;
+  for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++)
+    netlink_add_device(&nlmsg, sock, devtypes[i].type, devtypes[i].dev);
+  for (i = 0; i < sizeof(devmasters) / (sizeof(devmasters[0])); i++) {
+    char master[32], slave0[32], veth0[32], slave1[32], veth1[32];
+    sprintf(slave0, "%s_slave_0", devmasters[i]);
+    sprintf(veth0, "veth0_to_%s", devmasters[i]);
+    netlink_add_veth(&nlmsg, sock, slave0, veth0);
+    sprintf(slave1, "%s_slave_1", devmasters[i]);
+    sprintf(veth1, "veth1_to_%s", devmasters[i]);
+    netlink_add_veth(&nlmsg, sock, slave1, veth1);
+    sprintf(master, "%s0", devmasters[i]);
+    netlink_device_change(&nlmsg, sock, slave0, false, master, 0, 0, NULL);
+    netlink_device_change(&nlmsg, sock, slave1, false, master, 0, 0, NULL);
+  }
+  netlink_device_change(&nlmsg, sock, "bridge_slave_0", true, 0, 0, 0, NULL);
+  netlink_device_change(&nlmsg, sock, "bridge_slave_1", true, 0, 0, 0, NULL);
+  netlink_add_veth(&nlmsg, sock, "hsr_slave_0", "veth0_to_hsr");
+  netlink_add_veth(&nlmsg, sock, "hsr_slave_1", "veth1_to_hsr");
+  netlink_add_hsr(&nlmsg, sock, "hsr0", "hsr_slave_0", "hsr_slave_1");
+  netlink_device_change(&nlmsg, sock, "hsr_slave_0", true, 0, 0, 0, NULL);
+  netlink_device_change(&nlmsg, sock, "hsr_slave_1", true, 0, 0, 0, NULL);
+  netdevsim_add((int)procid, 4);
+  for (i = 0; i < sizeof(devices) / (sizeof(devices[0])); i++) {
+    char addr[32];
+    sprintf(addr, DEV_IPV4, i + 10);
+    netlink_add_addr4(&nlmsg, sock, devices[i].name, addr);
+    if (!devices[i].noipv6) {
+      sprintf(addr, DEV_IPV6, i + 10);
+      netlink_add_addr6(&nlmsg, sock, devices[i].name, addr);
+    }
+    uint64_t macaddr = DEV_MAC + ((i + 10ull) << 40);
+    netlink_device_change(&nlmsg, sock, devices[i].name, true, 0, &macaddr,
+                          devices[i].macsize, NULL);
+  }
+  close(sock);
+}
+static void initialize_netdevices_init(void)
+{
+  int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+  if (sock == -1)
+    exit(1);
+  struct {
+    const char* type;
+    int macsize;
+    bool noipv6;
+    bool noup;
+  } devtypes[] = {
+      {"nr", 7, true},
+      {"rose", 5, true, true},
+  };
+  unsigned i;
+  for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++) {
+    char dev[32], addr[32];
+    sprintf(dev, "%s%d", devtypes[i].type, (int)procid);
+    sprintf(addr, "172.30.%d.%d", i, (int)procid + 1);
+    netlink_add_addr4(&nlmsg, sock, dev, addr);
+    if (!devtypes[i].noipv6) {
+      sprintf(addr, "fe88::%02x:%02x", i, (int)procid + 1);
+      netlink_add_addr6(&nlmsg, sock, dev, addr);
+    }
+    int macsize = devtypes[i].macsize;
+    uint64_t macaddr = 0xbbbbbb +
+                       ((unsigned long long)i << (8 * (macsize - 2))) +
+                       (procid << (8 * (macsize - 1)));
+    netlink_device_change(&nlmsg, sock, dev, !devtypes[i].noup, 0, &macaddr,
+                          macsize, NULL);
+  }
+  close(sock);
+}
+
+static 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;
+    if (errno == EBADFD)
+      return -1;
+    exit(1);
+  }
+  return rv;
+}
+
+static void flush_tun()
+{
+  char data[1000];
+  while (read_tun(&data[0], sizeof(data)) != -1) {
+  }
+}
+
+#define MAX_FDS 30
+
+#define XT_TABLE_SIZE 1536
+#define XT_MAX_ENTRIES 10
+
+struct xt_counters {
+  uint64_t 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;
+  void* entrytable[XT_TABLE_SIZE / sizeof(void*)];
+};
+
+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;
+  char entrytable[XT_TABLE_SIZE];
+};
+
+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;
+  void* entrytable[XT_TABLE_SIZE / sizeof(void*)];
+};
+
+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;
+  char entrytable[XT_TABLE_SIZE];
+};
+
+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)
+{
+  struct ipt_get_entries entries;
+  socklen_t optlen;
+  int fd, i;
+  fd = socket(family, SOCK_STREAM, IPPROTO_TCP);
+  if (fd == -1) {
+    switch (errno) {
+    case EAFNOSUPPORT:
+    case ENOPROTOOPT:
+      return;
+    }
+    exit(1);
+  }
+  for (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);
+    optlen = sizeof(table->info);
+    if (getsockopt(fd, level, IPT_SO_GET_INFO, &table->info, &optlen)) {
+      switch (errno) {
+      case EPERM:
+      case ENOENT:
+      case ENOPROTOOPT:
+        continue;
+      }
+      exit(1);
+    }
+    if (table->info.size > sizeof(table->replace.entrytable))
+      exit(1);
+    if (table->info.num_entries > XT_MAX_ENTRIES)
+      exit(1);
+    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))
+      exit(1);
+    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)
+{
+  struct xt_counters counters[XT_MAX_ENTRIES];
+  struct ipt_get_entries entries;
+  struct ipt_getinfo info;
+  socklen_t optlen;
+  int fd, i;
+  fd = socket(family, SOCK_STREAM, IPPROTO_TCP);
+  if (fd == -1) {
+    switch (errno) {
+    case EAFNOSUPPORT:
+    case ENOPROTOOPT:
+      return;
+    }
+    exit(1);
+  }
+  for (i = 0; i < num_tables; i++) {
+    struct ipt_table_desc* table = &tables[i];
+    if (table->info.valid_hooks == 0)
+      continue;
+    memset(&info, 0, sizeof(info));
+    strcpy(info.name, table->name);
+    optlen = sizeof(info);
+    if (getsockopt(fd, level, IPT_SO_GET_INFO, &info, &optlen))
+      exit(1);
+    if (memcmp(&table->info, &info, sizeof(table->info)) == 0) {
+      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))
+        exit(1);
+      if (memcmp(table->replace.entrytable, entries.entrytable,
+                 table->info.size) == 0)
+        continue;
+    }
+    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))
+      exit(1);
+  }
+  close(fd);
+}
+
+static void checkpoint_arptables(void)
+{
+  struct arpt_get_entries entries;
+  socklen_t optlen;
+  unsigned i;
+  int fd;
+  fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  if (fd == -1) {
+    switch (errno) {
+    case EAFNOSUPPORT:
+    case ENOPROTOOPT:
+      return;
+    }
+    exit(1);
+  }
+  for (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);
+    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;
+      }
+      exit(1);
+    }
+    if (table->info.size > sizeof(table->replace.entrytable))
+      exit(1);
+    if (table->info.num_entries > XT_MAX_ENTRIES)
+      exit(1);
+    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))
+      exit(1);
+    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()
+{
+  struct xt_counters counters[XT_MAX_ENTRIES];
+  struct arpt_get_entries entries;
+  struct arpt_getinfo info;
+  socklen_t optlen;
+  unsigned i;
+  int fd;
+  fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  if (fd == -1) {
+    switch (errno) {
+    case EAFNOSUPPORT:
+    case ENOPROTOOPT:
+      return;
+    }
+    exit(1);
+  }
+  for (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;
+    memset(&info, 0, sizeof(info));
+    strcpy(info.name, table->name);
+    optlen = sizeof(info);
+    if (getsockopt(fd, SOL_IP, ARPT_SO_GET_INFO, &info, &optlen))
+      exit(1);
+    if (memcmp(&table->info, &info, sizeof(table->info)) == 0) {
+      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))
+        exit(1);
+      if (memcmp(table->replace.entrytable, entries.entrytable,
+                 table->info.size) == 0)
+        continue;
+    } else {
+    }
+    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))
+      exit(1);
+  }
+  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)
+{
+  socklen_t optlen;
+  unsigned i;
+  int fd;
+  fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  if (fd == -1) {
+    switch (errno) {
+    case EAFNOSUPPORT:
+    case ENOPROTOOPT:
+      return;
+    }
+    exit(1);
+  }
+  for (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);
+    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;
+      }
+      exit(1);
+    }
+    if (table->replace.entries_size > sizeof(table->entrytable))
+      exit(1);
+    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))
+      exit(1);
+  }
+  close(fd);
+}
+
+static void reset_ebtables()
+{
+  struct ebt_replace replace;
+  char entrytable[XT_TABLE_SIZE];
+  socklen_t optlen;
+  unsigned i, j, h;
+  int fd;
+  fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  if (fd == -1) {
+    switch (errno) {
+    case EAFNOSUPPORT:
+    case ENOPROTOOPT:
+      return;
+    }
+    exit(1);
+  }
+  for (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;
+    memset(&replace, 0, sizeof(replace));
+    strcpy(replace.name, table->name);
+    optlen = sizeof(replace);
+    if (getsockopt(fd, SOL_IP, EBT_SO_GET_INFO, &replace, &optlen))
+      exit(1);
+    replace.num_counters = 0;
+    table->replace.entries = 0;
+    for (h = 0; h < NF_BR_NUMHOOKS; h++)
+      table->replace.hook_entry[h] = 0;
+    if (memcmp(&table->replace, &replace, sizeof(table->replace)) == 0) {
+      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))
+        exit(1);
+      if (memcmp(table->entrytable, entrytable, replace.entries_size) == 0)
+        continue;
+    }
+    for (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))
+      exit(1);
+  }
+  close(fd);
+}
+
+static void checkpoint_net_namespace(void)
+{
+  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)
+{
+  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);
+}
+
+static void setup_cgroups()
+{
+  if (mkdir("/syzcgroup", 0777)) {
+  }
+  if (mkdir("/syzcgroup/unified", 0777)) {
+  }
+  if (mount("none", "/syzcgroup/unified", "cgroup2", 0, NULL)) {
+  }
+  if (chmod("/syzcgroup/unified", 0777)) {
+  }
+  write_file("/syzcgroup/unified/cgroup.subtree_control",
+             "+cpu +memory +io +pids +rdma");
+  if (mkdir("/syzcgroup/cpu", 0777)) {
+  }
+  if (mount("none", "/syzcgroup/cpu", "cgroup", 0,
+            "cpuset,cpuacct,perf_event,hugetlb")) {
+  }
+  write_file("/syzcgroup/cpu/cgroup.clone_children", "1");
+  if (chmod("/syzcgroup/cpu", 0777)) {
+  }
+  if (mkdir("/syzcgroup/net", 0777)) {
+  }
+  if (mount("none", "/syzcgroup/net", "cgroup", 0,
+            "net_cls,net_prio,devices,freezer")) {
+  }
+  if (chmod("/syzcgroup/net", 0777)) {
+  }
+}
+
+static void setup_cgroups_loop()
+{
+  int pid = getpid();
+  char file[128];
+  char cgroupdir[64];
+  snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/unified/syz%llu", procid);
+  if (mkdir(cgroupdir, 0777)) {
+  }
+  snprintf(file, sizeof(file), "%s/pids.max", cgroupdir);
+  write_file(file, "32");
+  snprintf(file, sizeof(file), "%s/memory.low", cgroupdir);
+  write_file(file, "%d", 298 << 20);
+  snprintf(file, sizeof(file), "%s/memory.high", cgroupdir);
+  write_file(file, "%d", 299 << 20);
+  snprintf(file, sizeof(file), "%s/memory.max", cgroupdir);
+  write_file(file, "%d", 300 << 20);
+  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)) {
+  }
+  snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+  write_file(file, "%d", pid);
+  snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/net/syz%llu", procid);
+  if (mkdir(cgroupdir, 0777)) {
+  }
+  snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+  write_file(file, "%d", pid);
+}
+
+static void setup_cgroups_test()
+{
+  char cgroupdir[64];
+  snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/unified/syz%llu", procid);
+  if (symlink(cgroupdir, "./cgroup")) {
+  }
+  snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/cpu/syz%llu", procid);
+  if (symlink(cgroupdir, "./cgroup.cpu")) {
+  }
+  snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/net/syz%llu", procid);
+  if (symlink(cgroupdir, "./cgroup.net")) {
+  }
+}
+
+static void setup_common()
+{
+  if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+  }
+  setup_cgroups();
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+  prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+  setpgrp();
+  setsid();
+  int netns = open("/proc/self/ns/net", O_RDONLY);
+  if (netns == -1)
+    exit(1);
+  if (dup2(netns, kInitNetNsFd) < 0)
+    exit(1);
+  close(netns);
+  struct rlimit rlim;
+  rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+  setrlimit(RLIMIT_AS, &rlim);
+  rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+  setrlimit(RLIMIT_MEMLOCK, &rlim);
+  rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+  setrlimit(RLIMIT_FSIZE, &rlim);
+  rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+  setrlimit(RLIMIT_STACK, &rlim);
+  rlim.rlim_cur = rlim.rlim_max = 0;
+  setrlimit(RLIMIT_CORE, &rlim);
+  rlim.rlim_cur = rlim.rlim_max = 256;
+  setrlimit(RLIMIT_NOFILE, &rlim);
+  if (unshare(CLONE_NEWNS)) {
+  }
+  if (unshare(CLONE_NEWIPC)) {
+  }
+  if (unshare(0x02000000)) {
+  }
+  if (unshare(CLONE_NEWUTS)) {
+  }
+  if (unshare(CLONE_SYSVSEM)) {
+  }
+  typedef struct {
+    const char* name;
+    const char* value;
+  } sysctl_t;
+  static const sysctl_t sysctls[] = {
+      {"/proc/sys/kernel/shmmax", "16777216"},
+      {"/proc/sys/kernel/shmall", "536870912"},
+      {"/proc/sys/kernel/shmmni", "1024"},
+      {"/proc/sys/kernel/msgmax", "8192"},
+      {"/proc/sys/kernel/msgmni", "1024"},
+      {"/proc/sys/kernel/msgmnb", "1024"},
+      {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+  };
+  unsigned i;
+  for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+    write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+  if (pid < 0)
+    exit(1);
+  int status = 0;
+  while (waitpid(-1, &status, __WALL) != pid) {
+  }
+  return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+  struct __user_cap_header_struct cap_hdr = {};
+  struct __user_cap_data_struct cap_data[2] = {};
+  cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+  cap_hdr.pid = getpid();
+  if (syscall(SYS_capget, &cap_hdr, &cap_data))
+    exit(1);
+  const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+  cap_data[0].effective &= ~drop;
+  cap_data[0].permitted &= ~drop;
+  cap_data[0].inheritable &= ~drop;
+  if (syscall(SYS_capset, &cap_hdr, &cap_data))
+    exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+  if (unshare(CLONE_NEWPID)) {
+  }
+  int pid = fork();
+  if (pid != 0)
+    return wait_for_loop(pid);
+  setup_common();
+  sandbox_common();
+  drop_caps();
+  initialize_netdevices_init();
+  if (unshare(CLONE_NEWNET)) {
+  }
+  initialize_devlink_pci();
+  initialize_tun();
+  initialize_netdevices();
+  loop();
+  exit(1);
+}
+
+#define FS_IOC_SETFLAGS _IOW('f', 2, long)
+static void remove_dir(const char* dir)
+{
+  DIR* dp;
+  struct dirent* ep;
+  int iter = 0;
+retry:
+  while (umount2(dir, MNT_DETACH) == 0) {
+  }
+  dp = opendir(dir);
+  if (dp == NULL) {
+    if (errno == EMFILE) {
+      exit(1);
+    }
+    exit(1);
+  }
+  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);
+    while (umount2(filename, MNT_DETACH) == 0) {
+    }
+    struct stat st;
+    if (lstat(filename, &st))
+      exit(1);
+    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) {
+          }
+          close(fd);
+          continue;
+        }
+      }
+      if (errno == EROFS) {
+        break;
+      }
+      if (errno != EBUSY || i > 100)
+        exit(1);
+      if (umount2(filename, MNT_DETACH))
+        exit(1);
+    }
+  }
+  closedir(dp);
+  int i;
+  for (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) {
+          }
+          close(fd);
+          continue;
+        }
+      }
+      if (errno == EROFS) {
+        break;
+      }
+      if (errno == EBUSY) {
+        if (umount2(dir, MNT_DETACH))
+          exit(1);
+        continue;
+      }
+      if (errno == ENOTEMPTY) {
+        if (iter < 100) {
+          iter++;
+          goto retry;
+        }
+      }
+    }
+    exit(1);
+  }
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+  kill(-pid, SIGKILL);
+  kill(pid, SIGKILL);
+  int i;
+  for (i = 0; i < 100; i++) {
+    if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+      return;
+    usleep(1000);
+  }
+  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) {
+        continue;
+      }
+      if (write(fd, abort, 1) < 0) {
+      }
+      close(fd);
+    }
+    closedir(dir);
+  } else {
+  }
+  while (waitpid(-1, status, __WALL) != pid) {
+  }
+}
+
+static void setup_loop()
+{
+  setup_cgroups_loop();
+  checkpoint_net_namespace();
+}
+
+static void reset_loop()
+{
+  reset_net_namespace();
+}
+
+static void setup_test()
+{
+  prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+  setpgrp();
+  setup_cgroups_test();
+  write_file("/proc/self/oom_score_adj", "1000");
+  flush_tun();
+}
+
+static void close_fds()
+{
+  int fd;
+  for (fd = 3; fd < MAX_FDS; fd++)
+    close(fd);
+}
+
+static void setup_binfmt_misc()
+{
+  if (mount(0, "/proc/sys/fs/binfmt_misc", "binfmt_misc", 0, 0)) {
+  }
+  write_file("/proc/sys/fs/binfmt_misc/register", ":syz0:M:0:\x01::./file0:");
+  write_file("/proc/sys/fs/binfmt_misc/register",
+             ":syz1:M:1:\x02::./file0:POC");
+}
+
+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;
+}
+
+static void execute_one(void)
+{
+  int i, call, thread;
+  int collide = 0;
+again:
+  for (call = 0; call < 12; 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 (collide && (call % 2) == 0)
+        break;
+      event_timedwait(&th->done, 45);
+      break;
+    }
+  }
+  for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+    sleep_ms(1);
+  close_fds();
+  if (!collide) {
+    collide = 1;
+    goto again;
+  }
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+  setup_loop();
+  int iter;
+  for (iter = 0;; iter++) {
+    char cwdbuf[32];
+    sprintf(cwdbuf, "./%d", iter);
+    if (mkdir(cwdbuf, 0777))
+      exit(1);
+    reset_loop();
+    int pid = fork();
+    if (pid < 0)
+      exit(1);
+    if (pid == 0) {
+      if (chdir(cwdbuf))
+        exit(1);
+      setup_test();
+      execute_one();
+      exit(0);
+    }
+    int status = 0;
+    uint64_t start = current_time_ms();
+    for (;;) {
+      if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+        break;
+      sleep_ms(1);
+      if (current_time_ms() - start < 5 * 1000)
+        continue;
+      kill_and_wait(pid, &status);
+      break;
+    }
+    remove_dir(cwdbuf);
+  }
+}
+
+uint64_t r[3] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_call(int call)
+{
+  intptr_t res;
+  switch (call) {
+  case 0:
+    syscall(__NR_ptrace, -1ul, 0, 9ul, 0ul);
+    break;
+  case 1:
+    res = syscall(__NR_socket, 0xaul, 2ul, 0);
+    if (res != -1)
+      r[0] = res;
+    break;
+  case 2:
+    NONFAILING(*(uint16_t*)0x20000000 = 0xa);
+    NONFAILING(*(uint16_t*)0x20000002 = htobe16(0));
+    NONFAILING(*(uint32_t*)0x20000004 = htobe32(0));
+    NONFAILING(*(uint8_t*)0x20000008 = -1);
+    NONFAILING(*(uint8_t*)0x20000009 = 2);
+    NONFAILING(*(uint8_t*)0x2000000a = 0);
+    NONFAILING(*(uint8_t*)0x2000000b = 0);
+    NONFAILING(*(uint8_t*)0x2000000c = 0);
+    NONFAILING(*(uint8_t*)0x2000000d = 0);
+    NONFAILING(*(uint8_t*)0x2000000e = 0);
+    NONFAILING(*(uint8_t*)0x2000000f = 0);
+    NONFAILING(*(uint8_t*)0x20000010 = 0);
+    NONFAILING(*(uint8_t*)0x20000011 = 0);
+    NONFAILING(*(uint8_t*)0x20000012 = 0);
+    NONFAILING(*(uint8_t*)0x20000013 = 0);
+    NONFAILING(*(uint8_t*)0x20000014 = 0);
+    NONFAILING(*(uint8_t*)0x20000015 = 0);
+    NONFAILING(*(uint8_t*)0x20000016 = 0);
+    NONFAILING(*(uint8_t*)0x20000017 = 1);
+    NONFAILING(*(uint32_t*)0x20000018 = 6);
+    syscall(__NR_connect, r[0], 0x20000000ul, 0x1cul);
+    break;
+  case 3:
+    syscall(__NR_ioctl, -1, 0xc0585604ul, 0ul);
+    break;
+  case 4:
+    res = syscall(__NR_socket, 0x10ul, 3ul, 6ul);
+    if (res != -1)
+      r[1] = res;
+    break;
+  case 5:
+    NONFAILING(*(uint32_t*)0x20000180 = 1);
+    NONFAILING(*(uint32_t*)0x20000184 = 0x70);
+    NONFAILING(*(uint8_t*)0x20000188 = 0);
+    NONFAILING(*(uint8_t*)0x20000189 = 0);
+    NONFAILING(*(uint8_t*)0x2000018a = 0);
+    NONFAILING(*(uint8_t*)0x2000018b = 0);
+    NONFAILING(*(uint32_t*)0x2000018c = 0);
+    NONFAILING(*(uint64_t*)0x20000190 = 0x3660);
+    NONFAILING(*(uint64_t*)0x20000198 = 0);
+    NONFAILING(*(uint64_t*)0x200001a0 = 0);
+    NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200001a8, 0, 0, 1));
+    NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200001a8, 0, 1, 1));
+    NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200001a8, 0, 2, 1));
+    NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200001a8, 0, 3, 1));
+    NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200001a8, 0, 4, 1));
+    NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200001a8, 0, 5, 1));
+    NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200001a8, 0, 6, 1));
+    NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200001a8, 0, 7, 1));
+    NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200001a8, 0, 8, 1));
+    NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200001a8, 0, 9, 1));
+    NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200001a8, 0, 10, 1));
+    NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200001a8, 0, 11, 1));
+    NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200001a8, 0, 12, 1));
+    NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200001a8, 0, 13, 1));
+    NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200001a8, 0, 14, 1));
+    NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200001a8, 0, 15, 2));
+    NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200001a8, 0, 17, 1));
+    NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200001a8, 0, 18, 1));
+    NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200001a8, 0, 19, 1));
+    NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200001a8, 0, 20, 1));
+    NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200001a8, 0, 21, 1));
+    NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200001a8, 0, 22, 1));
+    NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200001a8, 0, 23, 1));
+    NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200001a8, 0, 24, 1));
+    NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200001a8, 0, 25, 1));
+    NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200001a8, 0, 26, 1));
+    NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200001a8, 0, 27, 1));
+    NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200001a8, 0, 28, 1));
+    NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x200001a8, 0, 29, 35));
+    NONFAILING(*(uint32_t*)0x200001b0 = 0);
+    NONFAILING(*(uint32_t*)0x200001b4 = 0);
+    NONFAILING(*(uint64_t*)0x200001b8 = 0);
+    NONFAILING(*(uint64_t*)0x200001c0 = 0);
+    NONFAILING(*(uint64_t*)0x200001c8 = 0);
+    NONFAILING(*(uint64_t*)0x200001d0 = 0);
+    NONFAILING(*(uint32_t*)0x200001d8 = 0);
+    NONFAILING(*(uint32_t*)0x200001dc = 0);
+    NONFAILING(*(uint64_t*)0x200001e0 = 0);
+    NONFAILING(*(uint32_t*)0x200001e8 = 0);
+    NONFAILING(*(uint16_t*)0x200001ec = 0);
+    NONFAILING(*(uint16_t*)0x200001ee = 0);
+    syscall(__NR_perf_event_open, 0x20000180ul, 0, -1ul, -1, 0ul);
+    break;
+  case 6:
+    syscall(__NR_sendmsg, r[1], 0ul, 0ul);
+    break;
+  case 7:
+    NONFAILING(memcpy((void*)0x20000300, "./file0\000", 8));
+    syscall(__NR_creat, 0x20000300ul, 0ul);
+    break;
+  case 8:
+    NONFAILING(memcpy(
+        (void*)0x200000c0,
+        "\023\023w\305\3745\324\024T\325\324\035)\255\032`)"
+        "Y\201F\346\276\026nA\255\r\275@T\003<\2373\273\332\202$"
+        "\242\363\327r\347cnH\263<\277p\203r\350\361\271\223>"
+        "\305\022wC\276\"\006 \236\360-\371\313\362\366\350\200\3238/\000",
+        78));
+    syscall(__NR_open, 0x200000c0ul, 0ul, 0ul);
+    break;
+  case 9:
+    NONFAILING(memcpy((void*)0x200000c0, "/dev/ptmx\000", 10));
+    res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x200000c0ul, 0ul, 0ul);
+    if (res != -1)
+      r[2] = res;
+    break;
+  case 10:
+    NONFAILING(*(uint32_t*)0x20000040 = 0xf);
+    syscall(__NR_ioctl, r[2], 0x5423ul, 0x20000040ul);
+    break;
+  case 11:
+    syscall(__NR_ioctl, r[2], 0x400455c8ul, 0x4000000000000009ul);
+    break;
+  }
+}
+int main(void)
+{
+  syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+  setup_binfmt_misc();
+  install_segv_handler();
+  for (procid = 0; procid < 6; procid++) {
+    if (fork() == 0) {
+      use_temporary_dir();
+      do_sandbox_none();
+    }
+  }
+  sleep(1000000);
+  return 0;
+}
diff --git a/syzkaller-repros/linux/0075499a00c437c2571fd521bd57068098df35ee.c b/syzkaller-repros/linux/0075499a00c437c2571fd521bd57068098df35ee.c
new file mode 100644
index 0000000..be7a751
--- /dev/null
+++ b/syzkaller-repros/linux/0075499a00c437c2571fd521bd57068098df35ee.c
@@ -0,0 +1,850 @@
+// WARNING in skb_warn_bad_offload
+// https://syzkaller.appspot.com/bug?id=0075499a00c437c2571fd521bd57068098df35ee
+// status:open
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.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[1024];
+};
+
+static struct nlmsg nlmsg;
+
+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;
+  memcpy(attr + 1, data, size);
+  nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+                            int* reply_len)
+{
+  if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+    exit(1);
+  struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+  hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+  struct sockaddr_nl addr;
+  memset(&addr, 0, sizeof(addr));
+  addr.nl_family = AF_NETLINK;
+  unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+                      (struct sockaddr*)&addr, sizeof(addr));
+  if (n != hdr->nlmsg_len)
+    exit(1);
+  n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+  if (hdr->nlmsg_type == NLMSG_DONE) {
+    *reply_len = 0;
+    return 0;
+  }
+  if (n < sizeof(struct nlmsghdr))
+    exit(1);
+  if (reply_len && hdr->nlmsg_type == reply_type) {
+    *reply_len = n;
+    return 0;
+  }
+  if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+    exit(1);
+  if (hdr->nlmsg_type != NLMSG_ERROR)
+    exit(1);
+  return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+  return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+                            unsigned int total_len)
+{
+  struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+  if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+    return -1;
+  return hdr->nlmsg_len;
+}
+
+static void netlink_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);
+  (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+  struct genlmsghdr genlhdr;
+  struct nlattr* attr;
+  int err, n;
+  uint16_t id = 0;
+  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, DEVLINK_FAMILY_NAME,
+               strlen(DEVLINK_FAMILY_NAME) + 1);
+  err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+  if (err) {
+    return -1;
+  }
+  attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+                          NLMSG_ALIGN(sizeof(genlhdr)));
+  for (; (char*)attr < nlmsg->buf + n;
+       attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+    if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+      id = *(uint16_t*)(attr + 1);
+      break;
+    }
+  }
+  if (!id) {
+    return -1;
+  }
+  recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+  return id;
+}
+
+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)
+    exit(1);
+  id = netlink_devlink_id_get(&nlmsg, sock);
+  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) {
+  }
+error:
+  close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+                                     const char* netdev_prefix)
+{
+  struct genlmsghdr genlhdr;
+  int len, total_len, id, err, offset;
+  uint16_t netdev_index;
+  int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+  if (sock == -1)
+    exit(1);
+  int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+  if (rtsock == -1)
+    exit(1);
+  id = netlink_devlink_id_get(&nlmsg, sock);
+  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);
+  if (err) {
+    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);
+}
+
+static void initialize_devlink_pci(void)
+{
+  int netns = open("/proc/self/ns/net", O_RDONLY);
+  if (netns == -1)
+    exit(1);
+  int ret = setns(kInitNetNsFd, 0);
+  if (ret == -1)
+    exit(1);
+  netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+  ret = setns(netns, 0);
+  if (ret == -1)
+    exit(1);
+  close(netns);
+  initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+int main(void)
+{
+  syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+  intptr_t res = 0;
+  res = syscall(__NR_socket, 2ul, 2ul, 0ul);
+  if (res != -1)
+    r[0] = res;
+  memcpy((void*)0x20000240, "mangle\000\000\000\000\000\000\000\000\000\000\000"
+                            "\000\000\000\000\000\000\000\000\000\000\000\000"
+                            "\000\000\000",
+         32);
+  *(uint32_t*)0x20000260 = 0x1f;
+  *(uint32_t*)0x20000264 = 6;
+  *(uint32_t*)0x20000268 = 0x3b0;
+  *(uint32_t*)0x2000026c = 0x280;
+  *(uint32_t*)0x20000270 = 0x280;
+  *(uint32_t*)0x20000274 = 0x130;
+  *(uint32_t*)0x20000278 = 0;
+  *(uint32_t*)0x2000027c = 0x280;
+  *(uint32_t*)0x20000280 = 0x318;
+  *(uint32_t*)0x20000284 = 0x318;
+  *(uint32_t*)0x20000288 = 0x318;
+  *(uint32_t*)0x2000028c = 0x318;
+  *(uint32_t*)0x20000290 = 0x318;
+  *(uint32_t*)0x20000294 = 6;
+  *(uint64_t*)0x20000298 = 0;
+  *(uint8_t*)0x200002a0 = 0;
+  *(uint8_t*)0x200002a1 = 0;
+  *(uint8_t*)0x200002a2 = 0;
+  *(uint8_t*)0x200002a3 = 0;
+  *(uint8_t*)0x200002a4 = 0;
+  *(uint8_t*)0x200002a5 = 0;
+  *(uint8_t*)0x200002a6 = 0;
+  *(uint8_t*)0x200002a7 = 0;
+  *(uint8_t*)0x200002a8 = 0;
+  *(uint8_t*)0x200002a9 = 0;
+  *(uint8_t*)0x200002aa = 0;
+  *(uint8_t*)0x200002ab = 0;
+  *(uint8_t*)0x200002ac = 0;
+  *(uint8_t*)0x200002ad = 0;
+  *(uint8_t*)0x200002ae = 0;
+  *(uint8_t*)0x200002af = 0;
+  *(uint8_t*)0x200002b0 = 0;
+  *(uint8_t*)0x200002b1 = 0;
+  *(uint8_t*)0x200002b2 = 0;
+  *(uint8_t*)0x200002b3 = 0;
+  *(uint8_t*)0x200002b4 = 0;
+  *(uint8_t*)0x200002b5 = 0;
+  *(uint8_t*)0x200002b6 = 0;
+  *(uint8_t*)0x200002b7 = 0;
+  *(uint8_t*)0x200002b8 = 0;
+  *(uint8_t*)0x200002b9 = 0;
+  *(uint8_t*)0x200002ba = 0;
+  *(uint8_t*)0x200002bb = 0;
+  *(uint8_t*)0x200002bc = 0;
+  *(uint8_t*)0x200002bd = 0;
+  *(uint8_t*)0x200002be = 0;
+  *(uint8_t*)0x200002bf = 0;
+  *(uint8_t*)0x200002c0 = 0;
+  *(uint8_t*)0x200002c1 = 0;
+  *(uint8_t*)0x200002c2 = 0;
+  *(uint8_t*)0x200002c3 = 0;
+  *(uint8_t*)0x200002c4 = 0;
+  *(uint8_t*)0x200002c5 = 0;
+  *(uint8_t*)0x200002c6 = 0;
+  *(uint8_t*)0x200002c7 = 0;
+  *(uint8_t*)0x200002c8 = 0;
+  *(uint8_t*)0x200002c9 = 0;
+  *(uint8_t*)0x200002ca = 0;
+  *(uint8_t*)0x200002cb = 0;
+  *(uint8_t*)0x200002cc = 0;
+  *(uint8_t*)0x200002cd = 0;
+  *(uint8_t*)0x200002ce = 0;
+  *(uint8_t*)0x200002cf = 0;
+  *(uint8_t*)0x200002d0 = 0;
+  *(uint8_t*)0x200002d1 = 0;
+  *(uint8_t*)0x200002d2 = 0;
+  *(uint8_t*)0x200002d3 = 0;
+  *(uint8_t*)0x200002d4 = 0;
+  *(uint8_t*)0x200002d5 = 0;
+  *(uint8_t*)0x200002d6 = 0;
+  *(uint8_t*)0x200002d7 = 0;
+  *(uint8_t*)0x200002d8 = 0;
+  *(uint8_t*)0x200002d9 = 0;
+  *(uint8_t*)0x200002da = 0;
+  *(uint8_t*)0x200002db = 0;
+  *(uint8_t*)0x200002dc = 0;
+  *(uint8_t*)0x200002dd = 0;
+  *(uint8_t*)0x200002de = 0;
+  *(uint8_t*)0x200002df = 0;
+  *(uint8_t*)0x200002e0 = 0;
+  *(uint8_t*)0x200002e1 = 0;
+  *(uint8_t*)0x200002e2 = 0;
+  *(uint8_t*)0x200002e3 = 0;
+  *(uint8_t*)0x200002e4 = 0;
+  *(uint8_t*)0x200002e5 = 0;
+  *(uint8_t*)0x200002e6 = 0;
+  *(uint8_t*)0x200002e7 = 0;
+  *(uint8_t*)0x200002e8 = 0;
+  *(uint8_t*)0x200002e9 = 0;
+  *(uint8_t*)0x200002ea = 0;
+  *(uint8_t*)0x200002eb = 0;
+  *(uint8_t*)0x200002ec = 0;
+  *(uint8_t*)0x200002ed = 0;
+  *(uint8_t*)0x200002ee = 0;
+  *(uint8_t*)0x200002ef = 0;
+  *(uint8_t*)0x200002f0 = 0;
+  *(uint8_t*)0x200002f1 = 0;
+  *(uint8_t*)0x200002f2 = 0;
+  *(uint8_t*)0x200002f3 = 0;
+  *(uint32_t*)0x200002f4 = 0;
+  *(uint16_t*)0x200002f8 = 0x70;
+  *(uint16_t*)0x200002fa = 0x98;
+  *(uint32_t*)0x200002fc = 0;
+  *(uint64_t*)0x20000300 = 0;
+  *(uint64_t*)0x20000308 = 0;
+  *(uint16_t*)0x20000310 = 0x28;
+  memcpy((void*)0x20000312, "TTL\000\000\000\000\000\000\000\000\000\000\000"
+                            "\000\000\000\000\000\000\000\000\000\000\000\000"
+                            "\000\000\000",
+         29);
+  *(uint8_t*)0x2000032f = 0;
+  *(uint8_t*)0x20000330 = 0;
+  *(uint8_t*)0x20000331 = 0;
+  *(uint8_t*)0x20000338 = 0;
+  *(uint8_t*)0x20000339 = 0;
+  *(uint8_t*)0x2000033a = 0;
+  *(uint8_t*)0x2000033b = 0;
+  *(uint8_t*)0x2000033c = 0;
+  *(uint8_t*)0x2000033d = 0;
+  *(uint8_t*)0x2000033e = 0;
+  *(uint8_t*)0x2000033f = 0;
+  *(uint8_t*)0x20000340 = 0;
+  *(uint8_t*)0x20000341 = 0;
+  *(uint8_t*)0x20000342 = 0;
+  *(uint8_t*)0x20000343 = 0;
+  *(uint8_t*)0x20000344 = 0;
+  *(uint8_t*)0x20000345 = 0;
+  *(uint8_t*)0x20000346 = 0;
+  *(uint8_t*)0x20000347 = 0;
+  *(uint8_t*)0x20000348 = 0;
+  *(uint8_t*)0x20000349 = 0;
+  *(uint8_t*)0x2000034a = 0;
+  *(uint8_t*)0x2000034b = 0;
+  *(uint8_t*)0x2000034c = 0;
+  *(uint8_t*)0x2000034d = 0;
+  *(uint8_t*)0x2000034e = 0;
+  *(uint8_t*)0x2000034f = 0;
+  *(uint8_t*)0x20000350 = 0;
+  *(uint8_t*)0x20000351 = 0;
+  *(uint8_t*)0x20000352 = 0;
+  *(uint8_t*)0x20000353 = 0;
+  *(uint8_t*)0x20000354 = 0;
+  *(uint8_t*)0x20000355 = 0;
+  *(uint8_t*)0x20000356 = 0;
+  *(uint8_t*)0x20000357 = 0;
+  *(uint8_t*)0x20000358 = 0;
+  *(uint8_t*)0x20000359 = 0;
+  *(uint8_t*)0x2000035a = 0;
+  *(uint8_t*)0x2000035b = 0;
+  *(uint8_t*)0x2000035c = 0;
+  *(uint8_t*)0x2000035d = 0;
+  *(uint8_t*)0x2000035e = 0;
+  *(uint8_t*)0x2000035f = 0;
+  *(uint8_t*)0x20000360 = 0;
+  *(uint8_t*)0x20000361 = 0;
+  *(uint8_t*)0x20000362 = 0;
+  *(uint8_t*)0x20000363 = 0;
+  *(uint8_t*)0x20000364 = 0;
+  *(uint8_t*)0x20000365 = 0;
+  *(uint8_t*)0x20000366 = 0;
+  *(uint8_t*)0x20000367 = 0;
+  *(uint8_t*)0x20000368 = 0;
+  *(uint8_t*)0x20000369 = 0;
+  *(uint8_t*)0x2000036a = 0;
+  *(uint8_t*)0x2000036b = 0;
+  *(uint8_t*)0x2000036c = 0;
+  *(uint8_t*)0x2000036d = 0;
+  *(uint8_t*)0x2000036e = 0;
+  *(uint8_t*)0x2000036f = 0;
+  *(uint8_t*)0x20000370 = 0;
+  *(uint8_t*)0x20000371 = 0;
+  *(uint8_t*)0x20000372 = 0;
+  *(uint8_t*)0x20000373 = 0;
+  *(uint8_t*)0x20000374 = 0;
+  *(uint8_t*)0x20000375 = 0;
+  *(uint8_t*)0x20000376 = 0;
+  *(uint8_t*)0x20000377 = 0;
+  *(uint8_t*)0x20000378 = 0;
+  *(uint8_t*)0x20000379 = 0;
+  *(uint8_t*)0x2000037a = 0;
+  *(uint8_t*)0x2000037b = 0;
+  *(uint8_t*)0x2000037c = 0;
+  *(uint8_t*)0x2000037d = 0;
+  *(uint8_t*)0x2000037e = 0;
+  *(uint8_t*)0x2000037f = 0;
+  *(uint8_t*)0x20000380 = 0;
+  *(uint8_t*)0x20000381 = 0;
+  *(uint8_t*)0x20000382 = 0;
+  *(uint8_t*)0x20000383 = 0;
+  *(uint8_t*)0x20000384 = 0;
+  *(uint8_t*)0x20000385 = 0;
+  *(uint8_t*)0x20000386 = 0;
+  *(uint8_t*)0x20000387 = 0;
+  *(uint8_t*)0x20000388 = 0;
+  *(uint8_t*)0x20000389 = 0;
+  *(uint8_t*)0x2000038a = 0;
+  *(uint8_t*)0x2000038b = 0;
+  *(uint32_t*)0x2000038c = 0;
+  *(uint16_t*)0x20000390 = 0x70;
+  *(uint16_t*)0x20000392 = 0x98;
+  *(uint32_t*)0x20000394 = 0;
+  *(uint64_t*)0x20000398 = 0;
+  *(uint64_t*)0x200003a0 = 0;
+  *(uint16_t*)0x200003a8 = 0x28;
+  memcpy((void*)0x200003aa, "TTL\000\000\000\000\000\000\000\000\000\000\000"
+                            "\000\000\000\000\000\000\000\000\000\000\000\000"
+                            "\000\000\000",
+         29);
+  *(uint8_t*)0x200003c7 = 0;
+  *(uint8_t*)0x200003c8 = 0;
+  *(uint8_t*)0x200003c9 = 0;
+  *(uint32_t*)0x200003d0 = htobe32(0xe0000002);
+  *(uint8_t*)0x200003d4 = 0xac;
+  *(uint8_t*)0x200003d5 = 0x14;
+  *(uint8_t*)0x200003d6 = 0x14;
+  *(uint8_t*)0x200003d7 = 0xaa;
+  *(uint32_t*)0x200003d8 = htobe32(0);
+  *(uint32_t*)0x200003dc = htobe32(0);
+  memcpy((void*)0x200003e0,
+         "bpq0\000\000\000\000\000\000\000\000\000\000\000\000", 16);
+  memcpy((void*)0x200003f0, "erspan0\000\000\000\000\000\000\000\000\000", 16);
+  *(uint8_t*)0x20000400 = 0;
+  *(uint8_t*)0x20000410 = 0;
+  *(uint16_t*)0x20000420 = 0;
+  *(uint8_t*)0x20000422 = 0;
+  *(uint8_t*)0x20000423 = 0;
+  *(uint32_t*)0x20000424 = 0;
+  *(uint16_t*)0x20000428 = 0x70;
+  *(uint16_t*)0x2000042a = 0xb8;
+  *(uint32_t*)0x2000042c = 0;
+  *(uint64_t*)0x20000430 = 0;
+  *(uint64_t*)0x20000438 = 0;
+  *(uint16_t*)0x20000440 = 0x48;
+  memcpy((void*)0x20000442, "TEE\000\000\000\000\000\000\000\000\000\000\000"
+                            "\000\000\000\000\000\000\000\000\000\000\000\000"
+                            "\000\000\000",
+         29);
+  *(uint8_t*)0x2000045f = 1;
+  *(uint8_t*)0x20000460 = -1;
+  *(uint8_t*)0x20000461 = 2;
+  *(uint8_t*)0x20000462 = 0;
+  *(uint8_t*)0x20000463 = 0;
+  *(uint8_t*)0x20000464 = 0;
+  *(uint8_t*)0x20000465 = 0;
+  *(uint8_t*)0x20000466 = 0;
+  *(uint8_t*)0x20000467 = 0;
+  *(uint8_t*)0x20000468 = 0;
+  *(uint8_t*)0x20000469 = 0;
+  *(uint8_t*)0x2000046a = 0;
+  *(uint8_t*)0x2000046b = 0;
+  *(uint8_t*)0x2000046c = 0;
+  *(uint8_t*)0x2000046d = 0;
+  *(uint8_t*)0x2000046e = 0;
+  *(uint8_t*)0x2000046f = 1;
+  memcpy((void*)0x20000470,
+         "gre0\000\000\000\000\000\000\000\000\000\000\000\000", 16);
+  *(uint64_t*)0x20000480 = 0;
+  *(uint8_t*)0x20000488 = 0;
+  *(uint8_t*)0x20000489 = 0;
+  *(uint8_t*)0x2000048a = 0;
+  *(uint8_t*)0x2000048b = 0;
+  *(uint8_t*)0x2000048c = 0;
+  *(uint8_t*)0x2000048d = 0;
+  *(uint8_t*)0x2000048e = 0;
+  *(uint8_t*)0x2000048f = 0;
+  *(uint8_t*)0x20000490 = 0;
+  *(uint8_t*)0x20000491 = 0;
+  *(uint8_t*)0x20000492 = 0;
+  *(uint8_t*)0x20000493 = 0;
+  *(uint8_t*)0x20000494 = 0;
+  *(uint8_t*)0x20000495 = 0;
+  *(uint8_t*)0x20000496 = 0;
+  *(uint8_t*)0x20000497 = 0;
+  *(uint8_t*)0x20000498 = 0;
+  *(uint8_t*)0x20000499 = 0;
+  *(uint8_t*)0x2000049a = 0;
+  *(uint8_t*)0x2000049b = 0;
+  *(uint8_t*)0x2000049c = 0;
+  *(uint8_t*)0x2000049d = 0;
+  *(uint8_t*)0x2000049e = 0;
+  *(uint8_t*)0x2000049f = 0;
+  *(uint8_t*)0x200004a0 = 0;
+  *(uint8_t*)0x200004a1 = 0;
+  *(uint8_t*)0x200004a2 = 0;
+  *(uint8_t*)0x200004a3 = 0;
+  *(uint8_t*)0x200004a4 = 0;
+  *(uint8_t*)0x200004a5 = 0;
+  *(uint8_t*)0x200004a6 = 0;
+  *(uint8_t*)0x200004a7 = 0;
+  *(uint8_t*)0x200004a8 = 0;
+  *(uint8_t*)0x200004a9 = 0;
+  *(uint8_t*)0x200004aa = 0;
+  *(uint8_t*)0x200004ab = 0;
+  *(uint8_t*)0x200004ac = 0;
+  *(uint8_t*)0x200004ad = 0;
+  *(uint8_t*)0x200004ae = 0;
+  *(uint8_t*)0x200004af = 0;
+  *(uint8_t*)0x200004b0 = 0;
+  *(uint8_t*)0x200004b1 = 0;
+  *(uint8_t*)0x200004b2 = 0;
+  *(uint8_t*)0x200004b3 = 0;
+  *(uint8_t*)0x200004b4 = 0;
+  *(uint8_t*)0x200004b5 = 0;
+  *(uint8_t*)0x200004b6 = 0;
+  *(uint8_t*)0x200004b7 = 0;
+  *(uint8_t*)0x200004b8 = 0;
+  *(uint8_t*)0x200004b9 = 0;
+  *(uint8_t*)0x200004ba = 0;
+  *(uint8_t*)0x200004bb = 0;
+  *(uint8_t*)0x200004bc = 0;
+  *(uint8_t*)0x200004bd = 0;
+  *(uint8_t*)0x200004be = 0;
+  *(uint8_t*)0x200004bf = 0;
+  *(uint8_t*)0x200004c0 = 0;
+  *(uint8_t*)0x200004c1 = 0;
+  *(uint8_t*)0x200004c2 = 0;
+  *(uint8_t*)0x200004c3 = 0;
+  *(uint8_t*)0x200004c4 = 0;
+  *(uint8_t*)0x200004c5 = 0;
+  *(uint8_t*)0x200004c6 = 0;
+  *(uint8_t*)0x200004c7 = 0;
+  *(uint8_t*)0x200004c8 = 0;
+  *(uint8_t*)0x200004c9 = 0;
+  *(uint8_t*)0x200004ca = 0;
+  *(uint8_t*)0x200004cb = 0;
+  *(uint8_t*)0x200004cc = 0;
+  *(uint8_t*)0x200004cd = 0;
+  *(uint8_t*)0x200004ce = 0;
+  *(uint8_t*)0x200004cf = 0;
+  *(uint8_t*)0x200004d0 = 0;
+  *(uint8_t*)0x200004d1 = 0;
+  *(uint8_t*)0x200004d2 = 0;
+  *(uint8_t*)0x200004d3 = 0;
+  *(uint8_t*)0x200004d4 = 0;
+  *(uint8_t*)0x200004d5 = 0;
+  *(uint8_t*)0x200004d6 = 0;
+  *(uint8_t*)0x200004d7 = 0;
+  *(uint8_t*)0x200004d8 = 0;
+  *(uint8_t*)0x200004d9 = 0;
+  *(uint8_t*)0x200004da = 0;
+  *(uint8_t*)0x200004db = 0;
+  *(uint32_t*)0x200004dc = 0;
+  *(uint16_t*)0x200004e0 = 0x70;
+  *(uint16_t*)0x200004e2 = 0x98;
+  *(uint32_t*)0x200004e4 = 0;
+  *(uint64_t*)0x200004e8 = 0;
+  *(uint64_t*)0x200004f0 = 0;
+  *(uint16_t*)0x200004f8 = 0x28;
+  memcpy((void*)0x200004fa, "CHECKSUM\000\000\000\000\000\000\000\000\000\000"
+                            "\000\000\000\000\000\000\000\000\000\000\000",
+         29);
+  *(uint8_t*)0x20000517 = 0;
+  *(uint8_t*)0x20000518 = 1;
+  *(uint8_t*)0x20000520 = 0;
+  *(uint8_t*)0x20000521 = 0;
+  *(uint8_t*)0x20000522 = 0;
+  *(uint8_t*)0x20000523 = 0;
+  *(uint8_t*)0x20000524 = 0;
+  *(uint8_t*)0x20000525 = 0;
+  *(uint8_t*)0x20000526 = 0;
+  *(uint8_t*)0x20000527 = 0;
+  *(uint8_t*)0x20000528 = 0;
+  *(uint8_t*)0x20000529 = 0;
+  *(uint8_t*)0x2000052a = 0;
+  *(uint8_t*)0x2000052b = 0;
+  *(uint8_t*)0x2000052c = 0;
+  *(uint8_t*)0x2000052d = 0;
+  *(uint8_t*)0x2000052e = 0;
+  *(uint8_t*)0x2000052f = 0;
+  *(uint8_t*)0x20000530 = 0;
+  *(uint8_t*)0x20000531 = 0;
+  *(uint8_t*)0x20000532 = 0;
+  *(uint8_t*)0x20000533 = 0;
+  *(uint8_t*)0x20000534 = 0;
+  *(uint8_t*)0x20000535 = 0;
+  *(uint8_t*)0x20000536 = 0;
+  *(uint8_t*)0x20000537 = 0;
+  *(uint8_t*)0x20000538 = 0;
+  *(uint8_t*)0x20000539 = 0;
+  *(uint8_t*)0x2000053a = 0;
+  *(uint8_t*)0x2000053b = 0;
+  *(uint8_t*)0x2000053c = 0;
+  *(uint8_t*)0x2000053d = 0;
+  *(uint8_t*)0x2000053e = 0;
+  *(uint8_t*)0x2000053f = 0;
+  *(uint8_t*)0x20000540 = 0;
+  *(uint8_t*)0x20000541 = 0;
+  *(uint8_t*)0x20000542 = 0;
+  *(uint8_t*)0x20000543 = 0;
+  *(uint8_t*)0x20000544 = 0;
+  *(uint8_t*)0x20000545 = 0;
+  *(uint8_t*)0x20000546 = 0;
+  *(uint8_t*)0x20000547 = 0;
+  *(uint8_t*)0x20000548 = 0;
+  *(uint8_t*)0x20000549 = 0;
+  *(uint8_t*)0x2000054a = 0;
+  *(uint8_t*)0x2000054b = 0;
+  *(uint8_t*)0x2000054c = 0;
+  *(uint8_t*)0x2000054d = 0;
+  *(uint8_t*)0x2000054e = 0;
+  *(uint8_t*)0x2000054f = 0;
+  *(uint8_t*)0x20000550 = 0;
+  *(uint8_t*)0x20000551 = 0;
+  *(uint8_t*)0x20000552 = 0;
+  *(uint8_t*)0x20000553 = 0;
+  *(uint8_t*)0x20000554 = 0;
+  *(uint8_t*)0x20000555 = 0;
+  *(uint8_t*)0x20000556 = 0;
+  *(uint8_t*)0x20000557 = 0;
+  *(uint8_t*)0x20000558 = 0;
+  *(uint8_t*)0x20000559 = 0;
+  *(uint8_t*)0x2000055a = 0;
+  *(uint8_t*)0x2000055b = 0;
+  *(uint8_t*)0x2000055c = 0;
+  *(uint8_t*)0x2000055d = 0;
+  *(uint8_t*)0x2000055e = 0;
+  *(uint8_t*)0x2000055f = 0;
+  *(uint8_t*)0x20000560 = 0;
+  *(uint8_t*)0x20000561 = 0;
+  *(uint8_t*)0x20000562 = 0;
+  *(uint8_t*)0x20000563 = 0;
+  *(uint8_t*)0x20000564 = 0;
+  *(uint8_t*)0x20000565 = 0;
+  *(uint8_t*)0x20000566 = 0;
+  *(uint8_t*)0x20000567 = 0;
+  *(uint8_t*)0x20000568 = 0;
+  *(uint8_t*)0x20000569 = 0;
+  *(uint8_t*)0x2000056a = 0;
+  *(uint8_t*)0x2000056b = 0;
+  *(uint8_t*)0x2000056c = 0;
+  *(uint8_t*)0x2000056d = 0;
+  *(uint8_t*)0x2000056e = 0;
+  *(uint8_t*)0x2000056f = 0;
+  *(uint8_t*)0x20000570 = 0;
+  *(uint8_t*)0x20000571 = 0;
+  *(uint8_t*)0x20000572 = 0;
+  *(uint8_t*)0x20000573 = 0;
+  *(uint32_t*)0x20000574 = 0;
+  *(uint16_t*)0x20000578 = 0x70;
+  *(uint16_t*)0x2000057a = 0x98;
+  *(uint32_t*)0x2000057c = 0;
+  *(uint64_t*)0x20000580 = 0;
+  *(uint64_t*)0x20000588 = 0;
+  *(uint16_t*)0x20000590 = 0x28;
+  memcpy((void*)0x20000592, "CHECKSUM\000\000\000\000\000\000\000\000\000\000"
+                            "\000\000\000\000\000\000\000\000\000\000\000",
+         29);
+  *(uint8_t*)0x200005af = 0;
+  *(uint8_t*)0x200005b0 = 1;
+  *(uint8_t*)0x200005b8 = 0;
+  *(uint8_t*)0x200005b9 = 0;
+  *(uint8_t*)0x200005ba = 0;
+  *(uint8_t*)0x200005bb = 0;
+  *(uint8_t*)0x200005bc = 0;
+  *(uint8_t*)0x200005bd = 0;
+  *(uint8_t*)0x200005be = 0;
+  *(uint8_t*)0x200005bf = 0;
+  *(uint8_t*)0x200005c0 = 0;
+  *(uint8_t*)0x200005c1 = 0;
+  *(uint8_t*)0x200005c2 = 0;
+  *(uint8_t*)0x200005c3 = 0;
+  *(uint8_t*)0x200005c4 = 0;
+  *(uint8_t*)0x200005c5 = 0;
+  *(uint8_t*)0x200005c6 = 0;
+  *(uint8_t*)0x200005c7 = 0;
+  *(uint8_t*)0x200005c8 = 0;
+  *(uint8_t*)0x200005c9 = 0;
+  *(uint8_t*)0x200005ca = 0;
+  *(uint8_t*)0x200005cb = 0;
+  *(uint8_t*)0x200005cc = 0;
+  *(uint8_t*)0x200005cd = 0;
+  *(uint8_t*)0x200005ce = 0;
+  *(uint8_t*)0x200005cf = 0;
+  *(uint8_t*)0x200005d0 = 0;
+  *(uint8_t*)0x200005d1 = 0;
+  *(uint8_t*)0x200005d2 = 0;
+  *(uint8_t*)0x200005d3 = 0;
+  *(uint8_t*)0x200005d4 = 0;
+  *(uint8_t*)0x200005d5 = 0;
+  *(uint8_t*)0x200005d6 = 0;
+  *(uint8_t*)0x200005d7 = 0;
+  *(uint8_t*)0x200005d8 = 0;
+  *(uint8_t*)0x200005d9 = 0;
+  *(uint8_t*)0x200005da = 0;
+  *(uint8_t*)0x200005db = 0;
+  *(uint8_t*)0x200005dc = 0;
+  *(uint8_t*)0x200005dd = 0;
+  *(uint8_t*)0x200005de = 0;
+  *(uint8_t*)0x200005df = 0;
+  *(uint8_t*)0x200005e0 = 0;
+  *(uint8_t*)0x200005e1 = 0;
+  *(uint8_t*)0x200005e2 = 0;
+  *(uint8_t*)0x200005e3 = 0;
+  *(uint8_t*)0x200005e4 = 0;
+  *(uint8_t*)0x200005e5 = 0;
+  *(uint8_t*)0x200005e6 = 0;
+  *(uint8_t*)0x200005e7 = 0;
+  *(uint8_t*)0x200005e8 = 0;
+  *(uint8_t*)0x200005e9 = 0;
+  *(uint8_t*)0x200005ea = 0;
+  *(uint8_t*)0x200005eb = 0;
+  *(uint8_t*)0x200005ec = 0;
+  *(uint8_t*)0x200005ed = 0;
+  *(uint8_t*)0x200005ee = 0;
+  *(uint8_t*)0x200005ef = 0;
+  *(uint8_t*)0x200005f0 = 0;
+  *(uint8_t*)0x200005f1 = 0;
+  *(uint8_t*)0x200005f2 = 0;
+  *(uint8_t*)0x200005f3 = 0;
+  *(uint8_t*)0x200005f4 = 0;
+  *(uint8_t*)0x200005f5 = 0;
+  *(uint8_t*)0x200005f6 = 0;
+  *(uint8_t*)0x200005f7 = 0;
+  *(uint8_t*)0x200005f8 = 0;
+  *(uint8_t*)0x200005f9 = 0;
+  *(uint8_t*)0x200005fa = 0;
+  *(uint8_t*)0x200005fb = 0;
+  *(uint8_t*)0x200005fc = 0;
+  *(uint8_t*)0x200005fd = 0;
+  *(uint8_t*)0x200005fe = 0;
+  *(uint8_t*)0x200005ff = 0;
+  *(uint8_t*)0x20000600 = 0;
+  *(uint8_t*)0x20000601 = 0;
+  *(uint8_t*)0x20000602 = 0;
+  *(uint8_t*)0x20000603 = 0;
+  *(uint8_t*)0x20000604 = 0;
+  *(uint8_t*)0x20000605 = 0;
+  *(uint8_t*)0x20000606 = 0;
+  *(uint8_t*)0x20000607 = 0;
+  *(uint8_t*)0x20000608 = 0;
+  *(uint8_t*)0x20000609 = 0;
+  *(uint8_t*)0x2000060a = 0;
+  *(uint8_t*)0x2000060b = 0;
+  *(uint32_t*)0x2000060c = 0;
+  *(uint16_t*)0x20000610 = 0x70;
+  *(uint16_t*)0x20000612 = 0x98;
+  *(uint32_t*)0x20000614 = 0;
+  *(uint64_t*)0x20000618 = 0;
+  *(uint64_t*)0x20000620 = 0;
+  *(uint16_t*)0x20000628 = 0x28;
+  memcpy((void*)0x2000062a, "\000\000\000\000\000\000\000\000\000\000\000\000"
+                            "\000\000\000\000\000\000\000\000\000\000\000\000"
+                            "\000\000\000\000\000",
+         29);
+  *(uint8_t*)0x20000647 = 0;
+  *(uint32_t*)0x20000648 = 0xfffffffe;
+  syscall(__NR_setsockopt, r[0], 0ul, 0x40ul, 0x20000240ul, 0x263ul);
+  res = syscall(__NR_socket, 2ul, 0x4000000000000001ul, 0);
+  if (res != -1)
+    r[1] = res;
+  *(uint32_t*)0x20000040 = 0x74;
+  syscall(__NR_setsockopt, r[1], 6ul, 0x80000000000002ul, 0x20000040ul, 4ul);
+  *(uint16_t*)0x20000280 = 2;
+  *(uint16_t*)0x20000282 = htobe16(0x4e23);
+  *(uint32_t*)0x20000284 = htobe32(0xe0000001);
+  syscall(__NR_bind, r[1], 0x20000280ul, 0x10ul);
+  *(uint16_t*)0x20e68000 = 2;
+  *(uint16_t*)0x20e68002 = htobe16(0x4e23);
+  *(uint32_t*)0x20e68004 = htobe32(0x7f000001);
+  syscall(__NR_sendto, r[1], 0ul, 0ul, 0x200007fdul, 0x20e68000ul, 0x10ul);
+  memcpy((void*)0x20000180,
+         "\x20\x26\x8a\x92\x7f\x1f\x65\x88\xb9\x67\x48\x12\x41\xba\x78\x60\xf4"
+         "\x6e\xf6\x5a\xc6\x18\xde\xd8\x97\x48\x95\xab\xea\xf4\xb4\x83\x4f\xf9"
+         "\x22\xb3\xf1\xe0\xb0\x2b\xd6\x7a\xa0\x30\x59\xbc\xec\xc7\xa9\x5c\x25"
+         "\xa3\xa0\x7e\x75\x80\x44\xab\x4e\xa6\xf7\xae\x55\xd8\x8f\xec\xf9\x22"
+         "\x1a\x75\x11\xbf\x74\x6b\xec\x66\xba\x5c\x0f\xe3\xac\x47\xb6\x1d\xb6"
+         "\xb4\xc4\x1b\xd1\xa5\x25\x9e\x62\x50\x6c\xda\x28\x7b\x85\x7a\xac",
+         101);
+  syscall(__NR_sendto, r[1], 0x20000180ul, 0x8293ul, 0x4000002ul, 0ul, 0x27ul);
+  return 0;
+}
diff --git a/syzkaller-repros/linux/010ab5cdbd5d0ca73a4227be6e883bd65fec09bc.c b/syzkaller-repros/linux/010ab5cdbd5d0ca73a4227be6e883bd65fec09bc.c
new file mode 100644
index 0000000..d121462
--- /dev/null
+++ b/syzkaller-repros/linux/010ab5cdbd5d0ca73a4227be6e883bd65fec09bc.c
@@ -0,0 +1,256 @@
+// Invalid request partialResult in splice
+// https://syzkaller.appspot.com/bug?id=010ab5cdbd5d0ca73a4227be6e883bd65fec09bc
+// status:fixed
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <endian.h>
+#include <errno.h>
+#include <pthread.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/futex.h>
+
+static __thread int skip_segv;
+static __thread jmp_buf segv_env;
+
+static void segv_handler(int sig, siginfo_t* info, void* ctx)
+{
+  uintptr_t addr = (uintptr_t)info->si_addr;
+  const uintptr_t prog_start = 1 << 20;
+  const uintptr_t prog_end = 100 << 20;
+  if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED) &&
+      (addr < prog_start || addr > prog_end)) {
+    _longjmp(segv_env, 1);
+  }
+  exit(sig);
+}
+
+static void install_segv_handler(void)
+{
+  struct sigaction sa;
+  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);
+  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(...)                                                        \
+  {                                                                            \
+    __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST);                       \
+    if (_setjmp(segv_env) == 0) {                                              \
+      __VA_ARGS__;                                                             \
+    }                                                                          \
+    __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST);                       \
+  }
+
+static void sleep_ms(uint64_t ms)
+{
+  usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+  struct timespec ts;
+  if (clock_gettime(CLOCK_MONOTONIC, &ts))
+    exit(1);
+  return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+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;
+  for (i = 0; i < 100; i++) {
+    if (pthread_create(&th, &attr, fn, arg) == 0) {
+      pthread_attr_destroy(&attr);
+      return;
+    }
+    if (errno == EAGAIN) {
+      usleep(50);
+      continue;
+    }
+    break;
+  }
+  exit(1);
+}
+
+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)
+    exit(1);
+  __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+  syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG);
+}
+
+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_t timeout)
+{
+  uint64_t start = current_time_ms();
+  uint64_t now = start;
+  for (;;) {
+    uint64_t 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_RELAXED))
+      return 1;
+    now = current_time_ms();
+    if (now - start > timeout)
+      return 0;
+  }
+}
+
+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;
+}
+
+static void loop(void)
+{
+  int i, call, thread;
+  for (call = 0; call < 6; 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);
+      event_timedwait(&th->done, 45);
+      break;
+    }
+  }
+  for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+    sleep_ms(1);
+}
+
+uint64_t r[3] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_call(int call)
+{
+  intptr_t res;
+  switch (call) {
+  case 0:
+    res = syscall(__NR_socketpair, 1, 5, 0, 0x200019c0);
+    if (res != -1)
+      NONFAILING(r[0] = *(uint32_t*)0x200019c0);
+    break;
+  case 1:
+    syscall(__NR_sendto, -1, 0, 0, 0, 0, 0);
+    break;
+  case 2:
+    res = syscall(__NR_pipe, 0x200002c0);
+    if (res != -1) {
+      NONFAILING(r[1] = *(uint32_t*)0x200002c0);
+      NONFAILING(r[2] = *(uint32_t*)0x200002c4);
+    }
+    break;
+  case 3:
+    syscall(__NR_splice, r[1], 0, r[0], 0, 0x420000a77, 0);
+    break;
+  case 4:
+    NONFAILING(*(uint32_t*)0x20000000 = 0x66);
+    NONFAILING(*(uint8_t*)0x20000004 = 0x7d);
+    NONFAILING(*(uint16_t*)0x20000005 = 2);
+    NONFAILING(*(uint16_t*)0x20000007 = 0);
+    NONFAILING(*(uint16_t*)0x20000009 = 0x5f);
+    NONFAILING(*(uint16_t*)0x2000000b = 0);
+    NONFAILING(*(uint32_t*)0x2000000d = 5);
+    NONFAILING(*(uint8_t*)0x20000011 = 2);
+    NONFAILING(*(uint32_t*)0x20000012 = 4);
+    NONFAILING(*(uint64_t*)0x20000016 = 2);
+    NONFAILING(*(uint32_t*)0x2000001e = 0x4000000);
+    NONFAILING(*(uint32_t*)0x20000022 = 0xcc);
+    NONFAILING(*(uint32_t*)0x20000026 = 0x3ff);
+    NONFAILING(*(uint64_t*)0x2000002a = 0xf057);
+    NONFAILING(*(uint16_t*)0x20000032 = 0xe);
+    NONFAILING(memcpy((void*)0x20000034, "wlan0Mmd5sum@)", 14));
+    NONFAILING(*(uint16_t*)0x20000042 = 3);
+    NONFAILING(memcpy((void*)0x20000044, "!%/", 3));
+    NONFAILING(*(uint16_t*)0x20000047 = 0x1b);
+    NONFAILING(memcpy((void*)0x20000049, "selinux\\!*proc-GPL*vboxnet0", 27));
+    NONFAILING(*(uint16_t*)0x20000064 = 0);
+    syscall(__NR_write, r[2], 0x20000000, 0x66);
+    break;
+  case 5:
+    syscall(__NR_write, r[2], 0x20000000, 0xfffffd88);
+    break;
+  }
+}
+int main(void)
+{
+  syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+  install_segv_handler();
+  loop();
+  return 0;
+}
diff --git a/syzkaller-repros/linux/01a2b05ebbe9be9802bcccfd2008e74cc3a55ed1.c b/syzkaller-repros/linux/01a2b05ebbe9be9802bcccfd2008e74cc3a55ed1.c
new file mode 100644
index 0000000..8b3307d
--- /dev/null
+++ b/syzkaller-repros/linux/01a2b05ebbe9be9802bcccfd2008e74cc3a55ed1.c
@@ -0,0 +1,374 @@
+// KASAN: user-memory-access Read in insert_char
+// https://syzkaller.appspot.com/bug?id=01a2b05ebbe9be9802bcccfd2008e74cc3a55ed1
+// status:open
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.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[1024];
+};
+
+static struct nlmsg nlmsg;
+
+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;
+  memcpy(attr + 1, data, size);
+  nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+                            int* reply_len)
+{
+  if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+    exit(1);
+  struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+  hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+  struct sockaddr_nl addr;
+  memset(&addr, 0, sizeof(addr));
+  addr.nl_family = AF_NETLINK;
+  unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+                      (struct sockaddr*)&addr, sizeof(addr));
+  if (n != hdr->nlmsg_len)
+    exit(1);
+  n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+  if (hdr->nlmsg_type == NLMSG_DONE) {
+    *reply_len = 0;
+    return 0;
+  }
+  if (n < sizeof(struct nlmsghdr))
+    exit(1);
+  if (reply_len && hdr->nlmsg_type == reply_type) {
+    *reply_len = n;
+    return 0;
+  }
+  if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+    exit(1);
+  if (hdr->nlmsg_type != NLMSG_ERROR)
+    exit(1);
+  return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+  return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+                            unsigned int total_len)
+{
+  struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+  if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+    return -1;
+  return hdr->nlmsg_len;
+}
+
+static void netlink_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);
+  (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+  struct genlmsghdr genlhdr;
+  struct nlattr* attr;
+  int err, n;
+  uint16_t id = 0;
+  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, DEVLINK_FAMILY_NAME,
+               strlen(DEVLINK_FAMILY_NAME) + 1);
+  err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+  if (err) {
+    return -1;
+  }
+  attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+                          NLMSG_ALIGN(sizeof(genlhdr)));
+  for (; (char*)attr < nlmsg->buf + n;
+       attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+    if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+      id = *(uint16_t*)(attr + 1);
+      break;
+    }
+  }
+  if (!id) {
+    return -1;
+  }
+  recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+  return id;
+}
+
+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)
+    exit(1);
+  id = netlink_devlink_id_get(&nlmsg, sock);
+  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) {
+  }
+error:
+  close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+                                     const char* netdev_prefix)
+{
+  struct genlmsghdr genlhdr;
+  int len, total_len, id, err, offset;
+  uint16_t netdev_index;
+  int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+  if (sock == -1)
+    exit(1);
+  int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+  if (rtsock == -1)
+    exit(1);
+  id = netlink_devlink_id_get(&nlmsg, sock);
+  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);
+  if (err) {
+    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);
+}
+
+static void initialize_devlink_pci(void)
+{
+  int netns = open("/proc/self/ns/net", O_RDONLY);
+  if (netns == -1)
+    exit(1);
+  int ret = setns(kInitNetNsFd, 0);
+  if (ret == -1)
+    exit(1);
+  netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+  ret = setns(netns, 0);
+  if (ret == -1)
+    exit(1);
+  close(netns);
+  initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+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_t)a1,
+            (uint8_t)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);
+  }
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+int main(void)
+{
+  syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+  intptr_t res = 0;
+  memcpy((void*)0x20000180, "/dev/fb0\000", 9);
+  res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x20000180ul, 0ul, 0ul);
+  if (res != -1)
+    r[0] = res;
+  *(uint32_t*)0x20000000 = 0x356;
+  *(uint32_t*)0x20000004 = 0;
+  *(uint32_t*)0x20000008 = 0;
+  *(uint32_t*)0x2000000c = 0;
+  *(uint32_t*)0x20000010 = 0;
+  *(uint32_t*)0x20000014 = 0;
+  *(uint32_t*)0x20000018 = 8;
+  *(uint32_t*)0x2000001c = 0;
+  *(uint32_t*)0x20000020 = 0;
+  *(uint32_t*)0x20000024 = 0;
+  *(uint32_t*)0x20000028 = 0;
+  *(uint32_t*)0x2000002c = 0;
+  *(uint32_t*)0x20000030 = 0;
+  *(uint32_t*)0x20000034 = 0;
+  *(uint32_t*)0x20000038 = 0;
+  *(uint32_t*)0x2000003c = 0;
+  *(uint32_t*)0x20000040 = 0;
+  *(uint32_t*)0x20000044 = 0;
+  *(uint32_t*)0x20000048 = 0;
+  *(uint32_t*)0x2000004c = 0;
+  *(uint32_t*)0x20000050 = 0;
+  *(uint32_t*)0x20000054 = 0;
+  *(uint32_t*)0x20000058 = 0;
+  *(uint32_t*)0x2000005c = 0;
+  *(uint32_t*)0x20000060 = 0;
+  *(uint32_t*)0x20000064 = 0;
+  *(uint32_t*)0x20000068 = 0;
+  *(uint32_t*)0x2000006c = 0;
+  *(uint32_t*)0x20000070 = 0;
+  *(uint32_t*)0x20000074 = 0;
+  *(uint32_t*)0x20000078 = 0;
+  *(uint32_t*)0x2000007c = 0;
+  *(uint32_t*)0x20000080 = 0;
+  *(uint32_t*)0x20000084 = 0;
+  *(uint32_t*)0x20000088 = 0;
+  *(uint32_t*)0x2000008c = 0;
+  *(uint32_t*)0x20000090 = 0;
+  *(uint32_t*)0x20000094 = 0;
+  *(uint32_t*)0x20000098 = 0;
+  *(uint32_t*)0x2000009c = 0;
+  syscall(__NR_ioctl, r[0], 0x4601ul, 0x20000000ul);
+  res = syz_open_dev(0xc, 4, 0x14);
+  if (res != -1)
+    r[1] = res;
+  *(uint8_t*)0x20000000 = 0xe;
+  *(uint8_t*)0x20000001 = 0x9b;
+  *(uint8_t*)0x20000002 = 0x3e;
+  *(uint8_t*)0x20000003 = 0x9b;
+  *(uint8_t*)0x20000004 = 0;
+  *(uint8_t*)0x20000005 = 0;
+  *(uint8_t*)0x20000006 = 0;
+  *(uint8_t*)0x20000007 = 0;
+  *(uint64_t*)0x20000008 = 0;
+  *(uint16_t*)0x20000010 = 0;
+  *(uint16_t*)0x20000012 = 0;
+  *(uint32_t*)0x20000014 = 0;
+  *(uint64_t*)0x20000018 = 0;
+  *(uint64_t*)0x20000020 = 0x40;
+  *(uint64_t*)0x20000028 = 0;
+  *(uint32_t*)0x20000030 = 0;
+  *(uint16_t*)0x20000034 = 0;
+  *(uint16_t*)0x20000036 = 0x38;
+  *(uint16_t*)0x20000038 = 0;
+  *(uint16_t*)0x2000003a = 0;
+  *(uint16_t*)0x2000003c = 0;
+  *(uint16_t*)0x2000003e = 0;
+  *(uint32_t*)0x20000040 = 0;
+  *(uint32_t*)0x20000044 = 0;
+  *(uint64_t*)0x20000048 = 0;
+  *(uint64_t*)0x20000050 = 0;
+  *(uint64_t*)0x20000058 = 0;
+  *(uint64_t*)0x20000060 = 0;
+  *(uint64_t*)0x20000068 = 0;
+  *(uint64_t*)0x20000070 = 0;
+  syscall(__NR_write, r[1], 0x20000000ul, 0x78ul);
+  return 0;
+}
diff --git a/syzkaller-repros/linux/024b4f3d076f4b520b80b7affdb89a4c7c1797ff.c b/syzkaller-repros/linux/024b4f3d076f4b520b80b7affdb89a4c7c1797ff.c
new file mode 100644
index 0000000..65b31ed
--- /dev/null
+++ b/syzkaller-repros/linux/024b4f3d076f4b520b80b7affdb89a4c7c1797ff.c
@@ -0,0 +1,191 @@
+// general protection fault in pagemap_pmd_range
+// https://syzkaller.appspot.com/bug?id=024b4f3d076f4b520b80b7affdb89a4c7c1797ff
+// status:invalid
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.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>
+
+static struct {
+  char* pos;
+  int nesting;
+  struct nlattr* nested[8];
+  char buf[1024];
+} nlmsg;
+
+static void netlink_init(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(int typ, const void* data, int size)
+{
+  struct nlattr* attr = (struct nlattr*)nlmsg.pos;
+  attr->nla_len = sizeof(*attr) + size;
+  attr->nla_type = typ;
+  memcpy(attr + 1, data, size);
+  nlmsg.pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(int sock, uint16_t reply_type, int* reply_len)
+{
+  if (nlmsg.pos > nlmsg.buf + sizeof(nlmsg.buf) || nlmsg.nesting)
+    exit(1);
+  struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg.buf;
+  hdr->nlmsg_len = nlmsg.pos - nlmsg.buf;
+  struct sockaddr_nl addr;
+  memset(&addr, 0, sizeof(addr));
+  addr.nl_family = AF_NETLINK;
+  unsigned n = sendto(sock, nlmsg.buf, hdr->nlmsg_len, 0,
+                      (struct sockaddr*)&addr, sizeof(addr));
+  if (n != hdr->nlmsg_len)
+    exit(1);
+  n = recv(sock, nlmsg.buf, sizeof(nlmsg.buf), 0);
+  if (n < sizeof(struct nlmsghdr))
+    exit(1);
+  if (reply_len && hdr->nlmsg_type == reply_type) {
+    *reply_len = n;
+    return 0;
+  }
+  if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+    exit(1);
+  if (hdr->nlmsg_type != NLMSG_ERROR)
+    exit(1);
+  return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(int sock)
+{
+  return netlink_send_ext(sock, 0, NULL);
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETNS_FD 137
+
+static void netlink_devlink_netns_move(const char* bus_name,
+                                       const char* dev_name, int netns_fd)
+{
+  struct genlmsghdr genlhdr;
+  struct nlattr* attr;
+  int sock, err, n;
+  uint16_t id = 0;
+  sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+  if (sock == -1)
+    exit(1);
+  memset(&genlhdr, 0, sizeof(genlhdr));
+  genlhdr.cmd = CTRL_CMD_GETFAMILY;
+  netlink_init(GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+  netlink_attr(CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+               strlen(DEVLINK_FAMILY_NAME) + 1);
+  err = netlink_send_ext(sock, GENL_ID_CTRL, &n);
+  if (err) {
+    goto error;
+  }
+  attr =
+      (struct nlattr*)(nlmsg.buf + NLMSG_HDRLEN + NLMSG_ALIGN(sizeof(genlhdr)));
+  for (; (char*)attr < nlmsg.buf + n;
+       attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+    if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+      id = *(uint16_t*)(attr + 1);
+      break;
+    }
+  }
+  if (!id) {
+    goto error;
+  }
+  recv(sock, nlmsg.buf, sizeof(nlmsg.buf), 0); /* recv ack */
+  memset(&genlhdr, 0, sizeof(genlhdr));
+  genlhdr.cmd = DEVLINK_CMD_RELOAD;
+  netlink_init(id, 0, &genlhdr, sizeof(genlhdr));
+  netlink_attr(DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+  netlink_attr(DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+  netlink_attr(DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+  netlink_send(sock);
+error:
+  close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+  int netns = open("/proc/self/ns/net", O_RDONLY);
+  if (netns == -1)
+    exit(1);
+  int ret = setns(kInitNetNsFd, 0);
+  if (ret == -1)
+    exit(1);
+  netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+  ret = setns(netns, 0);
+  if (ret == -1)
+    exit(1);
+  close(netns);
+}
+
+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;
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+int main(void)
+{
+  syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+  intptr_t res = 0;
+  res = syscall(__NR_socket, 0xa, 2, 0);
+  if (res != -1)
+    r[0] = res;
+  memcpy((void*)0x20000440, "pagemap\000", 8);
+  res = syz_open_procfs(0, 0x20000440);
+  if (res != -1)
+    r[1] = res;
+  syscall(__NR_sendfile, r[0], r[1], 0, 0x100000206201);
+  syscall(__NR_connect, -1, 0, 0);
+  return 0;
+}
diff --git a/syzkaller-repros/linux/02faf2901eb60e0683ed6f9bd415ff946b6a2f1d.c b/syzkaller-repros/linux/02faf2901eb60e0683ed6f9bd415ff946b6a2f1d.c
new file mode 100644
index 0000000..8e54859
--- /dev/null
+++ b/syzkaller-repros/linux/02faf2901eb60e0683ed6f9bd415ff946b6a2f1d.c
@@ -0,0 +1,541 @@
+// BUG: sleeping function called from invalid context in tpk_write
+// https://syzkaller.appspot.com/bug?id=02faf2901eb60e0683ed6f9bd415ff946b6a2f1d
+// status:open
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/futex.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>
+
+static void sleep_ms(uint64_t ms)
+{
+  usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+  struct timespec ts;
+  if (clock_gettime(CLOCK_MONOTONIC, &ts))
+    exit(1);
+  return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+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;
+  for (i = 0; i < 100; i++) {
+    if (pthread_create(&th, &attr, fn, arg) == 0) {
+      pthread_attr_destroy(&attr);
+      return;
+    }
+    if (errno == EAGAIN) {
+      usleep(50);
+      continue;
+    }
+    break;
+  }
+  exit(1);
+}
+
+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)
+    exit(1);
+  __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+  syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG);
+}
+
+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_t timeout)
+{
+  uint64_t start = current_time_ms();
+  uint64_t now = start;
+  for (;;) {
+    uint64_t 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_RELAXED))
+      return 1;
+    now = current_time_ms();
+    if (now - start > timeout)
+      return 0;
+  }
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+  char buf[1024];
+  va_list args;
+  va_start(args, what);
+  vsnprintf(buf, sizeof(buf), what, args);
+  va_end(args);
+  buf[sizeof(buf) - 1] = 0;
+  int len = strlen(buf);
+  int fd = open(file, O_WRONLY | O_CLOEXEC);
+  if (fd == -1)
+    return false;
+  if (write(fd, buf, len) != len) {
+    int err = errno;
+    close(fd);
+    errno = err;
+    return false;
+  }
+  close(fd);
+  return true;
+}
+
+struct nlmsg {
+  char* pos;
+  int nesting;
+  struct nlattr* nested[8];
+  char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+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;
+  memcpy(attr + 1, data, size);
+  nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+                            int* reply_len)
+{
+  if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+    exit(1);
+  struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+  hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+  struct sockaddr_nl addr;
+  memset(&addr, 0, sizeof(addr));
+  addr.nl_family = AF_NETLINK;
+  unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+                      (struct sockaddr*)&addr, sizeof(addr));
+  if (n != hdr->nlmsg_len)
+    exit(1);
+  n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+  if (hdr->nlmsg_type == NLMSG_DONE) {
+    *reply_len = 0;
+    return 0;
+  }
+  if (n < sizeof(struct nlmsghdr))
+    exit(1);
+  if (reply_len && hdr->nlmsg_type == reply_type) {
+    *reply_len = n;
+    return 0;
+  }
+  if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+    exit(1);
+  if (hdr->nlmsg_type != NLMSG_ERROR)
+    exit(1);
+  return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+  return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+                            unsigned int total_len)
+{
+  struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+  if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+    return -1;
+  return hdr->nlmsg_len;
+}
+
+static void netlink_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);
+  (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+  struct genlmsghdr genlhdr;
+  struct nlattr* attr;
+  int err, n;
+  uint16_t id = 0;
+  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, DEVLINK_FAMILY_NAME,
+               strlen(DEVLINK_FAMILY_NAME) + 1);
+  err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+  if (err) {
+    return -1;
+  }
+  attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+                          NLMSG_ALIGN(sizeof(genlhdr)));
+  for (; (char*)attr < nlmsg->buf + n;
+       attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+    if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+      id = *(uint16_t*)(attr + 1);
+      break;
+    }
+  }
+  if (!id) {
+    return -1;
+  }
+  recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+  return id;
+}
+
+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)
+    exit(1);
+  id = netlink_devlink_id_get(&nlmsg, sock);
+  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) {
+  }
+error:
+  close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+                                     const char* netdev_prefix)
+{
+  struct genlmsghdr genlhdr;
+  int len, total_len, id, err, offset;
+  uint16_t netdev_index;
+  int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+  if (sock == -1)
+    exit(1);
+  int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+  if (rtsock == -1)
+    exit(1);
+  id = netlink_devlink_id_get(&nlmsg, sock);
+  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);
+  if (err) {
+    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);
+}
+
+static void initialize_devlink_pci(void)
+{
+  int netns = open("/proc/self/ns/net", O_RDONLY);
+  if (netns == -1)
+    exit(1);
+  int ret = setns(kInitNetNsFd, 0);
+  if (ret == -1)
+    exit(1);
+  netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+  ret = setns(netns, 0);
+  if (ret == -1)
+    exit(1);
+  close(netns);
+  initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+  kill(-pid, SIGKILL);
+  kill(pid, SIGKILL);
+  int i;
+  for (i = 0; i < 100; i++) {
+    if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+      return;
+    usleep(1000);
+  }
+  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) {
+        continue;
+      }
+      if (write(fd, abort, 1) < 0) {
+      }
+      close(fd);
+    }
+    closedir(dir);
+  } else {
+  }
+  while (waitpid(-1, status, __WALL) != pid) {
+  }
+}
+
+static void setup_test()
+{
+  prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+  setpgrp();
+  write_file("/proc/self/oom_score_adj", "1000");
+}
+
+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;
+}
+
+static void execute_one(void)
+{
+  int i, call, thread;
+  int collide = 0;
+again:
+  for (call = 0; call < 3; 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 (collide && (call % 2) == 0)
+        break;
+      event_timedwait(&th->done, 45);
+      break;
+    }
+  }
+  for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+    sleep_ms(1);
+  if (!collide) {
+    collide = 1;
+    goto again;
+  }
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+  int iter;
+  for (iter = 0;; iter++) {
+    int pid = fork();
+    if (pid < 0)
+      exit(1);
+    if (pid == 0) {
+      setup_test();
+      execute_one();
+      exit(0);
+    }
+    int status = 0;
+    uint64_t start = current_time_ms();
+    for (;;) {
+      if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+        break;
+      sleep_ms(1);
+      if (current_time_ms() - start < 5 * 1000)
+        continue;
+      kill_and_wait(pid, &status);
+      break;
+    }
+  }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_call(int call)
+{
+  intptr_t res;
+  switch (call) {
+  case 0:
+    syscall(__NR_clone, 0ul, 0ul, 0ul, 0ul, 0ul);
+    break;
+  case 1:
+    memcpy((void*)0x20001540, "/dev/ttyprintk\000", 15);
+    res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x20001540ul, 0ul, 0ul);
+    if (res != -1)
+      r[0] = res;
+    break;
+  case 2:
+    *(uint32_t*)0x20001580 = 7;
+    syscall(__NR_ioctl, r[0], 0x5423ul, 0x20001580ul);
+    break;
+  }
+}
+int main(void)
+{
+  syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+  loop();
+  return 0;
+}
diff --git a/syzkaller-repros/linux/03d4470b64b2524f9dfdc814940972203d04d398.c b/syzkaller-repros/linux/03d4470b64b2524f9dfdc814940972203d04d398.c
new file mode 100644
index 0000000..2012a46
--- /dev/null
+++ b/syzkaller-repros/linux/03d4470b64b2524f9dfdc814940972203d04d398.c
@@ -0,0 +1,347 @@
+// general protection fault in virtio_transport_release
+// https://syzkaller.appspot.com/bug?id=03d4470b64b2524f9dfdc814940972203d04d398
+// status:fixed
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.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>
+
+static bool write_file(const char* file, const char* what, ...)
+{
+  char buf[1024];
+  va_list args;
+  va_start(args, what);
+  vsnprintf(buf, sizeof(buf), what, args);
+  va_end(args);
+  buf[sizeof(buf) - 1] = 0;
+  int len = strlen(buf);
+  int fd = open(file, O_WRONLY | O_CLOEXEC);
+  if (fd == -1)
+    return false;
+  if (write(fd, buf, len) != len) {
+    int err = errno;
+    close(fd);
+    errno = err;
+    return false;
+  }
+  close(fd);
+  return true;
+}
+
+struct nlmsg {
+  char* pos;
+  int nesting;
+  struct nlattr* nested[8];
+  char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+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;
+  memcpy(attr + 1, data, size);
+  nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+                            int* reply_len)
+{
+  if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+    exit(1);
+  struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+  hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+  struct sockaddr_nl addr;
+  memset(&addr, 0, sizeof(addr));
+  addr.nl_family = AF_NETLINK;
+  unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+                      (struct sockaddr*)&addr, sizeof(addr));
+  if (n != hdr->nlmsg_len)
+    exit(1);
+  n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+  if (hdr->nlmsg_type == NLMSG_DONE) {
+    *reply_len = 0;
+    return 0;
+  }
+  if (n < sizeof(struct nlmsghdr))
+    exit(1);
+  if (reply_len && hdr->nlmsg_type == reply_type) {
+    *reply_len = n;
+    return 0;
+  }
+  if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+    exit(1);
+  if (hdr->nlmsg_type != NLMSG_ERROR)
+    exit(1);
+  return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+  return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+                            unsigned int total_len)
+{
+  struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+  if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+    return -1;
+  return hdr->nlmsg_len;
+}
+
+static void netlink_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);
+  (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 137
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+  struct genlmsghdr genlhdr;
+  struct nlattr* attr;
+  int err, n;
+  uint16_t id = 0;
+  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, DEVLINK_FAMILY_NAME,
+               strlen(DEVLINK_FAMILY_NAME) + 1);
+  err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+  if (err) {
+    return -1;
+  }
+  attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+                          NLMSG_ALIGN(sizeof(genlhdr)));
+  for (; (char*)attr < nlmsg->buf + n;
+       attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+    if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+      id = *(uint16_t*)(attr + 1);
+      break;
+    }
+  }
+  if (!id) {
+    return -1;
+  }
+  recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+  return id;
+}
+
+static void netlink_devlink_netns_move(const char* bus_name,
+                                       const char* dev_name, int netns_fd)
+{
+  struct genlmsghdr genlhdr;
+  int sock;
+  int id;
+  sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+  if (sock == -1)
+    exit(1);
+  id = netlink_devlink_id_get(&nlmsg, sock);
+  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));
+  netlink_send(&nlmsg, sock);
+error:
+  close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+                                     const char* netdev_prefix)
+{
+  struct genlmsghdr genlhdr;
+  int len, total_len, id, err, offset;
+  uint16_t netdev_index;
+  int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+  if (sock == -1)
+    exit(1);
+  int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+  if (rtsock == -1)
+    exit(1);
+  id = netlink_devlink_id_get(&nlmsg, sock);
+  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);
+  if (err) {
+    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);
+}
+
+static void initialize_devlink_pci(void)
+{
+  int netns = open("/proc/self/ns/net", O_RDONLY);
+  if (netns == -1)
+    exit(1);
+  int ret = setns(kInitNetNsFd, 0);
+  if (ret == -1)
+    exit(1);
+  netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+  ret = setns(netns, 0);
+  if (ret == -1)
+    exit(1);
+  close(netns);
+  initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+static int inject_fault(int nth)
+{
+  int fd;
+  fd = open("/proc/thread-self/fail-nth", O_RDWR);
+  if (fd == -1)
+    exit(1);
+  char buf[16];
+  sprintf(buf, "%d", nth + 1);
+  if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf))
+    exit(1);
+  return fd;
+}
+
+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)) {
+      if (files[i].fatal)
+        exit(1);
+    }
+  }
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+int main(void)
+{
+  syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+  setup_fault();
+  intptr_t res = 0;
+  res = syscall(__NR_socket, 2ul, 2ul, 0x88ul);
+  if (res != -1)
+    r[0] = res;
+  syscall(__NR_ioctl, r[0], 0x1000008912ul, 0ul);
+  res = syscall(__NR_socket, 0x28ul, 1ul, 0ul);
+  if (res != -1)
+    r[1] = res;
+  *(uint16_t*)0x200000c0 = 0x28;
+  *(uint16_t*)0x200000c2 = 0;
+  *(uint32_t*)0x200000c4 = 0;
+  *(uint32_t*)0x200000c8 = -1;
+  *(uint32_t*)0x200000cc = 0;
+  inject_fault(0);
+  syscall(__NR_connect, r[1], 0x200000c0ul, 0x10ul);
+  return 0;
+}
diff --git a/syzkaller-repros/linux/04775771a119c1ba4974a07c365475ada756a40d.c b/syzkaller-repros/linux/04775771a119c1ba4974a07c365475ada756a40d.c
new file mode 100644
index 0000000..8e92a66
--- /dev/null
+++ b/syzkaller-repros/linux/04775771a119c1ba4974a07c365475ada756a40d.c
@@ -0,0 +1,374 @@
+// BUG: unable to handle kernel paging request in do_con_trol
+// https://syzkaller.appspot.com/bug?id=04775771a119c1ba4974a07c365475ada756a40d
+// status:open
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <endian.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.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[1024];
+};
+
+static struct nlmsg nlmsg;
+
+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;
+  memcpy(attr + 1, data, size);
+  nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+                            int* reply_len)
+{
+  if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+    exit(1);
+  struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+  hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+  struct sockaddr_nl addr;
+  memset(&addr, 0, sizeof(addr));
+  addr.nl_family = AF_NETLINK;
+  unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+                      (struct sockaddr*)&addr, sizeof(addr));
+  if (n != hdr->nlmsg_len)
+    exit(1);
+  n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+  if (hdr->nlmsg_type == NLMSG_DONE) {
+    *reply_len = 0;
+    return 0;
+  }
+  if (n < sizeof(struct nlmsghdr))
+    exit(1);
+  if (reply_len && hdr->nlmsg_type == reply_type) {
+    *reply_len = n;
+    return 0;
+  }
+  if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+    exit(1);
+  if (hdr->nlmsg_type != NLMSG_ERROR)
+    exit(1);
+  return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+  return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+                            unsigned int total_len)
+{
+  struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+  if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+    return -1;
+  return hdr->nlmsg_len;
+}
+
+static void netlink_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);
+  (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+  struct genlmsghdr genlhdr;
+  struct nlattr* attr;
+  int err, n;
+  uint16_t id = 0;
+  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, DEVLINK_FAMILY_NAME,
+               strlen(DEVLINK_FAMILY_NAME) + 1);
+  err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+  if (err) {
+    return -1;
+  }
+  attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+                          NLMSG_ALIGN(sizeof(genlhdr)));
+  for (; (char*)attr < nlmsg->buf + n;
+       attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+    if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+      id = *(uint16_t*)(attr + 1);
+      break;
+    }
+  }
+  if (!id) {
+    return -1;
+  }
+  recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+  return id;
+}
+
+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)
+    exit(1);
+  id = netlink_devlink_id_get(&nlmsg, sock);
+  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) {
+  }
+error:
+  close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+                                     const char* netdev_prefix)
+{
+  struct genlmsghdr genlhdr;
+  int len, total_len, id, err, offset;
+  uint16_t netdev_index;
+  int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+  if (sock == -1)
+    exit(1);
+  int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+  if (rtsock == -1)
+    exit(1);
+  id = netlink_devlink_id_get(&nlmsg, sock);
+  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);
+  if (err) {
+    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);
+}
+
+static void initialize_devlink_pci(void)
+{
+  int netns = open("/proc/self/ns/net", O_RDONLY);
+  if (netns == -1)
+    exit(1);
+  int ret = setns(kInitNetNsFd, 0);
+  if (ret == -1)
+    exit(1);
+  netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+  ret = setns(netns, 0);
+  if (ret == -1)
+    exit(1);
+  close(netns);
+  initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+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_t)a1,
+            (uint8_t)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);
+  }
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+int main(void)
+{
+  syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+  intptr_t res = 0;
+  memcpy((void*)0x20000100, "/dev/fb0\000", 9);
+  res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x20000100ul, 0ul, 0ul);
+  if (res != -1)
+    r[0] = res;
+  *(uint32_t*)0x20000140 = 0;
+  *(uint32_t*)0x20000144 = 0;
+  *(uint32_t*)0x20000148 = 0;
+  *(uint32_t*)0x2000014c = 0;
+  *(uint32_t*)0x20000150 = 0;
+  *(uint32_t*)0x20000154 = 0;
+  *(uint32_t*)0x20000158 = 8;
+  *(uint32_t*)0x2000015c = 0;
+  *(uint32_t*)0x20000160 = 0;
+  *(uint32_t*)0x20000164 = 0;
+  *(uint32_t*)0x20000168 = 0;
+  *(uint32_t*)0x2000016c = 0;
+  *(uint32_t*)0x20000170 = 0;
+  *(uint32_t*)0x20000174 = 0;
+  *(uint32_t*)0x20000178 = 0;
+  *(uint32_t*)0x2000017c = 0;
+  *(uint32_t*)0x20000180 = 0;
+  *(uint32_t*)0x20000184 = 0;
+  *(uint32_t*)0x20000188 = 0;
+  *(uint32_t*)0x2000018c = 0;
+  *(uint32_t*)0x20000190 = 0;
+  *(uint32_t*)0x20000194 = 0;
+  *(uint32_t*)0x20000198 = 0;
+  *(uint32_t*)0x2000019c = 0;
+  *(uint32_t*)0x200001a0 = 0;
+  *(uint32_t*)0x200001a4 = 0;
+  *(uint32_t*)0x200001a8 = 0;
+  *(uint32_t*)0x200001ac = 0;
+  *(uint32_t*)0x200001b0 = 0;
+  *(uint32_t*)0x200001b4 = 0;
+  *(uint32_t*)0x200001b8 = 0;
+  *(uint32_t*)0x200001bc = 0;
+  *(uint32_t*)0x200001c0 = 0;
+  *(uint32_t*)0x200001c4 = 3;
+  *(uint32_t*)0x200001c8 = 0;
+  *(uint32_t*)0x200001cc = 0;
+  *(uint32_t*)0x200001d0 = 0;
+  *(uint32_t*)0x200001d4 = 0;
+  *(uint32_t*)0x200001d8 = 0;
+  *(uint32_t*)0x200001dc = 0;
+  syscall(__NR_ioctl, r[0], 0x4601ul, 0x20000140ul);
+  res = syz_open_dev(0xc, 4, 0x14);
+  if (res != -1)
+    r[1] = res;
+  *(uint8_t*)0x20000200 = 0x1b;
+  *(uint8_t*)0x20000201 = 0x5b;
+  *(uint8_t*)0x20000202 = 0x4b;
+  *(uint8_t*)0x20000203 = 0x9b;
+  *(uint8_t*)0x20000204 = 0;
+  *(uint8_t*)0x20000205 = 0;
+  *(uint8_t*)0x20000206 = 0;
+  *(uint8_t*)0x20000207 = 0;
+  *(uint64_t*)0x20000208 = 0;
+  *(uint16_t*)0x20000210 = 0;
+  *(uint16_t*)0x20000212 = 0;
+  *(uint32_t*)0x20000214 = 0;
+  *(uint64_t*)0x20000218 = 0;
+  *(uint64_t*)0x20000220 = 0x40;
+  *(uint64_t*)0x20000228 = 0;
+  *(uint32_t*)0x20000230 = 0;
+  *(uint16_t*)0x20000234 = 0;
+  *(uint16_t*)0x20000236 = 0x38;
+  *(uint16_t*)0x20000238 = 0;
+  *(uint16_t*)0x2000023a = 0;
+  *(uint16_t*)0x2000023c = 0;
+  *(uint16_t*)0x2000023e = 0;
+  *(uint32_t*)0x20000240 = 0;
+  *(uint32_t*)0x20000244 = 0;
+  *(uint64_t*)0x20000248 = 0;
+  *(uint64_t*)0x20000250 = 0;
+  *(uint64_t*)0x20000258 = 0;
+  *(uint64_t*)0x20000260 = 0;
+  *(uint64_t*)0x20000268 = 0;
+  *(uint64_t*)0x20000270 = 0;
+  syscall(__NR_write, r[1], 0x20000200ul, 0x78ul);
+  return 0;
+}
diff --git a/syzkaller-repros/linux/059f48dafc729cacafe8430d24a70920d4134c05.c b/syzkaller-repros/linux/059f48dafc729cacafe8430d24a70920d4134c05.c
new file mode 100644
index 0000000..6f06a0c
--- /dev/null
+++ b/syzkaller-repros/linux/059f48dafc729cacafe8430d24a70920d4134c05.c
@@ -0,0 +1,111 @@
+// general protection fault in nft_chain_parse_hook
+// https://syzkaller.appspot.com/bug?id=059f48dafc729cacafe8430d24a70920d4134c05
+// status:open
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <endian.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#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))))
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+int main(void)
+{
+  syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+  intptr_t res = 0;
+  res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+  if (res != -1)
+    r[0] = res;
+  *(uint64_t*)0x20000280 = 0;
+  *(uint32_t*)0x20000288 = 8;
+  *(uint64_t*)0x20000290 = 0x20000240;
+  *(uint64_t*)0x20000240 = 0x20000100;
+  memcpy((void*)0x20000100,
+         "\x14\x00\x00\x00\x10\x00\x00\x00\x1e\x6c\x00\x00\x00\x08\x00\x00\x00"
+         "\x00\x00\x0a\x20\x00\x00\x00\x00\x0a\x01\x00\x00\x00\x00\x00\x00\x00"
+         "\x00\x00\x00\x00\x00\x00\x09\x00\x01\x00\x73\x79\x7a\x30\x00\x00\x00"
+         "\x00\x38\x00\x00\x00\x12\x0a\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+         "\x00\x00\x00\x08\x04\x00\x04\x80\x09\x00\x02\x00\x00\x39\x7d\x00\x00"
+         "\x00\x00\x00\x09\x00\x01\x00\x73\x79\x7a\x30\x00\x00\x00\x00\x08\x00"
+         "\x03\x40\x00\x00\x00\x01\x14\x00\x00\x00\x11\x00\xdf\x00\x00\x00\x00"
+         "\x00\x00\x00\x00\x00\x00\x00\x00\x0a",
+         128);
+  *(uint64_t*)0x20000248 = 0x80;
+  *(uint64_t*)0x20000298 = 1;
+  *(uint64_t*)0x200002a0 = 0;
+  *(uint64_t*)0x200002a8 = 0;
+  *(uint32_t*)0x200002b0 = 0;
+  syscall(__NR_sendmsg, r[0], 0x20000280ul, 0ul);
+  res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+  if (res != -1)
+    r[1] = res;
+  *(uint64_t*)0x2000d400 = 0;
+  *(uint32_t*)0x2000d408 = 0;
+  *(uint64_t*)0x2000d410 = 0x2000d3c0;
+  *(uint64_t*)0x2000d3c0 = 0x20009e80;
+  *(uint32_t*)0x20009e80 = 0x14;
+  *(uint16_t*)0x20009e84 = 0x10;
+  *(uint16_t*)0x20009e86 = 1;
+  *(uint32_t*)0x20009e88 = 0;
+  *(uint32_t*)0x20009e8c = 0;
+  *(uint8_t*)0x20009e90 = 0;
+  *(uint8_t*)0x20009e91 = 0;
+  *(uint16_t*)0x20009e92 = htobe16(0xa);
+  *(uint32_t*)0x20009e94 = 0x40;
+  *(uint8_t*)0x20009e98 = 3;
+  *(uint8_t*)0x20009e99 = 0xa;
+  *(uint16_t*)0x20009e9a = 0x401;
+  *(uint32_t*)0x20009e9c = 0;
+  *(uint32_t*)0x20009ea0 = 0;
+  *(uint8_t*)0x20009ea4 = 0;
+  *(uint8_t*)0x20009ea5 = 0;
+  *(uint16_t*)0x20009ea6 = htobe16(0);
+  *(uint16_t*)0x20009ea8 = 9;
+  *(uint16_t*)0x20009eaa = 3;
+  memcpy((void*)0x20009eac, "syz2\000", 5);
+  *(uint16_t*)0x20009eb4 = 9;
+  *(uint16_t*)0x20009eb6 = 1;
+  memcpy((void*)0x20009eb8, "syz0\000", 5);
+  *(uint16_t*)0x20009ec0 = 0x14;
+  STORE_BY_BITMASK(uint16_t, , 0x20009ec2, 4, 0, 14);
+  STORE_BY_BITMASK(uint16_t, , 0x20009ec3, 0, 6, 1);
+  STORE_BY_BITMASK(uint16_t, , 0x20009ec3, 1, 7, 1);
+  *(uint16_t*)0x20009ec4 = 8;
+  STORE_BY_BITMASK(uint16_t, , 0x20009ec6, 1, 0, 14);
+  STORE_BY_BITMASK(uint16_t, , 0x20009ec7, 1, 6, 1);
+  STORE_BY_BITMASK(uint16_t, , 0x20009ec7, 0, 7, 1);
+  *(uint32_t*)0x20009ec8 = htobe32(0);
+  *(uint16_t*)0x20009ecc = 8;
+  STORE_BY_BITMASK(uint16_t, , 0x20009ece, 2, 0, 14);
+  STORE_BY_BITMASK(uint16_t, , 0x20009ecf, 1, 6, 1);
+  STORE_BY_BITMASK(uint16_t, , 0x20009ecf, 0, 7, 1);
+  *(uint32_t*)0x20009ed0 = htobe32(0);
+  *(uint32_t*)0x20009ed4 = 0x14;
+  *(uint16_t*)0x20009ed8 = 0x11;
+  *(uint16_t*)0x20009eda = 1;
+  *(uint32_t*)0x20009edc = 0;
+  *(uint32_t*)0x20009ee0 = 0;
+  *(uint8_t*)0x20009ee4 = 0;
+  *(uint8_t*)0x20009ee5 = 0;
+  *(uint16_t*)0x20009ee6 = htobe16(0xa);
+  *(uint64_t*)0x2000d3c8 = 0x68;
+  *(uint64_t*)0x2000d418 = 1;
+  *(uint64_t*)0x2000d420 = 0;
+  *(uint64_t*)0x2000d428 = 0;
+  *(uint32_t*)0x2000d430 = 0x4000000;
+  syscall(__NR_sendmsg, r[1], 0x2000d400ul, 0x4000000ul);
+  return 0;
+}
diff --git a/syzkaller-repros/linux/05d4108490c9f7ccbac76be758384126551f65e2.c b/syzkaller-repros/linux/05d4108490c9f7ccbac76be758384126551f65e2.c
new file mode 100644
index 0000000..de1d4f0
--- /dev/null
+++ b/syzkaller-repros/linux/05d4108490c9f7ccbac76be758384126551f65e2.c
@@ -0,0 +1,1435 @@
+// KASAN: use-after-free Read in ccid2_hc_tx_packet_recv (2)
+// https://syzkaller.appspot.com/bug?id=05d4108490c9f7ccbac76be758384126551f65e2
+// status:open
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <sched.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static __thread int skip_segv;
+static __thread jmp_buf segv_env;
+
+static void segv_handler(int sig, siginfo_t* info, void* ctx)
+{
+  uintptr_t addr = (uintptr_t)info->si_addr;
+  const uintptr_t prog_start = 1 << 20;
+  const uintptr_t prog_end = 100 << 20;
+  if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED) &&
+      (addr < prog_start || addr > prog_end)) {
+    _longjmp(segv_env, 1);
+  }
+  exit(sig);
+}
+
+static void install_segv_handler(void)
+{
+  struct sigaction sa;
+  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);
+  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(...)                                                        \
+  {                                                                            \
+    __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST);                       \
+    if (_setjmp(segv_env) == 0) {                                              \
+      __VA_ARGS__;                                                             \
+    }                                                                          \
+    __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST);                       \
+  }
+
+static void sleep_ms(uint64_t ms)
+{
+  usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+  struct timespec ts;
+  if (clock_gettime(CLOCK_MONOTONIC, &ts))
+    exit(1);
+  return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void use_temporary_dir(void)
+{
+  char tmpdir_template[] = "./syzkaller.XXXXXX";
+  char* tmpdir = mkdtemp(tmpdir_template);
+  if (!tmpdir)
+    exit(1);
+  if (chmod(tmpdir, 0777))
+    exit(1);
+  if (chdir(tmpdir))
+    exit(1);
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+  char buf[1024];
+  va_list args;
+  va_start(args, what);
+  vsnprintf(buf, sizeof(buf), what, args);
+  va_end(args);
+  buf[sizeof(buf) - 1] = 0;
+  int len = strlen(buf);
+  int fd = open(file, O_WRONLY | O_CLOEXEC);
+  if (fd == -1)
+    return false;
+  if (write(fd, buf, len) != len) {
+    int err = errno;
+    close(fd);
+    errno = err;
+    return false;
+  }
+  close(fd);
+  return true;
+}
+
+static struct {
+  char* pos;
+  int nesting;
+  struct nlattr* nested[8];
+  char buf[1024];
+} nlmsg;
+
+static void netlink_init(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(int typ, const void* data, int size)
+{
+  struct nlattr* attr = (struct nlattr*)nlmsg.pos;
+  attr->nla_len = sizeof(*attr) + size;
+  attr->nla_type = typ;
+  memcpy(attr + 1, data, size);
+  nlmsg.pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static void netlink_nest(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(void)
+{
+  struct nlattr* attr = nlmsg.nested[--nlmsg.nesting];
+  attr->nla_len = nlmsg.pos - (char*)attr;
+}
+
+static int netlink_send_ext(int sock, uint16_t reply_type, int* reply_len)
+{
+  if (nlmsg.pos > nlmsg.buf + sizeof(nlmsg.buf) || nlmsg.nesting)
+    exit(1);
+  struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg.buf;
+  hdr->nlmsg_len = nlmsg.pos - nlmsg.buf;
+  struct sockaddr_nl addr;
+  memset(&addr, 0, sizeof(addr));
+  addr.nl_family = AF_NETLINK;
+  unsigned n = sendto(sock, nlmsg.buf, hdr->nlmsg_len, 0,
+                      (struct sockaddr*)&addr, sizeof(addr));
+  if (n != hdr->nlmsg_len)
+    exit(1);
+  n = recv(sock, nlmsg.buf, sizeof(nlmsg.buf), 0);
+  if (n < sizeof(struct nlmsghdr))
+    exit(1);
+  if (reply_len && hdr->nlmsg_type == reply_type) {
+    *reply_len = n;
+    return 0;
+  }
+  if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+    exit(1);
+  if (hdr->nlmsg_type != NLMSG_ERROR)
+    exit(1);
+  return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(int sock)
+{
+  return netlink_send_ext(sock, 0, NULL);
+}
+
+static void netlink_add_device_impl(const char* type, const char* name)
+{
+  struct ifinfomsg hdr;
+  memset(&hdr, 0, sizeof(hdr));
+  netlink_init(RTM_NEWLINK, NLM_F_EXCL | NLM_F_CREATE, &hdr, sizeof(hdr));
+  if (name)
+    netlink_attr(IFLA_IFNAME, name, strlen(name));
+  netlink_nest(IFLA_LINKINFO);
+  netlink_attr(IFLA_INFO_KIND, type, strlen(type));
+}
+
+static void netlink_add_device(int sock, const char* type, const char* name)
+{
+  netlink_add_device_impl(type, name);
+  netlink_done();
+  int err = netlink_send(sock);
+  (void)err;
+}
+
+static void netlink_add_veth(int sock, const char* name, const char* peer)
+{
+  netlink_add_device_impl("veth", name);
+  netlink_nest(IFLA_INFO_DATA);
+  netlink_nest(VETH_INFO_PEER);
+  nlmsg.pos += sizeof(struct ifinfomsg);
+  netlink_attr(IFLA_IFNAME, peer, strlen(peer));
+  netlink_done();
+  netlink_done();
+  netlink_done();
+  int err = netlink_send(sock);
+  (void)err;
+}
+
+static void netlink_add_hsr(int sock, const char* name, const char* slave1,
+                            const char* slave2)
+{
+  netlink_add_device_impl("hsr", name);
+  netlink_nest(IFLA_INFO_DATA);
+  int ifindex1 = if_nametoindex(slave1);
+  netlink_attr(IFLA_HSR_SLAVE1, &ifindex1, sizeof(ifindex1));
+  int ifindex2 = if_nametoindex(slave2);
+  netlink_attr(IFLA_HSR_SLAVE2, &ifindex2, sizeof(ifindex2));
+  netlink_done();
+  netlink_done();
+  int err = netlink_send(sock);
+  (void)err;
+}
+
+static void netlink_device_change(int sock, const char* name, bool up,
+                                  const char* master, const void* mac,
+                                  int macsize)
+{
+  struct ifinfomsg hdr;
+  memset(&hdr, 0, sizeof(hdr));
+  if (up)
+    hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+  netlink_init(RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+  netlink_attr(IFLA_IFNAME, name, strlen(name));
+  if (master) {
+    int ifindex = if_nametoindex(master);
+    netlink_attr(IFLA_MASTER, &ifindex, sizeof(ifindex));
+  }
+  if (macsize)
+    netlink_attr(IFLA_ADDRESS, mac, macsize);
+  int err = netlink_send(sock);
+  (void)err;
+}
+
+static int netlink_add_addr(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(RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr, sizeof(hdr));
+  netlink_attr(IFA_LOCAL, addr, addrsize);
+  netlink_attr(IFA_ADDRESS, addr, addrsize);
+  return netlink_send(sock);
+}
+
+static void netlink_add_addr4(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(sock, dev, &in_addr, sizeof(in_addr));
+  (void)err;
+}
+
+static void netlink_add_addr6(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(sock, dev, &in6_addr, sizeof(in6_addr));
+  (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETNS_FD 137
+
+static void netlink_devlink_netns_move(const char* bus_name,
+                                       const char* dev_name, int netns_fd)
+{
+  struct genlmsghdr genlhdr;
+  struct nlattr* attr;
+  int sock, err, n;
+  uint16_t id = 0;
+  sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+  if (sock == -1)
+    exit(1);
+  memset(&genlhdr, 0, sizeof(genlhdr));
+  genlhdr.cmd = CTRL_CMD_GETFAMILY;
+  netlink_init(GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
+  netlink_attr(CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME,
+               strlen(DEVLINK_FAMILY_NAME) + 1);
+  err = netlink_send_ext(sock, GENL_ID_CTRL, &n);
+  if (err) {
+    goto error;
+  }
+  attr =
+      (struct nlattr*)(nlmsg.buf + NLMSG_HDRLEN + NLMSG_ALIGN(sizeof(genlhdr)));
+  for (; (char*)attr < nlmsg.buf + n;
+       attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+    if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+      id = *(uint16_t*)(attr + 1);
+      break;
+    }
+  }
+  if (!id) {
+    goto error;
+  }
+  recv(sock, nlmsg.buf, sizeof(nlmsg.buf), 0); /* recv ack */
+  memset(&genlhdr, 0, sizeof(genlhdr));
+  genlhdr.cmd = DEVLINK_CMD_RELOAD;
+  netlink_init(id, 0, &genlhdr, sizeof(genlhdr));
+  netlink_attr(DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
+  netlink_attr(DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
+  netlink_attr(DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd));
+  netlink_send(sock);
+error:
+  close(sock);
+}
+
+static void initialize_devlink_pci(void)
+{
+  int netns = open("/proc/self/ns/net", O_RDONLY);
+  if (netns == -1)
+    exit(1);
+  int ret = setns(kInitNetNsFd, 0);
+  if (ret == -1)
+    exit(1);
+  netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+  ret = setns(netns, 0);
+  if (ret == -1)
+    exit(1);
+  close(netns);
+}
+
+#define DEV_IPV4 "172.20.20.%d"
+#define DEV_IPV6 "fe80::%02x"
+#define DEV_MAC 0x00aaaaaaaaaa
+
+static void netdevsim_add(unsigned int addr, unsigned int port_count)
+{
+  char buf[16];
+  sprintf(buf, "%u %u", addr, port_count);
+  write_file("/sys/bus/netdevsim/new_device", buf);
+}
+static void initialize_netdevices(void)
+{
+  char netdevsim[16];
+  sprintf(netdevsim, "netdevsim%d", (int)procid);
+  struct {
+    const char* type;
+    const char* dev;
+  } devtypes[] = {
+      {"ip6gretap", "ip6gretap0"}, {"bridge", "bridge0"},
+      {"vcan", "vcan0"},           {"bond", "bond0"},
+      {"team", "team0"},           {"dummy", "dummy0"},
+      {"nlmon", "nlmon0"},         {"caif", "caif0"},
+      {"batadv", "batadv0"},       {"vxcan", "vxcan1"},
+      {"netdevsim", netdevsim},    {"veth", 0},
+  };
+  const char* devmasters[] = {"bridge", "bond", "team"};
+  struct {
+    const char* name;
+    int macsize;
+    bool noipv6;
+  } devices[] = {
+      {"lo", ETH_ALEN},
+      {"sit0", 0},
+      {"bridge0", ETH_ALEN},
+      {"vcan0", 0, true},
+      {"tunl0", 0},
+      {"gre0", 0},
+      {"gretap0", ETH_ALEN},
+      {"ip_vti0", 0},
+      {"ip6_vti0", 0},
+      {"ip6tnl0", 0},
+      {"ip6gre0", 0},
+      {"ip6gretap0", ETH_ALEN},
+      {"erspan0", ETH_ALEN},
+      {"bond0", ETH_ALEN},
+      {"veth0", ETH_ALEN},
+      {"veth1", ETH_ALEN},
+      {"team0", ETH_ALEN},
+      {"veth0_to_bridge", ETH_ALEN},
+      {"veth1_to_bridge", ETH_ALEN},
+      {"veth0_to_bond", ETH_ALEN},
+      {"veth1_to_bond", ETH_ALEN},
+      {"veth0_to_team", ETH_ALEN},
+      {"veth1_to_team", ETH_ALEN},
+      {"veth0_to_hsr", ETH_ALEN},
+      {"veth1_to_hsr", ETH_ALEN},
+      {"hsr0", 0},
+      {"dummy0", ETH_ALEN},
+      {"nlmon0", 0},
+      {"vxcan0", 0, true},
+      {"vxcan1", 0, true},
+      {"caif0", ETH_ALEN},
+      {"batadv0", ETH_ALEN},
+      {netdevsim, ETH_ALEN},
+  };
+  int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+  if (sock == -1)
+    exit(1);
+  unsigned i;
+  for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++)
+    netlink_add_device(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(sock, slave0, veth0);
+    sprintf(slave1, "%s_slave_1", devmasters[i]);
+    sprintf(veth1, "veth1_to_%s", devmasters[i]);
+    netlink_add_veth(sock, slave1, veth1);
+    sprintf(master, "%s0", devmasters[i]);
+    netlink_device_change(sock, slave0, false, master, 0, 0);
+    netlink_device_change(sock, slave1, false, master, 0, 0);
+  }
+  netlink_device_change(sock, "bridge_slave_0", true, 0, 0, 0);
+  netlink_device_change(sock, "bridge_slave_1", true, 0, 0, 0);
+  netlink_add_veth(sock, "hsr_slave_0", "veth0_to_hsr");
+  netlink_add_veth(sock, "hsr_slave_1", "veth1_to_hsr");
+  netlink_add_hsr(sock, "hsr0", "hsr_slave_0", "hsr_slave_1");
+  netlink_device_change(sock, "hsr_slave_0", true, 0, 0, 0);
+  netlink_device_change(sock, "hsr_slave_1", true, 0, 0, 0);
+  netdevsim_add((int)procid, 4);
+  for (i = 0; i < sizeof(devices) / (sizeof(devices[0])); i++) {
+    char addr[32];
+    sprintf(addr, DEV_IPV4, i + 10);
+    netlink_add_addr4(sock, devices[i].name, addr);
+    if (!devices[i].noipv6) {
+      sprintf(addr, DEV_IPV6, i + 10);
+      netlink_add_addr6(sock, devices[i].name, addr);
+    }
+    uint64_t macaddr = DEV_MAC + ((i + 10ull) << 40);
+    netlink_device_change(sock, devices[i].name, true, 0, &macaddr,
+                          devices[i].macsize);
+  }
+  close(sock);
+}
+static void initialize_netdevices_init(void)
+{
+  int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+  if (sock == -1)
+    exit(1);
+  struct {
+    const char* type;
+    int macsize;
+    bool noipv6;
+    bool noup;
+  } devtypes[] = {
+      {"nr", 7, true}, {"rose", 5, true, true},
+  };
+  unsigned i;
+  for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++) {
+    char dev[32], addr[32];
+    sprintf(dev, "%s%d", devtypes[i].type, (int)procid);
+    sprintf(addr, "172.30.%d.%d", i, (int)procid + 1);
+    netlink_add_addr4(sock, dev, addr);
+    if (!devtypes[i].noipv6) {
+      sprintf(addr, "fe88::%02x:%02x", i, (int)procid + 1);
+      netlink_add_addr6(sock, dev, addr);
+    }
+    int macsize = devtypes[i].macsize;
+    uint64_t macaddr = 0xbbbbbb +
+                       ((unsigned long long)i << (8 * (macsize - 2))) +
+                       (procid << (8 * (macsize - 1)));
+    netlink_device_change(sock, dev, !devtypes[i].noup, 0, &macaddr, macsize);
+  }
+  close(sock);
+}
+
+#define MAX_FDS 30
+
+#define XT_TABLE_SIZE 1536
+#define XT_MAX_ENTRIES 10
+
+struct xt_counters {
+  uint64_t 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;
+  void* entrytable[XT_TABLE_SIZE / sizeof(void*)];
+};
+
+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;
+  char entrytable[XT_TABLE_SIZE];
+};
+
+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;
+  void* entrytable[XT_TABLE_SIZE / sizeof(void*)];
+};
+
+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;
+  char entrytable[XT_TABLE_SIZE];
+};
+
+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)
+{
+  struct ipt_get_entries entries;
+  socklen_t optlen;
+  int fd, i;
+  fd = socket(family, SOCK_STREAM, IPPROTO_TCP);
+  if (fd == -1) {
+    switch (errno) {
+    case EAFNOSUPPORT:
+    case ENOPROTOOPT:
+      return;
+    }
+    exit(1);
+  }
+  for (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);
+    optlen = sizeof(table->info);
+    if (getsockopt(fd, level, IPT_SO_GET_INFO, &table->info, &optlen)) {
+      switch (errno) {
+      case EPERM:
+      case ENOENT:
+      case ENOPROTOOPT:
+        continue;
+      }
+      exit(1);
+    }
+    if (table->info.size > sizeof(table->replace.entrytable))
+      exit(1);
+    if (table->info.num_entries > XT_MAX_ENTRIES)
+      exit(1);
+    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))
+      exit(1);
+    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)
+{
+  struct xt_counters counters[XT_MAX_ENTRIES];
+  struct ipt_get_entries entries;
+  struct ipt_getinfo info;
+  socklen_t optlen;
+  int fd, i;
+  fd = socket(family, SOCK_STREAM, IPPROTO_TCP);
+  if (fd == -1) {
+    switch (errno) {
+    case EAFNOSUPPORT:
+    case ENOPROTOOPT:
+      return;
+    }
+    exit(1);
+  }
+  for (i = 0; i < num_tables; i++) {
+    struct ipt_table_desc* table = &tables[i];
+    if (table->info.valid_hooks == 0)
+      continue;
+    memset(&info, 0, sizeof(info));
+    strcpy(info.name, table->name);
+    optlen = sizeof(info);
+    if (getsockopt(fd, level, IPT_SO_GET_INFO, &info, &optlen))
+      exit(1);
+    if (memcmp(&table->info, &info, sizeof(table->info)) == 0) {
+      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))
+        exit(1);
+      if (memcmp(table->replace.entrytable, entries.entrytable,
+                 table->info.size) == 0)
+        continue;
+    }
+    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))
+      exit(1);
+  }
+  close(fd);
+}
+
+static void checkpoint_arptables(void)
+{
+  struct arpt_get_entries entries;
+  socklen_t optlen;
+  unsigned i;
+  int fd;
+  fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  if (fd == -1) {
+    switch (errno) {
+    case EAFNOSUPPORT:
+    case ENOPROTOOPT:
+      return;
+    }
+    exit(1);
+  }
+  for (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);
+    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;
+      }
+      exit(1);
+    }
+    if (table->info.size > sizeof(table->replace.entrytable))
+      exit(1);
+    if (table->info.num_entries > XT_MAX_ENTRIES)
+      exit(1);
+    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))
+      exit(1);
+    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()
+{
+  struct xt_counters counters[XT_MAX_ENTRIES];
+  struct arpt_get_entries entries;
+  struct arpt_getinfo info;
+  socklen_t optlen;
+  unsigned i;
+  int fd;
+  fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  if (fd == -1) {
+    switch (errno) {
+    case EAFNOSUPPORT:
+    case ENOPROTOOPT:
+      return;
+    }
+    exit(1);
+  }
+  for (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;
+    memset(&info, 0, sizeof(info));
+    strcpy(info.name, table->name);
+    optlen = sizeof(info);
+    if (getsockopt(fd, SOL_IP, ARPT_SO_GET_INFO, &info, &optlen))
+      exit(1);
+    if (memcmp(&table->info, &info, sizeof(table->info)) == 0) {
+      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))
+        exit(1);
+      if (memcmp(table->replace.entrytable, entries.entrytable,
+                 table->info.size) == 0)
+        continue;
+    } else {
+    }
+    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))
+      exit(1);
+  }
+  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)
+{
+  socklen_t optlen;
+  unsigned i;
+  int fd;
+  fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  if (fd == -1) {
+    switch (errno) {
+    case EAFNOSUPPORT:
+    case ENOPROTOOPT:
+      return;
+    }
+    exit(1);
+  }
+  for (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);
+    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;
+      }
+      exit(1);
+    }
+    if (table->replace.entries_size > sizeof(table->entrytable))
+      exit(1);
+    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))
+      exit(1);
+  }
+  close(fd);
+}
+
+static void reset_ebtables()
+{
+  struct ebt_replace replace;
+  char entrytable[XT_TABLE_SIZE];
+  socklen_t optlen;
+  unsigned i, j, h;
+  int fd;
+  fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  if (fd == -1) {
+    switch (errno) {
+    case EAFNOSUPPORT:
+    case ENOPROTOOPT:
+      return;
+    }
+    exit(1);
+  }
+  for (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;
+    memset(&replace, 0, sizeof(replace));
+    strcpy(replace.name, table->name);
+    optlen = sizeof(replace);
+    if (getsockopt(fd, SOL_IP, EBT_SO_GET_INFO, &replace, &optlen))
+      exit(1);
+    replace.num_counters = 0;
+    table->replace.entries = 0;
+    for (h = 0; h < NF_BR_NUMHOOKS; h++)
+      table->replace.hook_entry[h] = 0;
+    if (memcmp(&table->replace, &replace, sizeof(table->replace)) == 0) {
+      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))
+        exit(1);
+      if (memcmp(table->entrytable, entrytable, replace.entries_size) == 0)
+        continue;
+    }
+    for (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))
+      exit(1);
+  }
+  close(fd);
+}
+
+static void checkpoint_net_namespace(void)
+{
+  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)
+{
+  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);
+}
+
+static void setup_cgroups()
+{
+  if (mkdir("/syzcgroup", 0777)) {
+  }
+  if (mkdir("/syzcgroup/unified", 0777)) {
+  }
+  if (mount("none", "/syzcgroup/unified", "cgroup2", 0, NULL)) {
+  }
+  if (chmod("/syzcgroup/unified", 0777)) {
+  }
+  write_file("/syzcgroup/unified/cgroup.subtree_control",
+             "+cpu +memory +io +pids +rdma");
+  if (mkdir("/syzcgroup/cpu", 0777)) {
+  }
+  if (mount("none", "/syzcgroup/cpu", "cgroup", 0,
+            "cpuset,cpuacct,perf_event,hugetlb")) {
+  }
+  write_file("/syzcgroup/cpu/cgroup.clone_children", "1");
+  if (chmod("/syzcgroup/cpu", 0777)) {
+  }
+  if (mkdir("/syzcgroup/net", 0777)) {
+  }
+  if (mount("none", "/syzcgroup/net", "cgroup", 0,
+            "net_cls,net_prio,devices,freezer")) {
+  }
+  if (chmod("/syzcgroup/net", 0777)) {
+  }
+}
+
+static void setup_cgroups_loop()
+{
+  int pid = getpid();
+  char file[128];
+  char cgroupdir[64];
+  snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/unified/syz%llu", procid);
+  if (mkdir(cgroupdir, 0777)) {
+  }
+  snprintf(file, sizeof(file), "%s/pids.max", cgroupdir);
+  write_file(file, "32");
+  snprintf(file, sizeof(file), "%s/memory.low", cgroupdir);
+  write_file(file, "%d", 298 << 20);
+  snprintf(file, sizeof(file), "%s/memory.high", cgroupdir);
+  write_file(file, "%d", 299 << 20);
+  snprintf(file, sizeof(file), "%s/memory.max", cgroupdir);
+  write_file(file, "%d", 300 << 20);
+  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)) {
+  }
+  snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+  write_file(file, "%d", pid);
+  snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/net/syz%llu", procid);
+  if (mkdir(cgroupdir, 0777)) {
+  }
+  snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+  write_file(file, "%d", pid);
+}
+
+static void setup_cgroups_test()
+{
+  char cgroupdir[64];
+  snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/unified/syz%llu", procid);
+  if (symlink(cgroupdir, "./cgroup")) {
+  }
+  snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/cpu/syz%llu", procid);
+  if (symlink(cgroupdir, "./cgroup.cpu")) {
+  }
+  snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/net/syz%llu", procid);
+  if (symlink(cgroupdir, "./cgroup.net")) {
+  }
+}
+
+static void setup_common()
+{
+  if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+  }
+  setup_cgroups();
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+  prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+  setpgrp();
+  setsid();
+  int netns = open("/proc/self/ns/net", O_RDONLY);
+  if (netns == -1)
+    exit(1);
+  if (dup2(netns, kInitNetNsFd) < 0)
+    exit(1);
+  close(netns);
+  struct rlimit rlim;
+  rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+  setrlimit(RLIMIT_AS, &rlim);
+  rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+  setrlimit(RLIMIT_MEMLOCK, &rlim);
+  rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+  setrlimit(RLIMIT_FSIZE, &rlim);
+  rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+  setrlimit(RLIMIT_STACK, &rlim);
+  rlim.rlim_cur = rlim.rlim_max = 0;
+  setrlimit(RLIMIT_CORE, &rlim);
+  rlim.rlim_cur = rlim.rlim_max = 256;
+  setrlimit(RLIMIT_NOFILE, &rlim);
+  if (unshare(CLONE_NEWNS)) {
+  }
+  if (unshare(CLONE_NEWIPC)) {
+  }
+  if (unshare(0x02000000)) {
+  }
+  if (unshare(CLONE_NEWUTS)) {
+  }
+  if (unshare(CLONE_SYSVSEM)) {
+  }
+  typedef struct {
+    const char* name;
+    const char* value;
+  } sysctl_t;
+  static const sysctl_t sysctls[] = {
+      {"/proc/sys/kernel/shmmax", "16777216"},
+      {"/proc/sys/kernel/shmall", "536870912"},
+      {"/proc/sys/kernel/shmmni", "1024"},
+      {"/proc/sys/kernel/msgmax", "8192"},
+      {"/proc/sys/kernel/msgmni", "1024"},
+      {"/proc/sys/kernel/msgmnb", "1024"},
+      {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+  };
+  unsigned i;
+  for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+    write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+  if (pid < 0)
+    exit(1);
+  int status = 0;
+  while (waitpid(-1, &status, __WALL) != pid) {
+  }
+  return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+  struct __user_cap_header_struct cap_hdr = {};
+  struct __user_cap_data_struct cap_data[2] = {};
+  cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+  cap_hdr.pid = getpid();
+  if (syscall(SYS_capget, &cap_hdr, &cap_data))
+    exit(1);
+  const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+  cap_data[0].effective &= ~drop;
+  cap_data[0].permitted &= ~drop;
+  cap_data[0].inheritable &= ~drop;
+  if (syscall(SYS_capset, &cap_hdr, &cap_data))
+    exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+  if (unshare(CLONE_NEWPID)) {
+  }
+  int pid = fork();
+  if (pid != 0)
+    return wait_for_loop(pid);
+  setup_common();
+  sandbox_common();
+  drop_caps();
+  initialize_netdevices_init();
+  if (unshare(CLONE_NEWNET)) {
+  }
+  initialize_devlink_pci();
+  initialize_netdevices();
+  loop();
+  exit(1);
+}
+
+#define FS_IOC_SETFLAGS _IOW('f', 2, long)
+static void remove_dir(const char* dir)
+{
+  DIR* dp;
+  struct dirent* ep;
+  int iter = 0;
+retry:
+  while (umount2(dir, MNT_DETACH) == 0) {
+  }
+  dp = opendir(dir);
+  if (dp == NULL) {
+    if (errno == EMFILE) {
+      exit(1);
+    }
+    exit(1);
+  }
+  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);
+    while (umount2(filename, MNT_DETACH) == 0) {
+    }
+    struct stat st;
+    if (lstat(filename, &st))
+      exit(1);
+    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)
+            close(fd);
+          continue;
+        }
+      }
+      if (errno == EROFS) {
+        break;
+      }
+      if (errno != EBUSY || i > 100)
+        exit(1);
+      if (umount2(filename, MNT_DETACH))
+        exit(1);
+    }
+  }
+  closedir(dp);
+  int i;
+  for (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)
+            close(fd);
+          continue;
+        }
+      }
+      if (errno == EROFS) {
+        break;
+      }
+      if (errno == EBUSY) {
+        if (umount2(dir, MNT_DETACH))
+          exit(1);
+        continue;
+      }
+      if (errno == ENOTEMPTY) {
+        if (iter < 100) {
+          iter++;
+          goto retry;
+        }
+      }
+    }
+    exit(1);
+  }
+}
+
+static int inject_fault(int nth)
+{
+  int fd;
+  fd = open("/proc/thread-self/fail-nth", O_RDWR);
+  if (fd == -1)
+    exit(1);
+  char buf[16];
+  sprintf(buf, "%d", nth + 1);
+  if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf))
+    exit(1);
+  return fd;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+  kill(-pid, SIGKILL);
+  kill(pid, SIGKILL);
+  int i;
+  for (i = 0; i < 100; i++) {
+    if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+      return;
+    usleep(1000);
+  }
+  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) {
+        continue;
+      }
+      if (write(fd, abort, 1) < 0) {
+      }
+      close(fd);
+    }
+    closedir(dir);
+  } else {
+  }
+  while (waitpid(-1, status, __WALL) != pid) {
+  }
+}
+
+static void setup_loop()
+{
+  setup_cgroups_loop();
+  checkpoint_net_namespace();
+}
+
+static void reset_loop()
+{
+  reset_net_namespace();
+}
+
+static void setup_test()
+{
+  prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+  setpgrp();
+  setup_cgroups_test();
+  write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void close_fds()
+{
+  int fd;
+  for (fd = 3; fd < MAX_FDS; fd++)
+    close(fd);
+}
+
+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)) {
+      if (files[i].fatal)
+        exit(1);
+    }
+  }
+}
+
+static void setup_binfmt_misc()
+{
+  if (mount(0, "/proc/sys/fs/binfmt_misc", "binfmt_misc", 0, 0)) {
+  }
+  write_file("/proc/sys/fs/binfmt_misc/register", ":syz0:M:0:\x01::./file0:");
+  write_file("/proc/sys/fs/binfmt_misc/register",
+             ":syz1:M:1:\x02::./file0:POC");
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+  setup_loop();
+  int iter;
+  for (iter = 0;; iter++) {
+    char cwdbuf[32];
+    sprintf(cwdbuf, "./%d", iter);
+    if (mkdir(cwdbuf, 0777))
+      exit(1);
+    reset_loop();
+    int pid = fork();
+    if (pid < 0)
+      exit(1);
+    if (pid == 0) {
+      if (chdir(cwdbuf))
+        exit(1);
+      setup_test();
+      execute_one();
+      close_fds();
+      exit(0);
+    }
+    int status = 0;
+    uint64_t start = current_time_ms();
+    for (;;) {
+      if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+        break;
+      sleep_ms(1);
+      if (current_time_ms() - start < 5 * 1000)
+        continue;
+      kill_and_wait(pid, &status);
+      break;
+    }
+    remove_dir(cwdbuf);
+  }
+}
+
+uint64_t r[4] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff,
+                 0xffffffffffffffff};
+
+void execute_one(void)
+{
+  intptr_t res = 0;
+  res = syscall(__NR_socket, 2, 2, 0x88);
+  if (res != -1)
+    r[0] = res;
+  syscall(__NR_ioctl, r[0], 0x1000008912, 0);
+  NONFAILING(*(uint32_t*)0x200009c0 = 0);
+  NONFAILING(*(uint16_t*)0x200009c4 = 2);
+  NONFAILING(*(uint16_t*)0x200009c6 = htobe16(0));
+  NONFAILING(*(uint32_t*)0x200009c8 = htobe32(0xe0000001));
+  NONFAILING(*(uint32_t*)0x20000a44 = 0);
+  NONFAILING(*(uint16_t*)0x20000a48 = 0);
+  NONFAILING(*(uint32_t*)0x20000a4a = 0);
+  NONFAILING(*(uint32_t*)0x20000a4e = 0);
+  NONFAILING(*(uint32_t*)0x20000a52 = 0);
+  syscall(__NR_getsockopt, 0xffffff9c, 0x84, 9, 0x200009c0, 0);
+  res = syscall(__NR_socket, 0xa, 6, 0);
+  if (res != -1)
+    r[1] = res;
+  NONFAILING(*(uint16_t*)0x20000000 = 0xa);
+  NONFAILING(*(uint16_t*)0x20000002 = htobe16(0x4e23));
+  NONFAILING(*(uint32_t*)0x20000004 = htobe32(0));
+  NONFAILING(memcpy(
+      (void*)0x20000008,
+      "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000", 16));
+  NONFAILING(*(uint32_t*)0x20000018 = 0);
+  syscall(__NR_bind, r[1], 0x20000000, 0x1c);
+  syscall(__NR_listen, r[1], 0x5eb857);
+  res = syscall(__NR_socket, 2, 6, 0);
+  if (res != -1)
+    r[2] = res;
+  NONFAILING(*(uint16_t*)0x20000340 = 2);
+  NONFAILING(*(uint16_t*)0x20000342 = htobe16(0x4e23));
+  NONFAILING(*(uint8_t*)0x20000344 = 0xac);
+  NONFAILING(*(uint8_t*)0x20000345 = 0x14);
+  NONFAILING(*(uint8_t*)0x20000346 = 0x14);
+  NONFAILING(*(uint8_t*)0x20000347 = 0x20);
+  syscall(__NR_connect, r[2], 0x20000340, 0x10);
+  res = syscall(__NR_accept4, r[1], 0, 0, 0);
+  if (res != -1)
+    r[3] = res;
+  syscall(__NR_sendmmsg, r[3], 0x20000180, 0x40001d0, 0);
+  syscall(__NR_write, r[2], 0, 0);
+  inject_fault(7);
+  syscall(__NR_sendmmsg, r[3], 0x20000c00, 0x4000000000001e6, 0);
+}
+int main(void)
+{
+  syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+  setup_binfmt_misc();
+  setup_fault();
+  install_segv_handler();
+  use_temporary_dir();
+  do_sandbox_none();
+  return 0;
+}
diff --git a/syzkaller-repros/linux/05f556857bcf9b64d3d1ee88b71909d8b3a11528.c b/syzkaller-repros/linux/05f556857bcf9b64d3d1ee88b71909d8b3a11528.c
new file mode 100644
index 0000000..1b1ba1d
--- /dev/null
+++ b/syzkaller-repros/linux/05f556857bcf9b64d3d1ee88b71909d8b3a11528.c
@@ -0,0 +1,1128 @@
+// panic: munmap(ADDR, ADDR)) failed: function not implemented
+// https://syzkaller.appspot.com/bug?id=05f556857bcf9b64d3d1ee88b71909d8b3a11528
+// status:invalid
+// autogenerated by syzkaller (http://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/futex.h>
+#include <linux/if.h>
+#include <linux/if_ether.h>
+#include <linux/if_tun.h>
+#include <linux/ip.h>
+#include <linux/net.h>
+#include <linux/tcp.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+__attribute__((noreturn)) static void doexit(int status)
+{
+  volatile unsigned i;
+  syscall(__NR_exit_group, status);
+  for (i = 0;; i++) {
+  }
+}
+#include <errno.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+
+const int kFailStatus = 67;
+const int kRetryStatus = 69;
+
+static void fail(const char* msg, ...)
+{
+  int e = errno;
+  va_list args;
+  va_start(args, msg);
+  vfprintf(stderr, msg, args);
+  va_end(args);
+  fprintf(stderr, " (errno %d)\n", e);
+  doexit((e == ENOMEM || e == EAGAIN) ? kRetryStatus : kFailStatus);
+}
+
+static void exitf(const char* msg, ...)
+{
+  int e = errno;
+  va_list args;
+  va_start(args, msg);
+  vfprintf(stderr, msg, args);
+  va_end(args);
+  fprintf(stderr, " (errno %d)\n", e);
+  doexit(kRetryStatus);
+}
+
+static __thread int skip_segv;
+static __thread jmp_buf segv_env;
+
+static void segv_handler(int sig, siginfo_t* info, void* uctx)
+{
+  uintptr_t addr = (uintptr_t)info->si_addr;
+  const uintptr_t prog_start = 1 << 20;
+  const uintptr_t prog_end = 100 << 20;
+  if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED) &&
+      (addr < prog_start || addr > prog_end)) {
+    _longjmp(segv_env, 1);
+  }
+  doexit(sig);
+}
+
+static void install_segv_handler()
+{
+  struct sigaction sa;
+
+  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);
+
+  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(...)                                                        \
+  {                                                                            \
+    __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST);                       \
+    if (_setjmp(segv_env) == 0) {                                              \
+      __VA_ARGS__;                                                             \
+    }                                                                          \
+    __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST);                       \
+  }
+
+static uint64_t current_time_ms()
+{
+  struct timespec ts;
+
+  if (clock_gettime(CLOCK_MONOTONIC, &ts))
+    fail("clock_gettime failed");
+  return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void use_temporary_dir()
+{
+  char tmpdir_template[] = "./syzkaller.XXXXXX";
+  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");
+}
+
+static void vsnprintf_check(char* str, size_t size, const char* format,
+                            va_list args)
+{
+  int rv;
+
+  rv = vsnprintf(str, size, format, args);
+  if (rv < 0)
+    fail("tun: snprintf failed");
+  if ((size_t)rv >= size)
+    fail("tun: string '%s...' doesn't fit into buffer", str);
+}
+
+#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;
+  char command[PATH_PREFIX_LEN + COMMAND_MAX_LEN];
+  int rv;
+
+  va_start(args, format);
+  memcpy(command, PATH_PREFIX, PATH_PREFIX_LEN);
+  vsnprintf_check(command + PATH_PREFIX_LEN, COMMAND_MAX_LEN, format, args);
+  va_end(args);
+  rv = system(command);
+  if (rv) {
+    if (panic)
+      fail("command '%s' failed: %d", &command[0], rv);
+  }
+}
+
+static int tunfd = -1;
+static int tun_frags_enabled;
+
+#define SYZ_TUN_MAX_PACKET_SIZE 1000
+
+#define TUN_IFACE "syz_tun"
+
+#define LOCAL_MAC "aa:aa:aa:aa:aa:aa"
+#define REMOTE_MAC "aa:aa:aa:aa:aa:bb"
+
+#define LOCAL_IPV4 "172.20.20.170"
+#define REMOTE_IPV4 "172.20.20.187"
+
+#define LOCAL_IPV6 "fe80::aa"
+#define REMOTE_IPV6 "fe80::bb"
+
+#define IFF_NAPI 0x0010
+#define IFF_NAPI_FRAGS 0x0020
+
+static void initialize_tun(void)
+{
+  tunfd = open("/dev/net/tun", O_RDWR | O_NONBLOCK);
+  if (tunfd == -1) {
+    printf("tun: can't open /dev/net/tun: please enable CONFIG_TUN=y\n");
+    printf("otherwise fuzzing or reproducing might not work as intended\n");
+    return;
+  }
+  const int kTunFd = 252;
+  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 | IFF_NAPI | IFF_NAPI_FRAGS;
+  if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0) {
+    ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+    if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0)
+      fail("tun: ioctl(TUNSETIFF) failed");
+  }
+  if (ioctl(tunfd, TUNGETIFF, (void*)&ifr) < 0)
+    fail("tun: ioctl(TUNGETIFF) failed");
+  tun_frags_enabled = (ifr.ifr_flags & IFF_NAPI_FRAGS) != 0;
+
+  execute_command(0, "sysctl -w net.ipv6.conf.%s.accept_dad=0", TUN_IFACE);
+
+  execute_command(0, "sysctl -w net.ipv6.conf.%s.router_solicitations=0",
+                  TUN_IFACE);
+
+  execute_command(1, "ip link set dev %s address %s", TUN_IFACE, LOCAL_MAC);
+  execute_command(1, "ip addr add %s/24 dev %s", LOCAL_IPV4, TUN_IFACE);
+  execute_command(1, "ip neigh add %s lladdr %s dev %s nud permanent",
+                  REMOTE_IPV4, REMOTE_MAC, TUN_IFACE);
+  execute_command(0, "ip -6 addr add %s/120 dev %s", LOCAL_IPV6, TUN_IFACE);
+  execute_command(0, "ip -6 neigh add %s lladdr %s dev %s nud permanent",
+                  REMOTE_IPV6, REMOTE_MAC, TUN_IFACE);
+  execute_command(1, "ip link set dev %s up", TUN_IFACE);
+}
+
+#define DEV_IPV4 "172.20.20.%d"
+#define DEV_IPV6 "fe80::%02hx"
+#define DEV_MAC "aa:aa:aa:aa:aa:%02hx"
+
+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);
+}
+
+static void initialize_netdevices(void)
+{
+  unsigned i;
+  const char* devtypes[] = {"ip6gretap", "bridge", "vcan", "bond", "team"};
+  const char* devnames[] = {"lo",
+                            "sit0",
+                            "bridge0",
+                            "vcan0",
+                            "tunl0",
+                            "gre0",
+                            "gretap0",
+                            "ip_vti0",
+                            "ip6_vti0",
+                            "ip6tnl0",
+                            "ip6gre0",
+                            "ip6gretap0",
+                            "erspan0",
+                            "bond0",
+                            "veth0",
+                            "veth1",
+                            "team0",
+                            "veth0_to_bridge",
+                            "veth1_to_bridge",
+                            "veth0_to_bond",
+                            "veth1_to_bond",
+                            "veth0_to_team",
+                            "veth1_to_team"};
+  const char* devmasters[] = {"bridge", "bond", "team"};
+
+  for (i = 0; i < sizeof(devtypes) / (sizeof(devtypes[0])); i++)
+    execute_command(0, "ip link add dev %s0 type %s", devtypes[i], devtypes[i]);
+  execute_command(0, "ip link add type veth");
+
+  for (i = 0; i < sizeof(devmasters) / (sizeof(devmasters[0])); i++) {
+    execute_command(
+        0, "ip link add name %s_slave_0 type veth peer name veth0_to_%s",
+        devmasters[i], devmasters[i]);
+    execute_command(
+        0, "ip link add name %s_slave_1 type veth peer name veth1_to_%s",
+        devmasters[i], devmasters[i]);
+    execute_command(0, "ip link set %s_slave_0 master %s0", devmasters[i],
+                    devmasters[i]);
+    execute_command(0, "ip link set %s_slave_1 master %s0", devmasters[i],
+                    devmasters[i]);
+    execute_command(0, "ip link set veth0_to_%s up", devmasters[i]);
+    execute_command(0, "ip link set veth1_to_%s up", devmasters[i]);
+  }
+  execute_command(0, "ip link set bridge_slave_0 up");
+  execute_command(0, "ip link set bridge_slave_1 up");
+
+  for (i = 0; i < sizeof(devnames) / (sizeof(devnames[0])); i++) {
+    char addr[32];
+    snprintf_check(addr, sizeof(addr), DEV_IPV4, i + 10);
+    execute_command(0, "ip -4 addr add %s/24 dev %s", addr, devnames[i]);
+    snprintf_check(addr, sizeof(addr), DEV_IPV6, i + 10);
+    execute_command(0, "ip -6 addr add %s/120 dev %s", addr, devnames[i]);
+    snprintf_check(addr, sizeof(addr), DEV_MAC, i + 10);
+    execute_command(0, "ip link set dev %s address %s", devnames[i], addr);
+    execute_command(0, "ip link set dev %s up", devnames[i]);
+  }
+}
+
+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;
+    if (errno == EBADFD)
+      return -1;
+    fail("tun: read failed with %d", rv);
+  }
+  return rv;
+}
+
+static void flush_tun()
+{
+  char data[SYZ_TUN_MAX_PACKET_SIZE];
+  while (read_tun(&data[0], sizeof(data)) != -1)
+    ;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+  char buf[1024];
+  va_list args;
+  va_start(args, what);
+  vsnprintf(buf, sizeof(buf), what, args);
+  va_end(args);
+  buf[sizeof(buf) - 1] = 0;
+  int len = strlen(buf);
+
+  int fd = open(file, O_WRONLY | O_CLOEXEC);
+  if (fd == -1)
+    return false;
+  if (write(fd, buf, len) != len) {
+    int err = errno;
+    close(fd);
+    errno = err;
+    return false;
+  }
+  close(fd);
+  return true;
+}
+
+static void setup_cgroups()
+{
+  if (mkdir("/syzcgroup", 0777)) {
+  }
+  if (mkdir("/syzcgroup/unified", 0777)) {
+  }
+  if (mount("none", "/syzcgroup/unified", "cgroup2", 0, NULL)) {
+  }
+  if (chmod("/syzcgroup/unified", 0777)) {
+  }
+  if (!write_file("/syzcgroup/unified/cgroup.subtree_control",
+                  "+cpu +memory +io +pids +rdma")) {
+  }
+  if (mkdir("/syzcgroup/cpu", 0777)) {
+  }
+  if (mount("none", "/syzcgroup/cpu", "cgroup", 0,
+            "cpuset,cpuacct,perf_event,hugetlb")) {
+  }
+  if (!write_file("/syzcgroup/cpu/cgroup.clone_children", "1")) {
+  }
+  if (chmod("/syzcgroup/cpu", 0777)) {
+  }
+  if (mkdir("/syzcgroup/net", 0777)) {
+  }
+  if (mount("none", "/syzcgroup/net", "cgroup", 0,
+            "net_cls,net_prio,devices,freezer")) {
+  }
+  if (chmod("/syzcgroup/net", 0777)) {
+  }
+}
+
+static void setup_binfmt_misc()
+{
+  if (!write_file("/proc/sys/fs/binfmt_misc/register",
+                  ":syz0:M:0:syz0::./file0:")) {
+  }
+  if (!write_file("/proc/sys/fs/binfmt_misc/register",
+                  ":syz1:M:1:yz1::./file0:POC")) {
+  }
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+  prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+  setpgrp();
+  setsid();
+
+  struct rlimit rlim;
+  rlim.rlim_cur = rlim.rlim_max = 160 << 20;
+  setrlimit(RLIMIT_AS, &rlim);
+  rlim.rlim_cur = rlim.rlim_max = 8 << 20;
+  setrlimit(RLIMIT_MEMLOCK, &rlim);
+  rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+  setrlimit(RLIMIT_FSIZE, &rlim);
+  rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+  setrlimit(RLIMIT_STACK, &rlim);
+  rlim.rlim_cur = rlim.rlim_max = 0;
+  setrlimit(RLIMIT_CORE, &rlim);
+
+  if (unshare(CLONE_NEWNS)) {
+  }
+  if (unshare(CLONE_NEWIPC)) {
+  }
+  if (unshare(0x02000000)) {
+  }
+  if (unshare(CLONE_NEWUTS)) {
+  }
+  if (unshare(CLONE_SYSVSEM)) {
+  }
+}
+
+int wait_for_loop(int pid)
+{
+  if (pid < 0)
+    fail("sandbox fork failed");
+  int status = 0;
+  while (waitpid(-1, &status, __WALL) != pid) {
+  }
+  return WEXITSTATUS(status);
+}
+
+static int do_sandbox_none(void)
+{
+  if (unshare(CLONE_NEWPID)) {
+  }
+  int pid = fork();
+  if (pid != 0)
+    return wait_for_loop(pid);
+
+  setup_cgroups();
+  setup_binfmt_misc();
+  sandbox_common();
+  if (unshare(CLONE_NEWNET)) {
+  }
+  initialize_tun();
+  initialize_netdevices();
+  loop();
+  doexit(1);
+}
+
+#define XT_TABLE_SIZE 1536
+#define XT_MAX_ENTRIES 10
+
+struct xt_counters {
+  uint64_t 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;
+  void* entrytable[XT_TABLE_SIZE / sizeof(void*)];
+};
+
+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;
+  char entrytable[XT_TABLE_SIZE];
+};
+
+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;
+  void* entrytable[XT_TABLE_SIZE / sizeof(void*)];
+};
+
+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;
+  char entrytable[XT_TABLE_SIZE];
+};
+
+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)
+{
+  struct ipt_get_entries entries;
+  socklen_t optlen;
+  int fd, i;
+
+  fd = socket(family, SOCK_STREAM, IPPROTO_TCP);
+  if (fd == -1) {
+    switch (errno) {
+    case EAFNOSUPPORT:
+    case ENOPROTOOPT:
+      return;
+    }
+    fail("socket(%d, SOCK_STREAM, IPPROTO_TCP)", family);
+  }
+  for (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);
+    optlen = sizeof(table->info);
+    if (getsockopt(fd, level, IPT_SO_GET_INFO, &table->info, &optlen)) {
+      switch (errno) {
+      case EPERM:
+      case ENOENT:
+      case ENOPROTOOPT:
+        continue;
+      }
+      fail("getsockopt(IPT_SO_GET_INFO)");
+    }
+    if (table->info.size > sizeof(table->replace.entrytable))
+      fail("table size is too large: %u", table->info.size);
+    if (table->info.num_entries > XT_MAX_ENTRIES)
+      fail("too many counters: %u", table->info.num_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))
+      fail("getsockopt(IPT_SO_GET_ENTRIES)");
+    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)
+{
+  struct xt_counters counters[XT_MAX_ENTRIES];
+  struct ipt_get_entries entries;
+  struct ipt_getinfo info;
+  socklen_t optlen;
+  int fd, i;
+
+  fd = socket(family, SOCK_STREAM, IPPROTO_TCP);
+  if (fd == -1) {
+    switch (errno) {
+    case EAFNOSUPPORT:
+    case ENOPROTOOPT:
+      return;
+    }
+    fail("socket(%d, SOCK_STREAM, IPPROTO_TCP)", family);
+  }
+  for (i = 0; i < num_tables; i++) {
+    struct ipt_table_desc* table = &tables[i];
+    if (table->info.valid_hooks == 0)
+      continue;
+    memset(&info, 0, sizeof(info));
+    strcpy(info.name, table->name);
+    optlen = sizeof(info);
+    if (getsockopt(fd, level, IPT_SO_GET_INFO, &info, &optlen))
+      fail("getsockopt(IPT_SO_GET_INFO)");
+    if (memcmp(&table->info, &info, sizeof(table->info)) == 0) {
+      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))
+        fail("getsockopt(IPT_SO_GET_ENTRIES)");
+      if (memcmp(table->replace.entrytable, entries.entrytable,
+                 table->info.size) == 0)
+        continue;
+    }
+    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))
+      fail("setsockopt(IPT_SO_SET_REPLACE)");
+  }
+  close(fd);
+}
+
+static void checkpoint_arptables(void)
+{
+  struct arpt_get_entries entries;
+  socklen_t optlen;
+  unsigned i;
+  int fd;
+
+  fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  if (fd == -1) {
+    switch (errno) {
+    case EAFNOSUPPORT:
+    case ENOPROTOOPT:
+      return;
+    }
+    fail("socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)");
+  }
+  for (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);
+    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;
+      }
+      fail("getsockopt(ARPT_SO_GET_INFO)");
+    }
+    if (table->info.size > sizeof(table->replace.entrytable))
+      fail("table size is too large: %u", table->info.size);
+    if (table->info.num_entries > XT_MAX_ENTRIES)
+      fail("too many counters: %u", table->info.num_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))
+      fail("getsockopt(ARPT_SO_GET_ENTRIES)");
+    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()
+{
+  struct xt_counters counters[XT_MAX_ENTRIES];
+  struct arpt_get_entries entries;
+  struct arpt_getinfo info;
+  socklen_t optlen;
+  unsigned i;
+  int fd;
+
+  fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  if (fd == -1) {
+    switch (errno) {
+    case EAFNOSUPPORT:
+    case ENOPROTOOPT:
+      return;
+    }
+    fail("socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)");
+  }
+  for (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;
+    memset(&info, 0, sizeof(info));
+    strcpy(info.name, table->name);
+    optlen = sizeof(info);
+    if (getsockopt(fd, SOL_IP, ARPT_SO_GET_INFO, &info, &optlen))
+      fail("getsockopt(ARPT_SO_GET_INFO)");
+    if (memcmp(&table->info, &info, sizeof(table->info)) == 0) {
+      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))
+        fail("getsockopt(ARPT_SO_GET_ENTRIES)");
+      if (memcmp(table->replace.entrytable, entries.entrytable,
+                 table->info.size) == 0)
+        continue;
+    }
+    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))
+      fail("setsockopt(ARPT_SO_SET_REPLACE)");
+  }
+  close(fd);
+}
+#include <linux/if.h>
+#include <linux/netfilter_bridge/ebtables.h>
+
+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)
+{
+  socklen_t optlen;
+  unsigned i;
+  int fd;
+
+  fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  if (fd == -1) {
+    switch (errno) {
+    case EAFNOSUPPORT:
+    case ENOPROTOOPT:
+      return;
+    }
+    fail("socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)");
+  }
+  for (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);
+    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;
+      }
+      fail("getsockopt(EBT_SO_GET_INIT_INFO)");
+    }
+    if (table->replace.entries_size > sizeof(table->entrytable))
+      fail("table size is too large: %u", 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))
+      fail("getsockopt(EBT_SO_GET_INIT_ENTRIES)");
+  }
+  close(fd);
+}
+
+static void reset_ebtables()
+{
+  struct ebt_replace replace;
+  char entrytable[XT_TABLE_SIZE];
+  socklen_t optlen;
+  unsigned i, j, h;
+  int fd;
+
+  fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  if (fd == -1) {
+    switch (errno) {
+    case EAFNOSUPPORT:
+    case ENOPROTOOPT:
+      return;
+    }
+    fail("socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)");
+  }
+  for (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;
+    memset(&replace, 0, sizeof(replace));
+    strcpy(replace.name, table->name);
+    optlen = sizeof(replace);
+    if (getsockopt(fd, SOL_IP, EBT_SO_GET_INFO, &replace, &optlen))
+      fail("getsockopt(EBT_SO_GET_INFO)");
+    replace.num_counters = 0;
+    table->replace.entries = 0;
+    for (h = 0; h < NF_BR_NUMHOOKS; h++)
+      table->replace.hook_entry[h] = 0;
+    if (memcmp(&table->replace, &replace, sizeof(table->replace)) == 0) {
+      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))
+        fail("getsockopt(EBT_SO_GET_ENTRIES)");
+      if (memcmp(table->entrytable, entrytable, replace.entries_size) == 0)
+        continue;
+    }
+    for (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))
+      fail("setsockopt(EBT_SO_SET_ENTRIES)");
+  }
+  close(fd);
+}
+
+static void checkpoint_net_namespace(void)
+{
+  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)
+{
+  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);
+}
+
+static void remove_dir(const char* dir)
+{
+  DIR* dp;
+  struct dirent* ep;
+  int iter = 0;
+retry:
+  while (umount2(dir, MNT_DETACH) == 0) {
+  }
+  dp = opendir(dir);
+  if (dp == NULL) {
+    if (errno == EMFILE) {
+      exitf("opendir(%s) failed due to NOFILE, exiting", dir);
+    }
+    exitf("opendir(%s) failed", dir);
+  }
+  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);
+    while (umount2(filename, MNT_DETACH) == 0) {
+    }
+    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 == EROFS) {
+        break;
+      }
+      if (errno != EBUSY || i > 100)
+        exitf("unlink(%s) failed", filename);
+      if (umount2(filename, MNT_DETACH))
+        exitf("umount(%s) failed", filename);
+    }
+  }
+  closedir(dp);
+  int i;
+  for (i = 0;; i++) {
+    if (rmdir(dir) == 0)
+      break;
+    if (i < 100) {
+      if (errno == EROFS) {
+        break;
+      }
+      if (errno == EBUSY) {
+        if (umount2(dir, MNT_DETACH))
+          exitf("umount(%s) failed", dir);
+        continue;
+      }
+      if (errno == ENOTEMPTY) {
+        if (iter < 100) {
+          iter++;
+          goto retry;
+        }
+      }
+    }
+    exitf("rmdir(%s) failed", dir);
+  }
+}
+
+static void execute_one();
+extern unsigned long long procid;
+
+static void loop()
+{
+  checkpoint_net_namespace();
+  char cgroupdir[64];
+  snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/unified/syz%llu", procid);
+  char cgroupdir_cpu[64];
+  snprintf(cgroupdir_cpu, sizeof(cgroupdir_cpu), "/syzcgroup/cpu/syz%llu",
+           procid);
+  char cgroupdir_net[64];
+  snprintf(cgroupdir_net, sizeof(cgroupdir_net), "/syzcgroup/net/syz%llu",
+           procid);
+  if (mkdir(cgroupdir, 0777)) {
+  }
+  if (mkdir(cgroupdir_cpu, 0777)) {
+  }
+  if (mkdir(cgroupdir_net, 0777)) {
+  }
+  int pid = getpid();
+  char procs_file[128];
+  snprintf(procs_file, sizeof(procs_file), "%s/cgroup.procs", cgroupdir);
+  if (!write_file(procs_file, "%d", pid)) {
+  }
+  snprintf(procs_file, sizeof(procs_file), "%s/cgroup.procs", cgroupdir_cpu);
+  if (!write_file(procs_file, "%d", pid)) {
+  }
+  snprintf(procs_file, sizeof(procs_file), "%s/cgroup.procs", cgroupdir_net);
+  if (!write_file(procs_file, "%d", pid)) {
+  }
+  int iter;
+  for (iter = 0;; iter++) {
+    char cwdbuf[32];
+    sprintf(cwdbuf, "./%d", iter);
+    if (mkdir(cwdbuf, 0777))
+      fail("failed to mkdir");
+    int pid = fork();
+    if (pid < 0)
+      fail("clone failed");
+    if (pid == 0) {
+      prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+      setpgrp();
+      if (chdir(cwdbuf))
+        fail("failed to chdir");
+      if (symlink(cgroupdir, "./cgroup")) {
+      }
+      if (symlink(cgroupdir_cpu, "./cgroup.cpu")) {
+      }
+      if (symlink(cgroupdir_net, "./cgroup.net")) {
+      }
+      flush_tun();
+      execute_one();
+      int fd;
+      for (fd = 3; fd < 30; fd++)
+        close(fd);
+      doexit(0);
+    }
+
+    int status = 0;
+    uint64_t start = current_time_ms();
+    for (;;) {
+      int res = waitpid(-1, &status, __WALL | WNOHANG);
+      if (res == pid) {
+        break;
+      }
+      usleep(1000);
+      if (current_time_ms() - start < 5 * 1000)
+        continue;
+      kill(-pid, SIGKILL);
+      kill(pid, SIGKILL);
+      while (waitpid(-1, &status, __WALL) != pid) {
+      }
+      break;
+    }
+    remove_dir(cwdbuf);
+    reset_net_namespace();
+  }
+}
+
+struct thread_t {
+  int created, running, call;
+  pthread_t th;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+static int collide;
+
+static void* thr(void* arg)
+{
+  struct thread_t* th = (struct thread_t*)arg;
+  for (;;) {
+    while (!__atomic_load_n(&th->running, __ATOMIC_ACQUIRE))
+      syscall(SYS_futex, &th->running, FUTEX_WAIT, 0, 0);
+    execute_call(th->call);
+    __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+    __atomic_store_n(&th->running, 0, __ATOMIC_RELEASE);
+    syscall(SYS_futex, &th->running, FUTEX_WAKE);
+  }
+  return 0;
+}
+
+static void execute(int num_calls)
+{
+  int call, thread;
+  running = 0;
+  for (call = 0; call < num_calls; call++) {
+    for (thread = 0; thread < sizeof(threads) / sizeof(threads[0]); thread++) {
+      struct thread_t* th = &threads[thread];
+      if (!th->created) {
+        th->created = 1;
+        pthread_attr_t attr;
+        pthread_attr_init(&attr);
+        pthread_attr_setstacksize(&attr, 128 << 10);
+        pthread_create(&th->th, &attr, thr, th);
+      }
+      if (!__atomic_load_n(&th->running, __ATOMIC_ACQUIRE)) {
+        th->call = call;
+        __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+        __atomic_store_n(&th->running, 1, __ATOMIC_RELEASE);
+        syscall(SYS_futex, &th->running, FUTEX_WAKE);
+        if (collide && call % 2)
+          break;
+        struct timespec ts;
+        ts.tv_sec = 0;
+        ts.tv_nsec = 20 * 1000 * 1000;
+        syscall(SYS_futex, &th->running, FUTEX_WAIT, 1, &ts);
+        if (__atomic_load_n(&running, __ATOMIC_RELAXED))
+          usleep((call == num_calls - 1) ? 10000 : 1000);
+        break;
+      }
+    }
+  }
+}
+
+unsigned long long procid;
+void execute_call(int call)
+{
+  switch (call) {
+  case 0:
+    NONFAILING(memcpy((void*)0x20000040, "./file0", 8));
+    syscall(__NR_readlink, 0x20000040, 0x20000000, 0);
+    break;
+  }
+}
+
+void execute_one()
+{
+  execute(1);
+  collide = 1;
+  execute(1);
+}
+
+int main()
+{
+  syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+  char* cwd = get_current_dir_name();
+  for (procid = 0; procid < 4; procid++) {
+    if (fork() == 0) {
+      install_segv_handler();
+      for (;;) {
+        if (chdir(cwd))
+          fail("failed to chdir");
+        use_temporary_dir();
+        do_sandbox_none();
+      }
+    }
+  }
+  sleep(1000000);
+  return 0;
+}
diff --git a/syzkaller-repros/linux/06c43cd0a71aec08de8ea55ca5cda816c45ab4e0.c b/syzkaller-repros/linux/06c43cd0a71aec08de8ea55ca5cda816c45ab4e0.c
new file mode 100644
index 0000000..2756f2f
--- /dev/null
+++ b/syzkaller-repros/linux/06c43cd0a71aec08de8ea55ca5cda816c45ab4e0.c
@@ -0,0 +1,639 @@
+// KMSAN: uninit-value in _mix_pool_bytes
+// https://syzkaller.appspot.com/bug?id=06c43cd0a71aec08de8ea55ca5cda816c45ab4e0
+// status:open
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sched.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <linux/usb/ch9.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+  usleep(ms * 1000);
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+  char buf[1024];
+  va_list args;
+  va_start(args, what);
+  vsnprintf(buf, sizeof(buf), what, args);
+  va_end(args);
+  buf[sizeof(buf) - 1] = 0;
+  int len = strlen(buf);
+  int fd = open(file, O_WRONLY | O_CLOEXEC);
+  if (fd == -1)
+    return false;
+  if (write(fd, buf, len) != len) {
+    int err = errno;
+    close(fd);
+    errno = err;
+    return false;
+  }
+  close(fd);
+  return true;
+}
+
+#define USB_MAX_EP_NUM 32
+
+struct usb_device_index {
+  struct usb_device_descriptor* dev;
+  struct usb_config_descriptor* config;
+  unsigned config_length;
+  struct usb_interface_descriptor* iface;
+  struct usb_endpoint_descriptor* eps[USB_MAX_EP_NUM];
+  unsigned eps_num;
+};
+
+static bool parse_usb_descriptor(char* buffer, size_t length,
+                                 struct usb_device_index* index)
+{
+  if (length <
+      sizeof(*index->dev) + sizeof(*index->config) + sizeof(*index->iface))
+    return false;
+  index->dev = (struct usb_device_descriptor*)buffer;
+  index->config = (struct usb_config_descriptor*)(buffer + sizeof(*index->dev));
+  index->config_length = length - sizeof(*index->dev);
+  index->iface =
+      (struct usb_interface_descriptor*)(buffer + sizeof(*index->dev) +
+                                         sizeof(*index->config));
+  index->eps_num = 0;
+  size_t offset = 0;
+  while (true) {
+    if (offset == length)
+      break;
+    if (offset + 1 < length)
+      break;
+    uint8_t length = buffer[offset];
+    uint8_t type = buffer[offset + 1];
+    if (type == USB_DT_ENDPOINT) {
+      index->eps[index->eps_num] =
+          (struct usb_endpoint_descriptor*)(buffer + offset);
+      index->eps_num++;
+    }
+    if (index->eps_num == USB_MAX_EP_NUM)
+      break;
+    offset += length;
+  }
+  return true;
+}
+
+enum usb_fuzzer_event_type {
+  USB_FUZZER_EVENT_INVALID,
+  USB_FUZZER_EVENT_CONNECT,
+  USB_FUZZER_EVENT_DISCONNECT,
+  USB_FUZZER_EVENT_SUSPEND,
+  USB_FUZZER_EVENT_RESUME,
+  USB_FUZZER_EVENT_CONTROL,
+};
+
+struct usb_fuzzer_event {
+  uint32_t type;
+  uint32_t length;
+  char data[0];
+};
+
+struct usb_fuzzer_init {
+  uint64_t speed;
+  const char* driver_name;
+  const char* device_name;
+};
+
+struct usb_fuzzer_ep_io {
+  uint16_t ep;
+  uint16_t flags;
+  uint32_t length;
+  char data[0];
+};
+
+#define USB_FUZZER_IOCTL_INIT _IOW('U', 0, struct usb_fuzzer_init)
+#define USB_FUZZER_IOCTL_RUN _IO('U', 1)
+#define USB_FUZZER_IOCTL_EP0_READ _IOWR('U', 2, struct usb_fuzzer_event)
+#define USB_FUZZER_IOCTL_EP0_WRITE _IOW('U', 3, struct usb_fuzzer_ep_io)
+#define USB_FUZZER_IOCTL_EP_ENABLE _IOW('U', 4, struct usb_endpoint_descriptor)
+#define USB_FUZZER_IOCTL_EP_WRITE _IOW('U', 6, struct usb_fuzzer_ep_io)
+#define USB_FUZZER_IOCTL_CONFIGURE _IO('U', 8)
+#define USB_FUZZER_IOCTL_VBUS_DRAW _IOW('U', 9, uint32_t)
+
+int usb_fuzzer_open()
+{
+  return open("/sys/kernel/debug/usb-fuzzer", O_RDWR);
+}
+
+int usb_fuzzer_init(int fd, uint32_t speed, const char* driver,
+                    const char* device)
+{
+  struct usb_fuzzer_init arg;
+  arg.speed = speed;
+  arg.driver_name = driver;
+  arg.device_name = device;
+  return ioctl(fd, USB_FUZZER_IOCTL_INIT, &arg);
+}
+
+int usb_fuzzer_run(int fd)
+{
+  return ioctl(fd, USB_FUZZER_IOCTL_RUN, 0);
+}
+
+int usb_fuzzer_ep0_read(int fd, struct usb_fuzzer_event* event)
+{
+  return ioctl(fd, USB_FUZZER_IOCTL_EP0_READ, event);
+}
+
+int usb_fuzzer_ep0_write(int fd, struct usb_fuzzer_ep_io* io)
+{
+  return ioctl(fd, USB_FUZZER_IOCTL_EP0_WRITE, io);
+}
+
+int usb_fuzzer_ep_write(int fd, struct usb_fuzzer_ep_io* io)
+{
+  return ioctl(fd, USB_FUZZER_IOCTL_EP_WRITE, io);
+}
+
+int usb_fuzzer_ep_enable(int fd, struct usb_endpoint_descriptor* desc)
+{
+  return ioctl(fd, USB_FUZZER_IOCTL_EP_ENABLE, desc);
+}
+
+int usb_fuzzer_configure(int fd)
+{
+  return ioctl(fd, USB_FUZZER_IOCTL_CONFIGURE, 0);
+}
+
+int usb_fuzzer_vbus_draw(int fd, uint32_t power)
+{
+  return ioctl(fd, USB_FUZZER_IOCTL_VBUS_DRAW, power);
+}
+
+#define USB_MAX_PACKET_SIZE 1024
+
+struct usb_fuzzer_control_event {
+  struct usb_fuzzer_event inner;
+  struct usb_ctrlrequest ctrl;
+  char data[USB_MAX_PACKET_SIZE];
+};
+
+struct usb_fuzzer_ep_io_data {
+  struct usb_fuzzer_ep_io inner;
+  char data[USB_MAX_PACKET_SIZE];
+};
+
+struct vusb_connect_string_descriptor {
+  uint32_t len;
+  char* str;
+} __attribute__((packed));
+
+struct vusb_connect_descriptors {
+  uint32_t qual_len;
+  char* qual;
+  uint32_t bos_len;
+  char* bos;
+  uint32_t strs_len;
+  struct vusb_connect_string_descriptor strs[0];
+} __attribute__((packed));
+
+static bool lookup_connect_response(struct vusb_connect_descriptors* descs,
+                                    struct usb_device_index* index,
+                                    struct usb_ctrlrequest* ctrl,
+                                    char** response_data,
+                                    uint32_t* response_length, bool* done)
+{
+  uint8_t str_idx;
+  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_t)ctrl->wValue;
+        if (str_idx >= descs->strs_len && descs->strs_len > 0) {
+          str_idx = descs->strs_len - 1;
+        }
+        *response_data = descs->strs[str_idx].str;
+        *response_length = descs->strs[str_idx].len;
+        return true;
+      case USB_DT_BOS:
+        *response_data = descs->bos;
+        *response_length = descs->bos_len;
+        return true;
+      case USB_DT_DEVICE_QUALIFIER:
+        *response_data = descs->qual;
+        *response_length = descs->qual_len;
+        return true;
+      default:
+        exit(1);
+        return false;
+      }
+      break;
+    case USB_REQ_SET_CONFIGURATION:
+      *response_length = 0;
+      *response_data = NULL;
+      *done = true;
+      return true;
+    default:
+      exit(1);
+      return false;
+    }
+    break;
+  default:
+    exit(1);
+    return false;
+  }
+  return false;
+}
+
+static volatile long syz_usb_connect(volatile long a0, volatile long a1,
+                                     volatile long a2, volatile long a3)
+{
+  int64_t speed = a0;
+  int64_t dev_len = a1;
+  char* dev = (char*)a2;
+  struct vusb_connect_descriptors* descs = (struct vusb_connect_descriptors*)a3;
+  if (!dev)
+    return -1;
+  struct usb_device_index index;
+  memset(&index, 0, sizeof(index));
+  int rv = 0;
+  rv = parse_usb_descriptor(dev, dev_len, &index);
+  if (!rv) {
+    return rv;
+  }
+  int fd = usb_fuzzer_open();
+  if (fd < 0) {
+    return fd;
+  }
+  char device[32];
+  sprintf(&device[0], "dummy_udc.%llu", procid);
+  rv = usb_fuzzer_init(fd, speed, "dummy_udc", &device[0]);
+  if (rv < 0) {
+    return rv;
+  }
+  rv = usb_fuzzer_run(fd);
+  if (rv < 0) {
+    return rv;
+  }
+  bool done = false;
+  while (!done) {
+    struct usb_fuzzer_control_event event;
+    event.inner.type = 0;
+    event.inner.length = sizeof(event.ctrl);
+    rv = usb_fuzzer_ep0_read(fd, (struct usb_fuzzer_event*)&event);
+    if (rv < 0) {
+      return rv;
+    }
+    if (event.inner.type != USB_FUZZER_EVENT_CONTROL)
+      continue;
+    bool response_found = false;
+    char* response_data = NULL;
+    uint32_t response_length = 0;
+    response_found = lookup_connect_response(
+        descs, &index, &event.ctrl, &response_data, &response_length, &done);
+    if (!response_found) {
+      return -1;
+    }
+    if (done) {
+      rv = usb_fuzzer_vbus_draw(fd, index.config->bMaxPower);
+      if (rv < 0) {
+        return rv;
+      }
+      rv = usb_fuzzer_configure(fd);
+      if (rv < 0) {
+        return rv;
+      }
+      unsigned ep;
+      for (ep = 0; ep < index.eps_num; ep++) {
+        rv = usb_fuzzer_ep_enable(fd, index.eps[ep]);
+        if (rv < 0)
+          exit(1);
+      }
+    }
+    struct usb_fuzzer_ep_io_data response;
+    response.inner.ep = 0;
+    response.inner.flags = 0;
+    if (response_length > sizeof(response.data))
+      response_length = 0;
+    response.inner.length = response_length;
+    if (response_data)
+      memcpy(&response.data[0], response_data, response_length);
+    if (event.ctrl.wLength < response.inner.length)
+      response.inner.length = event.ctrl.wLength;
+    rv = usb_fuzzer_ep0_write(fd, (struct usb_fuzzer_ep_io*)&response);
+    if (rv < 0) {
+      return rv;
+    }
+  }
+  sleep_ms(200);
+  return fd;
+}
+
+struct vusb_descriptor {
+  uint8_t req_type;
+  uint8_t desc_type;
+  uint32_t len;
+  char data[0];
+} __attribute__((packed));
+
+struct vusb_descriptors {
+  uint32_t len;
+  struct vusb_descriptor* generic;
+  struct vusb_descriptor* descs[0];
+} __attribute__((packed));
+
+struct vusb_response {
+  uint8_t type;
+  uint8_t req;
+  uint32_t len;
+  char data[0];
+} __attribute__((packed));
+
+struct vusb_responses {
+  uint32_t len;
+  struct vusb_response* generic;
+  struct vusb_response* resps[0];
+} __attribute__((packed));
+
+static bool lookup_control_io_response(struct vusb_descriptors* descs,
+                                       struct vusb_responses* resps,
+                                       struct usb_ctrlrequest* ctrl,
+                                       char** response_data,
+                                       uint32_t* response_length)
+{
+  int descs_num = (descs->len - offsetof(struct vusb_descriptors, descs)) /
+                  sizeof(descs->descs[0]);
+  int resps_num = (resps->len - offsetof(struct vusb_responses, resps)) /
+                  sizeof(resps->resps[0]);
+  uint8_t req = ctrl->bRequest;
+  uint8_t req_type = ctrl->bRequestType & USB_TYPE_MASK;
+  uint8_t 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->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->generic) {
+      *response_data = &resps->generic->data[0];
+      *response_length = resps->generic->len;
+      return true;
+    }
+  }
+  return false;
+}
+
+static volatile long syz_usb_control_io(volatile long a0, volatile long a1,
+                                        volatile long a2)
+{
+  int fd = a0;
+  struct vusb_descriptors* descs = (struct vusb_descriptors*)a1;
+  struct vusb_responses* resps = (struct vusb_responses*)a2;
+  struct usb_fuzzer_control_event event;
+  event.inner.type = 0;
+  event.inner.length = USB_MAX_PACKET_SIZE;
+  int rv = usb_fuzzer_ep0_read(fd, (struct usb_fuzzer_event*)&event);
+  if (rv < 0) {
+    return rv;
+  }
+  if (event.inner.type != USB_FUZZER_EVENT_CONTROL) {
+    return -1;
+  }
+  if (!(event.ctrl.bRequestType & USB_DIR_IN) && event.ctrl.wLength != 0) {
+  }
+  bool response_found = false;
+  char* response_data = NULL;
+  uint32_t response_length = 0;
+  response_found = lookup_control_io_response(descs, resps, &event.ctrl,
+                                              &response_data, &response_length);
+  if (!response_found) {
+    return -1;
+  }
+  struct usb_fuzzer_ep_io_data response;
+  response.inner.ep = 0;
+  response.inner.flags = 0;
+  if (response_length > sizeof(response.data))
+    response_length = 0;
+  response.inner.length = response_length;
+  if (response_data)
+    memcpy(&response.data[0], response_data, response_length);
+  if (event.ctrl.wLength < response.inner.length)
+    response.inner.length = event.ctrl.wLength;
+  rv = usb_fuzzer_ep0_write(fd, (struct usb_fuzzer_ep_io*)&response);
+  if (rv < 0) {
+    return rv;
+  }
+  sleep_ms(200);
+  return 0;
+}
+
+static void setup_common()
+{
+  if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+  }
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+  prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+  setpgrp();
+  setsid();
+  struct rlimit rlim;
+  rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+  setrlimit(RLIMIT_AS, &rlim);
+  rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+  setrlimit(RLIMIT_MEMLOCK, &rlim);
+  rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+  setrlimit(RLIMIT_FSIZE, &rlim);
+  rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+  setrlimit(RLIMIT_STACK, &rlim);
+  rlim.rlim_cur = rlim.rlim_max = 0;
+  setrlimit(RLIMIT_CORE, &rlim);
+  rlim.rlim_cur = rlim.rlim_max = 256;
+  setrlimit(RLIMIT_NOFILE, &rlim);
+  if (unshare(CLONE_NEWNS)) {
+  }
+  if (unshare(CLONE_NEWIPC)) {
+  }
+  if (unshare(0x02000000)) {
+  }
+  if (unshare(CLONE_NEWUTS)) {
+  }
+  if (unshare(CLONE_SYSVSEM)) {
+  }
+  typedef struct {
+    const char* name;
+    const char* value;
+  } sysctl_t;
+  static const sysctl_t sysctls[] = {
+      {"/proc/sys/kernel/shmmax", "16777216"},
+      {"/proc/sys/kernel/shmall", "536870912"},
+      {"/proc/sys/kernel/shmmni", "1024"},
+      {"/proc/sys/kernel/msgmax", "8192"},
+      {"/proc/sys/kernel/msgmni", "1024"},
+      {"/proc/sys/kernel/msgmnb", "1024"},
+      {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+  };
+  unsigned i;
+  for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+    write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+  if (pid < 0)
+    exit(1);
+  int status = 0;
+  while (waitpid(-1, &status, __WALL) != pid) {
+  }
+  return WEXITSTATUS(status);
+}
+
+static int do_sandbox_none(void)
+{
+  if (unshare(CLONE_NEWPID)) {
+  }
+  int pid = fork();
+  if (pid != 0)
+    return wait_for_loop(pid);
+  setup_common();
+  sandbox_common();
+  if (unshare(CLONE_NEWNET)) {
+  }
+  loop();
+  exit(1);
+}
+
+static void close_fds()
+{
+  int fd;
+  for (fd = 3; fd < 30; fd++)
+    close(fd);
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void loop(void)
+{
+  intptr_t res = 0;
+  *(uint8_t*)0x20000040 = 0x12;
+  *(uint8_t*)0x20000041 = 1;
+  *(uint16_t*)0x20000042 = 0;
+  *(uint8_t*)0x20000044 = 0xc4;
+  *(uint8_t*)0x20000045 = -1;
+  *(uint8_t*)0x20000046 = 0x41;
+  *(uint8_t*)0x20000047 = 8;
+  *(uint16_t*)0x20000048 = 0xbda;
+  *(uint16_t*)0x2000004a = 0x8150;
+  *(uint16_t*)0x2000004c = 0x31ce;
+  *(uint8_t*)0x2000004e = 0;
+  *(uint8_t*)0x2000004f = 0;
+  *(uint8_t*)0x20000050 = 0;
+  *(uint8_t*)0x20000051 = 1;
+  *(uint8_t*)0x20000052 = 9;
+  *(uint8_t*)0x20000053 = 2;
+  *(uint16_t*)0x20000054 = 0x12;
+  *(uint8_t*)0x20000056 = 1;
+  *(uint8_t*)0x20000057 = 0;
+  *(uint8_t*)0x20000058 = 0;
+  *(uint8_t*)0x20000059 = 0;
+  *(uint8_t*)0x2000005a = 0;
+  *(uint8_t*)0x2000005b = 9;
+  *(uint8_t*)0x2000005c = 4;
+  *(uint8_t*)0x2000005d = 0xfe;
+  *(uint8_t*)0x2000005e = 0;
+  *(uint8_t*)0x2000005f = 0;
+  *(uint8_t*)0x20000060 = 0xa2;
+  *(uint8_t*)0x20000061 = 0x39;
+  *(uint8_t*)0x20000062 = 0xb;
+  *(uint8_t*)0x20000063 = 0;
+  res = syz_usb_connect(0, 0x24, 0x20000040, 0);
+  if (res != -1)
+    r[0] = res;
+  *(uint32_t*)0x20000d80 = 0x34;
+  *(uint64_t*)0x20000d84 = 0;
+  *(uint64_t*)0x20000d8c = 0;
+  *(uint64_t*)0x20000d94 = 0;
+  *(uint64_t*)0x20000d9c = 0;
+  *(uint64_t*)0x20000da4 = 0;
+  *(uint64_t*)0x20000dac = 0;
+  *(uint32_t*)0x20001080 = 0x54;
+  *(uint64_t*)0x20001084 = 0x20000dc0;
+  memcpy((void*)0x20000dc0, "\x00\x1f\x46", 3);
+  *(uint64_t*)0x2000108c = 0;
+  *(uint64_t*)0x20001094 = 0;
+  *(uint64_t*)0x2000109c = 0;
+  *(uint64_t*)0x200010a4 = 0;
+  *(uint64_t*)0x200010ac = 0;
+  *(uint64_t*)0x200010b4 = 0;
+  *(uint64_t*)0x200010bc = 0;
+  *(uint64_t*)0x200010c4 = 0;
+  *(uint64_t*)0x200010cc = 0;
+  syz_usb_control_io(r[0], 0x20000d80, 0x20001080);
+  close_fds();
+}
+int main(void)
+{
+  syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+  do_sandbox_none();
+  return 0;
+}
diff --git a/syzkaller-repros/linux/07195aa24c0577cc6ebdccfb1ef032a3f544f3b1.c b/syzkaller-repros/linux/07195aa24c0577cc6ebdccfb1ef032a3f544f3b1.c
new file mode 100644
index 0000000..cd4a9b1
--- /dev/null
+++ b/syzkaller-repros/linux/07195aa24c0577cc6ebdccfb1ef032a3f544f3b1.c
@@ -0,0 +1,957 @@
+// KASAN: slab-out-of-bounds Read in fbcon_get_font
+// https://syzkaller.appspot.com/bug?id=07195aa24c0577cc6ebdccfb1ef032a3f544f3b1
+// status:open
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+#include <linux/futex.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+  usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+  struct timespec ts;
+  if (clock_gettime(CLOCK_MONOTONIC, &ts))
+    exit(1);
+  return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+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;
+  for (i = 0; i < 100; i++) {
+    if (pthread_create(&th, &attr, fn, arg) == 0) {
+      pthread_attr_destroy(&attr);
+      return;
+    }
+    if (errno == EAGAIN) {
+      usleep(50);
+      continue;
+    }
+    break;
+  }
+  exit(1);
+}
+
+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)
+    exit(1);
+  __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+  syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG);
+}
+
+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_t timeout)
+{
+  uint64_t start = current_time_ms();
+  uint64_t now = start;
+  for (;;) {
+    uint64_t 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_RELAXED))
+      return 1;
+    now = current_time_ms();
+    if (now - start > timeout)
+      return 0;
+  }
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+  char buf[1024];
+  va_list args;
+  va_start(args, what);
+  vsnprintf(buf, sizeof(buf), what, args);
+  va_end(args);
+  buf[sizeof(buf) - 1] = 0;
+  int len = strlen(buf);
+  int fd = open(file, O_WRONLY | O_CLOEXEC);
+  if (fd == -1)
+    return false;
+  if (write(fd, buf, len) != len) {
+    int err = errno;
+    close(fd);
+    errno = err;
+    return false;
+  }
+  close(fd);
+  return true;
+}
+
+struct nlmsg {
+  char* pos;
+  int nesting;
+  struct nlattr* nested[8];
+  char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+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;
+  memcpy(attr + 1, data, size);
+  nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static void netlink_nest(struct nlmsg* nlmsg, int typ)
+{
+  struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+  attr->nla_type = typ;
+  nlmsg->pos += sizeof(*attr);
+  nlmsg->nested[nlmsg->nesting++] = attr;
+}
+
+static void netlink_done(struct nlmsg* nlmsg)
+{
+  struct nlattr* attr = nlmsg->nested[--nlmsg->nesting];
+  attr->nla_len = nlmsg->pos - (char*)attr;
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+                            int* reply_len)
+{
+  if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+    exit(1);
+  struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+  hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+  struct sockaddr_nl addr;
+  memset(&addr, 0, sizeof(addr));
+  addr.nl_family = AF_NETLINK;
+  unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+                      (struct sockaddr*)&addr, sizeof(addr));
+  if (n != hdr->nlmsg_len)
+    exit(1);
+  n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+  if (hdr->nlmsg_type == NLMSG_DONE) {
+    *reply_len = 0;
+    return 0;
+  }
+  if (n < sizeof(struct nlmsghdr))
+    exit(1);
+  if (reply_len && hdr->nlmsg_type == reply_type) {
+    *reply_len = n;
+    return 0;
+  }
+  if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+    exit(1);
+  if (hdr->nlmsg_type != NLMSG_ERROR)
+    exit(1);
+  return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+  return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+                            unsigned int total_len)
+{
+  struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+  if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+    return -1;
+  return hdr->nlmsg_len;
+}
+
+static void netlink_add_device_impl(struct nlmsg* nlmsg, const char* type,
+                                    const char* name)
+{
+  struct ifinfomsg hdr;
+  memset(&hdr, 0, sizeof(hdr));
+  netlink_init(nlmsg, RTM_NEWLINK, NLM_F_EXCL | NLM_F_CREATE, &hdr,
+               sizeof(hdr));
+  if (name)
+    netlink_attr(nlmsg, IFLA_IFNAME, name, strlen(name));
+  netlink_nest(nlmsg, IFLA_LINKINFO);
+  netlink_attr(nlmsg, IFLA_INFO_KIND, type, strlen(type));
+}
+
+static void netlink_add_device(struct nlmsg* nlmsg, int sock, const char* type,
+                               const char* name)
+{
+  netlink_add_device_impl(nlmsg, type, name);
+  netlink_done(nlmsg);
+  int err = netlink_send(nlmsg, sock);
+  (void)err;
+}
+
+static void netlink_add_veth(struct nlmsg* nlmsg, int sock, const char* name,
+                             const char* peer)
+{
+  netlink_add_device_impl(nlmsg, "veth", name);
+  netlink_nest(nlmsg, IFLA_INFO_DATA);
+  netlink_nest(nlmsg, VETH_INFO_PEER);
+  nlmsg->pos += sizeof(struct ifinfomsg);
+  netlink_attr(nlmsg, IFLA_IFNAME, peer, strlen(peer));
+  netlink_done(nlmsg);
+  netlink_done(nlmsg);
+  netlink_done(nlmsg);
+  int err = netlink_send(nlmsg, sock);
+  (void)err;
+}
+
+static void netlink_add_hsr(struct nlmsg* nlmsg, int sock, const char* name,
+                            const char* slave1, const char* slave2)
+{
+  netlink_add_device_impl(nlmsg, "hsr", name);
+  netlink_nest(nlmsg, IFLA_INFO_DATA);
+  int ifindex1 = if_nametoindex(slave1);
+  netlink_attr(nlmsg, IFLA_HSR_SLAVE1, &ifindex1, sizeof(ifindex1));
+  int ifindex2 = if_nametoindex(slave2);
+  netlink_attr(nlmsg, IFLA_HSR_SLAVE2, &ifindex2, sizeof(ifindex2));
+  netlink_done(nlmsg);
+  netlink_done(nlmsg);
+  int err = netlink_send(nlmsg, sock);
+  (void)err;
+}
+
+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);
+  (void)err;
+}
+
+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));
+  (void)err;
+}
+
+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));
+  (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+  struct genlmsghdr genlhdr;
+  struct nlattr* attr;
+  int err, n;
+  uint16_t id = 0;
+  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, DEVLINK_FAMILY_NAME,
+               strlen(DEVLINK_FAMILY_NAME) + 1);
+  err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+  if (err) {
+    return -1;
+  }
+  attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+                          NLMSG_ALIGN(sizeof(genlhdr)));
+  for (; (char*)attr < nlmsg->buf + n;
+       attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+    if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+      id = *(uint16_t*)(attr + 1);
+      break;
+    }
+  }
+  if (!id) {
+    return -1;
+  }
+  recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+  return id;
+}
+
+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)
+    exit(1);
+  id = netlink_devlink_id_get(&nlmsg, sock);
+  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) {
+  }
+error:
+  close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+                                     const char* netdev_prefix)
+{
+  struct genlmsghdr genlhdr;
+  int len, total_len, id, err, offset;
+  uint16_t netdev_index;
+  int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+  if (sock == -1)
+    exit(1);
+  int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+  if (rtsock == -1)
+    exit(1);
+  id = netlink_devlink_id_get(&nlmsg, sock);
+  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);
+  if (err) {
+    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);
+}
+
+static void initialize_devlink_pci(void)
+{
+  int netns = open("/proc/self/ns/net", O_RDONLY);
+  if (netns == -1)
+    exit(1);
+  int ret = setns(kInitNetNsFd, 0);
+  if (ret == -1)
+    exit(1);
+  netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+  ret = setns(netns, 0);
+  if (ret == -1)
+    exit(1);
+  close(netns);
+  initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+#define DEV_IPV4 "172.20.20.%d"
+#define DEV_IPV6 "fe80::%02x"
+#define DEV_MAC 0x00aaaaaaaaaa
+
+static void netdevsim_add(unsigned int addr, unsigned int port_count)
+{
+  char buf[16];
+  sprintf(buf, "%u %u", addr, port_count);
+  if (write_file("/sys/bus/netdevsim/new_device", buf)) {
+    snprintf(buf, sizeof(buf), "netdevsim%d", addr);
+    initialize_devlink_ports("netdevsim", buf, "netdevsim");
+  }
+}
+static void initialize_netdevices(void)
+{
+  char netdevsim[16];
+  sprintf(netdevsim, "netdevsim%d", (int)procid);
+  struct {
+    const char* type;
+    const char* dev;
+  } devtypes[] = {
+      {"ip6gretap", "ip6gretap0"}, {"bridge", "bridge0"},
+      {"vcan", "vcan0"},           {"bond", "bond0"},
+      {"team", "team0"},           {"dummy", "dummy0"},
+      {"nlmon", "nlmon0"},         {"caif", "caif0"},
+      {"batadv", "batadv0"},       {"vxcan", "vxcan1"},
+      {"netdevsim", netdevsim},    {"veth", 0},
+  };
+  const char* devmasters[] = {"bridge", "bond", "team"};
+  struct {
+    const char* name;
+    int macsize;
+    bool noipv6;
+  } devices[] = {
+      {"lo", ETH_ALEN},
+      {"sit0", 0},
+      {"bridge0", ETH_ALEN},
+      {"vcan0", 0, true},
+      {"tunl0", 0},
+      {"gre0", 0},
+      {"gretap0", ETH_ALEN},
+      {"ip_vti0", 0},
+      {"ip6_vti0", 0},
+      {"ip6tnl0", 0},
+      {"ip6gre0", 0},
+      {"ip6gretap0", ETH_ALEN},
+      {"erspan0", ETH_ALEN},
+      {"bond0", ETH_ALEN},
+      {"veth0", ETH_ALEN},
+      {"veth1", ETH_ALEN},
+      {"team0", ETH_ALEN},
+      {"veth0_to_bridge", ETH_ALEN},
+      {"veth1_to_bridge", ETH_ALEN},
+      {"veth0_to_bond", ETH_ALEN},
+      {"veth1_to_bond", ETH_ALEN},
+      {"veth0_to_team", ETH_ALEN},
+      {"veth1_to_team", ETH_ALEN},
+      {"veth0_to_hsr", ETH_ALEN},
+      {"veth1_to_hsr", ETH_ALEN},
+      {"hsr0", 0},
+      {"dummy0", ETH_ALEN},
+      {"nlmon0", 0},
+      {"vxcan0", 0, true},
+      {"vxcan1", 0, true},
+      {"caif0", ETH_ALEN},
+      {"batadv0", ETH_ALEN},
+      {netdevsim, ETH_ALEN},
+  };
+  int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+  if (sock == -1)
+    exit(1);
+  unsigned i;
+  for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++)
+    netlink_add_device(&nlmsg, sock, devtypes[i].type, devtypes[i].dev);
+  for (i = 0; i < sizeof(devmasters) / (sizeof(devmasters[0])); i++) {
+    char master[32], slave0[32], veth0[32], slave1[32], veth1[32];
+    sprintf(slave0, "%s_slave_0", devmasters[i]);
+    sprintf(veth0, "veth0_to_%s", devmasters[i]);
+    netlink_add_veth(&nlmsg, sock, slave0, veth0);
+    sprintf(slave1, "%s_slave_1", devmasters[i]);
+    sprintf(veth1, "veth1_to_%s", devmasters[i]);
+    netlink_add_veth(&nlmsg, sock, slave1, veth1);
+    sprintf(master, "%s0", devmasters[i]);
+    netlink_device_change(&nlmsg, sock, slave0, false, master, 0, 0, NULL);
+    netlink_device_change(&nlmsg, sock, slave1, false, master, 0, 0, NULL);
+  }
+  netlink_device_change(&nlmsg, sock, "bridge_slave_0", true, 0, 0, 0, NULL);
+  netlink_device_change(&nlmsg, sock, "bridge_slave_1", true, 0, 0, 0, NULL);
+  netlink_add_veth(&nlmsg, sock, "hsr_slave_0", "veth0_to_hsr");
+  netlink_add_veth(&nlmsg, sock, "hsr_slave_1", "veth1_to_hsr");
+  netlink_add_hsr(&nlmsg, sock, "hsr0", "hsr_slave_0", "hsr_slave_1");
+  netlink_device_change(&nlmsg, sock, "hsr_slave_0", true, 0, 0, 0, NULL);
+  netlink_device_change(&nlmsg, sock, "hsr_slave_1", true, 0, 0, 0, NULL);
+  netdevsim_add((int)procid, 4);
+  for (i = 0; i < sizeof(devices) / (sizeof(devices[0])); i++) {
+    char addr[32];
+    sprintf(addr, DEV_IPV4, i + 10);
+    netlink_add_addr4(&nlmsg, sock, devices[i].name, addr);
+    if (!devices[i].noipv6) {
+      sprintf(addr, DEV_IPV6, i + 10);
+      netlink_add_addr6(&nlmsg, sock, devices[i].name, addr);
+    }
+    uint64_t macaddr = DEV_MAC + ((i + 10ull) << 40);
+    netlink_device_change(&nlmsg, sock, devices[i].name, true, 0, &macaddr,
+                          devices[i].macsize, NULL);
+  }
+  close(sock);
+}
+static void initialize_netdevices_init(void)
+{
+  int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+  if (sock == -1)
+    exit(1);
+  struct {
+    const char* type;
+    int macsize;
+    bool noipv6;
+    bool noup;
+  } devtypes[] = {
+      {"nr", 7, true}, {"rose", 5, true, true},
+  };
+  unsigned i;
+  for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++) {
+    char dev[32], addr[32];
+    sprintf(dev, "%s%d", devtypes[i].type, (int)procid);
+    sprintf(addr, "172.30.%d.%d", i, (int)procid + 1);
+    netlink_add_addr4(&nlmsg, sock, dev, addr);
+    if (!devtypes[i].noipv6) {
+      sprintf(addr, "fe88::%02x:%02x", i, (int)procid + 1);
+      netlink_add_addr6(&nlmsg, sock, dev, addr);
+    }
+    int macsize = devtypes[i].macsize;
+    uint64_t macaddr = 0xbbbbbb +
+                       ((unsigned long long)i << (8 * (macsize - 2))) +
+                       (procid << (8 * (macsize - 1)));
+    netlink_device_change(&nlmsg, sock, dev, !devtypes[i].noup, 0, &macaddr,
+                          macsize, NULL);
+  }
+  close(sock);
+}
+
+#define MAX_FDS 30
+
+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_t)a1,
+            (uint8_t)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);
+  }
+}
+
+static void setup_common()
+{
+  if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+  }
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+  prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+  setpgrp();
+  setsid();
+  int netns = open("/proc/self/ns/net", O_RDONLY);
+  if (netns == -1)
+    exit(1);
+  if (dup2(netns, kInitNetNsFd) < 0)
+    exit(1);
+  close(netns);
+  struct rlimit rlim;
+  rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+  setrlimit(RLIMIT_AS, &rlim);
+  rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+  setrlimit(RLIMIT_MEMLOCK, &rlim);
+  rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+  setrlimit(RLIMIT_FSIZE, &rlim);
+  rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+  setrlimit(RLIMIT_STACK, &rlim);
+  rlim.rlim_cur = rlim.rlim_max = 0;
+  setrlimit(RLIMIT_CORE, &rlim);
+  rlim.rlim_cur = rlim.rlim_max = 256;
+  setrlimit(RLIMIT_NOFILE, &rlim);
+  if (unshare(CLONE_NEWNS)) {
+  }
+  if (unshare(CLONE_NEWIPC)) {
+  }
+  if (unshare(0x02000000)) {
+  }
+  if (unshare(CLONE_NEWUTS)) {
+  }
+  if (unshare(CLONE_SYSVSEM)) {
+  }
+  typedef struct {
+    const char* name;
+    const char* value;
+  } sysctl_t;
+  static const sysctl_t sysctls[] = {
+      {"/proc/sys/kernel/shmmax", "16777216"},
+      {"/proc/sys/kernel/shmall", "536870912"},
+      {"/proc/sys/kernel/shmmni", "1024"},
+      {"/proc/sys/kernel/msgmax", "8192"},
+      {"/proc/sys/kernel/msgmni", "1024"},
+      {"/proc/sys/kernel/msgmnb", "1024"},
+      {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+  };
+  unsigned i;
+  for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+    write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+  if (pid < 0)
+    exit(1);
+  int status = 0;
+  while (waitpid(-1, &status, __WALL) != pid) {
+  }
+  return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+  struct __user_cap_header_struct cap_hdr = {};
+  struct __user_cap_data_struct cap_data[2] = {};
+  cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+  cap_hdr.pid = getpid();
+  if (syscall(SYS_capget, &cap_hdr, &cap_data))
+    exit(1);
+  const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+  cap_data[0].effective &= ~drop;
+  cap_data[0].permitted &= ~drop;
+  cap_data[0].inheritable &= ~drop;
+  if (syscall(SYS_capset, &cap_hdr, &cap_data))
+    exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+  if (unshare(CLONE_NEWPID)) {
+  }
+  int pid = fork();
+  if (pid != 0)
+    return wait_for_loop(pid);
+  setup_common();
+  sandbox_common();
+  drop_caps();
+  initialize_netdevices_init();
+  if (unshare(CLONE_NEWNET)) {
+  }
+  initialize_devlink_pci();
+  initialize_netdevices();
+  loop();
+  exit(1);
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+  kill(-pid, SIGKILL);
+  kill(pid, SIGKILL);
+  int i;
+  for (i = 0; i < 100; i++) {
+    if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+      return;
+    usleep(1000);
+  }
+  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) {
+        continue;
+      }
+      if (write(fd, abort, 1) < 0) {
+      }
+      close(fd);
+    }
+    closedir(dir);
+  } else {
+  }
+  while (waitpid(-1, status, __WALL) != pid) {
+  }
+}
+
+static void setup_test()
+{
+  prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+  setpgrp();
+  write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void close_fds()
+{
+  int fd;
+  for (fd = 3; fd < MAX_FDS; fd++)
+    close(fd);
+}
+
+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;
+}
+
+static void execute_one(void)
+{
+  int i, call, thread;
+  for (call = 0; call < 6; 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);
+      event_timedwait(&th->done, 45);
+      break;
+    }
+  }
+  for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+    sleep_ms(1);
+  close_fds();
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+  int iter;
+  for (iter = 0;; iter++) {
+    int pid = fork();
+    if (pid < 0)
+      exit(1);
+    if (pid == 0) {
+      setup_test();
+      execute_one();
+      exit(0);
+    }
+    int status = 0;
+    uint64_t start = current_time_ms();
+    for (;;) {
+      if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+        break;
+      sleep_ms(1);
+      if (current_time_ms() - start < 5 * 1000)
+        continue;
+      kill_and_wait(pid, &status);
+      break;
+    }
+  }
+}
+
+uint64_t r[3] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_call(int call)
+{
+  intptr_t res;
+  switch (call) {
+  case 0:
+    res = syz_open_dev(0xc, 4, 0x14 + procid * 2);
+    if (res != -1)
+      r[0] = res;
+    break;
+  case 1:
+    *(uint16_t*)0x20000140 = 0;
+    *(uint16_t*)0x20000142 = 0x101;
+    *(uint16_t*)0x20000144 = 0;
+    *(uint16_t*)0x20000146 = 0;
+    *(uint16_t*)0x20000148 = 0;
+    *(uint16_t*)0x2000014a = 0;
+    syscall(__NR_ioctl, r[0], 0x4b60ul, 0x20000140ul);
+    break;
+  case 2:
+    res = syz_open_dev(0xc, 4, 0x14 + procid * 2);
+    if (res != -1)
+      r[1] = res;
+    break;
+  case 3:
+    *(uint16_t*)0x20000140 = 0;
+    *(uint16_t*)0x20000142 = 0x101;
+    *(uint16_t*)0x20000144 = 0;
+    *(uint16_t*)0x20000146 = 0;
+    *(uint16_t*)0x20000148 = 0;
+    *(uint16_t*)0x2000014a = 0;
+    syscall(__NR_ioctl, r[1], 0x4b61ul, 0x20000140ul);
+    break;
+  case 4:
+    res = syz_open_dev(0xc, 4, 0x14 + procid * 2);
+    if (res != -1)
+      r[2] = res;
+    break;
+  case 5:
+    *(uint16_t*)0x20000140 = 0;
+    *(uint16_t*)0x20000142 = 0x101;
+    *(uint16_t*)0x20000144 = 0;
+    *(uint16_t*)0x20000146 = 5;
+    *(uint16_t*)0x20000148 = 0;
+    *(uint16_t*)0x2000014a = 0;
+    syscall(__NR_ioctl, r[2], 0x560aul, 0x20000140ul);
+    break;
+  }
+}
+int main(void)
+{
+  syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+  for (procid = 0; procid < 6; procid++) {
+    if (fork() == 0) {
+      do_sandbox_none();
+    }
+  }
+  sleep(1000000);
+  return 0;
+}
diff --git a/syzkaller-repros/linux/07e29d3c770ff7ffcb442ed0e0dfdce6a694d443.c b/syzkaller-repros/linux/07e29d3c770ff7ffcb442ed0e0dfdce6a694d443.c
new file mode 100644
index 0000000..f7fd7cc
--- /dev/null
+++ b/syzkaller-repros/linux/07e29d3c770ff7ffcb442ed0e0dfdce6a694d443.c
@@ -0,0 +1,405 @@
+// KMSAN: kernel-usb-infoleak in pcan_usb_wait_rsp
+// https://syzkaller.appspot.com/bug?id=07e29d3c770ff7ffcb442ed0e0dfdce6a694d443
+// status:fixed
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <linux/usb/ch9.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+  usleep(ms * 1000);
+}
+
+#define USB_DEBUG 0
+
+#define USB_MAX_IFACE_NUM 4
+#define USB_MAX_EP_NUM 32
+
+struct usb_iface_index {
+  struct usb_interface_descriptor* iface;
+  struct usb_endpoint_descriptor* eps[USB_MAX_EP_NUM];
+  unsigned eps_num;
+};
+
+struct usb_device_index {
+  struct usb_device_descriptor* dev;
+  struct usb_config_descriptor* config;
+  unsigned config_length;
+  struct usb_iface_index ifaces[USB_MAX_IFACE_NUM];
+  unsigned ifaces_num;
+};
+
+static bool parse_usb_descriptor(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->config_length = length - sizeof(*index->dev);
+  size_t offset = 0;
+  while (true) {
+    if (offset + 1 >= length)
+      break;
+    uint8_t desc_length = buffer[offset];
+    uint8_t 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);
+      index->ifaces[index->ifaces_num++].iface = iface;
+    }
+    if (desc_type == USB_DT_ENDPOINT && index->ifaces_num > 0) {
+      struct usb_iface_index* iface = &index->ifaces[index->ifaces_num - 1];
+      if (iface->eps_num < USB_MAX_EP_NUM)
+        iface->eps[iface->eps_num++] =
+            (struct usb_endpoint_descriptor*)(buffer + offset);
+    }
+    offset += desc_length;
+  }
+  return true;
+}
+
+enum usb_fuzzer_event_type {
+  USB_FUZZER_EVENT_INVALID,
+  USB_FUZZER_EVENT_CONNECT,
+  USB_FUZZER_EVENT_DISCONNECT,
+  USB_FUZZER_EVENT_SUSPEND,
+  USB_FUZZER_EVENT_RESUME,
+  USB_FUZZER_EVENT_CONTROL,
+};
+
+struct usb_fuzzer_event {
+  uint32_t type;
+  uint32_t length;
+  char data[0];
+};
+
+struct usb_fuzzer_init {
+  uint64_t speed;
+  const char* driver_name;
+  const char* device_name;
+};
+
+struct usb_fuzzer_ep_io {
+  uint16_t ep;
+  uint16_t flags;
+  uint32_t length;
+  char data[0];
+};
+
+#define USB_FUZZER_IOCTL_INIT _IOW('U', 0, struct usb_fuzzer_init)
+#define USB_FUZZER_IOCTL_RUN _IO('U', 1)
+#define USB_FUZZER_IOCTL_EVENT_FETCH _IOR('U', 2, struct usb_fuzzer_event)
+#define USB_FUZZER_IOCTL_EP0_WRITE _IOW('U', 3, struct usb_fuzzer_ep_io)
+#define USB_FUZZER_IOCTL_EP0_READ _IOWR('U', 4, struct usb_fuzzer_ep_io)
+#define USB_FUZZER_IOCTL_EP_ENABLE _IOW('U', 5, struct usb_endpoint_descriptor)
+#define USB_FUZZER_IOCTL_EP_WRITE _IOW('U', 7, struct usb_fuzzer_ep_io)
+#define USB_FUZZER_IOCTL_EP_READ _IOWR('U', 8, struct usb_fuzzer_ep_io)
+#define USB_FUZZER_IOCTL_CONFIGURE _IO('U', 9)
+#define USB_FUZZER_IOCTL_VBUS_DRAW _IOW('U', 10, uint32_t)
+
+int usb_fuzzer_open()
+{
+  return open("/sys/kernel/debug/usb-fuzzer", O_RDWR);
+}
+
+int usb_fuzzer_init(int fd, uint32_t speed, const char* driver,
+                    const char* device)
+{
+  struct usb_fuzzer_init arg;
+  arg.speed = speed;
+  arg.driver_name = driver;
+  arg.device_name = device;
+  return ioctl(fd, USB_FUZZER_IOCTL_INIT, &arg);
+}
+
+int usb_fuzzer_run(int fd)
+{
+  return ioctl(fd, USB_FUZZER_IOCTL_RUN, 0);
+}
+
+int usb_fuzzer_event_fetch(int fd, struct usb_fuzzer_event* event)
+{
+  return ioctl(fd, USB_FUZZER_IOCTL_EVENT_FETCH, event);
+}
+
+int usb_fuzzer_ep0_write(int fd, struct usb_fuzzer_ep_io* io)
+{
+  return ioctl(fd, USB_FUZZER_IOCTL_EP0_WRITE, io);
+}
+
+int usb_fuzzer_ep0_read(int fd, struct usb_fuzzer_ep_io* io)
+{
+  return ioctl(fd, USB_FUZZER_IOCTL_EP0_READ, io);
+}
+
+int usb_fuzzer_ep_write(int fd, struct usb_fuzzer_ep_io* io)
+{
+  return ioctl(fd, USB_FUZZER_IOCTL_EP_WRITE, io);
+}
+
+int usb_fuzzer_ep_read(int fd, struct usb_fuzzer_ep_io* io)
+{
+  return ioctl(fd, USB_FUZZER_IOCTL_EP_READ, io);
+}
+
+int usb_fuzzer_ep_enable(int fd, struct usb_endpoint_descriptor* desc)
+{
+  return ioctl(fd, USB_FUZZER_IOCTL_EP_ENABLE, desc);
+}
+
+int usb_fuzzer_configure(int fd)
+{
+  return ioctl(fd, USB_FUZZER_IOCTL_CONFIGURE, 0);
+}
+
+int usb_fuzzer_vbus_draw(int fd, uint32_t power)
+{
+  return ioctl(fd, USB_FUZZER_IOCTL_VBUS_DRAW, power);
+}
+
+#define USB_MAX_PACKET_SIZE 1024
+
+struct usb_fuzzer_control_event {
+  struct usb_fuzzer_event inner;
+  struct usb_ctrlrequest ctrl;
+  char data[USB_MAX_PACKET_SIZE];
+};
+
+struct usb_fuzzer_ep_io_data {
+  struct usb_fuzzer_ep_io inner;
+  char data[USB_MAX_PACKET_SIZE];
+};
+
+struct vusb_connect_string_descriptor {
+  uint32_t len;
+  char* str;
+} __attribute__((packed));
+
+struct vusb_connect_descriptors {
+  uint32_t qual_len;
+  char* qual;
+  uint32_t bos_len;
+  char* bos;
+  uint32_t strs_len;
+  struct vusb_connect_string_descriptor strs[0];
+} __attribute__((packed));
+
+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(struct vusb_connect_descriptors* descs,
+                                    struct usb_device_index* index,
+                                    struct usb_ctrlrequest* ctrl,
+                                    char** response_data,
+                                    uint32_t* response_length)
+{
+  uint8_t str_idx;
+  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_t)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) {
+          struct usb_qualifier_descriptor* qual =
+              (struct usb_qualifier_descriptor*)response_data;
+          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_length = sizeof(*qual);
+          return true;
+        }
+        *response_data = descs->qual;
+        *response_length = descs->qual_len;
+        return true;
+      default:
+        exit(1);
+        return false;
+      }
+      break;
+    default:
+      exit(1);
+      return false;
+    }
+    break;
+  default:
+    exit(1);
+    return false;
+  }
+  return false;
+}
+
+static volatile long syz_usb_connect(volatile long a0, volatile long a1,
+                                     volatile long a2, volatile long a3)
+{
+  uint64_t speed = a0;
+  uint64_t dev_len = a1;
+  char* dev = (char*)a2;
+  struct vusb_connect_descriptors* descs = (struct vusb_connect_descriptors*)a3;
+  if (!dev) {
+    return -1;
+  }
+  struct usb_device_index index;
+  memset(&index, 0, sizeof(index));
+  int rv = 0;
+  rv = parse_usb_descriptor(dev, dev_len, &index);
+  if (!rv) {
+    return rv;
+  }
+  int fd = usb_fuzzer_open();
+  if (fd < 0) {
+    return fd;
+  }
+  char device[32];
+  sprintf(&device[0], "dummy_udc.%llu", procid);
+  rv = usb_fuzzer_init(fd, speed, "dummy_udc", &device[0]);
+  if (rv < 0) {
+    return rv;
+  }
+  rv = usb_fuzzer_run(fd);
+  if (rv < 0) {
+    return rv;
+  }
+  bool done = false;
+  while (!done) {
+    struct usb_fuzzer_control_event event;
+    event.inner.type = 0;
+    event.inner.length = sizeof(event.ctrl);
+    rv = usb_fuzzer_event_fetch(fd, (struct usb_fuzzer_event*)&event);
+    if (rv < 0) {
+      return rv;
+    }
+    if (event.inner.type != USB_FUZZER_EVENT_CONTROL)
+      continue;
+    bool response_found = false;
+    char* response_data = NULL;
+    uint32_t response_length = 0;
+    if (event.ctrl.bRequestType & USB_DIR_IN) {
+      response_found = lookup_connect_response(
+          descs, &index, &event.ctrl, &response_data, &response_length);
+      if (!response_found) {
+        return -1;
+      }
+    } else {
+      if ((event.ctrl.bRequestType & USB_TYPE_MASK) != USB_TYPE_STANDARD ||
+          event.ctrl.bRequest != USB_REQ_SET_CONFIGURATION) {
+        exit(1);
+        return -1;
+      }
+      done = true;
+    }
+    if (done) {
+      rv = usb_fuzzer_vbus_draw(fd, index.config->bMaxPower);
+      if (rv < 0) {
+        return rv;
+      }
+      rv = usb_fuzzer_configure(fd);
+      if (rv < 0) {
+        return rv;
+      }
+      unsigned ep;
+      for (ep = 0; ep < index.ifaces[0].eps_num; ep++) {
+        rv = usb_fuzzer_ep_enable(fd, index.ifaces[0].eps[ep]);
+        if (rv < 0) {
+        } else {
+        }
+      }
+    }
+    struct usb_fuzzer_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) {
+      rv = usb_fuzzer_ep0_write(fd, (struct usb_fuzzer_ep_io*)&response);
+    } else {
+      rv = usb_fuzzer_ep0_read(fd, (struct usb_fuzzer_ep_io*)&response);
+    }
+    if (rv < 0) {
+      return rv;
+    }
+  }
+  sleep_ms(200);
+  return fd;
+}
+
+int main(void)
+{
+  syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+
+  memcpy((void*)0x20000000, "\x12\x01\x00\x00\x83\x1d\xda\x08\x72\x0c\x0c\x00"
+                            "\xaa\x7c\x00\x00\x00\x01\x09\x02\x1b\x00\x01\x00"
+                            "\x00\x00\x00\x09\x04\xd2\x00\x01\x09\x50\x29\x00"
+                            "\x09\x05\x01\x01\x00\x00\x00\x00\x00",
+         45);
+  syz_usb_connect(0, 0x2d, 0x20000000, 0);
+  return 0;
+}
diff --git a/syzkaller-repros/linux/08b8be45afea11888776f897895aef9ad1c3ecfd.c b/syzkaller-repros/linux/08b8be45afea11888776f897895aef9ad1c3ecfd.c
new file mode 100644
index 0000000..f329b74
--- /dev/null
+++ b/syzkaller-repros/linux/08b8be45afea11888776f897895aef9ad1c3ecfd.c
@@ -0,0 +1,586 @@
+// KASAN: global-out-of-bounds Read in fbcon_get_font
+// https://syzkaller.appspot.com/bug?id=08b8be45afea11888776f897895aef9ad1c3ecfd
+// status:open
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/futex.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>
+
+static void sleep_ms(uint64_t ms)
+{
+  usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+  struct timespec ts;
+  if (clock_gettime(CLOCK_MONOTONIC, &ts))
+    exit(1);
+  return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+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;
+  for (i = 0; i < 100; i++) {
+    if (pthread_create(&th, &attr, fn, arg) == 0) {
+      pthread_attr_destroy(&attr);
+      return;
+    }
+    if (errno == EAGAIN) {
+      usleep(50);
+      continue;
+    }
+    break;
+  }
+  exit(1);
+}
+
+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)
+    exit(1);
+  __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_t timeout)
+{
+  uint64_t start = current_time_ms();
+  uint64_t now = start;
+  for (;;) {
+    uint64_t 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_RELAXED))
+      return 1;
+    now = current_time_ms();
+    if (now - start > timeout)
+      return 0;
+  }
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+  char buf[1024];
+  va_list args;
+  va_start(args, what);
+  vsnprintf(buf, sizeof(buf), what, args);
+  va_end(args);
+  buf[sizeof(buf) - 1] = 0;
+  int len = strlen(buf);
+  int fd = open(file, O_WRONLY | O_CLOEXEC);
+  if (fd == -1)
+    return false;
+  if (write(fd, buf, len) != len) {
+    int err = errno;
+    close(fd);
+    errno = err;
+    return false;
+  }
+  close(fd);
+  return true;
+}
+
+struct nlmsg {
+  char* pos;
+  int nesting;
+  struct nlattr* nested[8];
+  char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+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;
+  memcpy(attr + 1, data, size);
+  nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+                            int* reply_len)
+{
+  if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+    exit(1);
+  struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+  hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+  struct sockaddr_nl addr;
+  memset(&addr, 0, sizeof(addr));
+  addr.nl_family = AF_NETLINK;
+  unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+                      (struct sockaddr*)&addr, sizeof(addr));
+  if (n != hdr->nlmsg_len)
+    exit(1);
+  n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+  if (hdr->nlmsg_type == NLMSG_DONE) {
+    *reply_len = 0;
+    return 0;
+  }
+  if (n < sizeof(struct nlmsghdr))
+    exit(1);
+  if (reply_len && hdr->nlmsg_type == reply_type) {
+    *reply_len = n;
+    return 0;
+  }
+  if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+    exit(1);
+  if (hdr->nlmsg_type != NLMSG_ERROR)
+    exit(1);
+  return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+  return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+                            unsigned int total_len)
+{
+  struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+  if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+    return -1;
+  return hdr->nlmsg_len;
+}
+
+static void netlink_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);
+  (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+  struct genlmsghdr genlhdr;
+  struct nlattr* attr;
+  int err, n;
+  uint16_t id = 0;
+  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, DEVLINK_FAMILY_NAME,
+               strlen(DEVLINK_FAMILY_NAME) + 1);
+  err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+  if (err) {
+    return -1;
+  }
+  attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+                          NLMSG_ALIGN(sizeof(genlhdr)));
+  for (; (char*)attr < nlmsg->buf + n;
+       attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+    if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+      id = *(uint16_t*)(attr + 1);
+      break;
+    }
+  }
+  if (!id) {
+    return -1;
+  }
+  recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+  return id;
+}
+
+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)
+    exit(1);
+  id = netlink_devlink_id_get(&nlmsg, sock);
+  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) {
+  }
+error:
+  close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+                                     const char* netdev_prefix)
+{
+  struct genlmsghdr genlhdr;
+  int len, total_len, id, err, offset;
+  uint16_t netdev_index;
+  int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+  if (sock == -1)
+    exit(1);
+  int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+  if (rtsock == -1)
+    exit(1);
+  id = netlink_devlink_id_get(&nlmsg, sock);
+  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);
+  if (err) {
+    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);
+}
+
+static void initialize_devlink_pci(void)
+{
+  int netns = open("/proc/self/ns/net", O_RDONLY);
+  if (netns == -1)
+    exit(1);
+  int ret = setns(kInitNetNsFd, 0);
+  if (ret == -1)
+    exit(1);
+  netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+  ret = setns(netns, 0);
+  if (ret == -1)
+    exit(1);
+  close(netns);
+  initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+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_t)a1,
+            (uint8_t)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);
+  }
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+  kill(-pid, SIGKILL);
+  kill(pid, SIGKILL);
+  int i;
+  for (i = 0; i < 100; i++) {
+    if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+      return;
+    usleep(1000);
+  }
+  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) {
+        continue;
+      }
+      if (write(fd, abort, 1) < 0) {
+      }
+      close(fd);
+    }
+    closedir(dir);
+  } else {
+  }
+  while (waitpid(-1, status, __WALL) != pid) {
+  }
+}
+
+static void setup_test()
+{
+  prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+  setpgrp();
+  write_file("/proc/self/oom_score_adj", "1000");
+}
+
+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;
+}
+
+static void execute_one(void)
+{
+  int i, call, thread;
+  for (call = 0; call < 6; 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);
+      event_timedwait(&th->done, 45);
+      break;
+    }
+  }
+  for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+    sleep_ms(1);
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+  int iter;
+  for (iter = 0;; iter++) {
+    int pid = fork();
+    if (pid < 0)
+      exit(1);
+    if (pid == 0) {
+      setup_test();
+      execute_one();
+      exit(0);
+    }
+    int status = 0;
+    uint64_t start = current_time_ms();
+    for (;;) {
+      if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+        break;
+      sleep_ms(1);
+      if (current_time_ms() - start < 5 * 1000)
+        continue;
+      kill_and_wait(pid, &status);
+      break;
+    }
+  }
+}
+
+uint64_t r[3] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_call(int call)
+{
+  intptr_t res;
+  switch (call) {
+  case 0:
+    res = syz_open_dev(0xc, 4, 1);
+    if (res != -1)
+      r[0] = res;
+    break;
+  case 1:
+    *(uint32_t*)0x200000c0 = 3;
+    *(uint32_t*)0x200000c4 = 0;
+    *(uint32_t*)0x200000c8 = 0;
+    *(uint32_t*)0x200000cc = 5;
+    *(uint32_t*)0x200000d0 = 0;
+    *(uint64_t*)0x200000d8 = 0;
+    syscall(__NR_ioctl, r[0], 0x4b72ul, 0x200000c0ul);
+    break;
+  case 2:
+    res = syz_open_dev(0xc, 4, 1);
+    if (res != -1)
+      r[1] = res;
+    break;
+  case 3:
+    *(uint32_t*)0x20000200 = 0x81;
+    *(uint32_t*)0x20000204 = 0;
+    *(uint32_t*)0x20000208 = 0;
+    *(uint32_t*)0x2000020c = 0;
+    *(uint8_t*)0x20000210 = 0;
+    memcpy((void*)0x20000211, "\x49\xd9\xfe\x4d\xa0\x87\xf5\xd6\xf1\x0f\x99\x76"
+                              "\x12\x7b\xcf\x86\xfe\x01\xfe",
+           19);
+    syscall(__NR_ioctl, r[1], 0x4b60ul, 0x20000200ul);
+    break;
+  case 4:
+    res = syz_open_dev(0xc, 4, 1);
+    if (res != -1)
+      r[2] = res;
+    break;
+  case 5:
+    *(uint32_t*)0x20000200 = 0x81;
+    *(uint32_t*)0x20000204 = 0;
+    *(uint32_t*)0x20000208 = 0;
+    *(uint32_t*)0x2000020c = 0;
+    *(uint8_t*)0x20000210 = 0;
+    memcpy((void*)0x20000211, "\x49\xd9\xfe\x4d\xa0\x87\xf5\xd6\xf1\x0f\x99\x76"
+                              "\x12\x7b\xcf\x86\xfe\x01\xfe",
+           19);
+    syscall(__NR_ioctl, r[2], 0x4b61ul, 0x20000200ul);
+    break;
+  }
+}
+int main(void)
+{
+  syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+  loop();
+  return 0;
+}
diff --git a/syzkaller-repros/linux/08e230febc579298f5be8f1081d98f006d2b8f4b.c b/syzkaller-repros/linux/08e230febc579298f5be8f1081d98f006d2b8f4b.c
new file mode 100644
index 0000000..f021fcd
--- /dev/null
+++ b/syzkaller-repros/linux/08e230febc579298f5be8f1081d98f006d2b8f4b.c
@@ -0,0 +1,585 @@
+// WARNING: refcount bug in smc_release (2)
+// https://syzkaller.appspot.com/bug?id=08e230febc579298f5be8f1081d98f006d2b8f4b
+// status:open
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/futex.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>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+  usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+  struct timespec ts;
+  if (clock_gettime(CLOCK_MONOTONIC, &ts))
+    exit(1);
+  return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+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;
+  for (i = 0; i < 100; i++) {
+    if (pthread_create(&th, &attr, fn, arg) == 0) {
+      pthread_attr_destroy(&attr);
+      return;
+    }
+    if (errno == EAGAIN) {
+      usleep(50);
+      continue;
+    }
+    break;
+  }
+  exit(1);
+}
+
+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)
+    exit(1);
+  __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+  syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG);
+}
+
+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_t timeout)
+{
+  uint64_t start = current_time_ms();
+  uint64_t now = start;
+  for (;;) {
+    uint64_t 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_RELAXED))
+      return 1;
+    now = current_time_ms();
+    if (now - start > timeout)
+      return 0;
+  }
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+  char buf[1024];
+  va_list args;
+  va_start(args, what);
+  vsnprintf(buf, sizeof(buf), what, args);
+  va_end(args);
+  buf[sizeof(buf) - 1] = 0;
+  int len = strlen(buf);
+  int fd = open(file, O_WRONLY | O_CLOEXEC);
+  if (fd == -1)
+    return false;
+  if (write(fd, buf, len) != len) {
+    int err = errno;
+    close(fd);
+    errno = err;
+    return false;
+  }
+  close(fd);
+  return true;
+}
+
+struct nlmsg {
+  char* pos;
+  int nesting;
+  struct nlattr* nested[8];
+  char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+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;
+  memcpy(attr + 1, data, size);
+  nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+                            int* reply_len)
+{
+  if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+    exit(1);
+  struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+  hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+  struct sockaddr_nl addr;
+  memset(&addr, 0, sizeof(addr));
+  addr.nl_family = AF_NETLINK;
+  unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+                      (struct sockaddr*)&addr, sizeof(addr));
+  if (n != hdr->nlmsg_len)
+    exit(1);
+  n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+  if (hdr->nlmsg_type == NLMSG_DONE) {
+    *reply_len = 0;
+    return 0;
+  }
+  if (n < sizeof(struct nlmsghdr))
+    exit(1);
+  if (reply_len && hdr->nlmsg_type == reply_type) {
+    *reply_len = n;
+    return 0;
+  }
+  if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+    exit(1);
+  if (hdr->nlmsg_type != NLMSG_ERROR)
+    exit(1);
+  return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+  return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+                            unsigned int total_len)
+{
+  struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+  if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+    return -1;
+  return hdr->nlmsg_len;
+}
+
+static void netlink_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);
+  (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+  struct genlmsghdr genlhdr;
+  struct nlattr* attr;
+  int err, n;
+  uint16_t id = 0;
+  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, DEVLINK_FAMILY_NAME,
+               strlen(DEVLINK_FAMILY_NAME) + 1);
+  err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+  if (err) {
+    return -1;
+  }
+  attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+                          NLMSG_ALIGN(sizeof(genlhdr)));
+  for (; (char*)attr < nlmsg->buf + n;
+       attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+    if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+      id = *(uint16_t*)(attr + 1);
+      break;
+    }
+  }
+  if (!id) {
+    return -1;
+  }
+  recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+  return id;
+}
+
+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)
+    exit(1);
+  id = netlink_devlink_id_get(&nlmsg, sock);
+  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) {
+  }
+error:
+  close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+                                     const char* netdev_prefix)
+{
+  struct genlmsghdr genlhdr;
+  int len, total_len, id, err, offset;
+  uint16_t netdev_index;
+  int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+  if (sock == -1)
+    exit(1);
+  int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+  if (rtsock == -1)
+    exit(1);
+  id = netlink_devlink_id_get(&nlmsg, sock);
+  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);
+  if (err) {
+    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);
+}
+
+static void initialize_devlink_pci(void)
+{
+  int netns = open("/proc/self/ns/net", O_RDONLY);
+  if (netns == -1)
+    exit(1);
+  int ret = setns(kInitNetNsFd, 0);
+  if (ret == -1)
+    exit(1);
+  netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+  ret = setns(netns, 0);
+  if (ret == -1)
+    exit(1);
+  close(netns);
+  initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+  kill(-pid, SIGKILL);
+  kill(pid, SIGKILL);
+  int i;
+  for (i = 0; i < 100; i++) {
+    if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+      return;
+    usleep(1000);
+  }
+  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) {
+        continue;
+      }
+      if (write(fd, abort, 1) < 0) {
+      }
+      close(fd);
+    }
+    closedir(dir);
+  } else {
+  }
+  while (waitpid(-1, status, __WALL) != pid) {
+  }
+}
+
+static void setup_test()
+{
+  prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+  setpgrp();
+  write_file("/proc/self/oom_score_adj", "1000");
+}
+
+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;
+}
+
+static void execute_one(void)
+{
+  int i, call, thread;
+  int collide = 0;
+again:
+  for (call = 0; call < 6; 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 (collide && (call % 2) == 0)
+        break;
+      event_timedwait(&th->done, 45);
+      break;
+    }
+  }
+  for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+    sleep_ms(1);
+  if (!collide) {
+    collide = 1;
+    goto again;
+  }
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+  int iter;
+  for (iter = 0;; iter++) {
+    int pid = fork();
+    if (pid < 0)
+      exit(1);
+    if (pid == 0) {
+      setup_test();
+      execute_one();
+      exit(0);
+    }
+    int status = 0;
+    uint64_t start = current_time_ms();
+    for (;;) {
+      if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+        break;
+      sleep_ms(1);
+      if (current_time_ms() - start < 5 * 1000)
+        continue;
+      kill_and_wait(pid, &status);
+      break;
+    }
+  }
+}
+
+#ifndef __NR_connect
+#define __NR_connect 362
+#endif
+#ifndef __NR_ioctl
+#define __NR_ioctl 54
+#endif
+#ifndef __NR_mmap
+#define __NR_mmap 192
+#endif
+#ifndef __NR_setsockopt
+#define __NR_setsockopt 366
+#endif
+#ifndef __NR_socket
+#define __NR_socket 359
+#endif
+#ifndef __NR_write
+#define __NR_write 4
+#endif
+#undef __NR_mmap
+#define __NR_mmap __NR_mmap2
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_call(int call)
+{
+  intptr_t res;
+  switch (call) {
+  case 0:
+    syscall(__NR_socket, 0xa, 2, 0);
+    break;
+  case 1:
+    syscall(__NR_write, 0xffffff9c, 0, 0);
+    break;
+  case 2:
+    syscall(__NR_ioctl, -1, 0x5452, 0);
+    break;
+  case 3:
+    res = syscall(__NR_socket, 0x2b, 0x801, 0);
+    if (res != -1)
+      r[0] = res;
+    break;
+  case 4:
+    *(uint16_t*)0x20000040 = 2;
+    *(uint16_t*)0x20000042 = htobe16(0);
+    *(uint8_t*)0x20000044 = 0xac;
+    *(uint8_t*)0x20000045 = 0x14;
+    *(uint8_t*)0x20000046 = 0x14;
+    *(uint8_t*)0x20000047 = 0xbb;
+    syscall(__NR_connect, (intptr_t)r[0], 0x20000040, 0x10);
+    break;
+  case 5:
+    memcpy((void*)0x20000000,
+           "\xec\x12\xda\x60\x30\x17\x21\x95\x0a\x73\xae\xf8\x8f\xc1\x52\x6c",
+           16);
+    syscall(__NR_setsockopt, (intptr_t)r[0], 6, 0x21, 0x20000000, 0x10);
+    break;
+  }
+}
+int main(void)
+{
+  syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+  for (procid = 0; procid < 6; procid++) {
+    if (fork() == 0) {
+      loop();
+    }
+  }
+  sleep(1000000);
+  return 0;
+}
diff --git a/syzkaller-repros/linux/0963dbc0fc0631658942daa90c170c70302dd20c.c b/syzkaller-repros/linux/0963dbc0fc0631658942daa90c170c70302dd20c.c
new file mode 100644
index 0000000..997440c
--- /dev/null
+++ b/syzkaller-repros/linux/0963dbc0fc0631658942daa90c170c70302dd20c.c
@@ -0,0 +1,612 @@
+// WARNING in cbq_destroy_class
+// https://syzkaller.appspot.com/bug?id=0963dbc0fc0631658942daa90c170c70302dd20c
+// status:open
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/futex.h>
+
+static void sleep_ms(uint64_t ms)
+{
+  usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+  struct timespec ts;
+  if (clock_gettime(CLOCK_MONOTONIC, &ts))
+    exit(1);
+  return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+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;
+  for (i = 0; i < 100; i++) {
+    if (pthread_create(&th, &attr, fn, arg) == 0) {
+      pthread_attr_destroy(&attr);
+      return;
+    }
+    if (errno == EAGAIN) {
+      usleep(50);
+      continue;
+    }
+    break;
+  }
+  exit(1);
+}
+
+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)
+    exit(1);
+  __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_t timeout)
+{
+  uint64_t start = current_time_ms();
+  uint64_t now = start;
+  for (;;) {
+    uint64_t 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_RELAXED))
+      return 1;
+    now = current_time_ms();
+    if (now - start > timeout)
+      return 0;
+  }
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+  char buf[1024];
+  va_list args;
+  va_start(args, what);
+  vsnprintf(buf, sizeof(buf), what, args);
+  va_end(args);
+  buf[sizeof(buf) - 1] = 0;
+  int len = strlen(buf);
+  int fd = open(file, O_WRONLY | O_CLOEXEC);
+  if (fd == -1)
+    return false;
+  if (write(fd, buf, len) != len) {
+    int err = errno;
+    close(fd);
+    errno = err;
+    return false;
+  }
+  close(fd);
+  return true;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+  kill(-pid, SIGKILL);
+  kill(pid, SIGKILL);
+  int i;
+  for (i = 0; i < 100; i++) {
+    if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+      return;
+    usleep(1000);
+  }
+  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) {
+        continue;
+      }
+      if (write(fd, abort, 1) < 0) {
+      }
+      close(fd);
+    }
+    closedir(dir);
+  } else {
+  }
+  while (waitpid(-1, status, __WALL) != pid) {
+  }
+}
+
+static void setup_test()
+{
+  prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+  setpgrp();
+  write_file("/proc/self/oom_score_adj", "1000");
+}
+
+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;
+}
+
+static void execute_one(void)
+{
+  int i, call, thread;
+  for (call = 0; call < 21; 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);
+      event_timedwait(&th->done, 45);
+      break;
+    }
+  }
+  for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+    sleep_ms(1);
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+  int iter;
+  for (iter = 0;; iter++) {
+    int pid = fork();
+    if (pid < 0)
+      exit(1);
+    if (pid == 0) {
+      setup_test();
+      execute_one();
+      exit(0);
+    }
+    int status = 0;
+    uint64_t start = current_time_ms();
+    for (;;) {
+      if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+        break;
+      sleep_ms(1);
+      if (current_time_ms() - start < 5 * 1000)
+        continue;
+      kill_and_wait(pid, &status);
+      break;
+    }
+  }
+}
+
+uint64_t r[11] = {0xffffffffffffffff, 0xffffffffffffffff, 0x0,
+                  0xffffffffffffffff, 0xffffffffffffffff, 0x0,
+                  0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff,
+                  0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_call(int call)
+{
+  intptr_t res;
+  switch (call) {
+  case 0:
+    res = syscall(__NR_socket, 0x10ul, 3ul, 0ul);
+    if (res != -1)
+      r[0] = res;
+    break;
+  case 1:
+    res = syscall(__NR_socket, 0x11ul, 0x800000003ul, 0);
+    if (res != -1)
+      r[1] = res;
+    break;
+  case 2:
+    *(uint16_t*)0x20000080 = 0x11;
+    memcpy((void*)0x20000082,
+           "\x00\x00\x01\x00\x00\x00\x00\x00\x08\x00\x44\x94\x4e\xeb\xa7\x1a"
+           "\x49\x76\xe2\x52\x92\x2c\xb1\x8f\x6e\x2e\x2a\xba\x00\x00\x00\x01"
+           "\x2e\x0b\x38\x36\x00\x54\x04\xb0\xe0\x30\x1a\x4c\xe8\x75\xf2\xe3"
+           "\xff\x5f\x16\x3e\xe3\x40\xb7\x67\x95\x00\x80\x00\x00\x00\x00\x00"
+           "\x00\x01\x01\x01\x3c\x58\x11\x03\x9e\x15\x77\x50\x27\xec\xce\x66"
+           "\xfd\x79\x2b\xbf\x0e\x5b\xf5\xff\x1b\x08\x16\xf3\xf6\xdb\x1c\x00"
+           "\x01\x00\x00\x00\x00\x00\x00\x00\x49\x74\x00\x00\x00\x00\x00\x00"
+           "\x00\x06\xad\x8e\x5e\xcc\x32\x6d\x3a\x09\xff\xc2\xc6\x54",
+           126);
+    syscall(__NR_bind, r[1], 0x20000080ul, 0x80ul);
+    break;
+  case 3:
+    *(uint32_t*)0x20000140 = 0x14;
+    res = syscall(__NR_getsockname, r[1], 0x20000040ul, 0x20000140ul);
+    if (res != -1)
+      r[2] = *(uint32_t*)0x20000044;
+    break;
+  case 4:
+    *(uint64_t*)0x200001c0 = 0;
+    *(uint32_t*)0x200001c8 = 0;
+    *(uint64_t*)0x200001d0 = 0x20000180;
+    *(uint64_t*)0x20000180 = 0x20000200;
+    *(uint32_t*)0x20000200 = 0x3c;
+    *(uint16_t*)0x20000204 = 0x2c;
+    *(uint16_t*)0x20000206 = 0xd27;
+    *(uint32_t*)0x20000208 = 0;
+    *(uint32_t*)0x2000020c = 0;
+    *(uint8_t*)0x20000210 = 0;
+    *(uint8_t*)0x20000211 = 0;
+    *(uint16_t*)0x20000212 = 0;
+    *(uint32_t*)0x20000214 = r[2];
+    *(uint16_t*)0x20000218 = 0;
+    *(uint16_t*)0x2000021a = 0;
+    *(uint16_t*)0x2000021c = 0;
+    *(uint16_t*)0x2000021e = -1;
+    *(uint16_t*)0x20000220 = 2;
+    *(uint16_t*)0x20000222 = 0;
+    *(uint16_t*)0x20000224 = 0xa;
+    *(uint16_t*)0x20000226 = 1;
+    memcpy((void*)0x20000228, "basic\000", 6);
+    *(uint16_t*)0x20000230 = 0xc;
+    *(uint16_t*)0x20000232 = 2;
+    *(uint16_t*)0x20000234 = 8;
+    *(uint16_t*)0x20000236 = 1;
+    *(uint16_t*)0x20000238 = 0;
+    *(uint16_t*)0x2000023a = -1;
+    *(uint64_t*)0x20000188 = 0x3c;
+    *(uint64_t*)0x200001d8 = 1;
+    *(uint64_t*)0x200001e0 = 0;
+    *(uint64_t*)0x200001e8 = 0;
+    *(uint32_t*)0x200001f0 = 0;
+    syscall(__NR_sendmsg, r[0], 0x200001c0ul, 0ul);
+    break;
+  case 5:
+    res = syscall(__NR_socket, 0x10ul, 3ul, 0ul);
+    if (res != -1)
+      r[3] = res;
+    break;
+  case 6:
+    res = syscall(__NR_socket, 0x11ul, 0x800000003ul, 0);
+    if (res != -1)
+      r[4] = res;
+    break;
+  case 7:
+    *(uint16_t*)0x20000180 = 0x11;
+    memcpy((void*)0x20000182,
+           "\x00\x00\x01\x00\x00\x00\x00\x00\x08\x00\x44\x94\x4e\xeb\xa7\x2e"
+           "\x2a\xba\x00\x00\x00\x01\x2e\x0b\x38\x36\x00\x54\x04\xb0\xe0\x30"
+           "\x1a\x08\x00\x00\x00\xe3\xff\x5f\x16\x3e\xe3\x40\xb7\x67\x95\x00"
+           "\x80\x00\x00\x00\x00\x00\x00\x01\x01\x01\x3c\x58\x11\x03\x9e\x15"
+           "\x77\x50\x27\xec\xce\x66\xfd\x79\x2b\xbf\x0e\x5b\xf5\xff\x1b\x08"
+           "\x16\xf3\xf6\xdb\x1c\x00\x01\x00\x00\x00\x00\x00\x00\x00\x49\x74"
+           "\x00\x00\x00\x00\x00\x00\x00\x06\x5e\xcc\x32\x6d\x3a\x09\xff\xc2"
+           "\xc6\x54\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+           126);
+    syscall(__NR_bind, r[4], 0x20000180ul, 0x80ul);
+    break;
+  case 8:
+    *(uint32_t*)0x20000140 = 0x14;
+    res = syscall(__NR_getsockname, r[4], 0x20000000ul, 0x20000140ul);
+    if (res != -1)
+      r[5] = *(uint32_t*)0x20000004;
+    break;
+  case 9:
+    *(uint64_t*)0x20000200 = 0;
+    *(uint32_t*)0x20000208 = 0;
+    *(uint64_t*)0x20000210 = 0x20000080;
+    *(uint64_t*)0x20000080 = 0x20000040;
+    *(uint32_t*)0x20000040 = 0x24;
+    *(uint16_t*)0x20000044 = 0x29;
+    *(uint16_t*)0x20000046 = 1;
+    *(uint32_t*)0x20000048 = 0;
+    *(uint32_t*)0x2000004c = 0;
+    *(uint8_t*)0x20000050 = 0;
+    *(uint8_t*)0x20000051 = 0;
+    *(uint16_t*)0x20000052 = 0;
+    *(uint32_t*)0x20000054 = r[5];
+    *(uint16_t*)0x20000058 = 0;
+    *(uint16_t*)0x2000005a = -1;
+    *(uint16_t*)0x2000005c = 0;
+    *(uint16_t*)0x2000005e = -1;
+    *(uint16_t*)0x20000060 = 0;
+    *(uint16_t*)0x20000062 = 0;
+    *(uint64_t*)0x20000088 = 0x24;
+    *(uint64_t*)0x20000218 = 1;
+    *(uint64_t*)0x20000220 = 0;
+    *(uint64_t*)0x20000228 = 0;
+    *(uint32_t*)0x20000230 = 0;
+    syscall(__NR_sendmsg, r[3], 0x20000200ul, 0ul);
+    break;
+  case 10:
+    res = syscall(__NR_pipe, 0x20000200ul);
+    if (res != -1) {
+      r[6] = *(uint32_t*)0x20000200;
+      r[7] = *(uint32_t*)0x20000204;
+    }
+    break;
+  case 11:
+    res = syscall(__NR_socket, 2ul, 2ul, 0ul);
+    if (res != -1)
+      r[8] = res;
+    break;
+  case 12:
+    *(uint8_t*)0x20000000 = -1;
+    *(uint8_t*)0x20000001 = 2;
+    *(uint8_t*)0x20000002 = 0;
+    *(uint8_t*)0x20000003 = 0;
+    *(uint8_t*)0x20000004 = 0;
+    *(uint8_t*)0x20000005 = 0;
+    *(uint8_t*)0x20000006 = 0;
+    *(uint8_t*)0x20000007 = 0;
+    *(uint8_t*)0x20000008 = 0;
+    *(uint8_t*)0x20000009 = 0;
+    *(uint8_t*)0x2000000a = 0;
+    *(uint8_t*)0x2000000b = 0;
+    *(uint8_t*)0x2000000c = 0;
+    *(uint8_t*)0x2000000d = 0;
+    *(uint8_t*)0x2000000e = 0;
+    *(uint8_t*)0x2000000f = 1;
+    *(uint32_t*)0x20000010 = 0;
+    syscall(__NR_setsockopt, -1, 0x29ul, 0ul, 0x20000000ul, 0x14ul);
+    break;
+  case 13:
+    syscall(__NR_close, r[8]);
+    break;
+  case 14:
+    syscall(__NR_socket, 0x10ul, 2ul, 0);
+    break;
+  case 15:
+    res = syscall(__NR_socket, 0x11ul, 0x800000003ul, 0);
+    if (res != -1)
+      r[9] = res;
+    break;
+  case 16:
+    *(uint16_t*)0x20000080 = 0x11;
+    memcpy((void*)0x20000082,
+           "\x00\x00\x01\x00\x00\x00\x00\x00\x08\x00\x25\x94\x4e\xeb\xa7\x1a"
+           "\x49\x76\xe2\x52\x92\x2c\x00\x00\x00\x00\x2a\xba\x00\x00\x00\x01"
+           "\x2e\x0b\x38\x36\x00\x54\x04\xb0\xe0\x30\x1a\x4c\xe8\x75\xf2\xe0"
+           "\xff\x5f\x16\x3e\xe3\x40\xb7\x67\x95\x00\x80\x00\x00\x00\x00\x00"
+           "\x00\x01\x01\x01\x3c\x58\x91\x03\x9e\x15\x77\x50\x27\xec\xce\x66"
+           "\xfd\x79\x2b\xbf\x0e\x5b\xf5\xff\x1b\x08\x16\xf3\xf6\xdb\x1c\x00"
+           "\x01\x00\x00\x00\x00\x00\x00\x00\x49\x74\x00\x00\x00\x00\x00\x00"
+           "\x00\x06\xad\x8e\x5e\xcc\x32\x6d\x3a\x09\xff\xc2\xc6\x54",
+           126);
+    syscall(__NR_bind, r[9], 0x20000080ul, 0x80ul);
+    break;
+  case 17:
+    *(uint32_t*)0x20000140 = 0x14;
+    res = syscall(__NR_getsockname, r[9], 0x20000100ul, 0x20000140ul);
+    if (res != -1)
+      r[10] = *(uint32_t*)0x20000104;
+    break;
+  case 18:
+    *(uint64_t*)0x20000280 = 0;
+    *(uint32_t*)0x20000288 = 0;
+    *(uint64_t*)0x20000290 = 0x200002c0;
+    *(uint64_t*)0x200002c0 = 0x20000300;
+    memcpy((void*)0x20000300, "\xd0\x08\x00\x00\x24\x00\xff\xff\xff\x7f\x00\x00"
+                              "\x00\x00\xff\xff\xa6\xff\xff\xf7",
+           20);
+    *(uint32_t*)0x20000314 = r[10];
+    memcpy(
+        (void*)0x20000318,
+        "\x00\x00\x00\x0b\xf1\xff\xff\xff\x00\x00\x00\x00\x08\x00\x01\x00\x63"
+        "\x62\x71\x00\xa4\x08\x02\x00\x04\x04\x06\x00\x03\x00\x00\x00\x05\x00"
+        "\x00\x00\x00\x70\x03\x00\xfd\xff\xff\xff\xff\xff\x00\x00\x1f\x00\x00"
+        "\x00\x05\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x10\x00\x83\x00\x00"
+        "\x00\xfd\xff\xff\xff\x07\x00\x00\x00\x08\x49\x00\x00\x01\x00\x00\x00"
+        "\x02\x00\x00\x00\xcf\x00\x00\x00\xfe\xff\xff\xff\x08\x00\x00\x33\x26"
+        "\xf6\x00\x01\x80\x00\x00\x03\x00\x00\x00\x09\x00\x00\x00\x02\x00\x00"
+        "\x00\x00\x27\x4a\x49\xef\x69\x49\xa7\xbb\x00\x00\x00\x05\x00\x00\x00"
+        "\x01\x00\x00\x00\x04\x00\x00\x00\xff\x7f\x00\x00\x00\x00\x00\x00\x00"
+        "\x04\x00\x00\x00\x02\x00\x00\x04\x00\x00\x00\xff\x0f\x00\x00\xf4\x4f"
+        "\x35\x00\x01\x00\x00\x00\x01\x04\x00\x00\x5e\xb7\x68\x35\x01\x00\x00"
+        "\x00\x08\x00\x00\x00\xff\xff\xff\xff\xc3\x8d\x00\x00\x1f\x00\x00\x00"
+        "\x04\x00\x08\x83\x06\x00\x00\x00\x00\x00\x01\x00\xf7\xff\xff\xff\x03"
+        "\x00\x00\x00\x00\x80\xff\xff\x05\x00\x00\x00\x06\x00\x00\x00\x06\x00"
+        "\x00\x00\xa9\x00\x00\x00\x00\x00\x00\x00\xc0\x00\x00\x00\xc0\xff\xff"
+        "\xff\x08\x00\x00\x00\x01\x80\x00\x00\x01\x01\x00\x00\x06\x00\x00\x00"
+        "\xb3\x00\x00\x00\x00\x00\x00\x20\x05\x00\x00\x00\x01\x04\x00\x00\x04"
+        "\x00\x00\x00\x07\x00\x00\x00\x08\x00\x00\x00\x01\x01\x00\x00\xc2\x2e"
+        "\x00\x00\xc0\xff\xff\xff\x05\x00\x00\x00\x04\x00\x00\x00\x06\x00\x00"
+        "\x00\x09\x00\x00\x00\x08\x00\x00\x00\xf7\xff\xff\xff\x08\x00\x00\x00"
+        "\x03\x00\x00\x00\x08\x00\x00\x00\x04\x00\x00\x00\x01\x03\x00\x80\x04"
+        "\x00\x00\x00\x04\x00\x00\x00\x00\x10\x00\x00\x04\x00\x00\x00\x07\x00"
+        "\x00\x00\x09\x00\x00\x00\xfc\xff\xff\xff\x01\x00\x00\x00\x01\x00\x00"
+        "\x00\x09\x00\x00\x00\x00\x02\x00\x00\x06\x0e\x00\x00\x08\x00\x00\x00"
+        "\x02\x00\x00\x00\x02\x00\x00\x00\x09\x00\x00\x00\x08\x00\x00\x00\x07"
+        "\x00\x00\x00\xab\x00\x00\x00\xfb\x00\x00\x00\x07\x00\x00\x00\xff\x01"
+        "\x00\x00\x08\x00\x00\x00\x01\x04\x00\x00\x07\x00\x00\x00\x03\x00\x00"
+        "\x00\x09\x00\x00\x00\xff\x07\x00\x00\x08\x00\x00\x00\xff\xff\x00\x00"
+        "\xa9\x01\x00\x00\x09\x00\x00\x00\x05\x00\x00\x00\x20\x00\x00\x00\x05"
+        "\x00\x00\x00\x01\x00\x00\x00\x07\x00\x00\x00\x8e\xb7\x00\x00\x00\x00"
+        "\x00\x80\x01\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\xff\xff\xff"
+        "\xff\xfc\xff\xff\xff\x01\xf0\xff\xff\x00\x00\x00\x00\x3f\x00\x00\x00"
+        "\x03\x00\x00\x00\x00\x01\x00\x00\x00\x80\x00\x00\x00\x80\x00\x00\x03"
+        "\x00\x00\x00\x05\x00\x00\x00\x05\x00\x00\x00\xff\xff\xff\xff\x07\x00"
+        "\x00\x00\x15\xba\x00\x00\x04\x00\x00\x00\x07\x00\x00\x00\x03\x00\x00"
+        "\x00\x03\x00\x00\x00\xff\xff\xff\xff\x04\x00\x00\x00\x55\x4f\x00\x00"
+        "\x6f\xf8\x00\x00\x07\x00\x00\x00\x03\x00\x00\x00\x00\x02\x00\x00\x06"
+        "\x00\x00\x00\x08\x00\x00\x00\xb3\x00\x00\x00\x06\x00\x00\x00\x00\x00"
+        "\x00\x00\x00\x07\x00\x00\x01\x01\x00\x00\x03\x00\x00\x00\x00\x80\x00"
+        "\x00\x00\x04\x00\x00\x73\x0a\x00\x00\x01\x00\x00\x80\x01\x00\x00\x00"
+        "\x9e\x0c\x00\x00\x00\x08\x00\x00\x01\x00\x00\x80\x00\x00\x00\x00\x00"
+        "\x00\x00\x00\x40\x00\x00\x00\x00\xfe\xff\xff\xf6\x7d\x00\x00\x06\x00"
+        "\x00\x00\xff\x01\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x40\x00\x00"
+        "\x00\x40\x00\x00\x00\xed\x00\x00\x00\x01\x00\x01\x00\x0e\x0a\x05\x00"
+        "\x00\x00\x00\x00\x00\x02\x00\x00\x04\x00\x00\x00\x06\x00\x00\x00\x02"
+        "\x00\x00\x00\xff\x7f\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x06\x00"
+        "\x00\x00\x7f\x00\x00\x00\x02\x00\x00\x00\x00\x04\x00\x00\x04\x00\x00"
+        "\x00\x09\x00\x00\x00\x90\x00\x00\x00\x08\x00\x00\x00\xb6\x7c\x00\x00"
+        "\x04\x00\x00\x00\x04\x00\x00\x00\x05\x00\x00\x00\xf5\x0a\x00\x00\xff"
+        "\xff\x00\x00\x06\x00\x00\x00\x8f\xf9\xff\xff\x07\x00\x00\x00\x1e\xaa"
+        "\xff\xff\x3f\x00\x00\x00\x80\x00\x00\x00\x00\x00\x00\x00\xff\x0c\x00"
+        "\x00\xff\x7f\x00\x00\x03\x00\x00\x00\x7f\x00\x00\x00\x2d\x00\x00\x00"
+        "\x08\x00\x00\x00\x00\x01\x00\x00\xff\x07\x00\x00\xff\xff\xff\xff\x2b"
+        "\xab\x00\x00\x02\x00\x00\x00\xac\xe8\x00\x00\x05\x00\x00\x00\x00\x00"
+        "\x00\x00\xe1\xbf\x93\x4d\x07\x00\x00\x00\x1f\x00\x0d\x00\x03\x00\x00"
+        "\x00\x04\x00\x00\x00\x07\x00\x00\x00\x09\x00\x00\x00\x05\x00\x00\x00"
+        "\x03\x00\x00\x00\x02\x00\x00\x00\x87\xd4\x00\x00\x02\x00\x00\x00\x08"
+        "\x00\x00\x00\x00\x01\x00\x00\x7f\x00\x00\x00\x0e\x00\x00\x00\x08\x00"
+        "\x00\x00\x02\x00\x00\x00\x07\x00\x00\x00\xff\xff\xff\x7f\x06\x00\x00"
+        "\x00\x00\x00\x00\x00\x05\x00\x00\x00\x01\x00\x00\x00\x82\x00\x00\x00"
+        "\x1f\x00\x00\x00\x00\x04\x00\x00\x01\x00\x00\x00\xfa\xff\xff\xff\x05"
+        "\x00\x00\x00\x06\x00\x00\x00\x07\x00\x00\x00\x03\x00\x00\x00\x10\x00"
+        "\x05\x00\x81\x03\x06\x00\x9f\xff\x04\x00\x08\x00\x00\x00\x04\x04\x06"
+        "\x00\xd9\x0b\x00\x00\xff\x00\x00\x00\x05\x00\x00\x00\x04\x00\x00\x00"
+        "\x1b\xa2\xcc\x3b\x00\x00\x00\x80\x01\x00\x00\x00\x3f\x00\x00\x00\xff"
+        "\x0f\x00\x20\x11\x52\x49\x73\x03\x00\x80\x00\xbe\x06\x00\x00\xff\xff"
+        "\xff\xff\xff\xfe\xff\xff\x7f\x00\x00\x00\xff\x00\x00\x00\x81\x00\x00"
+        "\x00\x00\xdb\x04\x00\x09\x00\x00\x00\x07\x00\x00\x00\x03\x00\x00\x00"
+        "\x00\x00\x00\x00\x06\x00\x00\x00\x8f\x5e\x00\x00\x01\x00\x00\x00\x00"
+        "\x02\x00\x00\x06\x00\x00\x00\x01\x01\x00\x00\x02\x00\x00\x00\x07\x00"
+        "\x00\x00\x00\x00\x00\xe0\x31\x89\x00\x00\x01\x04\x00\x00\x00\x08\x00"
+        "\x00\x06\x00\x00\x00\x04\x00\x00\x00\x08\x00\x00\x00\x04\x00\x00\x00"
+        "\x02\x00\x00\x00\xc0\x00\x00\x00\x08\x00\x00\x00\x08\x00\x00\x00\xf7"
+        "\xff\xff\xff\x05\x00\x00\x00\x81\x00\x00\x00\x4d\x00\x00\x00\x01\x00"
+        "\x00\x80\xeb\x07\x00\x00\x1f\x00\x00\x00\x09\x00\x00\x00\x05\x97\x00"
+        "\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00"
+        "\xff\xff\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\xe0\xa0"
+        "\x00\x00\x00\x40\x00\x00\x00\xff\x00\x00\x00\xf7\xff\xff\xff\x05\x00"
+        "\x00\x00\x09\x00\x00\x00\x07\x00\x00\x00\x06\x00\x00\x00\x28\x08\x00"
+        "\x00\x03\x00\x00\x00\x06\x00\x00\x00\x04\x00\x00\x00\xbe\x00\x00\x00"
+        "\x03\x00\x00\x00\x07\x00\x00\x00\x05\x00\x00\x00\x38\x08\x00\x00\xfa"
+        "\xff\xff\xff\xff\xff\xff\xff\x47\xb5\x55\x4d\x00\x10\x00\x00\x81\x00"
+        "\x00\x00\x07\x00\x00\x00\xff\xff\xff\xff\x04\x00\x00\x00\x01\x00\x00"
+        "\x00\x02\x00\x00\x00\x56\x6b\x00\x00\x20\x00\x00\x00\x04\x00\x00\x00"
+        "\x02\x00\x00\x00\x8b\x01\x00\x00\x01\x00\x00\x00\xff\xff\x00\x00\x04"
+        "\x00\x00\x00\xff\x0f\x00\x00\x05\x00\x00\x00\x20\x00\x00\x00\x03\x00"
+        "\x00\x00\xe4\x0d\x00\x00\x07\x00\x00\x00\xf8\xff\xff\xff\x20\x00\x00"
+        "\x00\x3f\x00\x00\x00\x38\x7f\x00\x00\x07\x00\x00\x00\x07\x00\x00\x00"
+        "\xc1\x0a\x00\x00\x09\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x00"
+        "\x00\x00\x00\x00\x80\x00\x00\x01\x00\x00\x80\x09\x00\x00\x00\x37\x0b"
+        "\x00\x00\x00\x00\x00\x80\xff\x07\x00\x00\x06\x00\x00\x00\xbb\x79\x00"
+        "\x00\x04\x00\x00\x00\x02\x00\x00\x00\xff\xff\xff\x7f\x03\x00\x00\x00"
+        "\x00\x00\x00\x00\x09\x00\x00\x00\x07\x00\x00\x00\x05\x00\x00\x00\x00"
+        "\x00\x00\x80\x7f\x00\x00\x00\x09\x00\x00\x00\x08\x00\x00\x00\xfa\xd4"
+        "\xff\xff\xff\x01\x00\x00\x01\x01\x00\x00\x01\x00\x00\x00\x3f\x00\x00"
+        "\x00\x04\x00\x00\x00\x20\xf2\xff\xff\x01\x00\x01\x00\xff\xff\x00\x00"
+        "\x01\x00\x00\x00\x02\x00\x00\x00\x08\x00\x00\x00\xfb\xff\xff\xff\xf9"
+        "\xff\xff\xff\x04\x00\x00\x00\x4d\x00\x00\x00\x06\x00\x00\x00\x02\x00"
+        "\x00\x00\x02\x00\x00\x00\x07\x00\x00\x00\x4e\x0d\x00\x00\x00\x02\x00"
+        "\x00\x08\x00\x00\x00\x35\x00\x00\x00\x30\x0e\x00\x00\x07\x00\x00\x00"
+        "\x00\x04\x00\x00\x02\x00\x00\x00\x01\x80\x00\x00\x20\x00\x00\x00\xf2"
+        "\xff\xff\xff\x07\x00\x00\x00\x05\x00\x00\x00\x00\x01\x00\x00\xff\xff"
+        "\xfe\xff\x09\x00\x00\x00\x00\x08\x00\x00\x07\x00\x00\x00\x08\x00\x00"
+        "\x00\x09\x00\x00\x00\xff\x7f\x00\x00\x09\x00\x00\x00\x04\x00\x00\x00"
+        "\x04\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x05\x00\x00\x00\x01"
+        "\x00\x00\x00\x09\x00\x00\x00\x08\x00\x00\x00\x7e\x07\x00\x00\x03\x00"
+        "\x00\x00\x00\x80\x00\x00\xbf\x16\x00\x00\x02\x00\x00\x06\x00\x00\x00"
+        "\xff\xee\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00"
+        "\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x7f\x00\x00\x00\x10"
+        "\x08\x00\x00\x00\x00\x00\x00\x01\x00\x00\x80\x02\x00\x00\x00\x08\x00"
+        "\x00\x00\x01\x01\x00\x00\x03\x00\x00\x00\xff\xff\xff\x7f\xff\xff\xff"
+        "\xff\xf7\xff\xff\xff\x06\x00\x00\x00\x03\x00\x00\x00\xa6\x06\x00\x00"
+        "\xff\x03\x00\x00\x07\x00\x00\x00\x01\x80\x00\x00\x09\x00\x00\x00\x02"
+        "\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x80\xff\xff\x00\x02"
+        "\x00\x00\x07\x00\x00\x00\x05\x00\x00\x00\x01\x00\x01\x00\x00\x00\x00"
+        "\x80\x00\x00\xaf\x06\x06\x00\x00\x00\x2b\x0a\x00\x00\x05\x00\x00\x00"
+        "\x01\x00\x00\x00\x05\x00\x00\x00\x09\x00\x00\x00\x04\x00\x00\x00\x05"
+        "\x00\x00\x00\x02\x00\x00\x00\xff\xff\xff\x7f\xf3\x00\x00\x00\x08\x00"
+        "\x00\x00\x02\x00\x00\x00\xff\xff\x00\x00\xff\x07\x00\x00\x81\x00\x00"
+        "\x00\x40\x00\x00\x00\x75\xfc\x00\x00\x09\x00\x00\x00\xfb\xff\xff\xff"
+        "\x05\x00\x00\x00\x00\x00\x00\x00\x81\x00\x00\x00\x01\x00\x00\x00\x80"
+        "\x00\x00\x00\xd0\x5e\x00\x00\x02\x00\x00\x00\x1f\x00\x00\x00\x00\x00"
+        "\x00\x00\xff\x01\x00\x00\x45\x1e\x00\x00\x2d\x00\x00\x00\x00\x00\x00"
+        "\x00\xff\x00\x00\x00\x10\x00\x03\x00\x08\x00\x10\x00\xff\x07\x00\x00"
+        "\x01\x00\x00\x00\x18\x00\x01\x00\x39",
+        2117);
+    *(uint64_t*)0x200002c8 = 3;
+    *(uint64_t*)0x20000298 = 1;
+    *(uint64_t*)0x200002a0 = 0;
+    *(uint64_t*)0x200002a8 = 0;
+    *(uint32_t*)0x200002b0 = 0;
+    syscall(__NR_sendmsg, -1, 0x20000280ul, 0ul);
+    break;
+  case 19:
+    syscall(__NR_write, r[7], 0x20000000ul, 0xfffffeccul);
+    break;
+  case 20:
+    syscall(__NR_splice, r[6], 0ul, r[8], 0ul, 0x4ffe0ul, 0ul);
+    break;
+  }
+}
+int main(void)
+{
+  syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+  loop();
+  return 0;
+}
diff --git a/syzkaller-repros/linux/09c941f946e4a934981811f9f53a015356d4d281.c b/syzkaller-repros/linux/09c941f946e4a934981811f9f53a015356d4d281.c
new file mode 100644
index 0000000..4ed45c9
--- /dev/null
+++ b/syzkaller-repros/linux/09c941f946e4a934981811f9f53a015356d4d281.c
@@ -0,0 +1,33 @@
+// WARNING: refcount bug in put_watch
+// https://syzkaller.appspot.com/bug?id=09c941f946e4a934981811f9f53a015356d4d281
+// status:open
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <endian.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#ifndef __NR_watch_devices
+#define __NR_watch_devices 436
+#endif
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+int main(void)
+{
+  syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+  intptr_t res = 0;
+  memcpy((void*)0x20000000, "/dev/watch_queue\000", 17);
+  res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x20000000ul, 0ul, 0ul);
+  if (res != -1)
+    r[0] = res;
+  syscall(__NR_watch_devices, r[0], 0x42ul, 0ul);
+  return 0;
+}
diff --git a/syzkaller-repros/linux/0af1e3d419e09dd056bd4bba017631d5584b1dc8.c b/syzkaller-repros/linux/0af1e3d419e09dd056bd4bba017631d5584b1dc8.c
new file mode 100644
index 0000000..d82af43
--- /dev/null
+++ b/syzkaller-repros/linux/0af1e3d419e09dd056bd4bba017631d5584b1dc8.c
@@ -0,0 +1,1569 @@
+// DATA RACE in kernel.(*Kernel).EmitUnimplementedEvent
+// https://syzkaller.appspot.com/bug?id=0af1e3d419e09dd056bd4bba017631d5584b1dc8
+// status:fixed
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <sched.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+#include <linux/futex.h>
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static __thread int skip_segv;
+static __thread jmp_buf segv_env;
+
+static void segv_handler(int sig, siginfo_t* info, void* ctx)
+{
+  uintptr_t addr = (uintptr_t)info->si_addr;
+  const uintptr_t prog_start = 1 << 20;
+  const uintptr_t prog_end = 100 << 20;
+  if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED) &&
+      (addr < prog_start || addr > prog_end)) {
+    _longjmp(segv_env, 1);
+  }
+  exit(sig);
+}
+
+static void install_segv_handler(void)
+{
+  struct sigaction sa;
+  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);
+  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(...)                                                        \
+  {                                                                            \
+    __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST);                       \
+    if (_setjmp(segv_env) == 0) {                                              \
+      __VA_ARGS__;                                                             \
+    }                                                                          \
+    __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST);                       \
+  }
+
+static void sleep_ms(uint64_t ms)
+{
+  usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+  struct timespec ts;
+  if (clock_gettime(CLOCK_MONOTONIC, &ts))
+    exit(1);
+  return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void use_temporary_dir(void)
+{
+  char tmpdir_template[] = "./syzkaller.XXXXXX";
+  char* tmpdir = mkdtemp(tmpdir_template);
+  if (!tmpdir)
+    exit(1);
+  if (chmod(tmpdir, 0777))
+    exit(1);
+  if (chdir(tmpdir))
+    exit(1);
+}
+
+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;
+  for (i = 0; i < 100; i++) {
+    if (pthread_create(&th, &attr, fn, arg) == 0) {
+      pthread_attr_destroy(&attr);
+      return;
+    }
+    if (errno == EAGAIN) {
+      usleep(50);
+      continue;
+    }
+    break;
+  }
+  exit(1);
+}
+
+#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))))
+
+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)
+    exit(1);
+  __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
+  syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG);
+}
+
+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_t timeout)
+{
+  uint64_t start = current_time_ms();
+  uint64_t now = start;
+  for (;;) {
+    uint64_t 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_RELAXED))
+      return 1;
+    now = current_time_ms();
+    if (now - start > timeout)
+      return 0;
+  }
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+  char buf[1024];
+  va_list args;
+  va_start(args, what);
+  vsnprintf(buf, sizeof(buf), what, args);
+  va_end(args);
+  buf[sizeof(buf) - 1] = 0;
+  int len = strlen(buf);
+  int fd = open(file, O_WRONLY | O_CLOEXEC);
+  if (fd == -1)
+    return false;
+  if (write(fd, buf, len) != len) {
+    int err = errno;
+    close(fd);
+    errno = err;
+    return false;
+  }
+  close(fd);
+  return true;
+}
+
+static struct {
+  char* pos;
+  int nesting;
+  struct nlattr* nested[8];
+  char buf[1024];
+} nlmsg;
+
+static void netlink_init(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(int typ, const void* data, int size)
+{
+  struct nlattr* attr = (struct nlattr*)nlmsg.pos;
+  attr->nla_len = sizeof(*attr) + size;
+  attr->nla_type = typ;
+  memcpy(attr + 1, data, size);
+  nlmsg.pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static void netlink_nest(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(void)
+{
+  struct nlattr* attr = nlmsg.nested[--nlmsg.nesting];
+  attr->nla_len = nlmsg.pos - (char*)attr;
+}
+
+static int netlink_send(int sock)
+{
+  if (nlmsg.pos > nlmsg.buf + sizeof(nlmsg.buf) || nlmsg.nesting)
+    exit(1);
+  struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg.buf;
+  hdr->nlmsg_len = nlmsg.pos - nlmsg.buf;
+  struct sockaddr_nl addr;
+  memset(&addr, 0, sizeof(addr));
+  addr.nl_family = AF_NETLINK;
+  unsigned n = sendto(sock, nlmsg.buf, hdr->nlmsg_len, 0,
+                      (struct sockaddr*)&addr, sizeof(addr));
+  if (n != hdr->nlmsg_len)
+    exit(1);
+  n = recv(sock, nlmsg.buf, sizeof(nlmsg.buf), 0);
+  if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+    exit(1);
+  if (hdr->nlmsg_type != NLMSG_ERROR)
+    exit(1);
+  return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static void netlink_add_device_impl(const char* type, const char* name)
+{
+  struct ifinfomsg hdr;
+  memset(&hdr, 0, sizeof(hdr));
+  netlink_init(RTM_NEWLINK, NLM_F_EXCL | NLM_F_CREATE, &hdr, sizeof(hdr));
+  if (name)
+    netlink_attr(IFLA_IFNAME, name, strlen(name));
+  netlink_nest(IFLA_LINKINFO);
+  netlink_attr(IFLA_INFO_KIND, type, strlen(type));
+}
+
+static void netlink_add_device(int sock, const char* type, const char* name)
+{
+  netlink_add_device_impl(type, name);
+  netlink_done();
+  int err = netlink_send(sock);
+  (void)err;
+}
+
+static void netlink_add_veth(int sock, const char* name, const char* peer)
+{
+  netlink_add_device_impl("veth", name);
+  netlink_nest(IFLA_INFO_DATA);
+  netlink_nest(VETH_INFO_PEER);
+  nlmsg.pos += sizeof(struct ifinfomsg);
+  netlink_attr(IFLA_IFNAME, peer, strlen(peer));
+  netlink_done();
+  netlink_done();
+  netlink_done();
+  int err = netlink_send(sock);
+  (void)err;
+}
+
+static void netlink_add_hsr(int sock, const char* name, const char* slave1,
+                            const char* slave2)
+{
+  netlink_add_device_impl("hsr", name);
+  netlink_nest(IFLA_INFO_DATA);
+  int ifindex1 = if_nametoindex(slave1);
+  netlink_attr(IFLA_HSR_SLAVE1, &ifindex1, sizeof(ifindex1));
+  int ifindex2 = if_nametoindex(slave2);
+  netlink_attr(IFLA_HSR_SLAVE2, &ifindex2, sizeof(ifindex2));
+  netlink_done();
+  netlink_done();
+  int err = netlink_send(sock);
+  (void)err;
+}
+
+static void netlink_device_change(int sock, const char* name, bool up,
+                                  const char* master, const void* mac,
+                                  int macsize)
+{
+  struct ifinfomsg hdr;
+  memset(&hdr, 0, sizeof(hdr));
+  if (up)
+    hdr.ifi_flags = hdr.ifi_change = IFF_UP;
+  netlink_init(RTM_NEWLINK, 0, &hdr, sizeof(hdr));
+  netlink_attr(IFLA_IFNAME, name, strlen(name));
+  if (master) {
+    int ifindex = if_nametoindex(master);
+    netlink_attr(IFLA_MASTER, &ifindex, sizeof(ifindex));
+  }
+  if (macsize)
+    netlink_attr(IFLA_ADDRESS, mac, macsize);
+  int err = netlink_send(sock);
+  (void)err;
+}
+
+static int netlink_add_addr(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(RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr, sizeof(hdr));
+  netlink_attr(IFA_LOCAL, addr, addrsize);
+  netlink_attr(IFA_ADDRESS, addr, addrsize);
+  return netlink_send(sock);
+}
+
+static void netlink_add_addr4(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(sock, dev, &in_addr, sizeof(in_addr));
+  (void)err;
+}
+
+static void netlink_add_addr6(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(sock, dev, &in6_addr, sizeof(in6_addr));
+  (void)err;
+}
+
+static void netlink_add_neigh(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(RTM_NEWNEIGH, NLM_F_EXCL | NLM_F_CREATE, &hdr, sizeof(hdr));
+  netlink_attr(NDA_DST, addr, addrsize);
+  netlink_attr(NDA_LLADDR, mac, macsize);
+  int err = netlink_send(sock);
+  (void)err;
+}
+
+static int tunfd = -1;
+static int tun_frags_enabled;
+#define SYZ_TUN_MAX_PACKET_SIZE 1000
+
+#define TUN_IFACE "syz_tun"
+
+#define LOCAL_MAC 0xaaaaaaaaaaaa
+#define REMOTE_MAC 0xaaaaaaaaaabb
+
+#define LOCAL_IPV4 "172.20.20.170"
+#define REMOTE_IPV4 "172.20.20.187"
+
+#define LOCAL_IPV6 "fe80::aa"
+#define REMOTE_IPV6 "fe80::bb"
+
+#define IFF_NAPI 0x0010
+#define IFF_NAPI_FRAGS 0x0020
+
+static void initialize_tun(void)
+{
+  tunfd = open("/dev/net/tun", O_RDWR | O_NONBLOCK);
+  if (tunfd == -1) {
+    printf("tun: can't open /dev/net/tun: please enable CONFIG_TUN=y\n");
+    printf("otherwise fuzzing or reproducing might not work as intended\n");
+    return;
+  }
+  const int kTunFd = 240;
+  if (dup2(tunfd, kTunFd) < 0)
+    exit(1);
+  close(tunfd);
+  tunfd = kTunFd;
+  struct ifreq ifr;
+  memset(&ifr, 0, sizeof(ifr));
+  strncpy(ifr.ifr_name, TUN_IFACE, IFNAMSIZ);
+  ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_NAPI | IFF_NAPI_FRAGS;
+  if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0) {
+    ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+    if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0)
+      exit(1);
+  }
+  if (ioctl(tunfd, TUNGETIFF, (void*)&ifr) < 0)
+    exit(1);
+  tun_frags_enabled = (ifr.ifr_flags & IFF_NAPI_FRAGS) != 0;
+  char sysctl[64];
+  sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/accept_dad", TUN_IFACE);
+  write_file(sysctl, "0");
+  sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/router_solicitations", TUN_IFACE);
+  write_file(sysctl, "0");
+  int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+  if (sock == -1)
+    exit(1);
+  netlink_add_addr4(sock, TUN_IFACE, LOCAL_IPV4);
+  netlink_add_addr6(sock, TUN_IFACE, LOCAL_IPV6);
+  uint64_t macaddr = REMOTE_MAC;
+  struct in_addr in_addr;
+  inet_pton(AF_INET, REMOTE_IPV4, &in_addr);
+  netlink_add_neigh(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(sock, TUN_IFACE, &in6_addr, sizeof(in6_addr), &macaddr,
+                    ETH_ALEN);
+  macaddr = LOCAL_MAC;
+  netlink_device_change(sock, TUN_IFACE, true, 0, &macaddr, ETH_ALEN);
+  close(sock);
+}
+
+#define DEV_IPV4 "172.20.20.%d"
+#define DEV_IPV6 "fe80::%02x"
+#define DEV_MAC 0x00aaaaaaaaaa
+static void initialize_netdevices(void)
+{
+  char netdevsim[16];
+  sprintf(netdevsim, "netdevsim%d", (int)procid);
+  struct {
+    const char* type;
+    const char* dev;
+  } devtypes[] = {
+      {"ip6gretap", "ip6gretap0"}, {"bridge", "bridge0"},
+      {"vcan", "vcan0"},           {"bond", "bond0"},
+      {"team", "team0"},           {"dummy", "dummy0"},
+      {"nlmon", "nlmon0"},         {"caif", "caif0"},
+      {"batadv", "batadv0"},       {"vxcan", "vxcan1"},
+      {"netdevsim", netdevsim},    {"veth", 0},
+  };
+  const char* devmasters[] = {"bridge", "bond", "team"};
+  struct {
+    const char* name;
+    int macsize;
+    bool noipv6;
+  } devices[] = {
+      {"lo", ETH_ALEN},
+      {"sit0", 0},
+      {"bridge0", ETH_ALEN},
+      {"vcan0", 0, true},
+      {"tunl0", 0},
+      {"gre0", 0},
+      {"gretap0", ETH_ALEN},
+      {"ip_vti0", 0},
+      {"ip6_vti0", 0},
+      {"ip6tnl0", 0},
+      {"ip6gre0", 0},
+      {"ip6gretap0", ETH_ALEN},
+      {"erspan0", ETH_ALEN},
+      {"bond0", ETH_ALEN},
+      {"veth0", ETH_ALEN},
+      {"veth1", ETH_ALEN},
+      {"team0", ETH_ALEN},
+      {"veth0_to_bridge", ETH_ALEN},
+      {"veth1_to_bridge", ETH_ALEN},
+      {"veth0_to_bond", ETH_ALEN},
+      {"veth1_to_bond", ETH_ALEN},
+      {"veth0_to_team", ETH_ALEN},
+      {"veth1_to_team", ETH_ALEN},
+      {"veth0_to_hsr", ETH_ALEN},
+      {"veth1_to_hsr", ETH_ALEN},
+      {"hsr0", 0},
+      {"dummy0", ETH_ALEN},
+      {"nlmon0", 0},
+      {"vxcan1", 0, true},
+      {"caif0", ETH_ALEN},
+      {"batadv0", ETH_ALEN},
+      {netdevsim, ETH_ALEN},
+  };
+  int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+  if (sock == -1)
+    exit(1);
+  unsigned i;
+  for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++)
+    netlink_add_device(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(sock, slave0, veth0);
+    sprintf(slave1, "%s_slave_1", devmasters[i]);
+    sprintf(veth1, "veth1_to_%s", devmasters[i]);
+    netlink_add_veth(sock, slave1, veth1);
+    sprintf(master, "%s0", devmasters[i]);
+    netlink_device_change(sock, slave0, false, master, 0, 0);
+    netlink_device_change(sock, slave1, false, master, 0, 0);
+  }
+  netlink_device_change(sock, "bridge_slave_0", true, 0, 0, 0);
+  netlink_device_change(sock, "bridge_slave_1", true, 0, 0, 0);
+  netlink_add_veth(sock, "hsr_slave_0", "veth0_to_hsr");
+  netlink_add_veth(sock, "hsr_slave_1", "veth1_to_hsr");
+  netlink_add_hsr(sock, "hsr0", "hsr_slave_0", "hsr_slave_1");
+  netlink_device_change(sock, "hsr_slave_0", true, 0, 0, 0);
+  netlink_device_change(sock, "hsr_slave_1", true, 0, 0, 0);
+  for (i = 0; i < sizeof(devices) / (sizeof(devices[0])); i++) {
+    char addr[32];
+    sprintf(addr, DEV_IPV4, i + 10);
+    netlink_add_addr4(sock, devices[i].name, addr);
+    if (!devices[i].noipv6) {
+      sprintf(addr, DEV_IPV6, i + 10);
+      netlink_add_addr6(sock, devices[i].name, addr);
+    }
+    uint64_t macaddr = DEV_MAC + ((i + 10ull) << 40);
+    netlink_device_change(sock, devices[i].name, true, 0, &macaddr,
+                          devices[i].macsize);
+  }
+  close(sock);
+}
+static void initialize_netdevices_init(void)
+{
+  int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+  if (sock == -1)
+    exit(1);
+  struct {
+    const char* type;
+    int macsize;
+    bool noipv6;
+    bool noup;
+  } devtypes[] = {
+      {"nr", 7, true},
+      {"rose", 5, true, true},
+  };
+  unsigned i;
+  for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++) {
+    char dev[32], addr[32];
+    sprintf(dev, "%s%d", devtypes[i].type, (int)procid);
+    sprintf(addr, "172.30.%d.%d", i, (int)procid + 1);
+    netlink_add_addr4(sock, dev, addr);
+    if (!devtypes[i].noipv6) {
+      sprintf(addr, "fe88::%02x:%02x", i, (int)procid + 1);
+      netlink_add_addr6(sock, dev, addr);
+    }
+    int macsize = devtypes[i].macsize;
+    uint64_t macaddr = 0xbbbbbb +
+                       ((unsigned long long)i << (8 * (macsize - 2))) +
+                       (procid << (8 * (macsize - 1)));
+    netlink_device_change(sock, dev, !devtypes[i].noup, 0, &macaddr, macsize);
+  }
+  close(sock);
+}
+
+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;
+    if (errno == EBADFD)
+      return -1;
+    exit(1);
+  }
+  return rv;
+}
+
+static void flush_tun()
+{
+  char data[SYZ_TUN_MAX_PACKET_SIZE];
+  while (read_tun(&data[0], sizeof(data)) != -1) {
+  }
+}
+
+#define XT_TABLE_SIZE 1536
+#define XT_MAX_ENTRIES 10
+
+struct xt_counters {
+  uint64_t 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;
+  void* entrytable[XT_TABLE_SIZE / sizeof(void*)];
+};
+
+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;
+  char entrytable[XT_TABLE_SIZE];
+};
+
+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;
+  void* entrytable[XT_TABLE_SIZE / sizeof(void*)];
+};
+
+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;
+  char entrytable[XT_TABLE_SIZE];
+};
+
+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)
+{
+  struct ipt_get_entries entries;
+  socklen_t optlen;
+  int fd, i;
+  fd = socket(family, SOCK_STREAM, IPPROTO_TCP);
+  if (fd == -1) {
+    switch (errno) {
+    case EAFNOSUPPORT:
+    case ENOPROTOOPT:
+      return;
+    }
+    exit(1);
+  }
+  for (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);
+    optlen = sizeof(table->info);
+    if (getsockopt(fd, level, IPT_SO_GET_INFO, &table->info, &optlen)) {
+      switch (errno) {
+      case EPERM:
+      case ENOENT:
+      case ENOPROTOOPT:
+        continue;
+      }
+      exit(1);
+    }
+    if (table->info.size > sizeof(table->replace.entrytable))
+      exit(1);
+    if (table->info.num_entries > XT_MAX_ENTRIES)
+      exit(1);
+    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))
+      exit(1);
+    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)
+{
+  struct xt_counters counters[XT_MAX_ENTRIES];
+  struct ipt_get_entries entries;
+  struct ipt_getinfo info;
+  socklen_t optlen;
+  int fd, i;
+  fd = socket(family, SOCK_STREAM, IPPROTO_TCP);
+  if (fd == -1) {
+    switch (errno) {
+    case EAFNOSUPPORT:
+    case ENOPROTOOPT:
+      return;
+    }
+    exit(1);
+  }
+  for (i = 0; i < num_tables; i++) {
+    struct ipt_table_desc* table = &tables[i];
+    if (table->info.valid_hooks == 0)
+      continue;
+    memset(&info, 0, sizeof(info));
+    strcpy(info.name, table->name);
+    optlen = sizeof(info);
+    if (getsockopt(fd, level, IPT_SO_GET_INFO, &info, &optlen))
+      exit(1);
+    if (memcmp(&table->info, &info, sizeof(table->info)) == 0) {
+      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))
+        exit(1);
+      if (memcmp(table->replace.entrytable, entries.entrytable,
+                 table->info.size) == 0)
+        continue;
+    }
+    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))
+      exit(1);
+  }
+  close(fd);
+}
+
+static void checkpoint_arptables(void)
+{
+  struct arpt_get_entries entries;
+  socklen_t optlen;
+  unsigned i;
+  int fd;
+  fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  if (fd == -1) {
+    switch (errno) {
+    case EAFNOSUPPORT:
+    case ENOPROTOOPT:
+      return;
+    }
+    exit(1);
+  }
+  for (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);
+    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;
+      }
+      exit(1);
+    }
+    if (table->info.size > sizeof(table->replace.entrytable))
+      exit(1);
+    if (table->info.num_entries > XT_MAX_ENTRIES)
+      exit(1);
+    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))
+      exit(1);
+    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()
+{
+  struct xt_counters counters[XT_MAX_ENTRIES];
+  struct arpt_get_entries entries;
+  struct arpt_getinfo info;
+  socklen_t optlen;
+  unsigned i;
+  int fd;
+  fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  if (fd == -1) {
+    switch (errno) {
+    case EAFNOSUPPORT:
+    case ENOPROTOOPT:
+      return;
+    }
+    exit(1);
+  }
+  for (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;
+    memset(&info, 0, sizeof(info));
+    strcpy(info.name, table->name);
+    optlen = sizeof(info);
+    if (getsockopt(fd, SOL_IP, ARPT_SO_GET_INFO, &info, &optlen))
+      exit(1);
+    if (memcmp(&table->info, &info, sizeof(table->info)) == 0) {
+      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))
+        exit(1);
+      if (memcmp(table->replace.entrytable, entries.entrytable,
+                 table->info.size) == 0)
+        continue;
+    } else {
+    }
+    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))
+      exit(1);
+  }
+  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)
+{
+  socklen_t optlen;
+  unsigned i;
+  int fd;
+  fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  if (fd == -1) {
+    switch (errno) {
+    case EAFNOSUPPORT:
+    case ENOPROTOOPT:
+      return;
+    }
+    exit(1);
+  }
+  for (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);
+    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;
+      }
+      exit(1);
+    }
+    if (table->replace.entries_size > sizeof(table->entrytable))
+      exit(1);
+    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))
+      exit(1);
+  }
+  close(fd);
+}
+
+static void reset_ebtables()
+{
+  struct ebt_replace replace;
+  char entrytable[XT_TABLE_SIZE];
+  socklen_t optlen;
+  unsigned i, j, h;
+  int fd;
+  fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  if (fd == -1) {
+    switch (errno) {
+    case EAFNOSUPPORT:
+    case ENOPROTOOPT:
+      return;
+    }
+    exit(1);
+  }
+  for (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;
+    memset(&replace, 0, sizeof(replace));
+    strcpy(replace.name, table->name);
+    optlen = sizeof(replace);
+    if (getsockopt(fd, SOL_IP, EBT_SO_GET_INFO, &replace, &optlen))
+      exit(1);
+    replace.num_counters = 0;
+    table->replace.entries = 0;
+    for (h = 0; h < NF_BR_NUMHOOKS; h++)
+      table->replace.hook_entry[h] = 0;
+    if (memcmp(&table->replace, &replace, sizeof(table->replace)) == 0) {
+      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))
+        exit(1);
+      if (memcmp(table->entrytable, entrytable, replace.entries_size) == 0)
+        continue;
+    }
+    for (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))
+      exit(1);
+  }
+  close(fd);
+}
+
+static void checkpoint_net_namespace(void)
+{
+  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)
+{
+  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);
+}
+
+static void setup_cgroups()
+{
+  if (mkdir("/syzcgroup", 0777)) {
+  }
+  if (mkdir("/syzcgroup/unified", 0777)) {
+  }
+  if (mount("none", "/syzcgroup/unified", "cgroup2", 0, NULL)) {
+  }
+  if (chmod("/syzcgroup/unified", 0777)) {
+  }
+  write_file("/syzcgroup/unified/cgroup.subtree_control",
+             "+cpu +memory +io +pids +rdma");
+  if (mkdir("/syzcgroup/cpu", 0777)) {
+  }
+  if (mount("none", "/syzcgroup/cpu", "cgroup", 0,
+            "cpuset,cpuacct,perf_event,hugetlb")) {
+  }
+  write_file("/syzcgroup/cpu/cgroup.clone_children", "1");
+  if (chmod("/syzcgroup/cpu", 0777)) {
+  }
+  if (mkdir("/syzcgroup/net", 0777)) {
+  }
+  if (mount("none", "/syzcgroup/net", "cgroup", 0,
+            "net_cls,net_prio,devices,freezer")) {
+  }
+  if (chmod("/syzcgroup/net", 0777)) {
+  }
+}
+
+static void setup_cgroups_loop()
+{
+  int pid = getpid();
+  char file[128];
+  char cgroupdir[64];
+  snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/unified/syz%llu", procid);
+  if (mkdir(cgroupdir, 0777)) {
+  }
+  snprintf(file, sizeof(file), "%s/pids.max", cgroupdir);
+  write_file(file, "32");
+  snprintf(file, sizeof(file), "%s/memory.low", cgroupdir);
+  write_file(file, "%d", 298 << 20);
+  snprintf(file, sizeof(file), "%s/memory.high", cgroupdir);
+  write_file(file, "%d", 299 << 20);
+  snprintf(file, sizeof(file), "%s/memory.max", cgroupdir);
+  write_file(file, "%d", 300 << 20);
+  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)) {
+  }
+  snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+  write_file(file, "%d", pid);
+  snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/net/syz%llu", procid);
+  if (mkdir(cgroupdir, 0777)) {
+  }
+  snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+  write_file(file, "%d", pid);
+}
+
+static void setup_cgroups_test()
+{
+  char cgroupdir[64];
+  snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/unified/syz%llu", procid);
+  if (symlink(cgroupdir, "./cgroup")) {
+  }
+  snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/cpu/syz%llu", procid);
+  if (symlink(cgroupdir, "./cgroup.cpu")) {
+  }
+  snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/net/syz%llu", procid);
+  if (symlink(cgroupdir, "./cgroup.net")) {
+  }
+}
+
+static void setup_common()
+{
+  if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
+  }
+  setup_cgroups();
+}
+
+static void loop();
+
+static void sandbox_common()
+{
+  prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+  setpgrp();
+  setsid();
+  struct rlimit rlim;
+  rlim.rlim_cur = rlim.rlim_max = (200 << 20);
+  setrlimit(RLIMIT_AS, &rlim);
+  rlim.rlim_cur = rlim.rlim_max = 32 << 20;
+  setrlimit(RLIMIT_MEMLOCK, &rlim);
+  rlim.rlim_cur = rlim.rlim_max = 136 << 20;
+  setrlimit(RLIMIT_FSIZE, &rlim);
+  rlim.rlim_cur = rlim.rlim_max = 1 << 20;
+  setrlimit(RLIMIT_STACK, &rlim);
+  rlim.rlim_cur = rlim.rlim_max = 0;
+  setrlimit(RLIMIT_CORE, &rlim);
+  rlim.rlim_cur = rlim.rlim_max = 256;
+  setrlimit(RLIMIT_NOFILE, &rlim);
+  if (unshare(CLONE_NEWNS)) {
+  }
+  if (unshare(CLONE_NEWIPC)) {
+  }
+  if (unshare(0x02000000)) {
+  }
+  if (unshare(CLONE_NEWUTS)) {
+  }
+  if (unshare(CLONE_SYSVSEM)) {
+  }
+  typedef struct {
+    const char* name;
+    const char* value;
+  } sysctl_t;
+  static const sysctl_t sysctls[] = {
+      {"/proc/sys/kernel/shmmax", "16777216"},
+      {"/proc/sys/kernel/shmall", "536870912"},
+      {"/proc/sys/kernel/shmmni", "1024"},
+      {"/proc/sys/kernel/msgmax", "8192"},
+      {"/proc/sys/kernel/msgmni", "1024"},
+      {"/proc/sys/kernel/msgmnb", "1024"},
+      {"/proc/sys/kernel/sem", "1024 1048576 500 1024"},
+  };
+  unsigned i;
+  for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)
+    write_file(sysctls[i].name, sysctls[i].value);
+}
+
+int wait_for_loop(int pid)
+{
+  if (pid < 0)
+    exit(1);
+  int status = 0;
+  while (waitpid(-1, &status, __WALL) != pid) {
+  }
+  return WEXITSTATUS(status);
+}
+
+static void drop_caps(void)
+{
+  struct __user_cap_header_struct cap_hdr = {};
+  struct __user_cap_data_struct cap_data[2] = {};
+  cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+  cap_hdr.pid = getpid();
+  if (syscall(SYS_capget, &cap_hdr, &cap_data))
+    exit(1);
+  const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
+  cap_data[0].effective &= ~drop;
+  cap_data[0].permitted &= ~drop;
+  cap_data[0].inheritable &= ~drop;
+  if (syscall(SYS_capset, &cap_hdr, &cap_data))
+    exit(1);
+}
+
+static int do_sandbox_none(void)
+{
+  if (unshare(CLONE_NEWPID)) {
+  }
+  int pid = fork();
+  if (pid != 0)
+    return wait_for_loop(pid);
+  setup_common();
+  sandbox_common();
+  drop_caps();
+  initialize_netdevices_init();
+  if (unshare(CLONE_NEWNET)) {
+  }
+  initialize_tun();
+  initialize_netdevices();
+  loop();
+  exit(1);
+}
+
+#define FS_IOC_SETFLAGS _IOW('f', 2, long)
+static void remove_dir(const char* dir)
+{
+  DIR* dp;
+  struct dirent* ep;
+  int iter = 0;
+retry:
+  while (umount2(dir, MNT_DETACH) == 0) {
+  }
+  dp = opendir(dir);
+  if (dp == NULL) {
+    if (errno == EMFILE) {
+      exit(1);
+    }
+    exit(1);
+  }
+  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);
+    while (umount2(filename, MNT_DETACH) == 0) {
+    }
+    struct stat st;
+    if (lstat(filename, &st))
+      exit(1);
+    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)
+            close(fd);
+          continue;
+        }
+      }
+      if (errno == EROFS) {
+        break;
+      }
+      if (errno != EBUSY || i > 100)
+        exit(1);
+      if (umount2(filename, MNT_DETACH))
+        exit(1);
+    }
+  }
+  closedir(dp);
+  int i;
+  for (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)
+            close(fd);
+          continue;
+        }
+      }
+      if (errno == EROFS) {
+        break;
+      }
+      if (errno == EBUSY) {
+        if (umount2(dir, MNT_DETACH))
+          exit(1);
+        continue;
+      }
+      if (errno == ENOTEMPTY) {
+        if (iter < 100) {
+          iter++;
+          goto retry;
+        }
+      }
+    }
+    exit(1);
+  }
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+  kill(-pid, SIGKILL);
+  kill(pid, SIGKILL);
+  int i;
+  for (i = 0; i < 100; i++) {
+    if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+      return;
+    usleep(1000);
+  }
+  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) {
+        continue;
+      }
+      if (write(fd, abort, 1) < 0) {
+      }
+      close(fd);
+    }
+    closedir(dir);
+  } else {
+  }
+  while (waitpid(-1, status, __WALL) != pid) {
+  }
+}
+
+static void setup_loop()
+{
+  setup_cgroups_loop();
+  checkpoint_net_namespace();
+}
+
+static void reset_loop()
+{
+  reset_net_namespace();
+}
+
+static void setup_test()
+{
+  prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+  setpgrp();
+  setup_cgroups_test();
+  write_file("/proc/self/oom_score_adj", "1000");
+  flush_tun();
+}
+
+static void close_fds()
+{
+  int fd;
+  for (fd = 3; fd < 30; fd++)
+    close(fd);
+}
+
+static void setup_binfmt_misc()
+{
+  if (mount(0, "/proc/sys/fs/binfmt_misc", "binfmt_misc", 0, 0)) {
+  }
+  write_file("/proc/sys/fs/binfmt_misc/register", ":syz0:M:0:\x01::./file0:");
+  write_file("/proc/sys/fs/binfmt_misc/register",
+             ":syz1:M:1:\x02::./file0:POC");
+}
+
+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;
+}
+
+static void execute_one(void)
+{
+  int i, call, thread;
+  int collide = 0;
+again:
+  for (call = 0; call < 3; 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 (collide && (call % 2) == 0)
+        break;
+      event_timedwait(&th->done, 45);
+      break;
+    }
+  }
+  for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+    sleep_ms(1);
+  close_fds();
+  if (!collide) {
+    collide = 1;
+    goto again;
+  }
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+  setup_loop();
+  int iter;
+  for (iter = 0;; iter++) {
+    char cwdbuf[32];
+    sprintf(cwdbuf, "./%d", iter);
+    if (mkdir(cwdbuf, 0777))
+      exit(1);
+    reset_loop();
+    int pid = fork();
+    if (pid < 0)
+      exit(1);
+    if (pid == 0) {
+      if (chdir(cwdbuf))
+        exit(1);
+      setup_test();
+      execute_one();
+      exit(0);
+    }
+    int status = 0;
+    uint64_t start = current_time_ms();
+    for (;;) {
+      if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+        break;
+      sleep_ms(1);
+      if (current_time_ms() - start < 5 * 1000)
+        continue;
+      kill_and_wait(pid, &status);
+      break;
+    }
+    remove_dir(cwdbuf);
+  }
+}
+
+void execute_call(int call)
+{
+  switch (call) {
+  case 0:
+    syscall(__NR_perf_event_open, 0, 0, -1, -1, 0);
+    break;
+  case 1:
+    NONFAILING(*(uint32_t*)0x2001d000 = 1);
+    NONFAILING(*(uint32_t*)0x2001d004 = 0x70);
+    NONFAILING(*(uint8_t*)0x2001d008 = 0);
+    NONFAILING(*(uint8_t*)0x2001d009 = 0);
+    NONFAILING(*(uint8_t*)0x2001d00a = 0);
+    NONFAILING(*(uint8_t*)0x2001d00b = 0);
+    NONFAILING(*(uint32_t*)0x2001d00c = 0);
+    NONFAILING(*(uint64_t*)0x2001d010 = 0x7f);
+    NONFAILING(*(uint64_t*)0x2001d018 = 0);
+    NONFAILING(*(uint64_t*)0x2001d020 = 0);
+    NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 0, 1));
+    NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 1, 1));
+    NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 2, 1));
+    NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 3, 1));
+    NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 4, 1));
+    NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 5, 1));
+    NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 6, 1));
+    NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 7, 1));
+    NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 8, 1));
+    NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 9, 1));
+    NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 10, 1));
+    NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 11, 1));
+    NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 12, 1));
+    NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 13, 1));
+    NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 14, 1));
+    NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 15, 2));
+    NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 17, 1));
+    NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 18, 1));
+    NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 19, 1));
+    NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 20, 1));
+    NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 21, 1));
+    NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 22, 1));
+    NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 23, 1));
+    NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 24, 1));
+    NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 25, 1));
+    NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 26, 1));
+    NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 27, 1));
+    NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 28, 1));
+    NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 29, 35));
+    NONFAILING(*(uint32_t*)0x2001d030 = 0);
+    NONFAILING(*(uint32_t*)0x2001d034 = 0);
+    NONFAILING(*(uint64_t*)0x2001d038 = 0);
+    NONFAILING(*(uint64_t*)0x2001d040 = 0);
+    NONFAILING(*(uint64_t*)0x2001d048 = 0);
+    NONFAILING(*(uint64_t*)0x2001d050 = 0);
+    NONFAILING(*(uint32_t*)0x2001d058 = 0);
+    NONFAILING(*(uint32_t*)0x2001d05c = 0);
+    NONFAILING(*(uint64_t*)0x2001d060 = 0);
+    NONFAILING(*(uint32_t*)0x2001d068 = 0);
+    NONFAILING(*(uint16_t*)0x2001d06c = 0);
+    NONFAILING(*(uint16_t*)0x2001d06e = 0);
+    syscall(__NR_perf_event_open, 0x2001d000, 0, -1, -1, 0);
+    break;
+  case 2:
+    syscall(__NR_socket, 0x11, 0x803, 0x25);
+    break;
+  }
+}
+int main(void)
+{
+  syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+  setup_binfmt_misc();
+  install_segv_handler();
+  for (procid = 0; procid < 4; procid++) {
+    if (fork() == 0) {
+      use_temporary_dir();
+      do_sandbox_none();
+    }
+  }
+  sleep(1000000);
+  return 0;
+}
diff --git a/syzkaller-repros/linux/0b5da7af1edc95677e6a4eb483c0eefcd4db4c55.c b/syzkaller-repros/linux/0b5da7af1edc95677e6a4eb483c0eefcd4db4c55.c
new file mode 100644
index 0000000..b05305b
--- /dev/null
+++ b/syzkaller-repros/linux/0b5da7af1edc95677e6a4eb483c0eefcd4db4c55.c
@@ -0,0 +1,194 @@
+// KMSAN: use-after-free in copyout
+// https://syzkaller.appspot.com/bug?id=0b5da7af1edc95677e6a4eb483c0eefcd4db4c55
+// status:fixed
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+  usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+  struct timespec ts;
+  if (clock_gettime(CLOCK_MONOTONIC, &ts))
+    exit(1);
+  return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+  char buf[1024];
+  va_list args;
+  va_start(args, what);
+  vsnprintf(buf, sizeof(buf), what, args);
+  va_end(args);
+  buf[sizeof(buf) - 1] = 0;
+  int len = strlen(buf);
+  int fd = open(file, O_WRONLY | O_CLOEXEC);
+  if (fd == -1)
+    return false;
+  if (write(fd, buf, len) != len) {
+    int err = errno;
+    close(fd);
+    errno = err;
+    return false;
+  }
+  close(fd);
+  return true;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+  kill(-pid, SIGKILL);
+  kill(pid, SIGKILL);
+  int i;
+  for (i = 0; i < 100; i++) {
+    if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+      return;
+    usleep(1000);
+  }
+  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) {
+        continue;
+      }
+      if (write(fd, abort, 1) < 0) {
+      }
+      close(fd);
+    }
+    closedir(dir);
+  } else {
+  }
+  while (waitpid(-1, status, __WALL) != pid) {
+  }
+}
+
+static void setup_test()
+{
+  prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+  setpgrp();
+  write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+  int iter;
+  for (iter = 0;; iter++) {
+    int pid = fork();
+    if (pid < 0)
+      exit(1);
+    if (pid == 0) {
+      setup_test();
+      execute_one();
+      exit(0);
+    }
+    int status = 0;
+    uint64_t start = current_time_ms();
+    for (;;) {
+      if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+        break;
+      sleep_ms(1);
+      if (current_time_ms() - start < 5 * 1000)
+        continue;
+      kill_and_wait(pid, &status);
+      break;
+    }
+  }
+}
+
+uint64_t r[3] = {0xffffffffffffffff, 0x0, 0x0};
+
+void execute_one(void)
+{
+  intptr_t res = 0;
+  memcpy((void*)0x200000c0, "/dev/ptmx\000", 10);
+  res = syscall(__NR_openat, 0xffffffffffffff9c, 0x200000c0, 0, 0);
+  if (res != -1)
+    r[0] = res;
+  *(uint32_t*)0x20000040 = 0xf;
+  syscall(__NR_ioctl, r[0], 0x5423, 0x20000040);
+  syscall(__NR_ioctl, r[0], 0x400455c8, 1);
+  memcpy((void*)0x20000040, "user\000", 5);
+  memcpy((void*)0x20000000, "syz", 3);
+  *(uint8_t*)0x20000003 = 0;
+  *(uint8_t*)0x20000004 = 0;
+  memcpy((void*)0x200002c0,
+         "\x58\x5c\xcb\xe4\xed\x83\xb8\x36\xc1\xa6\x47\x49\x14\xdc\x55\xe7\x22"
+         "\x06\x29\x7b\x68\x95\xb6\x61\x47\xb3\xc7\x21\x8a\x91\x69\xa8\x5e\xa0"
+         "\xbd\xc9\xe1\x58\x7a\x05\x00\x00\x00\x00\x00\x00\x00\x42\xe3\x30\x89"
+         "\x75\x4c\x81\x07\xc3\xcd\x39\x23\xdd\x4a\x71\xc2\xff\x06\x00\x7b\x6b"
+         "\x48\x16\x12\x2d\x25\x50\x82\x9e\xaa\x94\x35\xc9\x99\x26\x02\x2b\x87"
+         "\x53\xa1\x88\x74\x8c\x56\x9f\x43\x5f\xb3\xba\xe9\x6e\xfb\x74\xb5\x0e"
+         "\xc9\x3c\x15\x2f\x5e\x8e\x19\x8a\x29\xe5\xc0\xd0\xc6\x00\x00\xce\x06"
+         "\x37\xce\x00\x00\xb4\xec\x24\xc5\x3d\x3d\x66\x1f\xf5\xff\x70\xe4\x88"
+         "\x84\xca\x00\x00\x18\xce\xa7\x1f\xcf\xac\xf4\x0d\x32\xe4\xb5\x8a\x8d"
+         "\x27\x25\x56\x1f\x61\x10\xfd\x7b\x06\xf9\x0b\x52\x74\xcc\x5c\x1e\x29"
+         "\x8a\x16\x32\x4f\xe2\x7d\xa2\xa9\xd5\xba\x9f\xf3\xc0\x09\xd3\x08\xbd"
+         "\x73\xf4\x77\x25\x39",
+         192);
+  res = syscall(__NR_add_key, 0x20000040, 0x20000000, 0x200002c0, 0xc0,
+                0xfffffffe);
+  if (res != -1)
+    r[1] = res;
+  memcpy((void*)0x20000200, "user\000", 5);
+  memcpy((void*)0x200005c0, "syz", 3);
+  *(uint8_t*)0x200005c3 = 0;
+  *(uint8_t*)0x200005c4 = 0;
+  res = syscall(__NR_add_key, 0x20000200, 0x200005c0, 0x200000c0, 0x9a,
+                0xfffffffd);
+  if (res != -1)
+    r[2] = res;
+  *(uint32_t*)0x200000c0 = r[2];
+  *(uint32_t*)0x200000c4 = r[1];
+  *(uint32_t*)0x200000c8 = r[2];
+  syscall(__NR_keyctl, 0x17, 0x200000c0, 0x9999999999999999, 0xf9ffffff, 0);
+}
+int main(void)
+{
+  syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
+  for (procid = 0; procid < 6; procid++) {
+    if (fork() == 0) {
+      loop();
+    }
+  }
+  sleep(1000000);
+  return 0;
+}
diff --git a/syzkaller-repros/linux/0bd948d2fcdbd3ba337dbd53fdca59b4afe9787d.c b/syzkaller-repros/linux/0bd948d2fcdbd3ba337dbd53fdca59b4afe9787d.c
new file mode 100644
index 0000000..0e584de
--- /dev/null
+++ b/syzkaller-repros/linux/0bd948d2fcdbd3ba337dbd53fdca59b4afe9787d.c
@@ -0,0 +1,182 @@
+// KASAN: use-after-free Write in release_tty
+// https://syzkaller.appspot.com/bug?id=0bd948d2fcdbd3ba337dbd53fdca59b4afe9787d
+// status:open
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+  usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+  struct timespec ts;
+  if (clock_gettime(CLOCK_MONOTONIC, &ts))
+    exit(1);
+  return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+  char buf[1024];
+  va_list args;
+  va_start(args, what);
+  vsnprintf(buf, sizeof(buf), what, args);
+  va_end(args);
+  buf[sizeof(buf) - 1] = 0;
+  int len = strlen(buf);
+  int fd = open(file, O_WRONLY | O_CLOEXEC);
+  if (fd == -1)
+    return false;
+  if (write(fd, buf, len) != len) {
+    int err = errno;
+    close(fd);
+    errno = err;
+    return false;
+  }
+  close(fd);
+  return true;
+}
+
+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_t)a1,
+            (uint8_t)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);
+  }
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+  kill(-pid, SIGKILL);
+  kill(pid, SIGKILL);
+  int i;
+  for (i = 0; i < 100; i++) {
+    if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+      return;
+    usleep(1000);
+  }
+  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) {
+        continue;
+      }
+      if (write(fd, abort, 1) < 0) {
+      }
+      close(fd);
+    }
+    closedir(dir);
+  } else {
+  }
+  while (waitpid(-1, status, __WALL) != pid) {
+  }
+}
+
+static void setup_test()
+{
+  prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+  setpgrp();
+  write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+  int iter;
+  for (iter = 0;; iter++) {
+    int pid = fork();
+    if (pid < 0)
+      exit(1);
+    if (pid == 0) {
+      setup_test();
+      execute_one();
+      exit(0);
+    }
+    int status = 0;
+    uint64_t start = current_time_ms();
+    for (;;) {
+      if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+        break;
+      sleep_ms(1);
+      if (current_time_ms() - start < 5 * 1000)
+        continue;
+      kill_and_wait(pid, &status);
+      break;
+    }
+  }
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_one(void)
+{
+  intptr_t res = 0;
+  syz_open_dev(0xc, 4, 0x15 + procid * 2);
+  res = syz_open_dev(0xc, 4, 1);
+  if (res != -1)
+    r[0] = res;
+  res = syscall(__NR_pipe, 0x20000000ul);
+  if (res != -1)
+    r[1] = *(uint32_t*)0x20000000;
+  syscall(__NR_dup2, r[0], r[1]);
+  syscall(__NR_ioctl, r[1], 0x5608ul, 0);
+}
+int main(void)
+{
+  syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+  for (procid = 0; procid < 6; procid++) {
+    if (fork() == 0) {
+      loop();
+    }
+  }
+  sleep(1000000);
+  return 0;
+}
diff --git a/syzkaller-repros/linux/0bf4a81cd2cf6ff13e659062e6a561137dac7d3a.c b/syzkaller-repros/linux/0bf4a81cd2cf6ff13e659062e6a561137dac7d3a.c
new file mode 100644
index 0000000..42abe2d
--- /dev/null
+++ b/syzkaller-repros/linux/0bf4a81cd2cf6ff13e659062e6a561137dac7d3a.c
@@ -0,0 +1,883 @@
+// INFO: task hung in chaoskey_disconnect
+// https://syzkaller.appspot.com/bug?id=0bf4a81cd2cf6ff13e659062e6a561137dac7d3a
+// status:open
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.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/usb/ch9.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+  usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+  struct timespec ts;
+  if (clock_gettime(CLOCK_MONOTONIC, &ts))
+    exit(1);
+  return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+  char buf[1024];
+  va_list args;
+  va_start(args, what);
+  vsnprintf(buf, sizeof(buf), what, args);
+  va_end(args);
+  buf[sizeof(buf) - 1] = 0;
+  int len = strlen(buf);
+  int fd = open(file, O_WRONLY | O_CLOEXEC);
+  if (fd == -1)
+    return false;
+  if (write(fd, buf, len) != len) {
+    int err = errno;
+    close(fd);
+    errno = err;
+    return false;
+  }
+  close(fd);
+  return true;
+}
+
+struct nlmsg {
+  char* pos;
+  int nesting;
+  struct nlattr* nested[8];
+  char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+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;
+  memcpy(attr + 1, data, size);
+  nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+                            int* reply_len)
+{
+  if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+    exit(1);
+  struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+  hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+  struct sockaddr_nl addr;
+  memset(&addr, 0, sizeof(addr));
+  addr.nl_family = AF_NETLINK;
+  unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+                      (struct sockaddr*)&addr, sizeof(addr));
+  if (n != hdr->nlmsg_len)
+    exit(1);
+  n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+  if (hdr->nlmsg_type == NLMSG_DONE) {
+    *reply_len = 0;
+    return 0;
+  }
+  if (n < sizeof(struct nlmsghdr))
+    exit(1);
+  if (reply_len && hdr->nlmsg_type == reply_type) {
+    *reply_len = n;
+    return 0;
+  }
+  if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+    exit(1);
+  if (hdr->nlmsg_type != NLMSG_ERROR)
+    exit(1);
+  return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+  return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+                            unsigned int total_len)
+{
+  struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+  if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+    return -1;
+  return hdr->nlmsg_len;
+}
+
+static void netlink_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);
+  (void)err;
+}
+
+const int kInitNetNsFd = 239;
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_CMD_RELOAD 37
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+#define DEVLINK_ATTR_NETNS_FD 138
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+  struct genlmsghdr genlhdr;
+  struct nlattr* attr;
+  int err, n;
+  uint16_t id = 0;
+  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, DEVLINK_FAMILY_NAME,
+               strlen(DEVLINK_FAMILY_NAME) + 1);
+  err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+  if (err) {
+    return -1;
+  }
+  attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+                          NLMSG_ALIGN(sizeof(genlhdr)));
+  for (; (char*)attr < nlmsg->buf + n;
+       attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+    if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+      id = *(uint16_t*)(attr + 1);
+      break;
+    }
+  }
+  if (!id) {
+    return -1;
+  }
+  recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+  return id;
+}
+
+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)
+    exit(1);
+  id = netlink_devlink_id_get(&nlmsg, sock);
+  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) {
+  }
+error:
+  close(sock);
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+                                     const char* netdev_prefix)
+{
+  struct genlmsghdr genlhdr;
+  int len, total_len, id, err, offset;
+  uint16_t netdev_index;
+  int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+  if (sock == -1)
+    exit(1);
+  int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+  if (rtsock == -1)
+    exit(1);
+  id = netlink_devlink_id_get(&nlmsg, sock);
+  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);
+  if (err) {
+    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);
+}
+
+static void initialize_devlink_pci(void)
+{
+  int netns = open("/proc/self/ns/net", O_RDONLY);
+  if (netns == -1)
+    exit(1);
+  int ret = setns(kInitNetNsFd, 0);
+  if (ret == -1)
+    exit(1);
+  netlink_devlink_netns_move("pci", "0000:00:10.0", netns);
+  ret = setns(netns, 0);
+  if (ret == -1)
+    exit(1);
+  close(netns);
+  initialize_devlink_ports("pci", "0000:00:10.0", "netpci");
+}
+
+#define MAX_FDS 30
+
+#define USB_MAX_IFACE_NUM 4
+#define USB_MAX_EP_NUM 32
+
+struct usb_iface_index {
+  struct usb_interface_descriptor* iface;
+  uint8_t bInterfaceNumber;
+  uint8_t bAlternateSetting;
+  uint8_t bInterfaceClass;
+  struct usb_endpoint_descriptor eps[USB_MAX_EP_NUM];
+  int eps_num;
+};
+
+struct usb_device_index {
+  struct usb_device_descriptor* dev;
+  struct usb_config_descriptor* config;
+  uint8_t bDeviceClass;
+  uint8_t bMaxPower;
+  int config_length;
+  struct usb_iface_index ifaces[USB_MAX_IFACE_NUM];
+  int ifaces_num;
+  int iface_cur;
+};
+
+static bool parse_usb_descriptor(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_t desc_length = buffer[offset];
+    uint8_t 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);
+      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];
+      if (iface->eps_num < USB_MAX_EP_NUM) {
+        memcpy(&iface->eps[iface->eps_num], buffer + offset,
+               sizeof(iface->eps[iface->eps_num]));
+        iface->eps_num++;
+      }
+    }
+    offset += desc_length;
+  }
+  return true;
+}
+
+#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,
+  USB_RAW_EVENT_CONNECT,
+  USB_RAW_EVENT_CONTROL,
+};
+
+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_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)
+
+static int usb_raw_open()
+{
+  return open("/dev/raw-gadget", O_RDWR);
+}
+
+static int usb_raw_init(int fd, uint32_t 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);
+}
+
+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_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_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_configure(int fd)
+{
+  return ioctl(fd, USB_RAW_IOCTL_CONFIGURE, 0);
+}
+
+static int usb_raw_vbus_draw(int fd, uint32_t power)
+{
+  return ioctl(fd, USB_RAW_IOCTL_VBUS_DRAW, power);
+}
+
+#define MAX_USB_FDS 6
+
+struct usb_info {
+  int fd;
+  struct usb_device_index index;
+};
+
+static struct usb_info usb_devices[MAX_USB_FDS];
+static int usb_devices_num;
+
+static struct usb_device_index* add_usb_index(int fd, char* dev, size_t dev_len)
+{
+  int i = __atomic_fetch_add(&usb_devices_num, 1, __ATOMIC_RELAXED);
+  if (i >= MAX_USB_FDS)
+    return NULL;
+  int rv = 0;
+  rv = parse_usb_descriptor(dev, dev_len, &usb_devices[i].index);
+  if (!rv)
+    return NULL;
+  __atomic_store_n(&usb_devices[i].fd, fd, __ATOMIC_RELEASE);
+  return &usb_devices[i].index;
+}
+
+static struct usb_device_index* lookup_usb_index(int fd)
+{
+  int i;
+  for (i = 0; i < MAX_USB_FDS; i++) {
+    if (__atomic_load_n(&usb_devices[i].fd, __ATOMIC_ACQUIRE) == fd) {
+      return &usb_devices[i].index;
+    }
+  }
+  return NULL;
+}
+
+static void set_interface(int fd, int n)
+{
+  struct usb_device_index* index = lookup_usb_index(fd);
+  int ep;
+  if (!index)
+    return;
+  if (index->iface_cur >= 0 && index->iface_cur < index->ifaces_num) {
+    for (ep = 0; ep < index->ifaces[index->iface_cur].eps_num; ep++) {
+      int rv = usb_raw_ep_disable(fd, ep);
+      if (rv < 0) {
+      } else {
+      }
+    }
+  }
+  if (n >= 0 && n < index->ifaces_num) {
+    for (ep = 0; ep < index->ifaces[n].eps_num; ep++) {
+      int rv = usb_raw_ep_enable(fd, &index->ifaces[n].eps[ep]);
+      if (rv < 0) {
+      } else {
+      }
+    }
+    index->iface_cur = n;
+  }
+}
+
+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) {
+    return rv;
+  }
+  rv = usb_raw_configure(fd);
+  if (rv < 0) {
+    return rv;
+  }
+  set_interface(fd, 0);
+  return 0;
+}
+
+#define USB_MAX_PACKET_SIZE 1024
+
+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];
+};
+
+struct vusb_connect_string_descriptor {
+  uint32_t len;
+  char* str;
+} __attribute__((packed));
+
+struct vusb_connect_descriptors {
+  uint32_t qual_len;
+  char* qual;
+  uint32_t bos_len;
+  char* bos;
+  uint32_t strs_len;
+  struct vusb_connect_string_descriptor strs[0];
+} __attribute__((packed));
+
+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(int fd,
+                                    struct vusb_connect_descriptors* descs,
+                                    struct usb_ctrlrequest* ctrl,
+                                    char** response_data,
+                                    uint32_t* response_length)
+{
+  struct usb_device_index* index = lookup_usb_index(fd);
+  uint8_t 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_t)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) {
+          struct usb_qualifier_descriptor* qual =
+              (struct usb_qualifier_descriptor*)response_data;
+          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_length = sizeof(*qual);
+          return true;
+        }
+        *response_data = descs->qual;
+        *response_length = descs->qual_len;
+        return true;
+      default:
+        exit(1);
+        return false;
+      }
+      break;
+    default:
+      exit(1);
+      return false;
+    }
+    break;
+  default:
+    exit(1);
+    return false;
+  }
+  return false;
+}
+
+static volatile long syz_usb_connect(volatile long a0, volatile long a1,
+                                     volatile long a2, volatile long a3)
+{
+  uint64_t speed = a0;
+  uint64_t dev_len = a1;
+  char* dev = (char*)a2;
+  struct vusb_connect_descriptors* descs = (struct vusb_connect_descriptors*)a3;
+  if (!dev) {
+    return -1;
+  }
+  int fd = usb_raw_open();
+  if (fd < 0) {
+    return fd;
+  }
+  if (fd >= MAX_FDS) {
+    close(fd);
+    return -1;
+  }
+  struct usb_device_index* index = add_usb_index(fd, dev, dev_len);
+  if (!index) {
+    return -1;
+  }
+  char device[32];
+  sprintf(&device[0], "dummy_udc.%llu", procid);
+  int rv = usb_raw_init(fd, speed, "dummy_udc", &device[0]);
+  if (rv < 0) {
+    return rv;
+  }
+  rv = usb_raw_run(fd);
+  if (rv < 0) {
+    return rv;
+  }
+  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) {
+      return rv;
+    }
+    if (event.inner.type != USB_RAW_EVENT_CONTROL)
+      continue;
+    bool response_found = false;
+    char* response_data = NULL;
+    uint32_t response_length = 0;
+    if (event.ctrl.bRequestType & USB_DIR_IN) {
+      response_found = lookup_connect_response(
+          fd, descs, &event.ctrl, &response_data, &response_length);
+      if (!response_found) {
+        return -1;
+      }
+    } else {
+      if ((event.ctrl.bRequestType & USB_TYPE_MASK) != USB_TYPE_STANDARD ||
+          event.ctrl.bRequest != USB_REQ_SET_CONFIGURATION) {
+        exit(1);
+        return -1;
+      }
+      done = true;
+    }
+    if (done) {
+      rv = configure_device(fd);
+      if (rv < 0) {
+        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) {
+      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);
+    }
+    if (rv < 0) {
+      return rv;
+    }
+  }
+  sleep_ms(200);
+  return fd;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+  kill(-pid, SIGKILL);
+  kill(pid, SIGKILL);
+  int i;
+  for (i = 0; i < 100; i++) {
+    if (waitpid(-1, status, WNOHANG | __WALL) == pid)
+      return;
+    usleep(1000);
+  }
+  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) {
+        continue;
+      }
+      if (write(fd, abort, 1) < 0) {
+      }
+      close(fd);
+    }
+    closedir(dir);
+  } else {
+  }
+  while (waitpid(-1, status, __WALL) != pid) {
+  }
+}
+
+static void setup_test()
+{
+  prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+  setpgrp();
+  write_file("/proc/self/oom_score_adj", "1000");
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+  int iter;
+  for (iter = 0;; iter++) {
+    int pid = fork();
+    if (pid < 0)
+      exit(1);
+    if (pid == 0) {
+      setup_test();
+      execute_one();
+      exit(0);
+    }
+    int status = 0;
+    uint64_t start = current_time_ms();
+    for (;;) {
+      if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+        break;
+      sleep_ms(1);
+      if (current_time_ms() - start < 5 * 1000)
+        continue;
+      kill_and_wait(pid, &status);
+      break;
+    }
+  }
+}
+
+void execute_one(void)
+{
+  *(uint8_t*)0x20000000 = 0x12;
+  *(uint8_t*)0x20000001 = 1;
+  *(uint16_t*)0x20000002 = 0;
+  *(uint8_t*)0x20000004 = 0x2b;
+  *(uint8_t*)0x20000005 = 0x19;
+  *(uint8_t*)0x20000006 = 0x91;
+  *(uint8_t*)0x20000007 = 0x10;
+  *(uint16_t*)0x20000008 = 0x1d50;
+  *(uint16_t*)0x2000000a = 0x60c6;
+  *(uint16_t*)0x2000000c = 0x1ad7;
+  *(uint8_t*)0x2000000e = 0;
+  *(uint8_t*)0x2000000f = 0;
+  *(uint8_t*)0x20000010 = 0;
+  *(uint8_t*)0x20000011 = 1;
+  *(uint8_t*)0x20000012 = 9;
+  *(uint8_t*)0x20000013 = 2;
+  *(uint16_t*)0x20000014 = 0x1b;
+  *(uint8_t*)0x20000016 = 1;
+  *(uint8_t*)0x20000017 = 0;
+  *(uint8_t*)0x20000018 = 0;
+  *(uint8_t*)0x20000019 = 0;
+  *(uint8_t*)0x2000001a = 0;
+  *(uint8_t*)0x2000001b = 9;
+  *(uint8_t*)0x2000001c = 4;
+  *(uint8_t*)0x2000001d = 0;
+  *(uint8_t*)0x2000001e = 0;
+  *(uint8_t*)0x2000001f = 1;
+  *(uint8_t*)0x20000020 = 0xc9;
+  *(uint8_t*)0x20000021 = 0xb3;
+  *(uint8_t*)0x20000022 = 0xea;
+  *(uint8_t*)0x20000023 = 0;
+  *(uint8_t*)0x20000024 = 9;
+  *(uint8_t*)0x20000025 = 5;
+  *(uint8_t*)0x20000026 = 0x8f;
+  *(uint8_t*)0x20000027 = 2;
+  *(uint16_t*)0x20000028 = 0x49;
+  *(uint8_t*)0x2000002a = 0;
+  *(uint8_t*)0x2000002b = 0;
+  *(uint8_t*)0x2000002c = 0;
+  syz_usb_connect(0, 0x2d, 0x20000000, 0);
+}
+int main(void)
+{
+  syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+  for (procid = 0; procid < 6; procid++) {
+    if (fork() == 0) {
+      loop();
+    }
+  }
+  sleep(1000000);
+  return 0;
+}
diff --git a/syzkaller-repros/linux/0c160f657ea1d4f0c929ad3a38bfb2015287c068.c b/syzkaller-repros/linux/0c160f657ea1d4f0c929ad3a38bfb2015287c068.c
new file mode 100644
index 0000000..a27df17
--- /dev/null
+++ b/syzkaller-repros/linux/0c160f657ea1d4f0c929ad3a38bfb2015287c068.c
@@ -0,0 +1,983 @@
+// WARNING in batadv_iv_send_outstanding_bat_ogm_packet
+// https://syzkaller.appspot.com/bug?id=0c160f657ea1d4f0c929ad3a38bfb2015287c068
+// status:open
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+static void sleep_ms(uint64_t ms)
+{
+  usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+  struct timespec ts;
+  if (clock_gettime(CLOCK_MONOTONIC, &ts))
+    exit(1);
+  return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static bool write_file(const char* file, const char* what, ...)
+{
+  char buf[1024];
+  va_list args;
+  va_start(args, what);
+  vsnprintf(buf, sizeof(buf), what, args);
+  va_end(args);
+  buf[sizeof(buf) - 1] = 0;
+  int len = strlen(buf);
+  int fd = open(file, O_WRONLY | O_CLOEXEC);
+  if (fd == -1)
+    return false;
+  if (write(fd, buf, len) != len) {
+    int err = errno;
+    close(fd);
+    errno = err;
+    return false;
+  }
+  close(fd);
+  return true;
+}
+
+struct nlmsg {
+  char* pos;
+  int nesting;
+  struct nlattr* nested[8];
+  char buf[1024];
+};
+
+static struct nlmsg nlmsg;
+
+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;
+  memcpy(attr + 1, data, size);
+  nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
+}
+
+static void netlink_nest(struct nlmsg* nlmsg, int typ)
+{
+  struct nlattr* attr = (struct nlattr*)nlmsg->pos;
+  attr->nla_type = typ;
+  nlmsg->pos += sizeof(*attr);
+  nlmsg->nested[nlmsg->nesting++] = attr;
+}
+
+static void netlink_done(struct nlmsg* nlmsg)
+{
+  struct nlattr* attr = nlmsg->nested[--nlmsg->nesting];
+  attr->nla_len = nlmsg->pos - (char*)attr;
+}
+
+static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
+                            int* reply_len)
+{
+  if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
+    exit(1);
+  struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
+  hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
+  struct sockaddr_nl addr;
+  memset(&addr, 0, sizeof(addr));
+  addr.nl_family = AF_NETLINK;
+  unsigned n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
+                      (struct sockaddr*)&addr, sizeof(addr));
+  if (n != hdr->nlmsg_len)
+    exit(1);
+  n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
+  if (hdr->nlmsg_type == NLMSG_DONE) {
+    *reply_len = 0;
+    return 0;
+  }
+  if (n < sizeof(struct nlmsghdr))
+    exit(1);
+  if (reply_len && hdr->nlmsg_type == reply_type) {
+    *reply_len = n;
+    return 0;
+  }
+  if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))
+    exit(1);
+  if (hdr->nlmsg_type != NLMSG_ERROR)
+    exit(1);
+  return -((struct nlmsgerr*)(hdr + 1))->error;
+}
+
+static int netlink_send(struct nlmsg* nlmsg, int sock)
+{
+  return netlink_send_ext(nlmsg, sock, 0, NULL);
+}
+
+static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
+                            unsigned int total_len)
+{
+  struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
+  if (offset == total_len || offset + hdr->nlmsg_len > total_len)
+    return -1;
+  return hdr->nlmsg_len;
+}
+
+static void netlink_add_device_impl(struct nlmsg* nlmsg, const char* type,
+                                    const char* name)
+{
+  struct ifinfomsg hdr;
+  memset(&hdr, 0, sizeof(hdr));
+  netlink_init(nlmsg, RTM_NEWLINK, NLM_F_EXCL | NLM_F_CREATE, &hdr,
+               sizeof(hdr));
+  if (name)
+    netlink_attr(nlmsg, IFLA_IFNAME, name, strlen(name));
+  netlink_nest(nlmsg, IFLA_LINKINFO);
+  netlink_attr(nlmsg, IFLA_INFO_KIND, type, strlen(type));
+}
+
+static void netlink_add_device(struct nlmsg* nlmsg, int sock, const char* type,
+                               const char* name)
+{
+  netlink_add_device_impl(nlmsg, type, name);
+  netlink_done(nlmsg);
+  int err = netlink_send(nlmsg, sock);
+  (void)err;
+}
+
+static void netlink_add_veth(struct nlmsg* nlmsg, int sock, const char* name,
+                             const char* peer)
+{
+  netlink_add_device_impl(nlmsg, "veth", name);
+  netlink_nest(nlmsg, IFLA_INFO_DATA);
+  netlink_nest(nlmsg, VETH_INFO_PEER);
+  nlmsg->pos += sizeof(struct ifinfomsg);
+  netlink_attr(nlmsg, IFLA_IFNAME, peer, strlen(peer));
+  netlink_done(nlmsg);
+  netlink_done(nlmsg);
+  netlink_done(nlmsg);
+  int err = netlink_send(nlmsg, sock);
+  (void)err;
+}
+
+static void netlink_add_hsr(struct nlmsg* nlmsg, int sock, const char* name,
+                            const char* slave1, const char* slave2)
+{
+  netlink_add_device_impl(nlmsg, "hsr", name);
+  netlink_nest(nlmsg, IFLA_INFO_DATA);
+  int ifindex1 = if_nametoindex(slave1);
+  netlink_attr(nlmsg, IFLA_HSR_SLAVE1, &ifindex1, sizeof(ifindex1));
+  int ifindex2 = if_nametoindex(slave2);
+  netlink_attr(nlmsg, IFLA_HSR_SLAVE2, &ifindex2, sizeof(ifindex2));
+  netlink_done(nlmsg);
+  netlink_done(nlmsg);
+  int err = netlink_send(nlmsg, sock);
+  (void)err;
+}
+
+static void netlink_add_virt_wifi(struct nlmsg* nlmsg, int sock,
+                                  const char* name, const char* link)
+{
+  netlink_add_device_impl(nlmsg, "virt_wifi", name);
+  netlink_done(nlmsg);
+  int ifindex = if_nametoindex(link);
+  netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+  int err = netlink_send(nlmsg, sock);
+  (void)err;
+}
+
+static void netlink_add_vlan(struct nlmsg* nlmsg, int sock, const char* name,
+                             const char* link, uint16_t id, uint16_t proto)
+{
+  netlink_add_device_impl(nlmsg, "vlan", name);
+  netlink_nest(nlmsg, IFLA_INFO_DATA);
+  netlink_attr(nlmsg, IFLA_VLAN_ID, &id, sizeof(id));
+  netlink_attr(nlmsg, IFLA_VLAN_PROTOCOL, &proto, sizeof(proto));
+  netlink_done(nlmsg);
+  netlink_done(nlmsg);
+  int ifindex = if_nametoindex(link);
+  netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+  int err = netlink_send(nlmsg, sock);
+  (void)err;
+}
+
+static void netlink_add_macvlan(struct nlmsg* nlmsg, int sock, const char* name,
+                                const char* link)
+{
+  netlink_add_device_impl(nlmsg, "macvlan", name);
+  netlink_nest(nlmsg, IFLA_INFO_DATA);
+  uint32_t mode = MACVLAN_MODE_BRIDGE;
+  netlink_attr(nlmsg, IFLA_MACVLAN_MODE, &mode, sizeof(mode));
+  netlink_done(nlmsg);
+  netlink_done(nlmsg);
+  int ifindex = if_nametoindex(link);
+  netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+  int err = netlink_send(nlmsg, sock);
+  (void)err;
+}
+
+#define IFLA_IPVLAN_FLAGS 2
+#define IPVLAN_MODE_L3S 2
+#undef IPVLAN_F_VEPA
+#define IPVLAN_F_VEPA 2
+
+static void netlink_add_ipvlan(struct nlmsg* nlmsg, int sock, const char* name,
+                               const char* link, uint16_t mode, uint16_t flags)
+{
+  netlink_add_device_impl(nlmsg, "ipvlan", name);
+  netlink_nest(nlmsg, IFLA_INFO_DATA);
+  netlink_attr(nlmsg, IFLA_IPVLAN_MODE, &mode, sizeof(mode));
+  netlink_attr(nlmsg, IFLA_IPVLAN_FLAGS, &flags, sizeof(flags));
+  netlink_done(nlmsg);
+  netlink_done(nlmsg);
+  int ifindex = if_nametoindex(link);
+  netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+  int err = netlink_send(nlmsg, sock);
+  (void)err;
+}
+
+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);
+  (void)err;
+}
+
+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));
+  (void)err;
+}
+
+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));
+  (void)err;
+}
+
+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);
+  (void)err;
+}
+
+static int tunfd = -1;
+static int tun_frags_enabled;
+
+#define TUN_IFACE "syz_tun"
+
+#define LOCAL_MAC 0xaaaaaaaaaaaa
+#define REMOTE_MAC 0xaaaaaaaaaabb
+
+#define LOCAL_IPV4 "172.20.20.170"
+#define REMOTE_IPV4 "172.20.20.187"
+
+#define LOCAL_IPV6 "fe80::aa"
+#define REMOTE_IPV6 "fe80::bb"
+
+#define IFF_NAPI 0x0010
+#define IFF_NAPI_FRAGS 0x0020
+
+static void initialize_tun(void)
+{
+  tunfd = open("/dev/net/tun", O_RDWR | O_NONBLOCK);
+  if (tunfd == -1) {
+    printf("tun: can't open /dev/net/tun: please enable CONFIG_TUN=y\n");
+    printf("otherwise fuzzing or reproducing might not work as intended\n");
+    return;
+  }
+  const int kTunFd = 240;
+  if (dup2(tunfd, kTunFd) < 0)
+    exit(1);
+  close(tunfd);
+  tunfd = kTunFd;
+  struct ifreq ifr;
+  memset(&ifr, 0, sizeof(ifr));
+  strncpy(ifr.ifr_name, TUN_IFACE, IFNAMSIZ);
+  ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_NAPI | IFF_NAPI_FRAGS;
+  if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0) {
+    ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+    if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0)
+      exit(1);
+  }
+  if (ioctl(tunfd, TUNGETIFF, (void*)&ifr) < 0)
+    exit(1);
+  tun_frags_enabled = (ifr.ifr_flags & IFF_NAPI_FRAGS) != 0;
+  char sysctl[64];
+  sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/accept_dad", TUN_IFACE);
+  write_file(sysctl, "0");
+  sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/router_solicitations", TUN_IFACE);
+  write_file(sysctl, "0");
+  int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+  if (sock == -1)
+    exit(1);
+  netlink_add_addr4(&nlmsg, sock, TUN_IFACE, LOCAL_IPV4);
+  netlink_add_addr6(&nlmsg, sock, TUN_IFACE, LOCAL_IPV6);
+  uint64_t macaddr = REMOTE_MAC;
+  struct in_addr in_addr;
+  inet_pton(AF_INET, REMOTE_IPV4, &in_addr);
+  netlink_add_neigh(&nlmsg, sock, TUN_IFACE, &in_addr, sizeof(in_addr),
+                    &macaddr, ETH_ALEN);
+  struct in6_addr in6_addr;
+  inet_pton(AF_INET6, REMOTE_IPV6, &in6_addr);
+  netlink_add_neigh(&nlmsg, sock, TUN_IFACE, &in6_addr, sizeof(in6_addr),
+                    &macaddr, ETH_ALEN);
+  macaddr = LOCAL_MAC;
+  netlink_device_change(&nlmsg, sock, TUN_IFACE, true, 0, &macaddr, ETH_ALEN,
+                        NULL);
+  close(sock);
+}
+
+#define DEVLINK_FAMILY_NAME "devlink"
+
+#define DEVLINK_CMD_PORT_GET 5
+#define DEVLINK_ATTR_BUS_NAME 1
+#define DEVLINK_ATTR_DEV_NAME 2
+#define DEVLINK_ATTR_NETDEV_NAME 7
+
+static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock)
+{
+  struct genlmsghdr genlhdr;
+  struct nlattr* attr;
+  int err, n;
+  uint16_t id = 0;
+  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, DEVLINK_FAMILY_NAME,
+               strlen(DEVLINK_FAMILY_NAME) + 1);
+  err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n);
+  if (err) {
+    return -1;
+  }
+  attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
+                          NLMSG_ALIGN(sizeof(genlhdr)));
+  for (; (char*)attr < nlmsg->buf + n;
+       attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+    if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
+      id = *(uint16_t*)(attr + 1);
+      break;
+    }
+  }
+  if (!id) {
+    return -1;
+  }
+  recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */
+  return id;
+}
+
+static struct nlmsg nlmsg2;
+
+static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
+                                     const char* netdev_prefix)
+{
+  struct genlmsghdr genlhdr;
+  int len, total_len, id, err, offset;
+  uint16_t netdev_index;
+  int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+  if (sock == -1)
+    exit(1);
+  int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+  if (rtsock == -1)
+    exit(1);
+  id = netlink_devlink_id_get(&nlmsg, sock);
+  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);
+  if (err) {
+    goto error;
+  }
+  offset = 0;
+  netdev_index = 0;
+  while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
+    struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
+                                           NLMSG_ALIGN(sizeof(genlhdr)));
+    for (; (char*)attr < nlmsg.buf + offset + len;
+         attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
+      if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
+        char* port_name;
+        char netdev_name[IFNAMSIZ];
+        port_name = (char*)(attr + 1);
+        snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
+                 netdev_index);
+        netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
+                              netdev_name);
+        break;
+      }
+    }
+    offset += len;
+    netdev_index++;
+  }
+error:
+  close(rtsock);
+  close(sock);
+}
+
+#define DEV_IPV4 "172.20.20.%d"
+#define DEV_IPV6 "fe80::%02x"
+#define DEV_MAC 0x00aaaaaaaaaa
+
+static void netdevsim_add(unsigned int addr, unsigned int port_count)
+{
+  char buf[16];
+  sprintf(buf, "%u %u", addr, port_count);
+  if (write_file("/sys/bus/netdevsim/new_device", buf)) {
+    snprintf(buf, sizeof(buf), "netdevsim%d", addr);
+    initialize_devlink_ports("netdevsim", buf, "netdevsim");
+  }
+}
+static void initialize_netdevices(void)
+{
+  char netdevsim[16];
+  sprintf(netdevsim, "netdevsim%d", (int)procid);
+  struct {
+    const char* type;
+    const char* dev;
+  } devtypes[] = {
+      {"ip6gretap", "ip6gretap0"}, {"bridge", "bridge0"},
+      {"vcan", "vcan0"},           {"bond", "bond0"},
+      {"team", "team0"},           {"dummy", "dummy0"},
+      {"nlmon", "nlmon0"},         {"caif", "caif0"},
+      {"batadv", "batadv0"},       {"vxcan", "vxcan1"},
+      {"netdevsim", netdevsim},    {"veth", 0},
+      {"xfrm", "xfrm0"},
+  };
+  const char* devmasters[] = {"bridge", "bond", "team"};
+  struct {
+    const char* name;
+    int macsize;
+    bool noipv6;
+  } devices[] = {
+      {"lo", ETH_ALEN},
+      {"sit0", 0},
+      {"bridge0", ETH_ALEN},
+      {"vcan0", 0, true},
+      {"tunl0", 0},
+      {"gre0", 0},
+      {"gretap0", ETH_ALEN},
+      {"ip_vti0", 0},
+      {"ip6_vti0", 0},
+      {"ip6tnl0", 0},
+      {"ip6gre0", 0},
+      {"ip6gretap0", ETH_ALEN},
+      {"erspan0", ETH_ALEN},
+      {"bond0", ETH_ALEN},
+      {"veth0", ETH_ALEN},
+      {"veth1", ETH_ALEN},
+      {"team0", ETH_ALEN},
+      {"veth0_to_bridge", ETH_ALEN},
+      {"veth1_to_bridge", ETH_ALEN},
+      {"veth0_to_bond", ETH_ALEN},
+      {"veth1_to_bond", ETH_ALEN},
+      {"veth0_to_team", ETH_ALEN},
+      {"veth1_to_team", ETH_ALEN},
+      {"veth0_to_hsr", ETH_ALEN},
+      {"veth1_to_hsr", ETH_ALEN},
+      {"hsr0", 0},
+      {"dummy0", ETH_ALEN},
+      {"nlmon0", 0},
+      {"vxcan0", 0, true},
+      {"vxcan1", 0, true},
+      {"caif0", ETH_ALEN},
+      {"batadv0", ETH_ALEN},
+      {netdevsim, ETH_ALEN},
+      {"xfrm0", ETH_ALEN},
+      {"veth0_virt_wifi", ETH_ALEN},
+      {"veth1_virt_wifi", ETH_ALEN},
+      {"virt_wifi0", ETH_ALEN},
+      {"veth0_vlan", ETH_ALEN},
+      {"veth1_vlan", ETH_ALEN},
+      {"vlan0", ETH_ALEN},
+      {"vlan1", ETH_ALEN},
+      {"macvlan0", ETH_ALEN},
+      {"macvlan1", ETH_ALEN},
+      {"ipvlan0", ETH_ALEN},
+      {"ipvlan1", ETH_ALEN},
+  };
+  int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+  if (sock == -1)
+    exit(1);
+  unsigned i;
+  for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++)
+    netlink_add_device(&nlmsg, sock, devtypes[i].type, devtypes[i].dev);
+  for (i = 0; i < sizeof(devmasters) / (sizeof(devmasters[0])); i++) {
+    char master[32], slave0[32], veth0[32], slave1[32], veth1[32];
+    sprintf(slave0, "%s_slave_0", devmasters[i]);
+    sprintf(veth0, "veth0_to_%s", devmasters[i]);
+    netlink_add_veth(&nlmsg, sock, slave0, veth0);
+    sprintf(slave1, "%s_slave_1", devmasters[i]);
+    sprintf(veth1, "veth1_to_%s", devmasters[i]);
+    netlink_add_veth(&nlmsg, sock, slave1, veth1);
+    sprintf(master, "%s0", devmasters[i]);
+    netlink_device_change(&nlmsg, sock, slave0, false, master, 0, 0, NULL);
+    netlink_device_change(&nlmsg, sock, slave1, false, master, 0, 0, NULL);
+  }
+  netlink_device_change(&nlmsg, sock, "bridge_slave_0", true, 0, 0, 0, NULL);
+  netlink_device_change(&nlmsg, sock, "bridge_slave_1", true, 0, 0, 0, NULL);
+  netlink_add_veth(&nlmsg, sock, "hsr_slave_0", "veth0_to_hsr");
+  netlink_add_veth(&nlmsg, sock, "hsr_slave_1", "veth1_to_hsr");
+  netlink_add_hsr(&nlmsg, sock, "hsr0", "hsr_slave_0", "hsr_slave_1");
+  netlink_device_change(&nlmsg, sock, "hsr_slave_0", true, 0, 0, 0, NULL);
+  netlink_device_change(&nlmsg, sock, "hsr_slave_1", true, 0, 0, 0, NULL);
+  netlink_add_veth(&nlmsg, sock, "veth0_virt_wifi", "veth1_virt_wifi");
+  netlink_add_virt_wifi(&nlmsg, sock, "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);
+  netdevsim_add((int)procid, 4);
+  for (i = 0; i < sizeof(devices) / (sizeof(devices[0])); i++) {
+    char addr[32];
+    sprintf(addr, DEV_IPV4, i + 10);
+    netlink_add_addr4(&nlmsg, sock, devices[i].name, addr);
+    if (!devices[i].noipv6) {
+      sprintf(addr, DEV_IPV6, i + 10);
+      netlink_add_addr6(&nlmsg, sock, devices[i].name, addr);
+    }
+    uint64_t macaddr = DEV_MAC + ((i + 10ull) << 40);
+    netlink_device_change(&nlmsg, sock, devices[i].name, true, 0, &macaddr,
+                          devices[i].macsize, NULL);
+  }
+  close(sock);
+}
+static void initialize_netdevices_init(void)
+{
+  int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+  if (sock == -1)
+    exit(1);
+  struct {
+    const char* type;
+    int macsize;
+    bool noipv6;
+    bool noup;
+  } devtypes[] = {
+      {"nr", 7, true}, {"rose", 5, true, true},
<