linux: add 170 new repros from syzbot

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
index a3af5e7..5e79972 100644
--- a/syzkaller-repros/linux/.gitignore
+++ b/syzkaller-repros/linux/.gitignore
@@ -1,2 +1,3 @@
 *.norepro
 *.syz
+*.error
diff --git a/syzkaller-repros/linux/00fadf9a6326e13098672b601d57f644cae380e9.c b/syzkaller-repros/linux/00fadf9a6326e13098672b601d57f644cae380e9.c
new file mode 100644
index 0000000..f5c2471
--- /dev/null
+++ b/syzkaller-repros/linux/00fadf9a6326e13098672b601d57f644cae380e9.c
@@ -0,0 +1,262 @@
+// possible deadlock in xt_find_table_lock
+// https://syzkaller.appspot.com/bug?id=00fadf9a6326e13098672b601d57f644cae380e9
+// 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>
+
+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;
+}
+
+#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))))
+
+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, 0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_one(void)
+{
+  intptr_t res = 0;
+  res = syscall(__NR_socket, 0xaul, 2ul, 0ul);
+  if (res != -1)
+    r[0] = res;
+  memcpy(
+      (void*)0x20000180,
+      "\x66\x69\x6c\x74\x65\x72\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00\x00\x00"
+      "\x04\x00\x00\x00\xd8\x03\x00\x00\x18\x02\x00\x00\x00\x00\x00\x00\x00\x00"
+      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x03\x00\x00\x08\x03\x00\x00"
+      "\x08\x03\x00\x00\x08\x03\x00\x00\x08\x03\x00\x00\x04\x00\x00\x00\x00\x00"
+      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff"
+      "\xac\x14\x14\xaa\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xe0\x00"
+      "\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x69\x70"
+      "\x64\x64\x70\x30\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x73\x69\x74\x30"
+      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+      "\x00\x00\x00\x01\x48\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x30\x00\x72\x65\x61\x6c"
+      "\x6d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+      "\x00\x00\x00\x00\x00\x00\x28\x00\x61\x64\x64\x72\x74\x79\x70\x65\x00\x00"
+      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+      "\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x48\x00\x54\x45\x45\x00\x00\x00"
+      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+      "\x00\x00\x00\x00\x00\x01\xfe\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+      "\x00\x00\x00\xbb\x69\x70\x36\x65\x72\x73\x70\x61\x6e\x30\x00\x00\x00\x00"
+      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+      "\x00\x00\x00\x1b\xde\x5b\x2c\xe4\x43\xe9\x1f\x00\x00\x00\x00\x00\x00\x00"
+      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x21\x00"
+      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+      "\x00\x00\x00\x00\x00\x00\xa8\x00\xd0\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x28\x00"
+      "\x52\x45\x4a\x45\x43\x54\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x47\x00\x00\x00\x00\x00"
+      "\x00\x00\xff\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"
+      "\xfe\x88\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00"
+      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x6c\x61\x70\x62\x30\x00"
+      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x74\x78\x63\x61\x00\x00\x00\x00"
+      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa8\x00"
+      "\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00"
+      "\x00\x00\x00\x00\x00\x00\x00\x00\x48\x00\x54\x45\x45\x00\x00\x00\x00\x00"
+      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+      "\x00\x00\x00\x01\xac\x1e\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+      "\x00\x00\x00\x00\x00\x16\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+      "\x00\x00\x00\x00\xa8\x00\xd0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x28\x00\x00\x00"
+      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfe\xff\xff\xff",
+      1076);
+  syscall(__NR_setsockopt, r[0], 0x29ul, 0x40ul, 0x20000180ul, 1ul);
+  memcpy((void*)0x20000000, "/dev/net/tun\000", 13);
+  res =
+      syscall(__NR_openat, 0xffffffffffffff9cul, 0x20000000ul, 0x88042ul, 0ul);
+  if (res != -1)
+    r[1] = res;
+  memcpy((void*)0x200000c0, "syzkaller1\000\000\000\000\000\000", 16);
+  *(uint16_t*)0x200000d0 = 1;
+  syscall(__NR_ioctl, r[1], 0x400454caul, 0x200000c0ul);
+  res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul);
+  if (res != -1)
+    r[2] = res;
+  *(uint64_t*)0x20000240 = 0;
+  *(uint32_t*)0x20000248 = 0;
+  *(uint64_t*)0x20000250 = 0x20000080;
+  *(uint64_t*)0x20000080 = 0x200000c0;
+  *(uint32_t*)0x200000c0 = 0x2c;
+  *(uint8_t*)0x200000c4 = 0;
+  *(uint8_t*)0x200000c5 = 0xb;
+  *(uint16_t*)0x200000c6 = 0xf7d7;
+  *(uint32_t*)0x200000c8 = 0;
+  *(uint32_t*)0x200000cc = 0;
+  *(uint8_t*)0x200000d0 = 3;
+  *(uint8_t*)0x200000d1 = 0;
+  *(uint16_t*)0x200000d2 = htobe16(0);
+  *(uint16_t*)0x200000d4 = 8;
+  STORE_BY_BITMASK(uint16_t, , 0x200000d6, 2, 0, 14);
+  STORE_BY_BITMASK(uint16_t, , 0x200000d7, 1, 6, 1);
+  STORE_BY_BITMASK(uint16_t, , 0x200000d7, 0, 7, 1);
+  *(uint32_t*)0x200000d8 = htobe32(0);
+  *(uint16_t*)0x200000dc = 5;
+  *(uint16_t*)0x200000de = 1;
+  memcpy((void*)0x200000e0, "\000", 1);
+  *(uint16_t*)0x200000e4 = 8;
+  STORE_BY_BITMASK(uint16_t, , 0x200000e6, 3, 0, 14);
+  STORE_BY_BITMASK(uint16_t, , 0x200000e7, 1, 6, 1);
+  STORE_BY_BITMASK(uint16_t, , 0x200000e7, 0, 7, 1);
+  *(uint32_t*)0x200000e8 = htobe32(0);
+  *(uint64_t*)0x20000088 = 0x2c;
+  *(uint64_t*)0x20000258 = 1;
+  *(uint64_t*)0x20000260 = 0;
+  *(uint64_t*)0x20000268 = 0;
+  *(uint32_t*)0x20000270 = 0;
+  syscall(__NR_sendmsg, r[2], 0x20000240ul, 0ul);
+}
+int main(void)
+{
+  syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+  loop();
+  return 0;
+}
diff --git a/syzkaller-repros/linux/0233e754c626ef23e643a4d9e0d0580c3a43d866.c b/syzkaller-repros/linux/0233e754c626ef23e643a4d9e0d0580c3a43d866.c
new file mode 100644
index 0000000..f800150
--- /dev/null
+++ b/syzkaller-repros/linux/0233e754c626ef23e643a4d9e0d0580c3a43d866.c
@@ -0,0 +1,389 @@
+// memory leak in kcm_sendmsg
+// https://syzkaller.appspot.com/bug?id=0233e754c626ef23e643a4d9e0d0580c3a43d866
+// 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");
+}
+
+#define KMEMLEAK_FILE "/sys/kernel/debug/kmemleak"
+
+static void setup_leak()
+{
+  if (!write_file(KMEMLEAK_FILE, "scan"))
+    exit(1);
+  sleep(5);
+  if (!write_file(KMEMLEAK_FILE, "scan"))
+    exit(1);
+  if (!write_file(KMEMLEAK_FILE, "clear"))
+    exit(1);
+}
+
+static void check_leaks(void)
+{
+  int fd = open(KMEMLEAK_FILE, O_RDWR);
+  if (fd == -1)
+    exit(1);
+  uint64_t start = current_time_ms();
+  if (write(fd, "scan", 4) != 4)
+    exit(1);
+  sleep(1);
+  while (current_time_ms() - start < 4 * 1000)
+    sleep(1);
+  if (write(fd, "scan", 4) != 4)
+    exit(1);
+  static char buf[128 << 10];
+  ssize_t n = read(fd, buf, sizeof(buf) - 1);
+  if (n < 0)
+    exit(1);
+  int nleaks = 0;
+  if (n != 0) {
+    sleep(1);
+    if (write(fd, "scan", 4) != 4)
+      exit(1);
+    if (lseek(fd, 0, SEEK_SET) < 0)
+      exit(1);
+    n = read(fd, buf, sizeof(buf) - 1);
+    if (n < 0)
+      exit(1);
+    buf[n] = 0;
+    char* pos = buf;
+    char* end = buf + n;
+    while (pos < end) {
+      char* next = strstr(pos + 1, "unreferenced object");
+      if (!next)
+        next = end;
+      char prev = *next;
+      *next = 0;
+      fprintf(stderr, "BUG: memory leak\n%s\n", pos);
+      *next = prev;
+      pos = next;
+      nleaks++;
+    }
+  }
+  if (write(fd, "clear", 5) != 5)
+    exit(1);
+  close(fd);
+  if (nleaks)
+    exit(1);
+}
+
+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 < 7; 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;
+    }
+    check_leaks();
+  }
+}
+
+uint64_t r[4] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff,
+                 0xffffffffffffffff};
+
+void execute_call(int call)
+{
+  intptr_t res;
+  switch (call) {
+  case 0:
+    res = syscall(__NR_pipe, 0x200000c0ul);
+    if (res != -1) {
+      r[0] = *(uint32_t*)0x200000c0;
+      r[1] = *(uint32_t*)0x200000c4;
+    }
+    break;
+  case 1:
+    res = syscall(__NR_socket, 2ul, 2ul, 0ul);
+    if (res != -1)
+      r[2] = res;
+    break;
+  case 2:
+    syscall(__NR_close, r[2]);
+    break;
+  case 3:
+    res = syscall(__NR_socket, 0x29ul, 0x1000000000002ul, 0ul);
+    if (res != -1)
+      r[3] = res;
+    break;
+  case 4:
+    *(uint64_t*)0x20001bc0 = 0;
+    *(uint32_t*)0x20001bc8 = 0;
+    *(uint64_t*)0x20001bd0 = 0x20000180;
+    *(uint64_t*)0x20000180 = 0x20000040;
+    memcpy((void*)0x20000040, "\xb7", 1);
+    *(uint64_t*)0x20000188 = 0x100000;
+    *(uint64_t*)0x20001bd8 = 1;
+    *(uint64_t*)0x20001be0 = 0;
+    *(uint64_t*)0x20001be8 = 0;
+    *(uint32_t*)0x20001bf0 = 3;
+    *(uint32_t*)0x20001bf8 = 0;
+    *(uint64_t*)0x20001c00 = 0;
+    *(uint32_t*)0x20001c08 = 0;
+    *(uint64_t*)0x20001c10 = 0x200008c0;
+    *(uint64_t*)0x200008c0 = 0x20000540;
+    memcpy((void*)0x20000540, "Z", 1);
+    *(uint64_t*)0x200008c8 = 0x20100040;
+    *(uint64_t*)0x20001c18 = 1;
+    *(uint64_t*)0x20001c20 = 0;
+    *(uint64_t*)0x20001c28 = 0;
+    *(uint32_t*)0x20001c30 = 0;
+    *(uint32_t*)0x20001c38 = 0;
+    syscall(__NR_sendmmsg, r[3], 0x20001bc0ul, 0x729ul, 0xe803ul);
+    break;
+  case 5:
+    syscall(__NR_write, r[1], 0x20000140ul, 0x4240a2a0ul);
+    break;
+  case 6:
+    syscall(__NR_splice, r[0], 0ul, r[2], 0ul, 0x10005ul, 0ul);
+    break;
+  }
+}
+int main(void)
+{
+  syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+  setup_leak();
+  loop();
+  return 0;
+}
diff --git a/syzkaller-repros/linux/02d741673f1c6fff5867683ba98f91e01ac800ee.c b/syzkaller-repros/linux/02d741673f1c6fff5867683ba98f91e01ac800ee.c
new file mode 100644
index 0000000..95503ec
--- /dev/null
+++ b/syzkaller-repros/linux/02d741673f1c6fff5867683ba98f91e01ac800ee.c
@@ -0,0 +1,972 @@
+// panic: invalid allocation length: 0x0 (3)
+// https://syzkaller.appspot.com/bug?id=02d741673f1c6fff5867683ba98f91e01ac800ee
+// 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 <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 <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 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;
+}
+
+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_linked(struct nlmsg* nlmsg, int sock, const char* type,
+                               const char* name, const char* link)
+{
+  netlink_add_device_impl(nlmsg, type, name);
+  netlink_done(nlmsg);
+  int ifindex = if_nametoindex(link);
+  netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+  int err = netlink_send(nlmsg, sock);
+  (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;
+}
+
+static void netlink_add_geneve(struct nlmsg* nlmsg, int sock, const char* name,
+                               uint32_t vni, struct in_addr* addr4,
+                               struct in6_addr* addr6)
+{
+  netlink_add_device_impl(nlmsg, "geneve", name);
+  netlink_nest(nlmsg, IFLA_INFO_DATA);
+  netlink_attr(nlmsg, IFLA_GENEVE_ID, &vni, sizeof(vni));
+  if (addr4)
+    netlink_attr(nlmsg, IFLA_GENEVE_REMOTE, addr4, sizeof(*addr4));
+  if (addr6)
+    netlink_attr(nlmsg, IFLA_GENEVE_REMOTE6, addr6, sizeof(*addr6));
+  netlink_done(nlmsg);
+  netlink_done(nlmsg);
+  int err = netlink_send(nlmsg, sock);
+  (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);
+}
+
+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},
+      {"xfrm", "xfrm0"},
+  };
+  const char* devmasters[] = {"bridge", "bond", "team", "batadv"};
+  struct {
+    const char* name;
+    int macsize;
+    bool noipv6;
+  } devices[] = {
+      {"lo", ETH_ALEN},
+      {"sit0", 0},
+      {"bridge0", ETH_ALEN},
+      {"vcan0", 0, true},
+      {"tunl0", 0},
+      {"gre0", 0},
+      {"gretap0", ETH_ALEN},
+      {"ip_vti0", 0},
+      {"ip6_vti0", 0},
+      {"ip6tnl0", 0},
+      {"ip6gre0", 0},
+      {"ip6gretap0", ETH_ALEN},
+      {"erspan0", ETH_ALEN},
+      {"bond0", ETH_ALEN},
+      {"veth0", ETH_ALEN},
+      {"veth1", ETH_ALEN},
+      {"team0", ETH_ALEN},
+      {"veth0_to_bridge", ETH_ALEN},
+      {"veth1_to_bridge", ETH_ALEN},
+      {"veth0_to_bond", ETH_ALEN},
+      {"veth1_to_bond", ETH_ALEN},
+      {"veth0_to_team", ETH_ALEN},
+      {"veth1_to_team", ETH_ALEN},
+      {"veth0_to_hsr", ETH_ALEN},
+      {"veth1_to_hsr", ETH_ALEN},
+      {"hsr0", 0},
+      {"dummy0", ETH_ALEN},
+      {"nlmon0", 0},
+      {"vxcan0", 0, true},
+      {"vxcan1", 0, true},
+      {"caif0", ETH_ALEN},
+      {"batadv0", ETH_ALEN},
+      {netdevsim, ETH_ALEN},
+      {"xfrm0", ETH_ALEN},
+      {"veth0_virt_wifi", ETH_ALEN},
+      {"veth1_virt_wifi", ETH_ALEN},
+      {"virt_wifi0", ETH_ALEN},
+      {"veth0_vlan", ETH_ALEN},
+      {"veth1_vlan", ETH_ALEN},
+      {"vlan0", ETH_ALEN},
+      {"vlan1", ETH_ALEN},
+      {"macvlan0", ETH_ALEN},
+      {"macvlan1", ETH_ALEN},
+      {"ipvlan0", ETH_ALEN},
+      {"ipvlan1", ETH_ALEN},
+      {"veth0_macvtap", ETH_ALEN},
+      {"veth1_macvtap", ETH_ALEN},
+      {"macvtap0", ETH_ALEN},
+      {"macsec0", ETH_ALEN},
+      {"veth0_to_batadv", ETH_ALEN},
+      {"veth1_to_batadv", ETH_ALEN},
+      {"batadv_slave_0", ETH_ALEN},
+      {"batadv_slave_1", ETH_ALEN},
+      {"geneve0", ETH_ALEN},
+      {"geneve1", ETH_ALEN},
+  };
+  int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+  if (sock == -1)
+    exit(1);
+  unsigned i;
+  for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++)
+    netlink_add_device(&nlmsg, sock, devtypes[i].type, devtypes[i].dev);
+  for (i = 0; i < sizeof(devmasters) / (sizeof(devmasters[0])); i++) {
+    char master[32], slave0[32], veth0[32], slave1[32], veth1[32];
+    sprintf(slave0, "%s_slave_0", devmasters[i]);
+    sprintf(veth0, "veth0_to_%s", devmasters[i]);
+    netlink_add_veth(&nlmsg, sock, slave0, veth0);
+    sprintf(slave1, "%s_slave_1", devmasters[i]);
+    sprintf(veth1, "veth1_to_%s", devmasters[i]);
+    netlink_add_veth(&nlmsg, sock, slave1, veth1);
+    sprintf(master, "%s0", devmasters[i]);
+    netlink_device_change(&nlmsg, sock, slave0, false, master, 0, 0, NULL);
+    netlink_device_change(&nlmsg, sock, slave1, false, master, 0, 0, NULL);
+  }
+  netlink_device_change(&nlmsg, sock, "bridge_slave_0", true, 0, 0, 0, NULL);
+  netlink_device_change(&nlmsg, sock, "bridge_slave_1", true, 0, 0, 0, NULL);
+  netlink_add_veth(&nlmsg, sock, "hsr_slave_0", "veth0_to_hsr");
+  netlink_add_veth(&nlmsg, sock, "hsr_slave_1", "veth1_to_hsr");
+  netlink_add_hsr(&nlmsg, sock, "hsr0", "hsr_slave_0", "hsr_slave_1");
+  netlink_device_change(&nlmsg, sock, "hsr_slave_0", true, 0, 0, 0, NULL);
+  netlink_device_change(&nlmsg, sock, "hsr_slave_1", true, 0, 0, 0, NULL);
+  netlink_add_veth(&nlmsg, sock, "veth0_virt_wifi", "veth1_virt_wifi");
+  netlink_add_linked(&nlmsg, sock, "virt_wifi", "virt_wifi0",
+                     "veth1_virt_wifi");
+  netlink_add_veth(&nlmsg, sock, "veth0_vlan", "veth1_vlan");
+  netlink_add_vlan(&nlmsg, sock, "vlan0", "veth0_vlan", 0, htons(ETH_P_8021Q));
+  netlink_add_vlan(&nlmsg, sock, "vlan1", "veth0_vlan", 1, htons(ETH_P_8021AD));
+  netlink_add_macvlan(&nlmsg, sock, "macvlan0", "veth1_vlan");
+  netlink_add_macvlan(&nlmsg, sock, "macvlan1", "veth1_vlan");
+  netlink_add_ipvlan(&nlmsg, sock, "ipvlan0", "veth0_vlan", IPVLAN_MODE_L2, 0);
+  netlink_add_ipvlan(&nlmsg, sock, "ipvlan1", "veth0_vlan", IPVLAN_MODE_L3S,
+                     IPVLAN_F_VEPA);
+  netlink_add_veth(&nlmsg, sock, "veth0_macvtap", "veth1_macvtap");
+  netlink_add_linked(&nlmsg, sock, "macvtap", "macvtap0", "veth0_macvtap");
+  netlink_add_linked(&nlmsg, sock, "macsec", "macsec0", "veth1_macvtap");
+  char addr[32];
+  sprintf(addr, DEV_IPV4, 14 + 10);
+  struct in_addr geneve_addr4;
+  if (inet_pton(AF_INET, addr, &geneve_addr4) <= 0)
+    exit(1);
+  struct in6_addr geneve_addr6;
+  if (inet_pton(AF_INET6, "fc00::01", &geneve_addr6) <= 0)
+    exit(1);
+  netlink_add_geneve(&nlmsg, sock, "geneve0", 0, &geneve_addr4, 0);
+  netlink_add_geneve(&nlmsg, sock, "geneve1", 1, 0, &geneve_addr6);
+  netdevsim_add((int)procid, 4);
+  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 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_tun();
+  initialize_netdevices();
+  loop();
+  exit(1);
+}
+
+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");
+}
+
+#ifndef __NR_memfd_create
+#define __NR_memfd_create 319
+#endif
+
+uint64_t r[3] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff};
+
+void loop(void)
+{
+  intptr_t res = 0;
+  res = syscall(__NR_pipe, 0x20000440ul);
+  if (res != -1) {
+    NONFAILING(r[0] = *(uint32_t*)0x20000440);
+    NONFAILING(r[1] = *(uint32_t*)0x20000444);
+  }
+  NONFAILING(memcpy((void*)0x20000040, "/dev/auts\000", 10));
+  res = syscall(__NR_memfd_create, 0x20000040ul, 0ul);
+  if (res != -1)
+    r[2] = res;
+  NONFAILING(
+      memcpy((void*)0x20000000,
+             "\xfc\xbc\x79\xd9\x61\x87\xd3\x9b\x45\x4e\x37\x43\x6e\xd8\xd2\xc4"
+             "\x15\x40\xaf\x4d\x23\xbb\xce\xb6\x08\x6f\x40\x30\xc6\xc2\x73\x47"
+             "\xca\x78\xf6\x33\x59\xd9\xdc\x78\xd2\xca\x7b\x99\x9c\xd1\xac\xf9",
+             48));
+  syscall(__NR_write, r[1], 0x20000000ul, 0x30ul);
+  NONFAILING(*(uint64_t*)0x20000100 = 0xfffffffffffffffe);
+  syscall(__NR_splice, r[0], 0ul, r[2], 0x20000100ul, 7ul, 2ul);
+  close_fds();
+}
+int main(void)
+{
+  syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+  setup_binfmt_misc();
+  install_segv_handler();
+  use_temporary_dir();
+  do_sandbox_none();
+  return 0;
+}
diff --git a/syzkaller-repros/linux/033798263dc264e8df440efc73c0fb17c541d19a.c b/syzkaller-repros/linux/033798263dc264e8df440efc73c0fb17c541d19a.c
new file mode 100644
index 0000000..1501a4a
--- /dev/null
+++ b/syzkaller-repros/linux/033798263dc264e8df440efc73c0fb17c541d19a.c
@@ -0,0 +1,211 @@
+// possible deadlock in bpf_lru_push_free
+// https://syzkaller.appspot.com/bug?id=033798263dc264e8df440efc73c0fb17c541d19a
+// 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 <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/capability.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;
+}
+
+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 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)
+{
+  int pid = fork();
+  if (pid != 0)
+    return wait_for_loop(pid);
+  setup_common();
+  sandbox_common();
+  drop_caps();
+  if (unshare(CLONE_NEWNET)) {
+  }
+  loop();
+  exit(1);
+}
+
+#ifndef __NR_bpf
+#define __NR_bpf 321
+#endif
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void loop(void)
+{
+  intptr_t res = 0;
+  *(uint32_t*)0x20000140 = 0xa;
+  *(uint32_t*)0x20000144 = 3;
+  *(uint32_t*)0x20000148 = 0x6c0d;
+  *(uint32_t*)0x2000014c = 1;
+  *(uint32_t*)0x20000150 = 2;
+  *(uint32_t*)0x20000154 = -1;
+  *(uint32_t*)0x20000158 = 0;
+  *(uint8_t*)0x2000015c = 0;
+  *(uint8_t*)0x2000015d = 0;
+  *(uint8_t*)0x2000015e = 0;
+  *(uint8_t*)0x2000015f = 0;
+  *(uint8_t*)0x20000160 = 0;
+  *(uint8_t*)0x20000161 = 0;
+  *(uint8_t*)0x20000162 = 0;
+  *(uint8_t*)0x20000163 = 0;
+  *(uint8_t*)0x20000164 = 0;
+  *(uint8_t*)0x20000165 = 0;
+  *(uint8_t*)0x20000166 = 0;
+  *(uint8_t*)0x20000167 = 0;
+  *(uint8_t*)0x20000168 = 0;
+  *(uint8_t*)0x20000169 = 0;
+  *(uint8_t*)0x2000016a = 0;
+  *(uint8_t*)0x2000016b = 0;
+  *(uint32_t*)0x2000016c = 0;
+  *(uint32_t*)0x20000170 = -1;
+  *(uint32_t*)0x20000174 = 0;
+  *(uint32_t*)0x20000178 = 0;
+  *(uint32_t*)0x2000017c = 0;
+  res = syscall(__NR_bpf, 0ul, 0x20000140ul, 0x3cul);
+  if (res != -1)
+    r[0] = res;
+  *(uint32_t*)0x20000180 = r[0];
+  *(uint64_t*)0x20000188 = 0x20000000;
+  *(uint64_t*)0x20000190 = 0x20000080;
+  *(uint64_t*)0x20000198 = 0;
+  syscall(__NR_bpf, 2ul, 0x20000180ul, 0x20ul);
+  *(uint32_t*)0x20000340 = r[0];
+  *(uint64_t*)0x20000348 = 0x20000300;
+  *(uint64_t*)0x20000350 = 0x20000340;
+  *(uint64_t*)0x20000358 = 0;
+  syscall(__NR_bpf, 2ul, 0x20000340ul, 0x20ul);
+  *(uint64_t*)0x20000100 = 0;
+  *(uint64_t*)0x20000108 = 0;
+  *(uint64_t*)0x20000110 = 0;
+  *(uint64_t*)0x20000118 = 0;
+  *(uint32_t*)0x20000120 = 0x101;
+  *(uint32_t*)0x20000124 = r[0];
+  *(uint64_t*)0x20000128 = 0;
+  *(uint64_t*)0x20000130 = 0;
+  syscall(__NR_bpf, 0x19ul, 0x20000100ul, 0x38ul);
+}
+int main(void)
+{
+  syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+  do_sandbox_none();
+  return 0;
+}
diff --git a/syzkaller-repros/linux/067b1e60bab1b617c1208f078cd76c9087f070e0.c b/syzkaller-repros/linux/067b1e60bab1b617c1208f078cd76c9087f070e0.c
new file mode 100644
index 0000000..3858ac9
--- /dev/null
+++ b/syzkaller-repros/linux/067b1e60bab1b617c1208f078cd76c9087f070e0.c
@@ -0,0 +1,1358 @@
+// BUG: corrupted list in _cma_attach_to_dev
+// https://syzkaller.appspot.com/bug?id=067b1e60bab1b617c1208f078cd76c9087f070e0
+// 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, 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 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_linked(struct nlmsg* nlmsg, int sock, const char* type,
+                               const char* name, const char* link)
+{
+  netlink_add_device_impl(nlmsg, type, name);
+  netlink_done(nlmsg);
+  int ifindex = if_nametoindex(link);
+  netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+  int err = netlink_send(nlmsg, sock);
+  (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;
+}
+
+static void netlink_add_geneve(struct nlmsg* nlmsg, int sock, const char* name,
+                               uint32_t vni, struct in_addr* addr4,
+                               struct in6_addr* addr6)
+{
+  netlink_add_device_impl(nlmsg, "geneve", name);
+  netlink_nest(nlmsg, IFLA_INFO_DATA);
+  netlink_attr(nlmsg, IFLA_GENEVE_ID, &vni, sizeof(vni));
+  if (addr4)
+    netlink_attr(nlmsg, IFLA_GENEVE_REMOTE, addr4, sizeof(*addr4));
+  if (addr6)
+    netlink_attr(nlmsg, IFLA_GENEVE_REMOTE6, addr6, sizeof(*addr6));
+  netlink_done(nlmsg);
+  netlink_done(nlmsg);
+  int err = netlink_send(nlmsg, sock);
+  (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;
+}
+
+#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");
+  }
+}
+
+#define WG_GENL_NAME "wireguard"
+enum wg_cmd {
+  WG_CMD_GET_DEVICE,
+  WG_CMD_SET_DEVICE,
+};
+enum wgdevice_attribute {
+  WGDEVICE_A_UNSPEC,
+  WGDEVICE_A_IFINDEX,
+  WGDEVICE_A_IFNAME,
+  WGDEVICE_A_PRIVATE_KEY,
+  WGDEVICE_A_PUBLIC_KEY,
+  WGDEVICE_A_FLAGS,
+  WGDEVICE_A_LISTEN_PORT,
+  WGDEVICE_A_FWMARK,
+  WGDEVICE_A_PEERS,
+};
+enum wgpeer_attribute {
+  WGPEER_A_UNSPEC,
+  WGPEER_A_PUBLIC_KEY,
+  WGPEER_A_PRESHARED_KEY,
+  WGPEER_A_FLAGS,
+  WGPEER_A_ENDPOINT,
+  WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+  WGPEER_A_LAST_HANDSHAKE_TIME,
+  WGPEER_A_RX_BYTES,
+  WGPEER_A_TX_BYTES,
+  WGPEER_A_ALLOWEDIPS,
+  WGPEER_A_PROTOCOL_VERSION,
+};
+enum wgallowedip_attribute {
+  WGALLOWEDIP_A_UNSPEC,
+  WGALLOWEDIP_A_FAMILY,
+  WGALLOWEDIP_A_IPADDR,
+  WGALLOWEDIP_A_CIDR_MASK,
+};
+
+static int netlink_wireguard_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, WG_GENL_NAME,
+               strlen(WG_GENL_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_wireguard_setup(void)
+{
+  const char ifname_a[] = "wg0";
+  const char ifname_b[] = "wg1";
+  const char ifname_c[] = "wg2";
+  const char private_a[] = "\xa0\x5c\xa8\x4f\x6c\x9c\x8e\x38\x53\xe2\xfd\x7a"
+                           "\x70\xae\x0f\xb2\x0f\xa1\x52\x60\x0c\xb0\x08\x45"
+                           "\x17\x4f\x08\x07\x6f\x8d\x78\x43";
+  const char private_b[] = "\xb0\x80\x73\xe8\xd4\x4e\x91\xe3\xda\x92\x2c\x22"
+                           "\x43\x82\x44\xbb\x88\x5c\x69\xe2\x69\xc8\xe9\xd8"
+                           "\x35\xb1\x14\x29\x3a\x4d\xdc\x6e";
+  const char private_c[] = "\xa0\xcb\x87\x9a\x47\xf5\xbc\x64\x4c\x0e\x69\x3f"
+                           "\xa6\xd0\x31\xc7\x4a\x15\x53\xb6\xe9\x01\xb9\xff"
+                           "\x2f\x51\x8c\x78\x04\x2f\xb5\x42";
+  const char public_a[] = "\x97\x5c\x9d\x81\xc9\x83\xc8\x20\x9e\xe7\x81\x25\x4b"
+                          "\x89\x9f\x8e\xd9\x25\xae\x9f\x09\x23\xc2\x3c\x62\xf5"
+                          "\x3c\x57\xcd\xbf\x69\x1c";
+  const char public_b[] = "\xd1\x73\x28\x99\xf6\x11\xcd\x89\x94\x03\x4d\x7f\x41"
+                          "\x3d\xc9\x57\x63\x0e\x54\x93\xc2\x85\xac\xa4\x00\x65"
+                          "\xcb\x63\x11\xbe\x69\x6b";
+  const char public_c[] = "\xf4\x4d\xa3\x67\xa8\x8e\xe6\x56\x4f\x02\x02\x11\x45"
+                          "\x67\x27\x08\x2f\x5c\xeb\xee\x8b\x1b\xf5\xeb\x73\x37"
+                          "\x34\x1b\x45\x9b\x39\x22";
+  const uint16_t listen_a = 20001;
+  const uint16_t listen_b = 20002;
+  const uint16_t listen_c = 20003;
+  const uint16_t af_inet = AF_INET;
+  const uint16_t af_inet6 = AF_INET6;
+  /* Unused, but useful in case we change this:
+  const struct sockaddr_in endpoint_a_v4 = {
+      .sin_family = AF_INET,
+      .sin_port = htons(listen_a),
+      .sin_addr = {htonl(INADDR_LOOPBACK)}};*/
+  const struct sockaddr_in endpoint_b_v4 = {
+      .sin_family = AF_INET,
+      .sin_port = htons(listen_b),
+      .sin_addr = {htonl(INADDR_LOOPBACK)}};
+  const struct sockaddr_in endpoint_c_v4 = {
+      .sin_family = AF_INET,
+      .sin_port = htons(listen_c),
+      .sin_addr = {htonl(INADDR_LOOPBACK)}};
+  struct sockaddr_in6 endpoint_a_v6 = {.sin6_family = AF_INET6,
+                                       .sin6_port = htons(listen_a)};
+  endpoint_a_v6.sin6_addr = in6addr_loopback;
+  /* Unused, but useful in case we change this:
+  const struct sockaddr_in6 endpoint_b_v6 = {
+      .sin6_family = AF_INET6,
+      .sin6_port = htons(listen_b)};
+  endpoint_b_v6.sin6_addr = in6addr_loopback; */
+  struct sockaddr_in6 endpoint_c_v6 = {.sin6_family = AF_INET6,
+                                       .sin6_port = htons(listen_c)};
+  endpoint_c_v6.sin6_addr = in6addr_loopback;
+  const struct in_addr first_half_v4 = {0};
+  const struct in_addr second_half_v4 = {htonl(128 << 24)};
+  const struct in6_addr first_half_v6 = {{{0}}};
+  const struct in6_addr second_half_v6 = {{{0x80}}};
+  const uint8_t half_cidr = 1;
+  const uint16_t persistent_keepalives[] = {1, 3, 7, 9, 14, 19};
+  struct genlmsghdr genlhdr = {.cmd = WG_CMD_SET_DEVICE, .version = 1};
+  int sock;
+  int id, err;
+  sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+  if (sock == -1) {
+    return;
+  }
+  id = netlink_wireguard_id_get(&nlmsg, sock);
+  if (id == -1)
+    goto error;
+  netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+  netlink_attr(&nlmsg, WGDEVICE_A_IFNAME, ifname_a, strlen(ifname_a) + 1);
+  netlink_attr(&nlmsg, WGDEVICE_A_PRIVATE_KEY, private_a, 32);
+  netlink_attr(&nlmsg, WGDEVICE_A_LISTEN_PORT, &listen_a, 2);
+  netlink_nest(&nlmsg, NLA_F_NESTED | WGDEVICE_A_PEERS);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_b, 32);
+  netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_b_v4,
+               sizeof(endpoint_b_v4));
+  netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+               &persistent_keepalives[0], 2);
+  netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v4,
+               sizeof(first_half_v4));
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+  netlink_done(&nlmsg);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v6,
+               sizeof(first_half_v6));
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_c, 32);
+  netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_c_v6,
+               sizeof(endpoint_c_v6));
+  netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+               &persistent_keepalives[1], 2);
+  netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v4,
+               sizeof(second_half_v4));
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+  netlink_done(&nlmsg);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v6,
+               sizeof(second_half_v6));
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  err = netlink_send(&nlmsg, sock);
+  if (err) {
+  }
+  netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+  netlink_attr(&nlmsg, WGDEVICE_A_IFNAME, ifname_b, strlen(ifname_b) + 1);
+  netlink_attr(&nlmsg, WGDEVICE_A_PRIVATE_KEY, private_b, 32);
+  netlink_attr(&nlmsg, WGDEVICE_A_LISTEN_PORT, &listen_b, 2);
+  netlink_nest(&nlmsg, NLA_F_NESTED | WGDEVICE_A_PEERS);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_a, 32);
+  netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_a_v6,
+               sizeof(endpoint_a_v6));
+  netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+               &persistent_keepalives[2], 2);
+  netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v4,
+               sizeof(first_half_v4));
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+  netlink_done(&nlmsg);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v6,
+               sizeof(first_half_v6));
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_c, 32);
+  netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_c_v4,
+               sizeof(endpoint_c_v4));
+  netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+               &persistent_keepalives[3], 2);
+  netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v4,
+               sizeof(second_half_v4));
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+  netlink_done(&nlmsg);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v6,
+               sizeof(second_half_v6));
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  err = netlink_send(&nlmsg, sock);
+  if (err) {
+  }
+  netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+  netlink_attr(&nlmsg, WGDEVICE_A_IFNAME, ifname_c, strlen(ifname_c) + 1);
+  netlink_attr(&nlmsg, WGDEVICE_A_PRIVATE_KEY, private_c, 32);
+  netlink_attr(&nlmsg, WGDEVICE_A_LISTEN_PORT, &listen_c, 2);
+  netlink_nest(&nlmsg, NLA_F_NESTED | WGDEVICE_A_PEERS);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_a, 32);
+  netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_a_v6,
+               sizeof(endpoint_a_v6));
+  netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+               &persistent_keepalives[4], 2);
+  netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v4,
+               sizeof(first_half_v4));
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+  netlink_done(&nlmsg);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v6,
+               sizeof(first_half_v6));
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_b, 32);
+  netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_b_v4,
+               sizeof(endpoint_b_v4));
+  netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+               &persistent_keepalives[5], 2);
+  netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v4,
+               sizeof(second_half_v4));
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+  netlink_done(&nlmsg);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v6,
+               sizeof(second_half_v6));
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  err = netlink_send(&nlmsg, sock);
+  if (err) {
+  }
+
+error:
+  close(sock);
+}
+static void initialize_netdevices(void)
+{
+  char netdevsim[16];
+  sprintf(netdevsim, "netdevsim%d", (int)procid);
+  struct {
+    const char* type;
+    const char* dev;
+  } devtypes[] = {
+      {"ip6gretap", "ip6gretap0"}, {"bridge", "bridge0"},
+      {"vcan", "vcan0"},           {"bond", "bond0"},
+      {"team", "team0"},           {"dummy", "dummy0"},
+      {"nlmon", "nlmon0"},         {"caif", "caif0"},
+      {"batadv", "batadv0"},       {"vxcan", "vxcan1"},
+      {"netdevsim", netdevsim},    {"veth", 0},
+      {"xfrm", "xfrm0"},           {"wireguard", "wg0"},
+      {"wireguard", "wg1"},        {"wireguard", "wg2"},
+  };
+  const char* devmasters[] = {"bridge", "bond", "team", "batadv"};
+  struct {
+    const char* name;
+    int macsize;
+    bool noipv6;
+  } devices[] = {
+      {"lo", ETH_ALEN},
+      {"sit0", 0},
+      {"bridge0", ETH_ALEN},
+      {"vcan0", 0, true},
+      {"tunl0", 0},
+      {"gre0", 0},
+      {"gretap0", ETH_ALEN},
+      {"ip_vti0", 0},
+      {"ip6_vti0", 0},
+      {"ip6tnl0", 0},
+      {"ip6gre0", 0},
+      {"ip6gretap0", ETH_ALEN},
+      {"erspan0", ETH_ALEN},
+      {"bond0", ETH_ALEN},
+      {"veth0", ETH_ALEN},
+      {"veth1", ETH_ALEN},
+      {"team0", ETH_ALEN},
+      {"veth0_to_bridge", ETH_ALEN},
+      {"veth1_to_bridge", ETH_ALEN},
+      {"veth0_to_bond", ETH_ALEN},
+      {"veth1_to_bond", ETH_ALEN},
+      {"veth0_to_team", ETH_ALEN},
+      {"veth1_to_team", ETH_ALEN},
+      {"veth0_to_hsr", ETH_ALEN},
+      {"veth1_to_hsr", ETH_ALEN},
+      {"hsr0", 0},
+      {"dummy0", ETH_ALEN},
+      {"nlmon0", 0},
+      {"vxcan0", 0, true},
+      {"vxcan1", 0, true},
+      {"caif0", ETH_ALEN},
+      {"batadv0", ETH_ALEN},
+      {netdevsim, ETH_ALEN},
+      {"xfrm0", ETH_ALEN},
+      {"veth0_virt_wifi", ETH_ALEN},
+      {"veth1_virt_wifi", ETH_ALEN},
+      {"virt_wifi0", ETH_ALEN},
+      {"veth0_vlan", ETH_ALEN},
+      {"veth1_vlan", ETH_ALEN},
+      {"vlan0", ETH_ALEN},
+      {"vlan1", ETH_ALEN},
+      {"macvlan0", ETH_ALEN},
+      {"macvlan1", ETH_ALEN},
+      {"ipvlan0", ETH_ALEN},
+      {"ipvlan1", ETH_ALEN},
+      {"veth0_macvtap", ETH_ALEN},
+      {"veth1_macvtap", ETH_ALEN},
+      {"macvtap0", ETH_ALEN},
+      {"macsec0", ETH_ALEN},
+      {"veth0_to_batadv", ETH_ALEN},
+      {"veth1_to_batadv", ETH_ALEN},
+      {"batadv_slave_0", ETH_ALEN},
+      {"batadv_slave_1", ETH_ALEN},
+      {"geneve0", ETH_ALEN},
+      {"geneve1", ETH_ALEN},
+      {"wg0", 0},
+      {"wg1", 0},
+      {"wg2", 0},
+  };
+  int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+  if (sock == -1)
+    exit(1);
+  unsigned i;
+  for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++)
+    netlink_add_device(&nlmsg, sock, devtypes[i].type, devtypes[i].dev);
+  for (i = 0; i < sizeof(devmasters) / (sizeof(devmasters[0])); i++) {
+    char master[32], slave0[32], veth0[32], slave1[32], veth1[32];
+    sprintf(slave0, "%s_slave_0", devmasters[i]);
+    sprintf(veth0, "veth0_to_%s", devmasters[i]);
+    netlink_add_veth(&nlmsg, sock, slave0, veth0);
+    sprintf(slave1, "%s_slave_1", devmasters[i]);
+    sprintf(veth1, "veth1_to_%s", devmasters[i]);
+    netlink_add_veth(&nlmsg, sock, slave1, veth1);
+    sprintf(master, "%s0", devmasters[i]);
+    netlink_device_change(&nlmsg, sock, slave0, false, master, 0, 0, NULL);
+    netlink_device_change(&nlmsg, sock, slave1, false, master, 0, 0, NULL);
+  }
+  netlink_device_change(&nlmsg, sock, "bridge_slave_0", true, 0, 0, 0, NULL);
+  netlink_device_change(&nlmsg, sock, "bridge_slave_1", true, 0, 0, 0, NULL);
+  netlink_add_veth(&nlmsg, sock, "hsr_slave_0", "veth0_to_hsr");
+  netlink_add_veth(&nlmsg, sock, "hsr_slave_1", "veth1_to_hsr");
+  netlink_add_hsr(&nlmsg, sock, "hsr0", "hsr_slave_0", "hsr_slave_1");
+  netlink_device_change(&nlmsg, sock, "hsr_slave_0", true, 0, 0, 0, NULL);
+  netlink_device_change(&nlmsg, sock, "hsr_slave_1", true, 0, 0, 0, NULL);
+  netlink_add_veth(&nlmsg, sock, "veth0_virt_wifi", "veth1_virt_wifi");
+  netlink_add_linked(&nlmsg, sock, "virt_wifi", "virt_wifi0",
+                     "veth1_virt_wifi");
+  netlink_add_veth(&nlmsg, sock, "veth0_vlan", "veth1_vlan");
+  netlink_add_vlan(&nlmsg, sock, "vlan0", "veth0_vlan", 0, htons(ETH_P_8021Q));
+  netlink_add_vlan(&nlmsg, sock, "vlan1", "veth0_vlan", 1, htons(ETH_P_8021AD));
+  netlink_add_macvlan(&nlmsg, sock, "macvlan0", "veth1_vlan");
+  netlink_add_macvlan(&nlmsg, sock, "macvlan1", "veth1_vlan");
+  netlink_add_ipvlan(&nlmsg, sock, "ipvlan0", "veth0_vlan", IPVLAN_MODE_L2, 0);
+  netlink_add_ipvlan(&nlmsg, sock, "ipvlan1", "veth0_vlan", IPVLAN_MODE_L3S,
+                     IPVLAN_F_VEPA);
+  netlink_add_veth(&nlmsg, sock, "veth0_macvtap", "veth1_macvtap");
+  netlink_add_linked(&nlmsg, sock, "macvtap", "macvtap0", "veth0_macvtap");
+  netlink_add_linked(&nlmsg, sock, "macsec", "macsec0", "veth1_macvtap");
+  char addr[32];
+  sprintf(addr, DEV_IPV4, 14 + 10);
+  struct in_addr geneve_addr4;
+  if (inet_pton(AF_INET, addr, &geneve_addr4) <= 0)
+    exit(1);
+  struct in6_addr geneve_addr6;
+  if (inet_pton(AF_INET6, "fc00::01", &geneve_addr6) <= 0)
+    exit(1);
+  netlink_add_geneve(&nlmsg, sock, "geneve0", 0, &geneve_addr4, 0);
+  netlink_add_geneve(&nlmsg, sock, "geneve1", 1, 0, &geneve_addr6);
+  netdevsim_add((int)procid, 4);
+  netlink_wireguard_setup();
+  for (i = 0; i < sizeof(devices) / (sizeof(devices[0])); i++) {
+    char addr[32];
+    sprintf(addr, DEV_IPV4, i + 10);
+    netlink_add_addr4(&nlmsg, sock, devices[i].name, addr);
+    if (!devices[i].noipv6) {
+      sprintf(addr, DEV_IPV6, i + 10);
+      netlink_add_addr6(&nlmsg, sock, devices[i].name, addr);
+    }
+    uint64_t macaddr = DEV_MAC + ((i + 10ull) << 40);
+    netlink_device_change(&nlmsg, sock, devices[i].name, true, 0, &macaddr,
+                          devices[i].macsize, NULL);
+  }
+  close(sock);
+}
+static void initialize_netdevices_init(void)
+{
+  int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+  if (sock == -1)
+    exit(1);
+  struct {
+    const char* type;
+    int macsize;
+    bool noipv6;
+    bool noup;
+  } devtypes[] = {
+      {"nr", 7, true}, {"rose", 5, true, true},
+  };
+  unsigned i;
+  for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++) {
+    char dev[32], addr[32];
+    sprintf(dev, "%s%d", devtypes[i].type, (int)procid);
+    sprintf(addr, "172.30.%d.%d", i, (int)procid + 1);
+    netlink_add_addr4(&nlmsg, sock, dev, addr);
+    if (!devtypes[i].noipv6) {
+      sprintf(addr, "fe88::%02x:%02x", i, (int)procid + 1);
+      netlink_add_addr6(&nlmsg, sock, dev, addr);
+    }
+    int macsize = devtypes[i].macsize;
+    uint64_t macaddr = 0xbbbbbb +
+                       ((unsigned long long)i << (8 * (macsize - 2))) +
+                       (procid << (8 * (macsize - 1)));
+    netlink_device_change(&nlmsg, sock, dev, !devtypes[i].noup, 0, &macaddr,
+                          macsize, NULL);
+  }
+  close(sock);
+}
+
+#define MAX_FDS 30
+
+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 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_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 = syscall(__NR_socket, 0x10ul, 3ul, 0x14ul);
+    if (res != -1)
+      r[0] = res;
+    break;
+  case 1:
+    *(uint64_t*)0x200031c0 = 0;
+    *(uint32_t*)0x200031c8 = 0;
+    *(uint64_t*)0x200031d0 = 0x20003180;
+    *(uint64_t*)0x20003180 = 0x20000000;
+    *(uint32_t*)0x20000000 = 0x38;
+    *(uint16_t*)0x20000004 = 0x1403;
+    *(uint16_t*)0x20000006 = 1;
+    *(uint32_t*)0x20000008 = 0;
+    *(uint32_t*)0x2000000c = 0;
+    *(uint16_t*)0x20000010 = 9;
+    *(uint16_t*)0x20000012 = 2;
+    memcpy((void*)0x20000014, "syz1\000", 5);
+    *(uint16_t*)0x2000001c = 8;
+    *(uint16_t*)0x2000001e = 0x41;
+    memcpy((void*)0x20000020, "siw\000", 4);
+    *(uint16_t*)0x20000024 = 0x14;
+    *(uint16_t*)0x20000026 = 0x33;
+    memcpy((void*)0x20000028,
+           "lo\000\000\000\000\000\000\000\000\000\000\000\000\000\000", 16);
+    *(uint64_t*)0x20003188 = 0x38;
+    *(uint64_t*)0x200031d8 = 1;
+    *(uint64_t*)0x200031e0 = 0;
+    *(uint64_t*)0x200031e8 = 0;
+    *(uint32_t*)0x200031f0 = 0;
+    syscall(__NR_sendmsg, r[0], 0x200031c0ul, 0ul);
+    break;
+  case 2:
+    memcpy((void*)0x20000140, "/dev/infiniband/rdma_cm\000", 24);
+    res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x20000140ul, 2ul, 0ul);
+    if (res != -1)
+      r[1] = res;
+    break;
+  case 3:
+    *(uint32_t*)0x200000c0 = 0;
+    *(uint16_t*)0x200000c4 = 0x18;
+    *(uint16_t*)0x200000c6 = 0xfa00;
+    *(uint64_t*)0x200000c8 = 0;
+    *(uint64_t*)0x200000d0 = 0x20000080;
+    *(uint16_t*)0x200000d8 = 0x13f;
+    *(uint8_t*)0x200000da = 0;
+    *(uint8_t*)0x200000db = 0;
+    *(uint8_t*)0x200000dc = 0;
+    *(uint8_t*)0x200000dd = 0;
+    *(uint8_t*)0x200000de = 0;
+    *(uint8_t*)0x200000df = 0;
+    res = syscall(__NR_write, r[1], 0x200000c0ul, 0x20ul);
+    if (res != -1)
+      r[2] = *(uint32_t*)0x20000080;
+    break;
+  case 4:
+    *(uint32_t*)0x200001c0 = 0x14;
+    *(uint16_t*)0x200001c4 = 0x88;
+    *(uint16_t*)0x200001c6 = 0xfa00;
+    *(uint32_t*)0x200001c8 = r[2];
+    *(uint16_t*)0x200001cc = 0x1c;
+    *(uint16_t*)0x200001ce = 0;
+    *(uint16_t*)0x200001d0 = 0xa;
+    *(uint16_t*)0x200001d2 = htobe16(0);
+    *(uint32_t*)0x200001d4 = htobe32(0);
+    *(uint8_t*)0x200001d8 = 0xfe;
+    *(uint8_t*)0x200001d9 = 0x80;
+    *(uint8_t*)0x200001da = 0;
+    *(uint8_t*)0x200001db = 0;
+    *(uint8_t*)0x200001dc = 0;
+    *(uint8_t*)0x200001dd = 0;
+    *(uint8_t*)0x200001de = 0;
+    *(uint8_t*)0x200001df = 0;
+    *(uint8_t*)0x200001e0 = 0;
+    *(uint8_t*)0x200001e1 = 0;
+    *(uint8_t*)0x200001e2 = 0;
+    *(uint8_t*)0x200001e3 = 0;
+    *(uint8_t*)0x200001e4 = 0;
+    *(uint8_t*)0x200001e5 = 0;
+    *(uint8_t*)0x200001e6 = 0;
+    *(uint8_t*)0x200001e7 = 0;
+    *(uint32_t*)0x200001e8 = 1;
+    syscall(__NR_write, r[1], 0x200001c0ul, 0x90ul);
+    break;
+  case 5:
+    *(uint32_t*)0x20000100 = 7;
+    *(uint16_t*)0x20000104 = 8;
+    *(uint16_t*)0x20000106 = 0xfa00;
+    *(uint32_t*)0x20000108 = r[2];
+    *(uint32_t*)0x2000010c = 0;
+    syscall(__NR_write, r[1], 0x20000100ul, 0x10ul);
+    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/08e208f050294509ab8e18439a8809bc54d91957.c b/syzkaller-repros/linux/08e208f050294509ab8e18439a8809bc54d91957.c
new file mode 100644
index 0000000..38b7aaf
--- /dev/null
+++ b/syzkaller-repros/linux/08e208f050294509ab8e18439a8809bc54d91957.c
@@ -0,0 +1,1083 @@
+// KASAN: use-after-free Read in mld_in_v1_mode
+// https://syzkaller.appspot.com/bug?id=08e208f050294509ab8e18439a8809bc54d91957
+// status:open
+// 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 <net/if_arp.h>
+#include <netinet/in.h>
+#include <sched.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+#include <linux/genetlink.h>
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/veth.h>
+
+unsigned long long procid;
+
+#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))))
+
+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_linked(struct nlmsg* nlmsg, int sock, const char* type,
+                               const char* name, const char* link)
+{
+  netlink_add_device_impl(nlmsg, type, name);
+  netlink_done(nlmsg);
+  int ifindex = if_nametoindex(link);
+  netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+  int err = netlink_send(nlmsg, sock);
+  (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;
+}
+
+static void netlink_add_geneve(struct nlmsg* nlmsg, int sock, const char* name,
+                               uint32_t vni, struct in_addr* addr4,
+                               struct in6_addr* addr6)
+{
+  netlink_add_device_impl(nlmsg, "geneve", name);
+  netlink_nest(nlmsg, IFLA_INFO_DATA);
+  netlink_attr(nlmsg, IFLA_GENEVE_ID, &vni, sizeof(vni));
+  if (addr4)
+    netlink_attr(nlmsg, IFLA_GENEVE_REMOTE, addr4, sizeof(*addr4));
+  if (addr6)
+    netlink_attr(nlmsg, IFLA_GENEVE_REMOTE6, addr6, sizeof(*addr6));
+  netlink_done(nlmsg);
+  netlink_done(nlmsg);
+  int err = netlink_send(nlmsg, sock);
+  (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;
+}
+
+#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");
+  }
+}
+
+#define WG_GENL_NAME "wireguard"
+enum wg_cmd {
+  WG_CMD_GET_DEVICE,
+  WG_CMD_SET_DEVICE,
+};
+enum wgdevice_attribute {
+  WGDEVICE_A_UNSPEC,
+  WGDEVICE_A_IFINDEX,
+  WGDEVICE_A_IFNAME,
+  WGDEVICE_A_PRIVATE_KEY,
+  WGDEVICE_A_PUBLIC_KEY,
+  WGDEVICE_A_FLAGS,
+  WGDEVICE_A_LISTEN_PORT,
+  WGDEVICE_A_FWMARK,
+  WGDEVICE_A_PEERS,
+};
+enum wgpeer_attribute {
+  WGPEER_A_UNSPEC,
+  WGPEER_A_PUBLIC_KEY,
+  WGPEER_A_PRESHARED_KEY,
+  WGPEER_A_FLAGS,
+  WGPEER_A_ENDPOINT,
+  WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+  WGPEER_A_LAST_HANDSHAKE_TIME,
+  WGPEER_A_RX_BYTES,
+  WGPEER_A_TX_BYTES,
+  WGPEER_A_ALLOWEDIPS,
+  WGPEER_A_PROTOCOL_VERSION,
+};
+enum wgallowedip_attribute {
+  WGALLOWEDIP_A_UNSPEC,
+  WGALLOWEDIP_A_FAMILY,
+  WGALLOWEDIP_A_IPADDR,
+  WGALLOWEDIP_A_CIDR_MASK,
+};
+
+static int netlink_wireguard_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, WG_GENL_NAME,
+               strlen(WG_GENL_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_wireguard_setup(void)
+{
+  const char ifname_a[] = "wg0";
+  const char ifname_b[] = "wg1";
+  const char ifname_c[] = "wg2";
+  const char private_a[] = "\xa0\x5c\xa8\x4f\x6c\x9c\x8e\x38\x53\xe2\xfd\x7a"
+                           "\x70\xae\x0f\xb2\x0f\xa1\x52\x60\x0c\xb0\x08\x45"
+                           "\x17\x4f\x08\x07\x6f\x8d\x78\x43";
+  const char private_b[] = "\xb0\x80\x73\xe8\xd4\x4e\x91\xe3\xda\x92\x2c\x22"
+                           "\x43\x82\x44\xbb\x88\x5c\x69\xe2\x69\xc8\xe9\xd8"
+                           "\x35\xb1\x14\x29\x3a\x4d\xdc\x6e";
+  const char private_c[] = "\xa0\xcb\x87\x9a\x47\xf5\xbc\x64\x4c\x0e\x69\x3f"
+                           "\xa6\xd0\x31\xc7\x4a\x15\x53\xb6\xe9\x01\xb9\xff"
+                           "\x2f\x51\x8c\x78\x04\x2f\xb5\x42";
+  const char public_a[] = "\x97\x5c\x9d\x81\xc9\x83\xc8\x20\x9e\xe7\x81\x25\x4b"
+                          "\x89\x9f\x8e\xd9\x25\xae\x9f\x09\x23\xc2\x3c\x62\xf5"
+                          "\x3c\x57\xcd\xbf\x69\x1c";
+  const char public_b[] = "\xd1\x73\x28\x99\xf6\x11\xcd\x89\x94\x03\x4d\x7f\x41"
+                          "\x3d\xc9\x57\x63\x0e\x54\x93\xc2\x85\xac\xa4\x00\x65"
+                          "\xcb\x63\x11\xbe\x69\x6b";
+  const char public_c[] = "\xf4\x4d\xa3\x67\xa8\x8e\xe6\x56\x4f\x02\x02\x11\x45"
+                          "\x67\x27\x08\x2f\x5c\xeb\xee\x8b\x1b\xf5\xeb\x73\x37"
+                          "\x34\x1b\x45\x9b\x39\x22";
+  const uint16_t listen_a = 20001;
+  const uint16_t listen_b = 20002;
+  const uint16_t listen_c = 20003;
+  const uint16_t af_inet = AF_INET;
+  const uint16_t af_inet6 = AF_INET6;
+  /* Unused, but useful in case we change this:
+  const struct sockaddr_in endpoint_a_v4 = {
+      .sin_family = AF_INET,
+      .sin_port = htons(listen_a),
+      .sin_addr = {htonl(INADDR_LOOPBACK)}};*/
+  const struct sockaddr_in endpoint_b_v4 = {
+      .sin_family = AF_INET,
+      .sin_port = htons(listen_b),
+      .sin_addr = {htonl(INADDR_LOOPBACK)}};
+  const struct sockaddr_in endpoint_c_v4 = {
+      .sin_family = AF_INET,
+      .sin_port = htons(listen_c),
+      .sin_addr = {htonl(INADDR_LOOPBACK)}};
+  struct sockaddr_in6 endpoint_a_v6 = {.sin6_family = AF_INET6,
+                                       .sin6_port = htons(listen_a)};
+  endpoint_a_v6.sin6_addr = in6addr_loopback;
+  /* Unused, but useful in case we change this:
+  const struct sockaddr_in6 endpoint_b_v6 = {
+      .sin6_family = AF_INET6,
+      .sin6_port = htons(listen_b)};
+  endpoint_b_v6.sin6_addr = in6addr_loopback; */
+  struct sockaddr_in6 endpoint_c_v6 = {.sin6_family = AF_INET6,
+                                       .sin6_port = htons(listen_c)};
+  endpoint_c_v6.sin6_addr = in6addr_loopback;
+  const struct in_addr first_half_v4 = {0};
+  const struct in_addr second_half_v4 = {htonl(128 << 24)};
+  const struct in6_addr first_half_v6 = {{{0}}};
+  const struct in6_addr second_half_v6 = {{{0x80}}};
+  const uint8_t half_cidr = 1;
+  const uint16_t persistent_keepalives[] = {1, 3, 7, 9, 14, 19};
+  struct genlmsghdr genlhdr = {.cmd = WG_CMD_SET_DEVICE, .version = 1};
+  int sock;
+  int id, err;
+  sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+  if (sock == -1)
+    exit(1);
+  id = netlink_wireguard_id_get(&nlmsg, sock);
+  if (id == -1)
+    goto error;
+  netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+  netlink_attr(&nlmsg, WGDEVICE_A_IFNAME, ifname_a, strlen(ifname_a) + 1);
+  netlink_attr(&nlmsg, WGDEVICE_A_PRIVATE_KEY, private_a, 32);
+  netlink_attr(&nlmsg, WGDEVICE_A_LISTEN_PORT, &listen_a, 2);
+  netlink_nest(&nlmsg, NLA_F_NESTED | WGDEVICE_A_PEERS);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_b, 32);
+  netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_b_v4,
+               sizeof(endpoint_b_v4));
+  netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+               &persistent_keepalives[0], 2);
+  netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v4,
+               sizeof(first_half_v4));
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+  netlink_done(&nlmsg);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v6,
+               sizeof(first_half_v6));
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_c, 32);
+  netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_c_v6,
+               sizeof(endpoint_c_v6));
+  netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+               &persistent_keepalives[1], 2);
+  netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v4,
+               sizeof(second_half_v4));
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+  netlink_done(&nlmsg);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v6,
+               sizeof(second_half_v6));
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  err = netlink_send(&nlmsg, sock);
+  if (err) {
+  }
+  netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+  netlink_attr(&nlmsg, WGDEVICE_A_IFNAME, ifname_b, strlen(ifname_b) + 1);
+  netlink_attr(&nlmsg, WGDEVICE_A_PRIVATE_KEY, private_b, 32);
+  netlink_attr(&nlmsg, WGDEVICE_A_LISTEN_PORT, &listen_b, 2);
+  netlink_nest(&nlmsg, NLA_F_NESTED | WGDEVICE_A_PEERS);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_a, 32);
+  netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_a_v6,
+               sizeof(endpoint_a_v6));
+  netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+               &persistent_keepalives[2], 2);
+  netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v4,
+               sizeof(first_half_v4));
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+  netlink_done(&nlmsg);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v6,
+               sizeof(first_half_v6));
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_c, 32);
+  netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_c_v4,
+               sizeof(endpoint_c_v4));
+  netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+               &persistent_keepalives[3], 2);
+  netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v4,
+               sizeof(second_half_v4));
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+  netlink_done(&nlmsg);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v6,
+               sizeof(second_half_v6));
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  err = netlink_send(&nlmsg, sock);
+  if (err) {
+  }
+  netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+  netlink_attr(&nlmsg, WGDEVICE_A_IFNAME, ifname_c, strlen(ifname_c) + 1);
+  netlink_attr(&nlmsg, WGDEVICE_A_PRIVATE_KEY, private_c, 32);
+  netlink_attr(&nlmsg, WGDEVICE_A_LISTEN_PORT, &listen_c, 2);
+  netlink_nest(&nlmsg, NLA_F_NESTED | WGDEVICE_A_PEERS);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_a, 32);
+  netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_a_v6,
+               sizeof(endpoint_a_v6));
+  netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+               &persistent_keepalives[4], 2);
+  netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v4,
+               sizeof(first_half_v4));
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+  netlink_done(&nlmsg);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v6,
+               sizeof(first_half_v6));
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_b, 32);
+  netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_b_v4,
+               sizeof(endpoint_b_v4));
+  netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+               &persistent_keepalives[5], 2);
+  netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v4,
+               sizeof(second_half_v4));
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+  netlink_done(&nlmsg);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v6,
+               sizeof(second_half_v6));
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  err = netlink_send(&nlmsg, sock);
+  if (err) {
+  }
+
+error:
+  close(sock);
+}
+static void initialize_netdevices(void)
+{
+  char netdevsim[16];
+  sprintf(netdevsim, "netdevsim%d", (int)procid);
+  struct {
+    const char* type;
+    const char* dev;
+  } devtypes[] = {
+      {"ip6gretap", "ip6gretap0"}, {"bridge", "bridge0"},
+      {"vcan", "vcan0"},           {"bond", "bond0"},
+      {"team", "team0"},           {"dummy", "dummy0"},
+      {"nlmon", "nlmon0"},         {"caif", "caif0"},
+      {"batadv", "batadv0"},       {"vxcan", "vxcan1"},
+      {"netdevsim", netdevsim},    {"veth", 0},
+      {"xfrm", "xfrm0"},           {"wireguard", "wg0"},
+      {"wireguard", "wg1"},        {"wireguard", "wg2"},
+  };
+  const char* devmasters[] = {"bridge", "bond", "team", "batadv"};
+  struct {
+    const char* name;
+    int macsize;
+    bool noipv6;
+  } devices[] = {
+      {"lo", ETH_ALEN},
+      {"sit0", 0},
+      {"bridge0", ETH_ALEN},
+      {"vcan0", 0, true},
+      {"tunl0", 0},
+      {"gre0", 0},
+      {"gretap0", ETH_ALEN},
+      {"ip_vti0", 0},
+      {"ip6_vti0", 0},
+      {"ip6tnl0", 0},
+      {"ip6gre0", 0},
+      {"ip6gretap0", ETH_ALEN},
+      {"erspan0", ETH_ALEN},
+      {"bond0", ETH_ALEN},
+      {"veth0", ETH_ALEN},
+      {"veth1", ETH_ALEN},
+      {"team0", ETH_ALEN},
+      {"veth0_to_bridge", ETH_ALEN},
+      {"veth1_to_bridge", ETH_ALEN},
+      {"veth0_to_bond", ETH_ALEN},
+      {"veth1_to_bond", ETH_ALEN},
+      {"veth0_to_team", ETH_ALEN},
+      {"veth1_to_team", ETH_ALEN},
+      {"veth0_to_hsr", ETH_ALEN},
+      {"veth1_to_hsr", ETH_ALEN},
+      {"hsr0", 0},
+      {"dummy0", ETH_ALEN},
+      {"nlmon0", 0},
+      {"vxcan0", 0, true},
+      {"vxcan1", 0, true},
+      {"caif0", ETH_ALEN},
+      {"batadv0", ETH_ALEN},
+      {netdevsim, ETH_ALEN},
+      {"xfrm0", ETH_ALEN},
+      {"veth0_virt_wifi", ETH_ALEN},
+      {"veth1_virt_wifi", ETH_ALEN},
+      {"virt_wifi0", ETH_ALEN},
+      {"veth0_vlan", ETH_ALEN},
+      {"veth1_vlan", ETH_ALEN},
+      {"vlan0", ETH_ALEN},
+      {"vlan1", ETH_ALEN},
+      {"macvlan0", ETH_ALEN},
+      {"macvlan1", ETH_ALEN},
+      {"ipvlan0", ETH_ALEN},
+      {"ipvlan1", ETH_ALEN},
+      {"veth0_macvtap", ETH_ALEN},
+      {"veth1_macvtap", ETH_ALEN},
+      {"macvtap0", ETH_ALEN},
+      {"macsec0", ETH_ALEN},
+      {"veth0_to_batadv", ETH_ALEN},
+      {"veth1_to_batadv", ETH_ALEN},
+      {"batadv_slave_0", ETH_ALEN},
+      {"batadv_slave_1", ETH_ALEN},
+      {"geneve0", ETH_ALEN},
+      {"geneve1", ETH_ALEN},
+      {"wg0", 0},
+      {"wg1", 0},
+      {"wg2", 0},
+  };
+  int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+  if (sock == -1)
+    exit(1);
+  unsigned i;
+  for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++)
+    netlink_add_device(&nlmsg, sock, devtypes[i].type, devtypes[i].dev);
+  for (i = 0; i < sizeof(devmasters) / (sizeof(devmasters[0])); i++) {
+    char master[32], slave0[32], veth0[32], slave1[32], veth1[32];
+    sprintf(slave0, "%s_slave_0", devmasters[i]);
+    sprintf(veth0, "veth0_to_%s", devmasters[i]);
+    netlink_add_veth(&nlmsg, sock, slave0, veth0);
+    sprintf(slave1, "%s_slave_1", devmasters[i]);
+    sprintf(veth1, "veth1_to_%s", devmasters[i]);
+    netlink_add_veth(&nlmsg, sock, slave1, veth1);
+    sprintf(master, "%s0", devmasters[i]);
+    netlink_device_change(&nlmsg, sock, slave0, false, master, 0, 0, NULL);
+    netlink_device_change(&nlmsg, sock, slave1, false, master, 0, 0, NULL);
+  }
+  netlink_device_change(&nlmsg, sock, "bridge_slave_0", true, 0, 0, 0, NULL);
+  netlink_device_change(&nlmsg, sock, "bridge_slave_1", true, 0, 0, 0, NULL);
+  netlink_add_veth(&nlmsg, sock, "hsr_slave_0", "veth0_to_hsr");
+  netlink_add_veth(&nlmsg, sock, "hsr_slave_1", "veth1_to_hsr");
+  netlink_add_hsr(&nlmsg, sock, "hsr0", "hsr_slave_0", "hsr_slave_1");
+  netlink_device_change(&nlmsg, sock, "hsr_slave_0", true, 0, 0, 0, NULL);
+  netlink_device_change(&nlmsg, sock, "hsr_slave_1", true, 0, 0, 0, NULL);
+  netlink_add_veth(&nlmsg, sock, "veth0_virt_wifi", "veth1_virt_wifi");
+  netlink_add_linked(&nlmsg, sock, "virt_wifi", "virt_wifi0",
+                     "veth1_virt_wifi");
+  netlink_add_veth(&nlmsg, sock, "veth0_vlan", "veth1_vlan");
+  netlink_add_vlan(&nlmsg, sock, "vlan0", "veth0_vlan", 0, htons(ETH_P_8021Q));
+  netlink_add_vlan(&nlmsg, sock, "vlan1", "veth0_vlan", 1, htons(ETH_P_8021AD));
+  netlink_add_macvlan(&nlmsg, sock, "macvlan0", "veth1_vlan");
+  netlink_add_macvlan(&nlmsg, sock, "macvlan1", "veth1_vlan");
+  netlink_add_ipvlan(&nlmsg, sock, "ipvlan0", "veth0_vlan", IPVLAN_MODE_L2, 0);
+  netlink_add_ipvlan(&nlmsg, sock, "ipvlan1", "veth0_vlan", IPVLAN_MODE_L3S,
+                     IPVLAN_F_VEPA);
+  netlink_add_veth(&nlmsg, sock, "veth0_macvtap", "veth1_macvtap");
+  netlink_add_linked(&nlmsg, sock, "macvtap", "macvtap0", "veth0_macvtap");
+  netlink_add_linked(&nlmsg, sock, "macsec", "macsec0", "veth1_macvtap");
+  char addr[32];
+  sprintf(addr, DEV_IPV4, 14 + 10);
+  struct in_addr geneve_addr4;
+  if (inet_pton(AF_INET, addr, &geneve_addr4) <= 0)
+    exit(1);
+  struct in6_addr geneve_addr6;
+  if (inet_pton(AF_INET6, "fc00::01", &geneve_addr6) <= 0)
+    exit(1);
+  netlink_add_geneve(&nlmsg, sock, "geneve0", 0, &geneve_addr4, 0);
+  netlink_add_geneve(&nlmsg, sock, "geneve1", 1, 0, &geneve_addr6);
+  netdevsim_add((int)procid, 4);
+  netlink_wireguard_setup();
+  for (i = 0; i < sizeof(devices) / (sizeof(devices[0])); i++) {
+    char addr[32];
+    sprintf(addr, DEV_IPV4, i + 10);
+    netlink_add_addr4(&nlmsg, sock, devices[i].name, addr);
+    if (!devices[i].noipv6) {
+      sprintf(addr, DEV_IPV6, i + 10);
+      netlink_add_addr6(&nlmsg, sock, devices[i].name, addr);
+    }
+    uint64_t macaddr = DEV_MAC + ((i + 10ull) << 40);
+    netlink_device_change(&nlmsg, sock, devices[i].name, true, 0, &macaddr,
+                          devices[i].macsize, NULL);
+  }
+  close(sock);
+}
+static void initialize_netdevices_init(void)
+{
+  int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+  if (sock == -1)
+    exit(1);
+  struct {
+    const char* type;
+    int macsize;
+    bool noipv6;
+    bool noup;
+  } devtypes[] = {
+      {"nr", 7, true}, {"rose", 5, true, true},
+  };
+  unsigned i;
+  for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++) {
+    char dev[32], addr[32];
+    sprintf(dev, "%s%d", devtypes[i].type, (int)procid);
+    sprintf(addr, "172.30.%d.%d", i, (int)procid + 1);
+    netlink_add_addr4(&nlmsg, sock, dev, addr);
+    if (!devtypes[i].noipv6) {
+      sprintf(addr, "fe88::%02x:%02x", i, (int)procid + 1);
+      netlink_add_addr6(&nlmsg, sock, dev, addr);
+    }
+    int macsize = devtypes[i].macsize;
+    uint64_t macaddr = 0xbbbbbb +
+                       ((unsigned long long)i << (8 * (macsize - 2))) +
+                       (procid << (8 * (macsize - 1)));
+    netlink_device_change(&nlmsg, sock, dev, !devtypes[i].noup, 0, &macaddr,
+                          macsize, NULL);
+  }
+  close(sock);
+}
+
+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 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_netdevices();
+  loop();
+  exit(1);
+}
+
+uint64_t r[4] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff,
+                 0x0};
+
+void loop(void)
+{
+  intptr_t res = 0;
+  res = syscall(__NR_socket, 0x10ul, 3ul, 0ul);
+  if (res != -1)
+    r[0] = res;
+  res = syscall(__NR_socketpair, 1ul, 5ul, 0ul, 0x200000c0ul);
+  if (res != -1)
+    r[1] = *(uint32_t*)0x200000c4;
+  res = syscall(__NR_dup, r[1]);
+  if (res != -1)
+    r[2] = res;
+  *(uint32_t*)0x20000140 = 0x14;
+  res = syscall(__NR_getsockname, r[2], 0x200000c0ul, 0x20000140ul);
+  if (res != -1)
+    r[3] = *(uint32_t*)0x200000c4;
+  *(uint64_t*)0x20000040 = 0;
+  *(uint32_t*)0x20000048 = 0;
+  *(uint64_t*)0x20000050 = 0x200000c0;
+  *(uint64_t*)0x200000c0 = 0x20000180;
+  *(uint32_t*)0x20000180 = 0x38;
+  *(uint16_t*)0x20000184 = 0x6d;
+  *(uint16_t*)0x20000186 = 0x705;
+  *(uint32_t*)0x20000188 = 0;
+  *(uint32_t*)0x2000018c = 0;
+  *(uint8_t*)0x20000190 = 0;
+  *(uint8_t*)0x20000191 = 0;
+  *(uint16_t*)0x20000192 = 0;
+  *(uint32_t*)0x20000194 = r[3];
+  *(uint32_t*)0x20000198 = 0;
+  *(uint32_t*)0x2000019c = 0;
+  *(uint16_t*)0x200001a0 = 0x18;
+  STORE_BY_BITMASK(uint16_t, , 0x200001a2, 0x34, 0, 14);
+  STORE_BY_BITMASK(uint16_t, , 0x200001a3, 0, 6, 1);
+  STORE_BY_BITMASK(uint16_t, , 0x200001a3, 1, 7, 1);
+  *(uint16_t*)0x200001a4 = 0x14;
+  *(uint16_t*)0x200001a6 = 0x35;
+  memcpy((void*)0x200001a8, "ip6_vti0\000\000\000\000\000\000\000\000", 16);
+  *(uint64_t*)0x200000c8 = 0x38;
+  *(uint64_t*)0x20000058 = 1;
+  *(uint64_t*)0x20000060 = 0;
+  *(uint64_t*)0x20000068 = 0;
+  *(uint32_t*)0x20000070 = 0;
+  syscall(__NR_sendmsg, r[0], 0x20000040ul, 0ul);
+}
+int main(void)
+{
+  syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+  do_sandbox_none();
+  return 0;
+}
diff --git a/syzkaller-repros/linux/0a11ca435e9c8fed23d1a251ac051b117ad12cd7.c b/syzkaller-repros/linux/0a11ca435e9c8fed23d1a251ac051b117ad12cd7.c
new file mode 100644
index 0000000..de957d3
--- /dev/null
+++ b/syzkaller-repros/linux/0a11ca435e9c8fed23d1a251ac051b117ad12cd7.c
@@ -0,0 +1,194 @@
+// INFO: task hung in xlog_grant_head_check
+// https://syzkaller.appspot.com/bug?id=0a11ca435e9c8fed23d1a251ac051b117ad12cd7
+// status:open
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <linux/loop.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);                       \
+  }
+
+struct fs_image_segment {
+  void* data;
+  uintptr_t size;
+  uintptr_t offset;
+};
+
+#define IMAGE_MAX_SEGMENTS 4096
+#define IMAGE_MAX_SIZE (129 << 20)
+
+#define sys_memfd_create 319
+
+static unsigned long fs_image_segment_check(unsigned long size,
+                                            unsigned long nsegs, long segments)
+{
+  unsigned long i;
+  struct fs_image_segment* segs = (struct fs_image_segment*)segments;
+  if (nsegs > IMAGE_MAX_SEGMENTS)
+    nsegs = IMAGE_MAX_SEGMENTS;
+  for (i = 0; i < nsegs; i++) {
+    if (segs[i].size > IMAGE_MAX_SIZE)
+      segs[i].size = IMAGE_MAX_SIZE;
+    segs[i].offset %= IMAGE_MAX_SIZE;
+    if (segs[i].offset > IMAGE_MAX_SIZE - segs[i].size)
+      segs[i].offset = IMAGE_MAX_SIZE - segs[i].size;
+    if (size < segs[i].offset + segs[i].offset)
+      size = segs[i].offset + segs[i].offset;
+  }
+  if (size > IMAGE_MAX_SIZE)
+    size = IMAGE_MAX_SIZE;
+  return size;
+}
+
+static long syz_mount_image(volatile long fsarg, volatile long dir,
+                            volatile unsigned long size,
+                            volatile unsigned long nsegs,
+                            volatile long segments, volatile long flags,
+                            volatile long optsarg)
+{
+  char loopname[64], fs[32], opts[256];
+  int loopfd, err = 0, res = -1;
+  unsigned long i;
+  NONFAILING(size = fs_image_segment_check(size, nsegs, segments));
+  int memfd = syscall(sys_memfd_create, "syz_mount_image", 0);
+  if (memfd == -1) {
+    err = errno;
+    goto error;
+  }
+  if (ftruncate(memfd, size)) {
+    err = errno;
+    goto error_close_memfd;
+  }
+  for (i = 0; i < nsegs; i++) {
+    struct fs_image_segment* segs = (struct fs_image_segment*)segments;
+    int res1 = 0;
+    NONFAILING(res1 =
+                   pwrite(memfd, segs[i].data, segs[i].size, segs[i].offset));
+    if (res1 < 0) {
+    }
+  }
+  snprintf(loopname, sizeof(loopname), "/dev/loop%llu", procid);
+  loopfd = open(loopname, O_RDWR);
+  if (loopfd == -1) {
+    err = errno;
+    goto error_close_memfd;
+  }
+  if (ioctl(loopfd, LOOP_SET_FD, memfd)) {
+    if (errno != EBUSY) {
+      err = errno;
+      goto error_close_loop;
+    }
+    ioctl(loopfd, LOOP_CLR_FD, 0);
+    usleep(1000);
+    if (ioctl(loopfd, LOOP_SET_FD, memfd)) {
+      err = errno;
+      goto error_close_loop;
+    }
+  }
+  mkdir((char*)dir, 0777);
+  memset(fs, 0, sizeof(fs));
+  NONFAILING(strncpy(fs, (char*)fsarg, sizeof(fs) - 1));
+  memset(opts, 0, sizeof(opts));
+  NONFAILING(strncpy(opts, (char*)optsarg, sizeof(opts) - 32));
+  if (strcmp(fs, "iso9660") == 0) {
+    flags |= MS_RDONLY;
+  } else if (strncmp(fs, "ext", 3) == 0) {
+    if (strstr(opts, "errors=panic") || strstr(opts, "errors=remount-ro") == 0)
+      strcat(opts, ",errors=continue");
+  } else if (strcmp(fs, "xfs") == 0) {
+    strcat(opts, ",nouuid");
+  }
+  if (mount(loopname, (char*)dir, fs, flags, opts)) {
+    err = errno;
+    goto error_clear_loop;
+  }
+  res = 0;
+error_clear_loop:
+  ioctl(loopfd, LOOP_CLR_FD, 0);
+error_close_loop:
+  close(loopfd);
+error_close_memfd:
+  close(memfd);
+error:
+  errno = err;
+  return res;
+}
+
+int main(void)
+{
+  syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+  install_segv_handler();
+  NONFAILING(memcpy((void*)0x20000180, "xfs\000", 4));
+  NONFAILING(memcpy((void*)0x20000140, "./file0\000", 8));
+  NONFAILING(*(uint64_t*)0x20000200 = 0x20010000);
+  NONFAILING(memcpy(
+      (void*)0x20010000,
+      "\x58\x46\x53\x42\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00"
+      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x34\xfb\x8f\xb9"
+      "\xe4\xbf\x48\xb6\xad\x26\xc5\x97\xeb\x4f\x5c\x19\x00\x00\x00\x00\x00\x00"
+      "\x00\x04\x00\x00\x40\x00\x00\x00\x0d\x88\x00\x00\x00\x00\x00\x00\x0d\x89"
+      "\x00\x00\x00\x00\x00\x00\x0d\x8a\x00\x00\x00\x01\x00\x00\x10\x00\x00\x00"
+      "\x00\x01\x00\x00\x00\x00\x03\x00\x00\x00\xb4\x24\x02\x00\x04\x00\x00\x04"
+      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\xec\x00\x00\x0c\x09\x0a\x02",
+      124));
+  NONFAILING(*(uint64_t*)0x20000208 = 0x7c);
+  NONFAILING(*(uint64_t*)0x20000210 = 0);
+  syz_mount_image(0x20000180, 0x20000140, 0x4000000000000000, 1, 0x20000200, 0,
+                  0);
+  return 0;
+}
diff --git a/syzkaller-repros/linux/0a6d199d4e60c03fe2cb8e2398cc7f4d654eb634.c b/syzkaller-repros/linux/0a6d199d4e60c03fe2cb8e2398cc7f4d654eb634.c
new file mode 100644
index 0000000..10f91a4
--- /dev/null
+++ b/syzkaller-repros/linux/0a6d199d4e60c03fe2cb8e2398cc7f4d654eb634.c
@@ -0,0 +1,68 @@
+// WARNING in sk_stream_kill_queues (4)
+// https://syzkaller.appspot.com/bug?id=0a6d199d4e60c03fe2cb8e2398cc7f4d654eb634
+// 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>
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+int main(void)
+{
+  syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+  intptr_t res = 0;
+  res = syscall(__NR_socket, 0xaul, 1ul, 0ul);
+  if (res != -1)
+    r[0] = res;
+  *(uint32_t*)0x20000100 = 1;
+  syscall(__NR_setsockopt, r[0], 6ul, 0x13ul, 0x20000100ul, 4ul);
+  *(uint16_t*)0x20000300 = 0xa;
+  *(uint16_t*)0x20000302 = htobe16(0);
+  *(uint32_t*)0x20000304 = htobe32(0);
+  *(uint8_t*)0x20000308 = 0;
+  *(uint8_t*)0x20000309 = 0;
+  *(uint8_t*)0x2000030a = 0;
+  *(uint8_t*)0x2000030b = 0;
+  *(uint8_t*)0x2000030c = 0;
+  *(uint8_t*)0x2000030d = 0;
+  *(uint8_t*)0x2000030e = 0;
+  *(uint8_t*)0x2000030f = 0;
+  *(uint8_t*)0x20000310 = 0;
+  *(uint8_t*)0x20000311 = 0;
+  *(uint8_t*)0x20000312 = -1;
+  *(uint8_t*)0x20000313 = -1;
+  *(uint8_t*)0x20000314 = 0xac;
+  *(uint8_t*)0x20000315 = 0x14;
+  *(uint8_t*)0x20000316 = 0x14;
+  *(uint8_t*)0x20000317 = 0xaa;
+  *(uint32_t*)0x20000318 = 0;
+  syscall(__NR_connect, r[0], 0x20000300ul, 0x1cul);
+  memcpy((void*)0x20000340, "tls\000", 4);
+  syscall(__NR_setsockopt, r[0], 6ul, 0x1ful, 0x20000340ul, 4ul);
+  *(uint16_t*)0x20000180 = 0x303;
+  *(uint16_t*)0x20000182 = 0x34;
+  memcpy((void*)0x20000184, "\xe5\x73\xb0\x37\xde\x86\x16\xdc", 8);
+  memcpy((void*)0x2000018c, "\xc4\x08\xee\x5d\xfa\x1b\xb5\xf0\x44\xb4\xea\x4a"
+                            "\xb5\x7a\x3a\x93\x29\x43\x17\x02\x43\x33\x3b\x60"
+                            "\x85\x93\x35\x87\x82\x86\xb7\xfb",
+         32);
+  memcpy((void*)0x200001ac, "\x99\x8a\x9d\xe9", 4);
+  memcpy((void*)0x200001b0, "\xff\xff\xff\xff\xff\xff\xff\xfe", 8);
+  syscall(__NR_setsockopt, r[0], 0x11aul, 1ul, 0x20000180ul, 0x38ul);
+  memcpy((void*)0x200001c0, "\x36\x49\x12\x5c\xfe\xf1\x9c\x02\xad\xa8\x8a\x6e"
+                            "\x5b\x0f\x90\x85\xd7\x7e\xfe",
+         19);
+  syscall(__NR_sendto, r[0], 0x200001c0ul, 0xfffffdeful, 0ul, 0ul, 0ul);
+  *(uint32_t*)0x200001c0 = 2;
+  syscall(__NR_setsockopt, r[0], 0x29ul, 1ul, 0x200001c0ul, 4ul);
+  return 0;
+}
diff --git a/syzkaller-repros/linux/0dc78f032d6dc7c10ecb7d0a59267d3cf801a70e.c b/syzkaller-repros/linux/0dc78f032d6dc7c10ecb7d0a59267d3cf801a70e.c
new file mode 100644
index 0000000..be19c68
--- /dev/null
+++ b/syzkaller-repros/linux/0dc78f032d6dc7c10ecb7d0a59267d3cf801a70e.c
@@ -0,0 +1,354 @@
+// KASAN: null-ptr-deref Read in tcf_generic_walker
+// https://syzkaller.appspot.com/bug?id=0dc78f032d6dc7c10ecb7d0a59267d3cf801a70e
+// 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 <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>
+
+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);
+}
+
+#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, 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 < 4; 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[2] = {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, 0x10ul, 3ul, 0ul);
+    if (res != -1)
+      r[1] = res;
+    break;
+  case 2:
+    *(uint64_t*)0x20000300 = 0;
+    *(uint32_t*)0x20000308 = 0;
+    *(uint64_t*)0x20000310 = 0x200002c0;
+    *(uint64_t*)0x200002c0 = 0x20000400;
+    memcpy((void*)0x20000400,
+           "\x54\x00\x00\x00\x30\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+           "\x00\x00\x00\x00\x40\x00\x01\x00\x3c\x00\x01\x00\x08\x00\x01\x00"
+           "\x69\x66\x65\x00\x2c\x00\x02\x80\x1c\x00\x01\x00\x00\x00\x00\x00"
+           "\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+           "\x00\x00\x00\x00\x0c\x00\x06\x00\x04\x00\x01\x00\x04\x00\x04\x00"
+           "\x04\x00\x06\x00\x18\x68\x2c\x99\x4a\xa0\x29\x37\xd9\x71\x9b\x26"
+           "\x10\x9f\x55\x75\x5d\x96\x4e\xd1\x53\x86\xea\xc6\xac\x81\xda\x3a"
+           "\x7b\x07\x5c\x62\x82\x4d\x14\xd2\xbf\x1d\x4e\x85\x7d\xeb\x41\x68"
+           "\xe8\x76\x55\x2c\x9b\xdd\x96\xd0\x81\xbd\xc3\x7c\x65\xf9\x52\xa7"
+           "\xf1\x7a\xac\xc3\x9b\x7c\xa7\x78\x0b\xb1\x2b\xcb\x0c\xc6\x13\xfd"
+           "\x42\x1c\xcd\x67\x76\xdd\x44\x1d\x4c\x72\x74\x2b\x8c\x52\x7b\xf7"
+           "\x30\xc9\x86\x0a\x41\x3a\xf5\x99\x26\x5e\x9e\x7d\x18\x65\x99\x25"
+           "\x1d\xc5\x48\x1a\xac\x8c\x89\x3b\x19\xd7\xbc\xb6\xce\x57\x94\xac"
+           "\x26\xef\xe5\xfe\xee\xba\x2d\x95\xd9\x00\x82\xd1\x8d\xd3\x29\x50"
+           "\x8b\xeb\x59\xa7\xed\xc0\x7e\x47\xec\x8c\x83\xa6\xd6\x38\xf8\x8e",
+           240);
+    *(uint64_t*)0x200002c8 = 0x54;
+    *(uint64_t*)0x20000318 = 1;
+    *(uint64_t*)0x20000320 = 0;
+    *(uint64_t*)0x20000328 = 0;
+    *(uint32_t*)0x20000330 = 0;
+    syscall(__NR_sendmsg, r[1], 0x20000300ul, 0ul);
+    break;
+  case 3:
+    *(uint64_t*)0x20000300 = 0;
+    *(uint32_t*)0x20000308 = 0;
+    *(uint64_t*)0x20000310 = 0x200002c0;
+    *(uint64_t*)0x200002c0 = 0x20000000;
+    *(uint32_t*)0x20000000 = 0x24;
+    *(uint16_t*)0x20000004 = 0x31;
+    *(uint16_t*)0x20000006 = 0x101;
+    *(uint32_t*)0x20000008 = 0;
+    *(uint32_t*)0x2000000c = 0;
+    *(uint8_t*)0x20000010 = 0;
+    *(uint8_t*)0x20000011 = 0;
+    *(uint16_t*)0x20000012 = 0;
+    *(uint16_t*)0x20000014 = 0x10;
+    *(uint16_t*)0x20000016 = 1;
+    *(uint16_t*)0x20000018 = 0xc;
+    STORE_BY_BITMASK(uint16_t, , 0x2000001a, 1, 0, 14);
+    STORE_BY_BITMASK(uint16_t, , 0x2000001b, 0, 6, 1);
+    STORE_BY_BITMASK(uint16_t, , 0x2000001b, 0, 7, 1);
+    *(uint16_t*)0x2000001c = 8;
+    *(uint16_t*)0x2000001e = 1;
+    memcpy((void*)0x20000020, "ife\000", 4);
+    *(uint64_t*)0x200002c8 = 0x24;
+    *(uint64_t*)0x20000318 = 1;
+    *(uint64_t*)0x20000320 = 0;
+    *(uint64_t*)0x20000328 = 0;
+    *(uint32_t*)0x20000330 = 0;
+    syscall(__NR_sendmsg, r[0], 0x20000300ul, 0ul);
+    break;
+  }
+}
+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/0f432ce7d3823ec269013f756ddf10f5423d8ba7.c b/syzkaller-repros/linux/0f432ce7d3823ec269013f756ddf10f5423d8ba7.c
new file mode 100644
index 0000000..7d860fc
--- /dev/null
+++ b/syzkaller-repros/linux/0f432ce7d3823ec269013f756ddf10f5423d8ba7.c
@@ -0,0 +1,380 @@
+// INFO: rcu detected stall in do_iter_write
+// https://syzkaller.appspot.com/bug?id=0f432ce7d3823ec269013f756ddf10f5423d8ba7
+// 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/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>
+
+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);
+}
+
+#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))))
+
+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 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);
+  }
+}
+
+#ifndef __NR_sched_setattr
+#define __NR_sched_setattr 314
+#endif
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_one(void)
+{
+  intptr_t res = 0;
+  *(uint64_t*)0x20000280 = 9;
+  *(uint64_t*)0x20000288 = 0x81;
+  syscall(__NR_prlimit64, 0, 0xeul, 0x20000280ul, 0ul);
+  *(uint32_t*)0x20000040 = 0x38;
+  *(uint32_t*)0x20000044 = 2;
+  *(uint64_t*)0x20000048 = 0;
+  *(uint32_t*)0x20000050 = 0;
+  *(uint32_t*)0x20000054 = 3;
+  *(uint64_t*)0x20000058 = 0;
+  *(uint64_t*)0x20000060 = 0;
+  *(uint64_t*)0x20000068 = 0;
+  *(uint32_t*)0x20000070 = 0;
+  *(uint32_t*)0x20000074 = 0;
+  syscall(__NR_sched_setattr, 0, 0x20000040ul, 0ul);
+  *(uint32_t*)0x2001d000 = 1;
+  *(uint32_t*)0x2001d004 = 0x70;
+  *(uint8_t*)0x2001d008 = 0;
+  *(uint8_t*)0x2001d009 = 0;
+  *(uint8_t*)0x2001d00a = 0;
+  *(uint8_t*)0x2001d00b = 0;
+  *(uint32_t*)0x2001d00c = 0;
+  *(uint64_t*)0x2001d010 = 3;
+  *(uint64_t*)0x2001d018 = 0;
+  *(uint64_t*)0x2001d020 = 0;
+  STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 0, 1);
+  STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 1, 1);
+  STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 2, 1);
+  STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 3, 1);
+  STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 4, 1);
+  STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 5, 1);
+  STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 6, 1);
+  STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 7, 1);
+  STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 8, 1);
+  STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 9, 1);
+  STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 10, 1);
+  STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 11, 1);
+  STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 12, 1);
+  STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 13, 1);
+  STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 14, 1);
+  STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 15, 2);
+  STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 17, 1);
+  STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 18, 1);
+  STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 19, 1);
+  STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 20, 1);
+  STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 21, 1);
+  STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 22, 1);
+  STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 23, 1);
+  STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 24, 1);
+  STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 25, 1);
+  STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 26, 1);
+  STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 27, 1);
+  STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 28, 1);
+  STORE_BY_BITMASK(uint64_t, , 0x2001d028, 0, 29, 35);
+  *(uint32_t*)0x2001d030 = 0;
+  *(uint32_t*)0x2001d034 = 0;
+  *(uint64_t*)0x2001d038 = 0;
+  *(uint64_t*)0x2001d040 = 0;
+  *(uint64_t*)0x2001d048 = 0;
+  *(uint64_t*)0x2001d050 = 0;
+  *(uint32_t*)0x2001d058 = 0;
+  *(uint32_t*)0x2001d05c = 0;
+  *(uint64_t*)0x2001d060 = 0;
+  *(uint32_t*)0x2001d068 = 0;
+  *(uint16_t*)0x2001d06c = 0;
+  *(uint16_t*)0x2001d06e = 0;
+  syscall(__NR_perf_event_open, 0x2001d000ul, 0, -1ul, -1, 0ul);
+  memcpy((void*)0x20000700, "./bus\000", 6);
+  res = syscall(__NR_creat, 0x20000700ul, 0ul);
+  if (res != -1)
+    r[0] = res;
+  *(uint64_t*)0x200006c0 = 0;
+  *(uint64_t*)0x200006c8 = 0;
+  *(uint64_t*)0x200006d0 = 0;
+  *(uint64_t*)0x200006d8 = 0;
+  *(uint64_t*)0x200006e0 = 0;
+  *(uint64_t*)0x200006e8 = 0;
+  *(uint64_t*)0x200006f0 = 0;
+  *(uint64_t*)0x200006f8 = 0;
+  *(uint64_t*)0x20000700 = 0;
+  *(uint64_t*)0x20000708 = 0;
+  *(uint64_t*)0x20000710 = 0;
+  *(uint64_t*)0x20000718 = 0;
+  *(uint64_t*)0x20000720 = 0;
+  *(uint64_t*)0x20000728 = 0;
+  *(uint64_t*)0x20000730 = 0x20000740;
+  memcpy((void*)0x20000740,
+         "\xaa\x47\x2e\x1f\xf8\xce\xa9\xf3\x22\x01\xc6\xdf\x7a\x20\x1e\x43\xf4"
+         "\x01\x8f\xab\x00\xc7\x82\x77\x29\x0b\xaa\xd4\x58\x21\x1e\x53\x74\x56"
+         "\xb6\x1e\xf7\xb2\x90\x1a\x08\x09\x2d\xa2\x8d\xf9\x1c\xdd\x6b\xc6\x6b"
+         "\x29\xde\xfb\x46\x90\x89\x6c\xdd\xfb\x0c\xdd\x5c\x06\x5d\xdb\x7d\x29"
+         "\xb2\x1e\xf1\xa6\x0e\x6b\x37\x1d\x34\x13\x00\xf3\xde\x60\xdd\x15\xcb"
+         "\x14\xce\x3c\x03\xe5\x65\x1f\xd7\x50\x33\x02\x7e\xe1\x8b\xff\xcd\x21"
+         "\x73\x51\xa8\x78\xda\x61\xa0\x83\x9c\x8e\x7e\x4c\xb8\x25\x29\xe4\x55"
+         "\x38\x30\x92\xaf\x6c\xda\x1f\x25\x34\xd1\xa7\x49\x7c\xd3\xc0\x98\xd0"
+         "\x5f\x8e\x39\xd0\x63\x43\x27\x4c\x2e\xef\x27\xb0\xc8\xa9\xac\xc6\x5c"
+         "\x84\x76\x0b\x90\xe5\xa9\x02\x37\x94\x43\x96\xf6\x11\xec\xa0\x11\xdf"
+         "\x51\x91\x3d\xcc\x47\x34\x02\xc2\x65\xde\x5e\x40\x8c\x21\xf5\x53\x36"
+         "\xfc\x10\xb9\xd1\x91\xfc\x3c\x14\x6c\x9c\x34\x74\xcb\x99\xd4\x04\xce"
+         "\xbc\x35\x27\x88\x4a\xf0\x0d\x10\x08\xf2",
+         214);
+  *(uint64_t*)0x20000738 = 0xd6;
+  syscall(__NR_writev, r[0], 0x200006c0ul, 8ul);
+  memcpy((void*)0x20000240, "./bus\000", 6);
+  res = syscall(__NR_open, 0x20000240ul, 0ul, 0ul);
+  if (res != -1)
+    r[1] = res;
+  syscall(__NR_sendfile, r[0], r[1], 0ul, 0x8000fffffffeul);
+}
+int main(void)
+{
+  syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -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/0ff14ee0c4b9da917e9874e250a5f95f92fcb221.c b/syzkaller-repros/linux/0ff14ee0c4b9da917e9874e250a5f95f92fcb221.c
new file mode 100644
index 0000000..743b9da
--- /dev/null
+++ b/syzkaller-repros/linux/0ff14ee0c4b9da917e9874e250a5f95f92fcb221.c
@@ -0,0 +1,39 @@
+// INFO: task hung in lock_sock_nested (2)
+// https://syzkaller.appspot.com/bug?id=0ff14ee0c4b9da917e9874e250a5f95f92fcb221
+// 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>
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+int main(void)
+{
+  syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+  intptr_t res = 0;
+  res = syscall(__NR_socket, 0x28ul, 1ul, 0ul);
+  if (res != -1)
+    r[0] = res;
+  *(uint16_t*)0x20000000 = 0x28;
+  *(uint16_t*)0x20000002 = 0;
+  *(uint32_t*)0x20000004 = 0;
+  *(uint32_t*)0x20000008 = 2;
+  *(uint32_t*)0x2000000c = 0;
+  syscall(__NR_connect, r[0], 0x20000000ul, 0x10ul);
+  *(uint16_t*)0x20000440 = 0x28;
+  *(uint16_t*)0x20000442 = 0;
+  *(uint32_t*)0x20000444 = 0xffffd8ef;
+  *(uint32_t*)0x20000448 = -1;
+  *(uint32_t*)0x2000044c = 0;
+  syscall(__NR_connect, r[0], 0x20000440ul, 0x10ul);
+  return 0;
+}
diff --git a/syzkaller-repros/linux/10a5b82e70465a6edacfdcdcef9a58c28819dc51.c b/syzkaller-repros/linux/10a5b82e70465a6edacfdcdcef9a58c28819dc51.c
new file mode 100644
index 0000000..03f96c0
--- /dev/null
+++ b/syzkaller-repros/linux/10a5b82e70465a6edacfdcdcef9a58c28819dc51.c
@@ -0,0 +1,1618 @@
+// kernel panic: audit: backlog limit exceeded
+// https://syzkaller.appspot.com/bug?id=10a5b82e70465a6edacfdcdcef9a58c28819dc51
+// status:invalid
+// 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_linked(struct nlmsg* nlmsg, int sock, const char* type,
+                               const char* name, const char* link)
+{
+  netlink_add_device_impl(nlmsg, type, name);
+  netlink_done(nlmsg);
+  int ifindex = if_nametoindex(link);
+  netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+  int err = netlink_send(nlmsg, sock);
+  (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;
+}
+
+static void netlink_add_geneve(struct nlmsg* nlmsg, int sock, const char* name,
+                               uint32_t vni, struct in_addr* addr4,
+                               struct in6_addr* addr6)
+{
+  netlink_add_device_impl(nlmsg, "geneve", name);
+  netlink_nest(nlmsg, IFLA_INFO_DATA);
+  netlink_attr(nlmsg, IFLA_GENEVE_ID, &vni, sizeof(vni));
+  if (addr4)
+    netlink_attr(nlmsg, IFLA_GENEVE_REMOTE, addr4, sizeof(*addr4));
+  if (addr6)
+    netlink_attr(nlmsg, IFLA_GENEVE_REMOTE6, addr6, sizeof(*addr6));
+  netlink_done(nlmsg);
+  netlink_done(nlmsg);
+  int err = netlink_send(nlmsg, sock);
+  (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;
+}
+
+#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");
+  }
+}
+
+#define WG_GENL_NAME "wireguard"
+enum wg_cmd {
+  WG_CMD_GET_DEVICE,
+  WG_CMD_SET_DEVICE,
+};
+enum wgdevice_attribute {
+  WGDEVICE_A_UNSPEC,
+  WGDEVICE_A_IFINDEX,
+  WGDEVICE_A_IFNAME,
+  WGDEVICE_A_PRIVATE_KEY,
+  WGDEVICE_A_PUBLIC_KEY,
+  WGDEVICE_A_FLAGS,
+  WGDEVICE_A_LISTEN_PORT,
+  WGDEVICE_A_FWMARK,
+  WGDEVICE_A_PEERS,
+};
+enum wgpeer_attribute {
+  WGPEER_A_UNSPEC,
+  WGPEER_A_PUBLIC_KEY,
+  WGPEER_A_PRESHARED_KEY,
+  WGPEER_A_FLAGS,
+  WGPEER_A_ENDPOINT,
+  WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+  WGPEER_A_LAST_HANDSHAKE_TIME,
+  WGPEER_A_RX_BYTES,
+  WGPEER_A_TX_BYTES,
+  WGPEER_A_ALLOWEDIPS,
+  WGPEER_A_PROTOCOL_VERSION,
+};
+enum wgallowedip_attribute {
+  WGALLOWEDIP_A_UNSPEC,
+  WGALLOWEDIP_A_FAMILY,
+  WGALLOWEDIP_A_IPADDR,
+  WGALLOWEDIP_A_CIDR_MASK,
+};
+
+static int netlink_wireguard_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, WG_GENL_NAME,
+               strlen(WG_GENL_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_wireguard_setup(void)
+{
+  const char ifname_a[] = "wg0";
+  const char ifname_b[] = "wg1";
+  const char ifname_c[] = "wg2";
+  const char private_a[] = "\xa0\x5c\xa8\x4f\x6c\x9c\x8e\x38\x53\xe2\xfd\x7a"
+                           "\x70\xae\x0f\xb2\x0f\xa1\x52\x60\x0c\xb0\x08\x45"
+                           "\x17\x4f\x08\x07\x6f\x8d\x78\x43";
+  const char private_b[] = "\xb0\x80\x73\xe8\xd4\x4e\x91\xe3\xda\x92\x2c\x22"
+                           "\x43\x82\x44\xbb\x88\x5c\x69\xe2\x69\xc8\xe9\xd8"
+                           "\x35\xb1\x14\x29\x3a\x4d\xdc\x6e";
+  const char private_c[] = "\xa0\xcb\x87\x9a\x47\xf5\xbc\x64\x4c\x0e\x69\x3f"
+                           "\xa6\xd0\x31\xc7\x4a\x15\x53\xb6\xe9\x01\xb9\xff"
+                           "\x2f\x51\x8c\x78\x04\x2f\xb5\x42";
+  const char public_a[] = "\x97\x5c\x9d\x81\xc9\x83\xc8\x20\x9e\xe7\x81\x25\x4b"
+                          "\x89\x9f\x8e\xd9\x25\xae\x9f\x09\x23\xc2\x3c\x62\xf5"
+                          "\x3c\x57\xcd\xbf\x69\x1c";
+  const char public_b[] = "\xd1\x73\x28\x99\xf6\x11\xcd\x89\x94\x03\x4d\x7f\x41"
+                          "\x3d\xc9\x57\x63\x0e\x54\x93\xc2\x85\xac\xa4\x00\x65"
+                          "\xcb\x63\x11\xbe\x69\x6b";
+  const char public_c[] = "\xf4\x4d\xa3\x67\xa8\x8e\xe6\x56\x4f\x02\x02\x11\x45"
+                          "\x67\x27\x08\x2f\x5c\xeb\xee\x8b\x1b\xf5\xeb\x73\x37"
+                          "\x34\x1b\x45\x9b\x39\x22";
+  const uint16_t listen_a = 20001;
+  const uint16_t listen_b = 20002;
+  const uint16_t listen_c = 20003;
+  const uint16_t af_inet = AF_INET;
+  const uint16_t af_inet6 = AF_INET6;
+  /* Unused, but useful in case we change this:
+  const struct sockaddr_in endpoint_a_v4 = {
+      .sin_family = AF_INET,
+      .sin_port = htons(listen_a),
+      .sin_addr = {htonl(INADDR_LOOPBACK)}};*/
+  const struct sockaddr_in endpoint_b_v4 = {
+      .sin_family = AF_INET,
+      .sin_port = htons(listen_b),
+      .sin_addr = {htonl(INADDR_LOOPBACK)}};
+  const struct sockaddr_in endpoint_c_v4 = {
+      .sin_family = AF_INET,
+      .sin_port = htons(listen_c),
+      .sin_addr = {htonl(INADDR_LOOPBACK)}};
+  struct sockaddr_in6 endpoint_a_v6 = {.sin6_family = AF_INET6,
+                                       .sin6_port = htons(listen_a)};
+  endpoint_a_v6.sin6_addr = in6addr_loopback;
+  /* Unused, but useful in case we change this:
+  const struct sockaddr_in6 endpoint_b_v6 = {
+      .sin6_family = AF_INET6,
+      .sin6_port = htons(listen_b)};
+  endpoint_b_v6.sin6_addr = in6addr_loopback; */
+  struct sockaddr_in6 endpoint_c_v6 = {.sin6_family = AF_INET6,
+                                       .sin6_port = htons(listen_c)};
+  endpoint_c_v6.sin6_addr = in6addr_loopback;
+  const struct in_addr first_half_v4 = {0};
+  const struct in_addr second_half_v4 = {htonl(128 << 24)};
+  const struct in6_addr first_half_v6 = {{{0}}};
+  const struct in6_addr second_half_v6 = {{{0x80}}};
+  const uint8_t half_cidr = 1;
+  const uint16_t persistent_keepalives[] = {1, 3, 7, 9, 14, 19};
+  struct genlmsghdr genlhdr = {.cmd = WG_CMD_SET_DEVICE, .version = 1};
+  int sock;
+  int id, err;
+  sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+  if (sock == -1)
+    exit(1);
+  id = netlink_wireguard_id_get(&nlmsg, sock);
+  if (id == -1)
+    goto error;
+  netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+  netlink_attr(&nlmsg, WGDEVICE_A_IFNAME, ifname_a, strlen(ifname_a) + 1);
+  netlink_attr(&nlmsg, WGDEVICE_A_PRIVATE_KEY, private_a, 32);
+  netlink_attr(&nlmsg, WGDEVICE_A_LISTEN_PORT, &listen_a, 2);
+  netlink_nest(&nlmsg, NLA_F_NESTED | WGDEVICE_A_PEERS);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_b, 32);
+  netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_b_v4,
+               sizeof(endpoint_b_v4));
+  netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+               &persistent_keepalives[0], 2);
+  netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v4,
+               sizeof(first_half_v4));
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+  netlink_done(&nlmsg);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v6,
+               sizeof(first_half_v6));
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_c, 32);
+  netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_c_v6,
+               sizeof(endpoint_c_v6));
+  netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+               &persistent_keepalives[1], 2);
+  netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v4,
+               sizeof(second_half_v4));
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+  netlink_done(&nlmsg);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v6,
+               sizeof(second_half_v6));
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  err = netlink_send(&nlmsg, sock);
+  if (err) {
+  }
+  netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+  netlink_attr(&nlmsg, WGDEVICE_A_IFNAME, ifname_b, strlen(ifname_b) + 1);
+  netlink_attr(&nlmsg, WGDEVICE_A_PRIVATE_KEY, private_b, 32);
+  netlink_attr(&nlmsg, WGDEVICE_A_LISTEN_PORT, &listen_b, 2);
+  netlink_nest(&nlmsg, NLA_F_NESTED | WGDEVICE_A_PEERS);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_a, 32);
+  netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_a_v6,
+               sizeof(endpoint_a_v6));
+  netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+               &persistent_keepalives[2], 2);
+  netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v4,
+               sizeof(first_half_v4));
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+  netlink_done(&nlmsg);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v6,
+               sizeof(first_half_v6));
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_c, 32);
+  netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_c_v4,
+               sizeof(endpoint_c_v4));
+  netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+               &persistent_keepalives[3], 2);
+  netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v4,
+               sizeof(second_half_v4));
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+  netlink_done(&nlmsg);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v6,
+               sizeof(second_half_v6));
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  err = netlink_send(&nlmsg, sock);
+  if (err) {
+  }
+  netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+  netlink_attr(&nlmsg, WGDEVICE_A_IFNAME, ifname_c, strlen(ifname_c) + 1);
+  netlink_attr(&nlmsg, WGDEVICE_A_PRIVATE_KEY, private_c, 32);
+  netlink_attr(&nlmsg, WGDEVICE_A_LISTEN_PORT, &listen_c, 2);
+  netlink_nest(&nlmsg, NLA_F_NESTED | WGDEVICE_A_PEERS);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_a, 32);
+  netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_a_v6,
+               sizeof(endpoint_a_v6));
+  netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+               &persistent_keepalives[4], 2);
+  netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v4,
+               sizeof(first_half_v4));
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+  netlink_done(&nlmsg);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v6,
+               sizeof(first_half_v6));
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_b, 32);
+  netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_b_v4,
+               sizeof(endpoint_b_v4));
+  netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+               &persistent_keepalives[5], 2);
+  netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v4,
+               sizeof(second_half_v4));
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+  netlink_done(&nlmsg);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v6,
+               sizeof(second_half_v6));
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  err = netlink_send(&nlmsg, sock);
+  if (err) {
+  }
+
+error:
+  close(sock);
+}
+static void initialize_netdevices(void)
+{
+  char netdevsim[16];
+  sprintf(netdevsim, "netdevsim%d", (int)procid);
+  struct {
+    const char* type;
+    const char* dev;
+  } devtypes[] = {
+      {"ip6gretap", "ip6gretap0"}, {"bridge", "bridge0"},
+      {"vcan", "vcan0"},           {"bond", "bond0"},
+      {"team", "team0"},           {"dummy", "dummy0"},
+      {"nlmon", "nlmon0"},         {"caif", "caif0"},
+      {"batadv", "batadv0"},       {"vxcan", "vxcan1"},
+      {"netdevsim", netdevsim},    {"veth", 0},
+      {"xfrm", "xfrm0"},           {"wireguard", "wg0"},
+      {"wireguard", "wg1"},        {"wireguard", "wg2"},
+  };
+  const char* devmasters[] = {"bridge", "bond", "team", "batadv"};
+  struct {
+    const char* name;
+    int macsize;
+    bool noipv6;
+  } devices[] = {
+      {"lo", ETH_ALEN},
+      {"sit0", 0},
+      {"bridge0", ETH_ALEN},
+      {"vcan0", 0, true},
+      {"tunl0", 0},
+      {"gre0", 0},
+      {"gretap0", ETH_ALEN},
+      {"ip_vti0", 0},
+      {"ip6_vti0", 0},
+      {"ip6tnl0", 0},
+      {"ip6gre0", 0},
+      {"ip6gretap0", ETH_ALEN},
+      {"erspan0", ETH_ALEN},
+      {"bond0", ETH_ALEN},
+      {"veth0", ETH_ALEN},
+      {"veth1", ETH_ALEN},
+      {"team0", ETH_ALEN},
+      {"veth0_to_bridge", ETH_ALEN},
+      {"veth1_to_bridge", ETH_ALEN},
+      {"veth0_to_bond", ETH_ALEN},
+      {"veth1_to_bond", ETH_ALEN},
+      {"veth0_to_team", ETH_ALEN},
+      {"veth1_to_team", ETH_ALEN},
+      {"veth0_to_hsr", ETH_ALEN},
+      {"veth1_to_hsr", ETH_ALEN},
+      {"hsr0", 0},
+      {"dummy0", ETH_ALEN},
+      {"nlmon0", 0},
+      {"vxcan0", 0, true},
+      {"vxcan1", 0, true},
+      {"caif0", ETH_ALEN},
+      {"batadv0", ETH_ALEN},
+      {netdevsim, ETH_ALEN},
+      {"xfrm0", ETH_ALEN},
+      {"veth0_virt_wifi", ETH_ALEN},
+      {"veth1_virt_wifi", ETH_ALEN},
+      {"virt_wifi0", ETH_ALEN},
+      {"veth0_vlan", ETH_ALEN},
+      {"veth1_vlan", ETH_ALEN},
+      {"vlan0", ETH_ALEN},
+      {"vlan1", ETH_ALEN},
+      {"macvlan0", ETH_ALEN},
+      {"macvlan1", ETH_ALEN},
+      {"ipvlan0", ETH_ALEN},
+      {"ipvlan1", ETH_ALEN},
+      {"veth0_macvtap", ETH_ALEN},
+      {"veth1_macvtap", ETH_ALEN},
+      {"macvtap0", ETH_ALEN},
+      {"macsec0", ETH_ALEN},
+      {"veth0_to_batadv", ETH_ALEN},
+      {"veth1_to_batadv", ETH_ALEN},
+      {"batadv_slave_0", ETH_ALEN},
+      {"batadv_slave_1", ETH_ALEN},
+      {"geneve0", ETH_ALEN},
+      {"geneve1", ETH_ALEN},
+      {"wg0", 0},
+      {"wg1", 0},
+      {"wg2", 0},
+  };
+  int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+  if (sock == -1)
+    exit(1);
+  unsigned i;
+  for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++)
+    netlink_add_device(&nlmsg, sock, devtypes[i].type, devtypes[i].dev);
+  for (i = 0; i < sizeof(devmasters) / (sizeof(devmasters[0])); i++) {
+    char master[32], slave0[32], veth0[32], slave1[32], veth1[32];
+    sprintf(slave0, "%s_slave_0", devmasters[i]);
+    sprintf(veth0, "veth0_to_%s", devmasters[i]);
+    netlink_add_veth(&nlmsg, sock, slave0, veth0);
+    sprintf(slave1, "%s_slave_1", devmasters[i]);
+    sprintf(veth1, "veth1_to_%s", devmasters[i]);
+    netlink_add_veth(&nlmsg, sock, slave1, veth1);
+    sprintf(master, "%s0", devmasters[i]);
+    netlink_device_change(&nlmsg, sock, slave0, false, master, 0, 0, NULL);
+    netlink_device_change(&nlmsg, sock, slave1, false, master, 0, 0, NULL);
+  }
+  netlink_device_change(&nlmsg, sock, "bridge_slave_0", true, 0, 0, 0, NULL);
+  netlink_device_change(&nlmsg, sock, "bridge_slave_1", true, 0, 0, 0, NULL);
+  netlink_add_veth(&nlmsg, sock, "hsr_slave_0", "veth0_to_hsr");
+  netlink_add_veth(&nlmsg, sock, "hsr_slave_1", "veth1_to_hsr");
+  netlink_add_hsr(&nlmsg, sock, "hsr0", "hsr_slave_0", "hsr_slave_1");
+  netlink_device_change(&nlmsg, sock, "hsr_slave_0", true, 0, 0, 0, NULL);
+  netlink_device_change(&nlmsg, sock, "hsr_slave_1", true, 0, 0, 0, NULL);
+  netlink_add_veth(&nlmsg, sock, "veth0_virt_wifi", "veth1_virt_wifi");
+  netlink_add_linked(&nlmsg, sock, "virt_wifi", "virt_wifi0",
+                     "veth1_virt_wifi");
+  netlink_add_veth(&nlmsg, sock, "veth0_vlan", "veth1_vlan");
+  netlink_add_vlan(&nlmsg, sock, "vlan0", "veth0_vlan", 0, htons(ETH_P_8021Q));
+  netlink_add_vlan(&nlmsg, sock, "vlan1", "veth0_vlan", 1, htons(ETH_P_8021AD));
+  netlink_add_macvlan(&nlmsg, sock, "macvlan0", "veth1_vlan");
+  netlink_add_macvlan(&nlmsg, sock, "macvlan1", "veth1_vlan");
+  netlink_add_ipvlan(&nlmsg, sock, "ipvlan0", "veth0_vlan", IPVLAN_MODE_L2, 0);
+  netlink_add_ipvlan(&nlmsg, sock, "ipvlan1", "veth0_vlan", IPVLAN_MODE_L3S,
+                     IPVLAN_F_VEPA);
+  netlink_add_veth(&nlmsg, sock, "veth0_macvtap", "veth1_macvtap");
+  netlink_add_linked(&nlmsg, sock, "macvtap", "macvtap0", "veth0_macvtap");
+  netlink_add_linked(&nlmsg, sock, "macsec", "macsec0", "veth1_macvtap");
+  char addr[32];
+  sprintf(addr, DEV_IPV4, 14 + 10);
+  struct in_addr geneve_addr4;
+  if (inet_pton(AF_INET, addr, &geneve_addr4) <= 0)
+    exit(1);
+  struct in6_addr geneve_addr6;
+  if (inet_pton(AF_INET6, "fc00::01", &geneve_addr6) <= 0)
+    exit(1);
+  netlink_add_geneve(&nlmsg, sock, "geneve0", 0, &geneve_addr4, 0);
+  netlink_add_geneve(&nlmsg, sock, "geneve1", 1, 0, &geneve_addr6);
+  netdevsim_add((int)procid, 4);
+  netlink_wireguard_setup();
+  for (i = 0; i < sizeof(devices) / (sizeof(devices[0])); i++) {
+    char addr[32];
+    sprintf(addr, DEV_IPV4, i + 10);
+    netlink_add_addr4(&nlmsg, sock, devices[i].name, addr);
+    if (!devices[i].noipv6) {
+      sprintf(addr, DEV_IPV6, i + 10);
+      netlink_add_addr6(&nlmsg, sock, devices[i].name, addr);
+    }
+    uint64_t macaddr = DEV_MAC + ((i + 10ull) << 40);
+    netlink_device_change(&nlmsg, sock, devices[i].name, true, 0, &macaddr,
+                          devices[i].macsize, NULL);
+  }
+  close(sock);
+}
+static void initialize_netdevices_init(void)
+{
+  int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+  if (sock == -1)
+    exit(1);
+  struct {
+    const char* type;
+    int macsize;
+    bool noipv6;
+    bool noup;
+  } devtypes[] = {
+      {"nr", 7, true}, {"rose", 5, true, true},
+  };
+  unsigned i;
+  for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++) {
+    char dev[32], addr[32];
+    sprintf(dev, "%s%d", devtypes[i].type, (int)procid);
+    sprintf(addr, "172.30.%d.%d", i, (int)procid + 1);
+    netlink_add_addr4(&nlmsg, sock, dev, addr);
+    if (!devtypes[i].noipv6) {
+      sprintf(addr, "fe88::%02x:%02x", i, (int)procid + 1);
+      netlink_add_addr6(&nlmsg, sock, dev, addr);
+    }
+    int macsize = devtypes[i].macsize;
+    uint64_t macaddr = 0xbbbbbb +
+                       ((unsigned long long)i << (8 * (macsize - 2))) +
+                       (procid << (8 * (macsize - 1)));
+    netlink_device_change(&nlmsg, sock, dev, !devtypes[i].noup, 0, &macaddr,
+                          macsize, NULL);
+  }
+  close(sock);
+}
+
+#define MAX_FDS 30
+
+#define 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_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 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)
+{
+  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_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_loop()
+{
+  checkpoint_net_namespace();
+}
+
+static void reset_loop()
+{
+  reset_net_namespace();
+}
+
+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);
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS __WALL
+
+static void loop(void)
+{
+  setup_loop();
+  int iter;
+  for (iter = 0;; iter++) {
+    reset_loop();
+    int pid = fork();
+    if (pid < 0)
+      exit(1);
+    if (pid == 0) {
+      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;
+    }
+  }
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void execute_one(void)
+{
+  intptr_t res = 0;
+  res = syscall(__NR_socket, 0x10ul, 3ul, 9ul);
+  if (res != -1)
+    r[0] = res;
+  *(uint64_t*)0x200006c0 = 0;
+  *(uint32_t*)0x200006c8 = 0;
+  *(uint64_t*)0x200006d0 = 0x20000040;
+  *(uint64_t*)0x20000040 = 0x20000000;
+  *(uint32_t*)0x20000000 = 0x34;
+  *(uint16_t*)0x20000004 = 0x3e9;
+  *(uint16_t*)0x20000006 = 0x400;
+  *(uint32_t*)0x20000008 = 0;
+  *(uint32_t*)0x2000000c = 0x25dfdc01;
+  *(uint32_t*)0x20000010 = 0x3f;
+  *(uint32_t*)0x20000014 = 1;
+  *(uint32_t*)0x20000018 = 2;
+  *(uint32_t*)0x2000001c = 0;
+  *(uint32_t*)0x20000020 = -1;
+  *(uint32_t*)0x20000024 = 2;
+  *(uint32_t*)0x20000028 = 4;
+  *(uint32_t*)0x2000002c = 0;
+  *(uint32_t*)0x20000030 = 0;
+  *(uint64_t*)0x20000048 = 0x34;
+  *(uint64_t*)0x200006d8 = 1;
+  *(uint64_t*)0x200006e0 = 0;
+  *(uint64_t*)0x200006e8 = 0;
+  *(uint32_t*)0x200006f0 = 0x40040c1;
+  syscall(__NR_sendmsg, r[0], 0x200006c0ul, 0ul);
+}
+int main(void)
+{
+  syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+  do_sandbox_none();
+  return 0;
+}
diff --git a/syzkaller-repros/linux/12211f9054a577a71f3900790773eec3776d4912.c b/syzkaller-repros/linux/12211f9054a577a71f3900790773eec3776d4912.c
new file mode 100644
index 0000000..502d38c
--- /dev/null
+++ b/syzkaller-repros/linux/12211f9054a577a71f3900790773eec3776d4912.c
@@ -0,0 +1,290 @@
+// panic: Incrementing non-positive ref count (4)
+// https://syzkaller.appspot.com/bug?id=12211f9054a577a71f3900790773eec3776d4912
+// 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/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>
+
+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;
+}
+
+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;
+}
+
+#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[1] = {0xffffffffffffffff};
+
+void execute_one(void)
+{
+  intptr_t res = 0;
+  memcpy((void*)0x200005c0, "./file0\000", 8);
+  syscall(__NR_creat, 0x200005c0ul, 0ul);
+  memcpy((void*)0x20000280, "./file0\000", 8);
+  memcpy((void*)0x20000180, "sysfs\000", 6);
+  syscall(__NR_mount, 0x20000600ul, 0x20000280ul, 0x20000180ul, 0ul, 0ul);
+  memcpy((void*)0x20000180, "mounts\000", 7);
+  res = syz_open_procfs(0, 0x20000180);
+  if (res != -1)
+    r[0] = res;
+  syscall(__NR_read, r[0], 0ul, 0ul);
+}
+int main(void)
+{
+  syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+  for (procid = 0; procid < 4; procid++) {
+    if (fork() == 0) {
+      use_temporary_dir();
+      loop();
+    }
+  }
+  sleep(1000000);
+  return 0;
+}
diff --git a/syzkaller-repros/linux/12c0ee39a5513b9a22411937566238edde02bef5.c b/syzkaller-repros/linux/12c0ee39a5513b9a22411937566238edde02bef5.c
new file mode 100644
index 0000000..31110a3
--- /dev/null
+++ b/syzkaller-repros/linux/12c0ee39a5513b9a22411937566238edde02bef5.c
@@ -0,0 +1,31 @@
+// BUG: unable to handle kernel NULL pointer dereference in cipso_v4_sock_setattr
+// https://syzkaller.appspot.com/bug?id=12c0ee39a5513b9a22411937566238edde02bef5
+// 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>
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+int main(void)
+{
+  syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+  intptr_t res = 0;
+  res = syscall(__NR_socket, 2ul, 1ul, 0x106ul);
+  if (res != -1)
+    r[0] = res;
+  memcpy((void*)0x200001c0, "security.SMACK64IPOUT\000", 22);
+  memcpy((void*)0x20000200, "batadv0\000", 8);
+  *(uint8_t*)0x20000208 = 0;
+  syscall(__NR_fsetxattr, r[0], 0x200001c0ul, 0x20000200ul, 9ul, 3ul);
+  return 0;
+}
diff --git a/syzkaller-repros/linux/13b8fc341d999cc4a3eaa66fd7f624f698aa4b29.c b/syzkaller-repros/linux/13b8fc341d999cc4a3eaa66fd7f624f698aa4b29.c
new file mode 100644
index 0000000..85485a5
--- /dev/null
+++ b/syzkaller-repros/linux/13b8fc341d999cc4a3eaa66fd7f624f698aa4b29.c
@@ -0,0 +1,2149 @@
+// DATA RACE in fsutil.(*InodeSimpleExtendedAttributes).GetXattr
+// https://syzkaller.appspot.com/bug?id=13b8fc341d999cc4a3eaa66fd7f624f698aa4b29
+// 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);
+}
+
+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 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_linked(struct nlmsg* nlmsg, int sock, const char* type,
+                               const char* name, const char* link)
+{
+  netlink_add_device_impl(nlmsg, type, name);
+  netlink_done(nlmsg);
+  int ifindex = if_nametoindex(link);
+  netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+  int err = netlink_send(nlmsg, sock);
+  (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;
+}
+
+static void netlink_add_geneve(struct nlmsg* nlmsg, int sock, const char* name,
+                               uint32_t vni, struct in_addr* addr4,
+                               struct in6_addr* addr6)
+{
+  netlink_add_device_impl(nlmsg, "geneve", name);
+  netlink_nest(nlmsg, IFLA_INFO_DATA);
+  netlink_attr(nlmsg, IFLA_GENEVE_ID, &vni, sizeof(vni));
+  if (addr4)
+    netlink_attr(nlmsg, IFLA_GENEVE_REMOTE, addr4, sizeof(*addr4));
+  if (addr6)
+    netlink_attr(nlmsg, IFLA_GENEVE_REMOTE6, addr6, sizeof(*addr6));
+  netlink_done(nlmsg);
+  netlink_done(nlmsg);
+  int err = netlink_send(nlmsg, sock);
+  (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;
+  if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0) {
+    exit(1);
+  }
+  char sysctl[64];
+  sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/accept_dad", TUN_IFACE);
+  write_file(sysctl, "0");
+  sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/router_solicitations", TUN_IFACE);
+  write_file(sysctl, "0");
+  int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+  if (sock == -1)
+    exit(1);
+  netlink_add_addr4(&nlmsg, sock, TUN_IFACE, LOCAL_IPV4);
+  netlink_add_addr6(&nlmsg, sock, TUN_IFACE, LOCAL_IPV6);
+  uint64_t macaddr = REMOTE_MAC;
+  struct in_addr in_addr;
+  inet_pton(AF_INET, REMOTE_IPV4, &in_addr);
+  netlink_add_neigh(&nlmsg, sock, TUN_IFACE, &in_addr, sizeof(in_addr),
+                    &macaddr, ETH_ALEN);
+  struct in6_addr in6_addr;
+  inet_pton(AF_INET6, REMOTE_IPV6, &in6_addr);
+  netlink_add_neigh(&nlmsg, sock, TUN_IFACE, &in6_addr, sizeof(in6_addr),
+                    &macaddr, ETH_ALEN);
+  macaddr = LOCAL_MAC;
+  netlink_device_change(&nlmsg, sock, TUN_IFACE, true, 0, &macaddr, ETH_ALEN,
+                        NULL);
+  close(sock);
+}
+
+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");
+  }
+}
+
+#define WG_GENL_NAME "wireguard"
+enum wg_cmd {
+  WG_CMD_GET_DEVICE,
+  WG_CMD_SET_DEVICE,
+};
+enum wgdevice_attribute {
+  WGDEVICE_A_UNSPEC,
+  WGDEVICE_A_IFINDEX,
+  WGDEVICE_A_IFNAME,
+  WGDEVICE_A_PRIVATE_KEY,
+  WGDEVICE_A_PUBLIC_KEY,
+  WGDEVICE_A_FLAGS,
+  WGDEVICE_A_LISTEN_PORT,
+  WGDEVICE_A_FWMARK,
+  WGDEVICE_A_PEERS,
+};
+enum wgpeer_attribute {
+  WGPEER_A_UNSPEC,
+  WGPEER_A_PUBLIC_KEY,
+  WGPEER_A_PRESHARED_KEY,
+  WGPEER_A_FLAGS,
+  WGPEER_A_ENDPOINT,
+  WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+  WGPEER_A_LAST_HANDSHAKE_TIME,
+  WGPEER_A_RX_BYTES,
+  WGPEER_A_TX_BYTES,
+  WGPEER_A_ALLOWEDIPS,
+  WGPEER_A_PROTOCOL_VERSION,
+};
+enum wgallowedip_attribute {
+  WGALLOWEDIP_A_UNSPEC,
+  WGALLOWEDIP_A_FAMILY,
+  WGALLOWEDIP_A_IPADDR,
+  WGALLOWEDIP_A_CIDR_MASK,
+};
+
+static int netlink_wireguard_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, WG_GENL_NAME,
+               strlen(WG_GENL_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_wireguard_setup(void)
+{
+  const char ifname_a[] = "wg0";
+  const char ifname_b[] = "wg1";
+  const char ifname_c[] = "wg2";
+  const char private_a[] =
+      "\xa0\x5c\xa8\x4f\x6c\x9c\x8e\x38\x53\xe2\xfd\x7a\x70\xae\x0f\xb2\x0f\xa1"
+      "\x52\x60\x0c\xb0\x08\x45\x17\x4f\x08\x07\x6f\x8d\x78\x43";
+  const char private_b[] =
+      "\xb0\x80\x73\xe8\xd4\x4e\x91\xe3\xda\x92\x2c\x22\x43\x82\x44\xbb\x88\x5c"
+      "\x69\xe2\x69\xc8\xe9\xd8\x35\xb1\x14\x29\x3a\x4d\xdc\x6e";
+  const char private_c[] =
+      "\xa0\xcb\x87\x9a\x47\xf5\xbc\x64\x4c\x0e\x69\x3f\xa6\xd0\x31\xc7\x4a\x15"
+      "\x53\xb6\xe9\x01\xb9\xff\x2f\x51\x8c\x78\x04\x2f\xb5\x42";
+  const char public_a[] =
+      "\x97\x5c\x9d\x81\xc9\x83\xc8\x20\x9e\xe7\x81\x25\x4b\x89\x9f\x8e\xd9\x25"
+      "\xae\x9f\x09\x23\xc2\x3c\x62\xf5\x3c\x57\xcd\xbf\x69\x1c";
+  const char public_b[] =
+      "\xd1\x73\x28\x99\xf6\x11\xcd\x89\x94\x03\x4d\x7f\x41\x3d\xc9\x57\x63\x0e"
+      "\x54\x93\xc2\x85\xac\xa4\x00\x65\xcb\x63\x11\xbe\x69\x6b";
+  const char public_c[] =
+      "\xf4\x4d\xa3\x67\xa8\x8e\xe6\x56\x4f\x02\x02\x11\x45\x67\x27\x08\x2f\x5c"
+      "\xeb\xee\x8b\x1b\xf5\xeb\x73\x37\x34\x1b\x45\x9b\x39\x22";
+  const uint16_t listen_a = 20001;
+  const uint16_t listen_b = 20002;
+  const uint16_t listen_c = 20003;
+  const uint16_t af_inet = AF_INET;
+  const uint16_t af_inet6 = AF_INET6;
+  /* Unused, but useful in case we change this:
+  const struct sockaddr_in endpoint_a_v4 = {
+      .sin_family = AF_INET,
+      .sin_port = htons(listen_a),
+      .sin_addr = {htonl(INADDR_LOOPBACK)}};*/
+  const struct sockaddr_in endpoint_b_v4 = {
+      .sin_family = AF_INET,
+      .sin_port = htons(listen_b),
+      .sin_addr = {htonl(INADDR_LOOPBACK)}};
+  const struct sockaddr_in endpoint_c_v4 = {
+      .sin_family = AF_INET,
+      .sin_port = htons(listen_c),
+      .sin_addr = {htonl(INADDR_LOOPBACK)}};
+  struct sockaddr_in6 endpoint_a_v6 = {.sin6_family = AF_INET6,
+                                       .sin6_port = htons(listen_a)};
+  endpoint_a_v6.sin6_addr = in6addr_loopback;
+  /* Unused, but useful in case we change this:
+  const struct sockaddr_in6 endpoint_b_v6 = {
+      .sin6_family = AF_INET6,
+      .sin6_port = htons(listen_b)};
+  endpoint_b_v6.sin6_addr = in6addr_loopback; */
+  struct sockaddr_in6 endpoint_c_v6 = {.sin6_family = AF_INET6,
+                                       .sin6_port = htons(listen_c)};
+  endpoint_c_v6.sin6_addr = in6addr_loopback;
+  const struct in_addr first_half_v4 = {0};
+  const struct in_addr second_half_v4 = {htonl(128 << 24)};
+  const struct in6_addr first_half_v6 = {{{0}}};
+  const struct in6_addr second_half_v6 = {{{0x80}}};
+  const uint8_t half_cidr = 1;
+  const uint16_t persistent_keepalives[] = {1, 3, 7, 9, 14, 19};
+  struct genlmsghdr genlhdr = {.cmd = WG_CMD_SET_DEVICE, .version = 1};
+  int sock;
+  int id, err;
+  sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+  if (sock == -1) {
+    return;
+  }
+  id = netlink_wireguard_id_get(&nlmsg, sock);
+  if (id == -1)
+    goto error;
+  netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+  netlink_attr(&nlmsg, WGDEVICE_A_IFNAME, ifname_a, strlen(ifname_a) + 1);
+  netlink_attr(&nlmsg, WGDEVICE_A_PRIVATE_KEY, private_a, 32);
+  netlink_attr(&nlmsg, WGDEVICE_A_LISTEN_PORT, &listen_a, 2);
+  netlink_nest(&nlmsg, NLA_F_NESTED | WGDEVICE_A_PEERS);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_b, 32);
+  netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_b_v4,
+               sizeof(endpoint_b_v4));
+  netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+               &persistent_keepalives[0], 2);
+  netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v4,
+               sizeof(first_half_v4));
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+  netlink_done(&nlmsg);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v6,
+               sizeof(first_half_v6));
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_c, 32);
+  netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_c_v6,
+               sizeof(endpoint_c_v6));
+  netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+               &persistent_keepalives[1], 2);
+  netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v4,
+               sizeof(second_half_v4));
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+  netlink_done(&nlmsg);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v6,
+               sizeof(second_half_v6));
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  err = netlink_send(&nlmsg, sock);
+  if (err) {
+  }
+  netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+  netlink_attr(&nlmsg, WGDEVICE_A_IFNAME, ifname_b, strlen(ifname_b) + 1);
+  netlink_attr(&nlmsg, WGDEVICE_A_PRIVATE_KEY, private_b, 32);
+  netlink_attr(&nlmsg, WGDEVICE_A_LISTEN_PORT, &listen_b, 2);
+  netlink_nest(&nlmsg, NLA_F_NESTED | WGDEVICE_A_PEERS);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_a, 32);
+  netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_a_v6,
+               sizeof(endpoint_a_v6));
+  netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+               &persistent_keepalives[2], 2);
+  netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v4,
+               sizeof(first_half_v4));
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+  netlink_done(&nlmsg);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v6,
+               sizeof(first_half_v6));
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_c, 32);
+  netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_c_v4,
+               sizeof(endpoint_c_v4));
+  netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+               &persistent_keepalives[3], 2);
+  netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v4,
+               sizeof(second_half_v4));
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+  netlink_done(&nlmsg);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v6,
+               sizeof(second_half_v6));
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  err = netlink_send(&nlmsg, sock);
+  if (err) {
+  }
+  netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+  netlink_attr(&nlmsg, WGDEVICE_A_IFNAME, ifname_c, strlen(ifname_c) + 1);
+  netlink_attr(&nlmsg, WGDEVICE_A_PRIVATE_KEY, private_c, 32);
+  netlink_attr(&nlmsg, WGDEVICE_A_LISTEN_PORT, &listen_c, 2);
+  netlink_nest(&nlmsg, NLA_F_NESTED | WGDEVICE_A_PEERS);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_a, 32);
+  netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_a_v6,
+               sizeof(endpoint_a_v6));
+  netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+               &persistent_keepalives[4], 2);
+  netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v4,
+               sizeof(first_half_v4));
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+  netlink_done(&nlmsg);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v6,
+               sizeof(first_half_v6));
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_b, 32);
+  netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_b_v4,
+               sizeof(endpoint_b_v4));
+  netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+               &persistent_keepalives[5], 2);
+  netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v4,
+               sizeof(second_half_v4));
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+  netlink_done(&nlmsg);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v6,
+               sizeof(second_half_v6));
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  err = netlink_send(&nlmsg, sock);
+  if (err) {
+  }
+
+error:
+  close(sock);
+}
+static void initialize_netdevices(void)
+{
+  char netdevsim[16];
+  sprintf(netdevsim, "netdevsim%d", (int)procid);
+  struct {
+    const char* type;
+    const char* dev;
+  } devtypes[] = {
+      {"ip6gretap", "ip6gretap0"}, {"bridge", "bridge0"},
+      {"vcan", "vcan0"},           {"bond", "bond0"},
+      {"team", "team0"},           {"dummy", "dummy0"},
+      {"nlmon", "nlmon0"},         {"caif", "caif0"},
+      {"batadv", "batadv0"},       {"vxcan", "vxcan1"},
+      {"netdevsim", netdevsim},    {"veth", 0},
+      {"xfrm", "xfrm0"},           {"wireguard", "wg0"},
+      {"wireguard", "wg1"},        {"wireguard", "wg2"},
+  };
+  const char* devmasters[] = {"bridge", "bond", "team", "batadv"};
+  struct {
+    const char* name;
+    int macsize;
+    bool noipv6;
+  } devices[] = {
+      {"lo", ETH_ALEN},
+      {"sit0", 0},
+      {"bridge0", ETH_ALEN},
+      {"vcan0", 0, true},
+      {"tunl0", 0},
+      {"gre0", 0},
+      {"gretap0", ETH_ALEN},
+      {"ip_vti0", 0},
+      {"ip6_vti0", 0},
+      {"ip6tnl0", 0},
+      {"ip6gre0", 0},
+      {"ip6gretap0", ETH_ALEN},
+      {"erspan0", ETH_ALEN},
+      {"bond0", ETH_ALEN},
+      {"veth0", ETH_ALEN},
+      {"veth1", ETH_ALEN},
+      {"team0", ETH_ALEN},
+      {"veth0_to_bridge", ETH_ALEN},
+      {"veth1_to_bridge", ETH_ALEN},
+      {"veth0_to_bond", ETH_ALEN},
+      {"veth1_to_bond", ETH_ALEN},
+      {"veth0_to_team", ETH_ALEN},
+      {"veth1_to_team", ETH_ALEN},
+      {"veth0_to_hsr", ETH_ALEN},
+      {"veth1_to_hsr", ETH_ALEN},
+      {"hsr0", 0},
+      {"dummy0", ETH_ALEN},
+      {"nlmon0", 0},
+      {"vxcan0", 0, true},
+      {"vxcan1", 0, true},
+      {"caif0", ETH_ALEN},
+      {"batadv0", ETH_ALEN},
+      {netdevsim, ETH_ALEN},
+      {"xfrm0", ETH_ALEN},
+      {"veth0_virt_wifi", ETH_ALEN},
+      {"veth1_virt_wifi", ETH_ALEN},
+      {"virt_wifi0", ETH_ALEN},
+      {"veth0_vlan", ETH_ALEN},
+      {"veth1_vlan", ETH_ALEN},
+      {"vlan0", ETH_ALEN},
+      {"vlan1", ETH_ALEN},
+      {"macvlan0", ETH_ALEN},
+      {"macvlan1", ETH_ALEN},
+      {"ipvlan0", ETH_ALEN},
+      {"ipvlan1", ETH_ALEN},
+      {"veth0_macvtap", ETH_ALEN},
+      {"veth1_macvtap", ETH_ALEN},
+      {"macvtap0", ETH_ALEN},
+      {"macsec0", ETH_ALEN},
+      {"veth0_to_batadv", ETH_ALEN},
+      {"veth1_to_batadv", ETH_ALEN},
+      {"batadv_slave_0", ETH_ALEN},
+      {"batadv_slave_1", ETH_ALEN},
+      {"geneve0", ETH_ALEN},
+      {"geneve1", ETH_ALEN},
+      {"wg0", 0},
+      {"wg1", 0},
+      {"wg2", 0},
+  };
+  int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+  if (sock == -1)
+    exit(1);
+  unsigned i;
+  for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++)
+    netlink_add_device(&nlmsg, sock, devtypes[i].type, devtypes[i].dev);
+  for (i = 0; i < sizeof(devmasters) / (sizeof(devmasters[0])); i++) {
+    char master[32], slave0[32], veth0[32], slave1[32], veth1[32];
+    sprintf(slave0, "%s_slave_0", devmasters[i]);
+    sprintf(veth0, "veth0_to_%s", devmasters[i]);
+    netlink_add_veth(&nlmsg, sock, slave0, veth0);
+    sprintf(slave1, "%s_slave_1", devmasters[i]);
+    sprintf(veth1, "veth1_to_%s", devmasters[i]);
+    netlink_add_veth(&nlmsg, sock, slave1, veth1);
+    sprintf(master, "%s0", devmasters[i]);
+    netlink_device_change(&nlmsg, sock, slave0, false, master, 0, 0, NULL);
+    netlink_device_change(&nlmsg, sock, slave1, false, master, 0, 0, NULL);
+  }
+  netlink_device_change(&nlmsg, sock, "bridge_slave_0", true, 0, 0, 0, NULL);
+  netlink_device_change(&nlmsg, sock, "bridge_slave_1", true, 0, 0, 0, NULL);
+  netlink_add_veth(&nlmsg, sock, "hsr_slave_0", "veth0_to_hsr");
+  netlink_add_veth(&nlmsg, sock, "hsr_slave_1", "veth1_to_hsr");
+  netlink_add_hsr(&nlmsg, sock, "hsr0", "hsr_slave_0", "hsr_slave_1");
+  netlink_device_change(&nlmsg, sock, "hsr_slave_0", true, 0, 0, 0, NULL);
+  netlink_device_change(&nlmsg, sock, "hsr_slave_1", true, 0, 0, 0, NULL);
+  netlink_add_veth(&nlmsg, sock, "veth0_virt_wifi", "veth1_virt_wifi");
+  netlink_add_linked(&nlmsg, sock, "virt_wifi", "virt_wifi0",
+                     "veth1_virt_wifi");
+  netlink_add_veth(&nlmsg, sock, "veth0_vlan", "veth1_vlan");
+  netlink_add_vlan(&nlmsg, sock, "vlan0", "veth0_vlan", 0, htons(ETH_P_8021Q));
+  netlink_add_vlan(&nlmsg, sock, "vlan1", "veth0_vlan", 1, htons(ETH_P_8021AD));
+  netlink_add_macvlan(&nlmsg, sock, "macvlan0", "veth1_vlan");
+  netlink_add_macvlan(&nlmsg, sock, "macvlan1", "veth1_vlan");
+  netlink_add_ipvlan(&nlmsg, sock, "ipvlan0", "veth0_vlan", IPVLAN_MODE_L2, 0);
+  netlink_add_ipvlan(&nlmsg, sock, "ipvlan1", "veth0_vlan", IPVLAN_MODE_L3S,
+                     IPVLAN_F_VEPA);
+  netlink_add_veth(&nlmsg, sock, "veth0_macvtap", "veth1_macvtap");
+  netlink_add_linked(&nlmsg, sock, "macvtap", "macvtap0", "veth0_macvtap");
+  netlink_add_linked(&nlmsg, sock, "macsec", "macsec0", "veth1_macvtap");
+  char addr[32];
+  sprintf(addr, DEV_IPV4, 14 + 10);
+  struct in_addr geneve_addr4;
+  if (inet_pton(AF_INET, addr, &geneve_addr4) <= 0)
+    exit(1);
+  struct in6_addr geneve_addr6;
+  if (inet_pton(AF_INET6, "fc00::01", &geneve_addr6) <= 0)
+    exit(1);
+  netlink_add_geneve(&nlmsg, sock, "geneve0", 0, &geneve_addr4, 0);
+  netlink_add_geneve(&nlmsg, sock, "geneve1", 1, 0, &geneve_addr6);
+  netdevsim_add((int)procid, 4);
+  netlink_wireguard_setup();
+  for (i = 0; i < sizeof(devices) / (sizeof(devices[0])); i++) {
+    char addr[32];
+    sprintf(addr, DEV_IPV4, i + 10);
+    netlink_add_addr4(&nlmsg, sock, devices[i].name, addr);
+    if (!devices[i].noipv6) {
+      sprintf(addr, DEV_IPV6, i + 10);
+      netlink_add_addr6(&nlmsg, sock, devices[i].name, addr);
+    }
+    uint64_t macaddr = DEV_MAC + ((i + 10ull) << 40);
+    netlink_device_change(&nlmsg, sock, devices[i].name, true, 0, &macaddr,
+                          devices[i].macsize, NULL);
+  }
+  close(sock);
+}
+static void initialize_netdevices_init(void)
+{
+  int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+  if (sock == -1)
+    exit(1);
+  struct {
+    const char* type;
+    int macsize;
+    bool noipv6;
+    bool noup;
+  } devtypes[] = {
+      {"nr", 7, true},
+      {"rose", 5, true, true},
+  };
+  unsigned i;
+  for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++) {
+    char dev[32], addr[32];
+    sprintf(dev, "%s%d", devtypes[i].type, (int)procid);
+    sprintf(addr, "172.30.%d.%d", i, (int)procid + 1);
+    netlink_add_addr4(&nlmsg, sock, dev, addr);
+    if (!devtypes[i].noipv6) {
+      sprintf(addr, "fe88::%02x:%02x", i, (int)procid + 1);
+      netlink_add_addr6(&nlmsg, sock, dev, addr);
+    }
+    int macsize = devtypes[i].macsize;
+    uint64_t macaddr = 0xbbbbbb +
+                       ((unsigned long long)i << (8 * (macsize - 2))) +
+                       (procid << (8 * (macsize - 1)));
+    netlink_device_change(&nlmsg, sock, dev, !devtypes[i].noup, 0, &macaddr,
+                          macsize, NULL);
+  }
+  close(sock);
+}
+
+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 < 7; 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[1] = {0xffffffffffffffff};
+
+void execute_call(int call)
+{
+  intptr_t res;
+  switch (call) {
+  case 0:
+    syscall(__NR_pipe, 0ul);
+    break;
+  case 1:
+    syscall(__NR_ioctl, -1, 0x4b44ul, 0ul);
+    break;
+  case 2:
+    syscall(__NR_prctl, 0x13ul, 0ul, 0, 0);
+    break;
+  case 3:
+    NONFAILING(memcpy((void*)0x20000280, "./bus\000", 6));
+    res = syscall(__NR_creat, 0x20000280ul, 0ul);
+    if (res != -1)
+      r[0] = res;
+    break;
+  case 4:
+    NONFAILING(memcpy((void*)0x200000c0, "user.syz\000", 9));
+    syscall(__NR_fsetxattr, r[0], 0x200000c0ul, 0ul, 0ul, 0ul);
+    break;
+  case 5:
+    NONFAILING(memcpy((void*)0x20000040, "user.syz\000", 9));
+    syscall(__NR_fremovexattr, r[0], 0x20000040ul);
+    break;
+  case 6:
+    NONFAILING(memcpy((void*)0x20000000, "./bus\000", 6));
+    NONFAILING(memcpy((void*)0x20000080, "user.", 5));
+    NONFAILING(memcpy((void*)0x20000085, "user.syz\000", 9));
+    syscall(__NR_getxattr, 0x20000000ul, 0x20000080ul, 0ul, 0ul);
+    break;
+  }
+}
+int main(void)
+{
+  syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+  setup_binfmt_misc();
+  install_segv_handler();
+  use_temporary_dir();
+  do_sandbox_none();
+  return 0;
+}
diff --git a/syzkaller-repros/linux/15f96d171c64999196ac7db3de107f24b9182a8e.c b/syzkaller-repros/linux/15f96d171c64999196ac7db3de107f24b9182a8e.c
new file mode 100644
index 0000000..d142aa5
--- /dev/null
+++ b/syzkaller-repros/linux/15f96d171c64999196ac7db3de107f24b9182a8e.c
@@ -0,0 +1,408 @@
+// general protection fault in rds_ib_add_one
+// https://syzkaller.appspot.com/bug?id=15f96d171c64999196ac7db3de107f24b9182a8e
+// status:open
+// 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 <net/if_arp.h>
+#include <netinet/in.h>
+#include <sched.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <linux/capability.h>
+#include <linux/if_addr.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_tun.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/neighbour.h>
+#include <linux/net.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/tcp.h>
+#include <linux/veth.h>
+
+static 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 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;
+  if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0) {
+    exit(1);
+  }
+  char sysctl[64];
+  sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/accept_dad", TUN_IFACE);
+  write_file(sysctl, "0");
+  sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/router_solicitations", TUN_IFACE);
+  write_file(sysctl, "0");
+  int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+  if (sock == -1)
+    exit(1);
+  netlink_add_addr4(&nlmsg, sock, TUN_IFACE, LOCAL_IPV4);
+  netlink_add_addr6(&nlmsg, sock, TUN_IFACE, LOCAL_IPV6);
+  uint64_t macaddr = REMOTE_MAC;
+  struct in_addr in_addr;
+  inet_pton(AF_INET, REMOTE_IPV4, &in_addr);
+  netlink_add_neigh(&nlmsg, sock, TUN_IFACE, &in_addr, sizeof(in_addr),
+                    &macaddr, ETH_ALEN);
+  struct in6_addr in6_addr;
+  inet_pton(AF_INET6, REMOTE_IPV6, &in6_addr);
+  netlink_add_neigh(&nlmsg, sock, TUN_IFACE, &in6_addr, sizeof(in6_addr),
+                    &macaddr, ETH_ALEN);
+  macaddr = LOCAL_MAC;
+  netlink_device_change(&nlmsg, sock, TUN_IFACE, true, 0, &macaddr, ETH_ALEN,
+                        NULL);
+  close(sock);
+}
+
+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 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();
+  if (unshare(CLONE_NEWNET)) {
+  }
+  initialize_tun();
+  loop();
+  exit(1);
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void loop(void)
+{
+  intptr_t res = 0;
+  res = syscall(__NR_socket, 0x10ul, 3ul, 0x14ul);
+  if (res != -1)
+    r[0] = res;
+  *(uint64_t*)0x20000000 = 0;
+  *(uint32_t*)0x20000008 = 0x500;
+  *(uint64_t*)0x20000010 = 0x200000c0;
+  *(uint64_t*)0x200000c0 = 0x20000100;
+  *(uint32_t*)0x20000100 = 0x38;
+  *(uint16_t*)0x20000104 = 0x1403;
+  *(uint16_t*)0x20000106 = 1;
+  *(uint32_t*)0x20000108 = 0;
+  *(uint32_t*)0x2000010c = 0;
+  *(uint16_t*)0x20000110 = 9;
+  *(uint16_t*)0x20000112 = 2;
+  memcpy((void*)0x20000114, "syz1\000", 5);
+  *(uint16_t*)0x2000011c = 8;
+  *(uint16_t*)0x2000011e = 0x41;
+  memcpy((void*)0x20000120, "rxe\000", 4);
+  *(uint16_t*)0x20000124 = 0x14;
+  *(uint16_t*)0x20000126 = 0x33;
+  memcpy((void*)0x20000128, "syz_tun\000\000\000\000\000\000\000\000\000", 16);
+  *(uint64_t*)0x200000c8 = 0x38;
+  *(uint64_t*)0x20000018 = 1;
+  *(uint64_t*)0x20000020 = 0;
+  *(uint64_t*)0x20000028 = 0;
+  *(uint32_t*)0x20000030 = 0;
+  syscall(__NR_sendmsg, r[0], 0x20000000ul, 0ul);
+}
+int main(void)
+{
+  syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+  do_sandbox_none();
+  return 0;
+}
diff --git a/syzkaller-repros/linux/180598f76646ec1ff99e945d171e3ed4ad9b95c9.c b/syzkaller-repros/linux/180598f76646ec1ff99e945d171e3ed4ad9b95c9.c
new file mode 100644
index 0000000..efdbbdf
--- /dev/null
+++ b/syzkaller-repros/linux/180598f76646ec1ff99e945d171e3ed4ad9b95c9.c
@@ -0,0 +1,329 @@
+// KASAN: slab-out-of-bounds Read in __nla_put_nohdr
+// https://syzkaller.appspot.com/bug?id=180598f76646ec1ff99e945d171e3ed4ad9b95c9
+// status:fixed
+// 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 <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/capability.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))))
+
+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_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 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();
+  if (unshare(CLONE_NEWNET)) {
+  }
+  loop();
+  exit(1);
+}
+
+uint64_t r[4] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff,
+                 0x0};
+
+void loop(void)
+{
+  intptr_t res = 0;
+  res = syscall(__NR_socket, 0x10ul, 3ul, 0ul);
+  if (res != -1)
+    r[0] = res;
+  res = syscall(__NR_socket, 0x10ul, 3ul, 0ul);
+  if (res != -1)
+    r[1] = res;
+  res = syscall(__NR_socket, 0x10ul, 0x803ul, 0);
+  if (res != -1)
+    r[2] = res;
+  *(uint64_t*)0x20000780 = 0;
+  *(uint32_t*)0x20000788 = 6;
+  *(uint64_t*)0x20000790 = 0x20000180;
+  *(uint64_t*)0x20000180 = 0;
+  *(uint64_t*)0x20000188 = 0;
+  *(uint64_t*)0x20000798 = 1;
+  *(uint64_t*)0x200007a0 = 0;
+  *(uint64_t*)0x200007a8 = 0;
+  *(uint32_t*)0x200007b0 = 0;
+  syscall(__NR_sendmsg, r[2], 0x20000780ul, 0ul);
+  *(uint32_t*)0x20000200 = 0x14;
+  res = syscall(__NR_getsockname, r[2], 0x20000100ul, 0x20000200ul);
+  if (res != -1)
+    r[3] = *(uint32_t*)0x20000104;
+  *(uint64_t*)0x20000240 = 0;
+  *(uint32_t*)0x20000248 = 0;
+  *(uint64_t*)0x20000250 = 0x20000140;
+  *(uint64_t*)0x20000140 = 0x200003c0;
+  memcpy((void*)0x200003c0, "\x38\x00\x00\x00\x24\x00\x07\x05\x00\x00\x00\x40"
+                            "\x07\xa2\xa3\x00\x05\x00\x00\x00",
+         20);
+  *(uint32_t*)0x200003d4 = r[3];
+  memcpy((void*)0x200003d8, "\x00\x00\x00\x00\xff\xff\xff\xff\x00\x00\x00\x00"
+                            "\x09\x00\x01\x00\x68\x66\x73\x63\x00\x00\x00\x00"
+                            "\x08\x00\x02\x00\x00\x00\x00\x00",
+         32);
+  *(uint64_t*)0x20000148 = 0x38;
+  *(uint64_t*)0x20000258 = 1;
+  *(uint64_t*)0x20000260 = 0;
+  *(uint64_t*)0x20000268 = 0;
+  *(uint32_t*)0x20000270 = 0;
+  syscall(__NR_sendmsg, r[1], 0x20000240ul, 0ul);
+  *(uint64_t*)0x200001c0 = 0;
+  *(uint32_t*)0x200001c8 = 0;
+  *(uint64_t*)0x200001d0 = 0x20000180;
+  *(uint64_t*)0x20000180 = 0x20000400;
+  *(uint32_t*)0x20000400 = 0xf0;
+  *(uint16_t*)0x20000404 = 0x2c;
+  *(uint16_t*)0x20000406 = 0xd27;
+  *(uint32_t*)0x20000408 = 0;
+  *(uint32_t*)0x2000040c = 0;
+  *(uint8_t*)0x20000410 = 0;
+  *(uint8_t*)0x20000411 = 0;
+  *(uint16_t*)0x20000412 = 0;
+  *(uint32_t*)0x20000414 = r[3];
+  *(uint16_t*)0x20000418 = 0;
+  *(uint16_t*)0x2000041a = 1;
+  *(uint16_t*)0x2000041c = 0;
+  *(uint16_t*)0x2000041e = 0;
+  *(uint16_t*)0x20000420 = 0xf;
+  *(uint16_t*)0x20000422 = 0;
+  *(uint16_t*)0x20000424 = 0xa;
+  *(uint16_t*)0x20000426 = 1;
+  memcpy((void*)0x20000428, "basic\000", 6);
+  *(uint16_t*)0x20000430 = 0xc0;
+  *(uint16_t*)0x20000432 = 2;
+  *(uint16_t*)0x20000434 = 0x60;
+  STORE_BY_BITMASK(uint16_t, , 0x20000436, 2, 0, 14);
+  STORE_BY_BITMASK(uint16_t, , 0x20000437, 0, 6, 1);
+  STORE_BY_BITMASK(uint16_t, , 0x20000437, 1, 7, 1);
+  *(uint16_t*)0x20000438 = 8;
+  *(uint16_t*)0x2000043a = 1;
+  *(uint16_t*)0x2000043c = 0x1e;
+  *(uint16_t*)0x2000043e = 0;
+  *(uint16_t*)0x20000440 = 8;
+  *(uint16_t*)0x20000442 = 1;
+  *(uint16_t*)0x20000444 = 4;
+  *(uint16_t*)0x20000446 = 0;
+  *(uint16_t*)0x20000448 = 8;
+  *(uint16_t*)0x2000044a = 1;
+  *(uint16_t*)0x2000044c = 3;
+  *(uint16_t*)0x2000044e = 0;
+  *(uint16_t*)0x20000450 = 0x2c;
+  STORE_BY_BITMASK(uint16_t, , 0x20000452, 2, 0, 14);
+  STORE_BY_BITMASK(uint16_t, , 0x20000453, 0, 6, 1);
+  STORE_BY_BITMASK(uint16_t, , 0x20000453, 1, 7, 1);
+  *(uint16_t*)0x20000454 = 0x14;
+  STORE_BY_BITMASK(uint16_t, , 0x20000456, 1, 0, 14);
+  STORE_BY_BITMASK(uint16_t, , 0x20000457, 0, 6, 1);
+  STORE_BY_BITMASK(uint16_t, , 0x20000457, 0, 7, 1);
+  *(uint16_t*)0x20000458 = 0x6722;
+  *(uint16_t*)0x2000045a = 7;
+  *(uint16_t*)0x2000045c = 0x401;
+  *(uint16_t*)0x2000045e = 0;
+  STORE_BY_BITMASK(uint32_t, , 0x20000460, 1, 0, 29);
+  STORE_BY_BITMASK(uint32_t, , 0x20000460, 1, 29, 1);
+  STORE_BY_BITMASK(uint32_t, , 0x20000460, 1, 30, 1);
+  STORE_BY_BITMASK(uint32_t, , 0x20000460, 1, 31, 1);
+  STORE_BY_BITMASK(uint32_t, , 0x20000464, 0, 0, 29);
+  STORE_BY_BITMASK(uint32_t, , 0x20000464, 1, 29, 1);
+  STORE_BY_BITMASK(uint32_t, , 0x20000464, 0, 30, 1);
+  STORE_BY_BITMASK(uint32_t, , 0x20000464, 1, 31, 1);
+  *(uint16_t*)0x20000468 = 0x14;
+  STORE_BY_BITMASK(uint16_t, , 0x2000046a, 2, 0, 14);
+  STORE_BY_BITMASK(uint16_t, , 0x2000046b, 0, 6, 1);
+  STORE_BY_BITMASK(uint16_t, , 0x2000046b, 0, 7, 1);
+  *(uint16_t*)0x2000046c = 0;
+  *(uint16_t*)0x2000046e = 2;
+  *(uint16_t*)0x20000470 = 0x8000;
+  *(uint16_t*)0x20000472 = 0;
+  *(uint32_t*)0x20000474 = 9;
+  STORE_BY_BITMASK(uint16_t, , 0x20000478, 0, 0, 12);
+  STORE_BY_BITMASK(uint8_t, , 0x20000479, 2, 4, 4);
+  *(uint16_t*)0x2000047c = 8;
+  *(uint16_t*)0x2000047e = 1;
+  *(uint16_t*)0x20000480 = 0x400;
+  *(uint16_t*)0x20000482 = 0;
+  *(uint16_t*)0x20000484 = 8;
+  *(uint16_t*)0x20000486 = 1;
+  *(uint16_t*)0x20000488 = 0x576a;
+  *(uint16_t*)0x2000048a = 0;
+  *(uint16_t*)0x2000048c = 8;
+  *(uint16_t*)0x2000048e = 1;
+  *(uint16_t*)0x20000490 = 2;
+  *(uint16_t*)0x20000492 = 0;
+  *(uint16_t*)0x20000494 = 0x5c;
+  *(uint16_t*)0x20000496 = 3;
+  *(uint16_t*)0x20000498 = 0x58;
+  STORE_BY_BITMASK(uint16_t, , 0x2000049a, 0x13, 0, 14);
+  STORE_BY_BITMASK(uint16_t, , 0x2000049b, 0, 6, 1);
+  STORE_BY_BITMASK(uint16_t, , 0x2000049b, 0, 7, 1);
+  *(uint16_t*)0x2000049c = 0xb;
+  *(uint16_t*)0x2000049e = 1;
+  memcpy((void*)0x200004a0, "mirred\000", 7);
+  *(uint16_t*)0x200004a8 = 0x44;
+  STORE_BY_BITMASK(uint16_t, , 0x200004aa, 2, 0, 14);
+  STORE_BY_BITMASK(uint16_t, , 0x200004ab, 0, 6, 1);
+  STORE_BY_BITMASK(uint16_t, , 0x200004ab, 1, 7, 1);
+  *(uint16_t*)0x200004ac = 0x20;
+  *(uint16_t*)0x200004ae = 2;
+  *(uint32_t*)0x200004b0 = 7;
+  *(uint32_t*)0x200004b4 = 0x20;
+  *(uint32_t*)0x200004b8 = 5;
+  *(uint32_t*)0x200004bc = 4;
+  *(uint32_t*)0x200004c0 = 1;
+  *(uint32_t*)0x200004c4 = 2;
+  *(uint32_t*)0x200004c8 = 0;
+  *(uint16_t*)0x200004cc = 0x20;
+  *(uint16_t*)0x200004ce = 2;
+  *(uint32_t*)0x200004d0 = 2;
+  *(uint32_t*)0x200004d4 = 0xffff;
+  *(uint32_t*)0x200004d8 = 0x10000000;
+  *(uint32_t*)0x200004dc = 0x101;
+  *(uint32_t*)0x200004e0 = 0x615;
+  *(uint32_t*)0x200004e4 = 2;
+  *(uint32_t*)0x200004e8 = r[3];
+  *(uint16_t*)0x200004ec = 4;
+  *(uint16_t*)0x200004ee = 6;
+  *(uint64_t*)0x20000188 = 0xf0;
+  *(uint64_t*)0x200001d8 = 1;
+  *(uint64_t*)0x200001e0 = 0;
+  *(uint64_t*)0x200001e8 = 0;
+  *(uint32_t*)0x200001f0 = 0;
+  syscall(__NR_sendmsg, r[0], 0x200001c0ul, 0ul);
+}
+int main(void)
+{
+  syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+  do_sandbox_none();
+  return 0;
+}
diff --git a/syzkaller-repros/linux/18fd68c40a8208c2cd7060c19ca1180350db763b.c b/syzkaller-repros/linux/18fd68c40a8208c2cd7060c19ca1180350db763b.c
new file mode 100644
index 0000000..9cfbcc3
--- /dev/null
+++ b/syzkaller-repros/linux/18fd68c40a8208c2cd7060c19ca1180350db763b.c
@@ -0,0 +1,382 @@
+// possible deadlock in pty_write
+// https://syzkaller.appspot.com/bug?id=18fd68c40a8208c2cd7060c19ca1180350db763b
+// 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/ioctl.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>
+
+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, 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 long syz_open_pts(volatile long a0, volatile long a1)
+{
+  int ptyno = 0;
+  if (ioctl(a0, TIOCGPTN, &ptyno))
+    return -1;
+  char buf[128];
+  sprintf(buf, "/dev/pts/%d", ptyno);
+  return open(buf, a1, 0);
+}
+
+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_test()
+{
+  prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+  setpgrp();
+  write_file("/proc/self/oom_score_adj", "1000");
+}
+
+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);
+    }
+  }
+}
+
+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 < 9; 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[4] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff,
+                 0xffffffffffffffff};
+
+void execute_call(int call)
+{
+  intptr_t res;
+  switch (call) {
+  case 0:
+    syscall(__NR_perf_event_open, 0ul, 0, 0ul, -1, 0ul);
+    break;
+  case 1:
+    memcpy((void*)0x20000180, "/dev/ptmx\000", 10);
+    res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x20000180ul,
+                  0x8000000000006ul, 0ul);
+    if (res != -1)
+      r[0] = res;
+    break;
+  case 2:
+    *(uint32_t*)0x20000280 = 0;
+    *(uint32_t*)0x20000284 = 0;
+    *(uint32_t*)0x20000288 = 0;
+    *(uint32_t*)0x2000028c = 0;
+    *(uint8_t*)0x20000290 = 0;
+    memcpy((void*)0x20000291, "\000\000\000\000\000\000\000\000\000\000\000\000"
+                              "\000\000\000\000\000\000\000",
+           19);
+    syscall(__NR_ioctl, r[0], 0x40045431ul, 0x20000280ul);
+    break;
+  case 3:
+    syscall(__NR_write, r[0], 0x20000240ul, 0x35bul);
+    break;
+  case 4:
+    res = syz_open_pts(r[0], 0);
+    if (res != -1)
+      r[1] = res;
+    break;
+  case 5:
+    res = syscall(__NR_socket, 2ul, 2ul, 0x88ul);
+    if (res != -1)
+      r[2] = res;
+    break;
+  case 6:
+    res = syscall(__NR_dup, r[2]);
+    if (res != -1)
+      r[3] = res;
+    break;
+  case 7:
+    syscall(__NR_ioctl, r[3], 0x8912ul, 0x400200ul);
+    break;
+  case 8:
+    *(uint32_t*)0x20000100 = 0x17;
+    *(uint32_t*)0x20000104 = 0;
+    *(uint32_t*)0x20000108 = 0;
+    *(uint32_t*)0x2000010c = 0;
+    *(uint8_t*)0x20000110 = 0;
+    memcpy((void*)0x20000111, "\000\000\000\000\000\000\000\000\000\000\000\000"
+                              "\000\000\000\000\000\000\000",
+           19);
+    inject_fault(0);
+    syscall(__NR_ioctl, r[1], 0x5412ul, 0x20000100ul);
+    break;
+  }
+}
+int main(void)
+{
+  syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+  setup_fault();
+  for (procid = 0; procid < 6; procid++) {
+    if (fork() == 0) {
+      loop();
+    }
+  }
+  sleep(1000000);
+  return 0;
+}
diff --git a/syzkaller-repros/linux/1bd2e7a7bb0310b1b0974022c78ee23975119187.c b/syzkaller-repros/linux/1bd2e7a7bb0310b1b0974022c78ee23975119187.c
new file mode 100644
index 0000000..76a7b25
--- /dev/null
+++ b/syzkaller-repros/linux/1bd2e7a7bb0310b1b0974022c78ee23975119187.c
@@ -0,0 +1,208 @@
+// inconsistent lock state in rxrpc_put_client_connection_id
+// https://syzkaller.appspot.com/bug?id=1bd2e7a7bb0310b1b0974022c78ee23975119187
+// status:fixed
+// 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 <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/capability.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;
+}
+
+#define MAX_FDS 30
+
+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 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();
+  if (unshare(CLONE_NEWNET)) {
+  }
+  loop();
+  exit(1);
+}
+
+static void close_fds()
+{
+  int fd;
+  for (fd = 3; fd < MAX_FDS; fd++)
+    close(fd);
+}
+
+uint64_t r[1] = {0xffffffffffffffff};
+
+void loop(void)
+{
+  intptr_t res = 0;
+  res = syscall(__NR_socket, 0x2000000000000021ul, 2ul, 2);
+  if (res != -1)
+    r[0] = res;
+  syscall(__NR_setsockopt, r[0], 0x110ul, 3ul, 0, 0);
+  *(uint16_t*)0x20000080 = 0x21;
+  *(uint16_t*)0x20000082 = 0;
+  *(uint16_t*)0x20000084 = 2;
+  *(uint16_t*)0x20000086 = 0x10;
+  *(uint16_t*)0x20000088 = 2;
+  *(uint16_t*)0x2000008a = htobe16(0x4e21);
+  *(uint8_t*)0x2000008c = 0xac;
+  *(uint8_t*)0x2000008d = 0x14;
+  *(uint8_t*)0x2000008e = 0x14;
+  *(uint8_t*)0x2000008f = 0;
+  syscall(__NR_connect, r[0], 0x20000080ul, 0x24ul);
+  *(uint64_t*)0x20005c00 = 0;
+  *(uint32_t*)0x20005c08 = 0;
+  *(uint64_t*)0x20005c10 = 0;
+  *(uint64_t*)0x20005c18 = 0;
+  *(uint64_t*)0x20005c20 = 0x20000180;
+  memcpy((void*)0x20000180,
+         "\x18\x00\x00\x00\x00\x00\x00\x00\x10\x01\x00\x00\x01\x00\x00\x00\x77"
+         "\x00\x00\x00\x00\x00\x00\x00\xdb\xee\x1f\x2b\xa6\x8d\xf5\x0d\x9d\x16"
+         "\x5f\xd7\x91\x54\x9e\xa2\x94\x19\xfa\x1c\x35\xdd\x96\x99\x22\xe4\xc5"
+         "\xea\xa8\x87\xd6\xf6\x5d\xd2\xf2\xbc\xf0\x36\x1d\x4c\x49\x31\xa9\x85"
+         "\x72\xfe\x33\x72\x78\xdb\x2f\x70\x10\xaf\x18\x87\x85\x15\x69\x42\x75"
+         "\x7d\x03\x9f\xc5\xf9\xc1\x1f\x08\x08\x66\xed\xc2\x10\xdb\xf2\xd9\x4a"
+         "\xec\xdf\x80\x5d\xcc\xc4\xdf\xcb\x24\x1a\x94\x33\x86\x7e\x95\xb9\xba"
+         "\x88\x00\xcf\x2c\xcc\xdd\x0e\x0a\x01\xe7\x51\xbc\xe3\x93\x61\xa2\x15"
+         "\x86\x06\x88\x66\x5e\x22\x9d\xcb\x84\x18\x1b\x1d\xf8\xb9\x5c\x06\x44"
+         "\x20\x05\x27\xe3\x9b\x68\x30\x2b\x1f\x40\x49\x34\x88\x58\x92\xce\xa3"
+         "\x32\xba\x4e\xe3\xb9\xde\x7c\x5e\xe0\x09\xcd\x97\x15\x42\x03\x1e\xda"
+         "\xa9\x39\x6b\xf4\x1b\x72\x43\xd1\xf8\xd9\x3b\x8a\x0a\x4b\xa1\xbe\x62"
+         "\xba\x14\xe3\x9f\xe9\xef\x9c\x91\x5f\x01\xa9\xc4\x49\x0a",
+         218);
+  *(uint64_t*)0x20005c28 = 0x18;
+  *(uint32_t*)0x20005c30 = 0;
+  *(uint32_t*)0x20005c38 = 0;
+  syscall(__NR_sendmmsg, r[0], 0x20005c00ul, 1ul, 0ul);
+  close_fds();
+}
+int main(void)
+{
+  syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+  do_sandbox_none();
+  return 0;
+}
diff --git a/syzkaller-repros/linux/1e86a4ebb5b456e95a9e267e75f08608c083a873.c b/syzkaller-repros/linux/1e86a4ebb5b456e95a9e267e75f08608c083a873.c
new file mode 100644
index 0000000..0704cc3
--- /dev/null
+++ b/syzkaller-repros/linux/1e86a4ebb5b456e95a9e267e75f08608c083a873.c
@@ -0,0 +1,2303 @@
+// possible deadlock in kcm_ioctl
+// https://syzkaller.appspot.com/bug?id=1e86a4ebb5b456e95a9e267e75f08608c083a873
+// 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);
+}
+
+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 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_linked(struct nlmsg* nlmsg, int sock, const char* type,
+                               const char* name, const char* link)
+{
+  netlink_add_device_impl(nlmsg, type, name);
+  netlink_done(nlmsg);
+  int ifindex = if_nametoindex(link);
+  netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
+  int err = netlink_send(nlmsg, sock);
+  (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;
+}
+
+static void netlink_add_geneve(struct nlmsg* nlmsg, int sock, const char* name,
+                               uint32_t vni, struct in_addr* addr4,
+                               struct in6_addr* addr6)
+{
+  netlink_add_device_impl(nlmsg, "geneve", name);
+  netlink_nest(nlmsg, IFLA_INFO_DATA);
+  netlink_attr(nlmsg, IFLA_GENEVE_ID, &vni, sizeof(vni));
+  if (addr4)
+    netlink_attr(nlmsg, IFLA_GENEVE_REMOTE, addr4, sizeof(*addr4));
+  if (addr6)
+    netlink_attr(nlmsg, IFLA_GENEVE_REMOTE6, addr6, sizeof(*addr6));
+  netlink_done(nlmsg);
+  netlink_done(nlmsg);
+  int err = netlink_send(nlmsg, sock);
+  (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;
+  if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0) {
+    exit(1);
+  }
+  char sysctl[64];
+  sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/accept_dad", TUN_IFACE);
+  write_file(sysctl, "0");
+  sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/router_solicitations", TUN_IFACE);
+  write_file(sysctl, "0");
+  int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+  if (sock == -1)
+    exit(1);
+  netlink_add_addr4(&nlmsg, sock, TUN_IFACE, LOCAL_IPV4);
+  netlink_add_addr6(&nlmsg, sock, TUN_IFACE, LOCAL_IPV6);
+  uint64_t macaddr = REMOTE_MAC;
+  struct in_addr in_addr;
+  inet_pton(AF_INET, REMOTE_IPV4, &in_addr);
+  netlink_add_neigh(&nlmsg, sock, TUN_IFACE, &in_addr, sizeof(in_addr),
+                    &macaddr, ETH_ALEN);
+  struct in6_addr in6_addr;
+  inet_pton(AF_INET6, REMOTE_IPV6, &in6_addr);
+  netlink_add_neigh(&nlmsg, sock, TUN_IFACE, &in6_addr, sizeof(in6_addr),
+                    &macaddr, ETH_ALEN);
+  macaddr = LOCAL_MAC;
+  netlink_device_change(&nlmsg, sock, TUN_IFACE, true, 0, &macaddr, ETH_ALEN,
+                        NULL);
+  close(sock);
+}
+
+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");
+  }
+}
+
+#define WG_GENL_NAME "wireguard"
+enum wg_cmd {
+  WG_CMD_GET_DEVICE,
+  WG_CMD_SET_DEVICE,
+};
+enum wgdevice_attribute {
+  WGDEVICE_A_UNSPEC,
+  WGDEVICE_A_IFINDEX,
+  WGDEVICE_A_IFNAME,
+  WGDEVICE_A_PRIVATE_KEY,
+  WGDEVICE_A_PUBLIC_KEY,
+  WGDEVICE_A_FLAGS,
+  WGDEVICE_A_LISTEN_PORT,
+  WGDEVICE_A_FWMARK,
+  WGDEVICE_A_PEERS,
+};
+enum wgpeer_attribute {
+  WGPEER_A_UNSPEC,
+  WGPEER_A_PUBLIC_KEY,
+  WGPEER_A_PRESHARED_KEY,
+  WGPEER_A_FLAGS,
+  WGPEER_A_ENDPOINT,
+  WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+  WGPEER_A_LAST_HANDSHAKE_TIME,
+  WGPEER_A_RX_BYTES,
+  WGPEER_A_TX_BYTES,
+  WGPEER_A_ALLOWEDIPS,
+  WGPEER_A_PROTOCOL_VERSION,
+};
+enum wgallowedip_attribute {
+  WGALLOWEDIP_A_UNSPEC,
+  WGALLOWEDIP_A_FAMILY,
+  WGALLOWEDIP_A_IPADDR,
+  WGALLOWEDIP_A_CIDR_MASK,
+};
+
+static int netlink_wireguard_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, WG_GENL_NAME,
+               strlen(WG_GENL_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_wireguard_setup(void)
+{
+  const char ifname_a[] = "wg0";
+  const char ifname_b[] = "wg1";
+  const char ifname_c[] = "wg2";
+  const char private_a[] =
+      "\xa0\x5c\xa8\x4f\x6c\x9c\x8e\x38\x53\xe2\xfd\x7a\x70\xae\x0f\xb2\x0f\xa1"
+      "\x52\x60\x0c\xb0\x08\x45\x17\x4f\x08\x07\x6f\x8d\x78\x43";
+  const char private_b[] =
+      "\xb0\x80\x73\xe8\xd4\x4e\x91\xe3\xda\x92\x2c\x22\x43\x82\x44\xbb\x88\x5c"
+      "\x69\xe2\x69\xc8\xe9\xd8\x35\xb1\x14\x29\x3a\x4d\xdc\x6e";
+  const char private_c[] =
+      "\xa0\xcb\x87\x9a\x47\xf5\xbc\x64\x4c\x0e\x69\x3f\xa6\xd0\x31\xc7\x4a\x15"
+      "\x53\xb6\xe9\x01\xb9\xff\x2f\x51\x8c\x78\x04\x2f\xb5\x42";
+  const char public_a[] =
+      "\x97\x5c\x9d\x81\xc9\x83\xc8\x20\x9e\xe7\x81\x25\x4b\x89\x9f\x8e\xd9\x25"
+      "\xae\x9f\x09\x23\xc2\x3c\x62\xf5\x3c\x57\xcd\xbf\x69\x1c";
+  const char public_b[] =
+      "\xd1\x73\x28\x99\xf6\x11\xcd\x89\x94\x03\x4d\x7f\x41\x3d\xc9\x57\x63\x0e"
+      "\x54\x93\xc2\x85\xac\xa4\x00\x65\xcb\x63\x11\xbe\x69\x6b";
+  const char public_c[] =
+      "\xf4\x4d\xa3\x67\xa8\x8e\xe6\x56\x4f\x02\x02\x11\x45\x67\x27\x08\x2f\x5c"
+      "\xeb\xee\x8b\x1b\xf5\xeb\x73\x37\x34\x1b\x45\x9b\x39\x22";
+  const uint16_t listen_a = 20001;
+  const uint16_t listen_b = 20002;
+  const uint16_t listen_c = 20003;
+  const uint16_t af_inet = AF_INET;
+  const uint16_t af_inet6 = AF_INET6;
+  /* Unused, but useful in case we change this:
+  const struct sockaddr_in endpoint_a_v4 = {
+      .sin_family = AF_INET,
+      .sin_port = htons(listen_a),
+      .sin_addr = {htonl(INADDR_LOOPBACK)}};*/
+  const struct sockaddr_in endpoint_b_v4 = {
+      .sin_family = AF_INET,
+      .sin_port = htons(listen_b),
+      .sin_addr = {htonl(INADDR_LOOPBACK)}};
+  const struct sockaddr_in endpoint_c_v4 = {
+      .sin_family = AF_INET,
+      .sin_port = htons(listen_c),
+      .sin_addr = {htonl(INADDR_LOOPBACK)}};
+  struct sockaddr_in6 endpoint_a_v6 = {.sin6_family = AF_INET6,
+                                       .sin6_port = htons(listen_a)};
+  endpoint_a_v6.sin6_addr = in6addr_loopback;
+  /* Unused, but useful in case we change this:
+  const struct sockaddr_in6 endpoint_b_v6 = {
+      .sin6_family = AF_INET6,
+      .sin6_port = htons(listen_b)};
+  endpoint_b_v6.sin6_addr = in6addr_loopback; */
+  struct sockaddr_in6 endpoint_c_v6 = {.sin6_family = AF_INET6,
+                                       .sin6_port = htons(listen_c)};
+  endpoint_c_v6.sin6_addr = in6addr_loopback;
+  const struct in_addr first_half_v4 = {0};
+  const struct in_addr second_half_v4 = {htonl(128 << 24)};
+  const struct in6_addr first_half_v6 = {{{0}}};
+  const struct in6_addr second_half_v6 = {{{0x80}}};
+  const uint8_t half_cidr = 1;
+  const uint16_t persistent_keepalives[] = {1, 3, 7, 9, 14, 19};
+  struct genlmsghdr genlhdr = {.cmd = WG_CMD_SET_DEVICE, .version = 1};
+  int sock;
+  int id, err;
+  sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+  if (sock == -1) {
+    return;
+  }
+  id = netlink_wireguard_id_get(&nlmsg, sock);
+  if (id == -1)
+    goto error;
+  netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+  netlink_attr(&nlmsg, WGDEVICE_A_IFNAME, ifname_a, strlen(ifname_a) + 1);
+  netlink_attr(&nlmsg, WGDEVICE_A_PRIVATE_KEY, private_a, 32);
+  netlink_attr(&nlmsg, WGDEVICE_A_LISTEN_PORT, &listen_a, 2);
+  netlink_nest(&nlmsg, NLA_F_NESTED | WGDEVICE_A_PEERS);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_b, 32);
+  netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_b_v4,
+               sizeof(endpoint_b_v4));
+  netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+               &persistent_keepalives[0], 2);
+  netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v4,
+               sizeof(first_half_v4));
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+  netlink_done(&nlmsg);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v6,
+               sizeof(first_half_v6));
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_c, 32);
+  netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_c_v6,
+               sizeof(endpoint_c_v6));
+  netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+               &persistent_keepalives[1], 2);
+  netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v4,
+               sizeof(second_half_v4));
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+  netlink_done(&nlmsg);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v6,
+               sizeof(second_half_v6));
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  err = netlink_send(&nlmsg, sock);
+  if (err) {
+  }
+  netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+  netlink_attr(&nlmsg, WGDEVICE_A_IFNAME, ifname_b, strlen(ifname_b) + 1);
+  netlink_attr(&nlmsg, WGDEVICE_A_PRIVATE_KEY, private_b, 32);
+  netlink_attr(&nlmsg, WGDEVICE_A_LISTEN_PORT, &listen_b, 2);
+  netlink_nest(&nlmsg, NLA_F_NESTED | WGDEVICE_A_PEERS);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_a, 32);
+  netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_a_v6,
+               sizeof(endpoint_a_v6));
+  netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+               &persistent_keepalives[2], 2);
+  netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v4,
+               sizeof(first_half_v4));
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+  netlink_done(&nlmsg);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v6,
+               sizeof(first_half_v6));
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_c, 32);
+  netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_c_v4,
+               sizeof(endpoint_c_v4));
+  netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+               &persistent_keepalives[3], 2);
+  netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v4,
+               sizeof(second_half_v4));
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+  netlink_done(&nlmsg);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v6,
+               sizeof(second_half_v6));
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  err = netlink_send(&nlmsg, sock);
+  if (err) {
+  }
+  netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
+  netlink_attr(&nlmsg, WGDEVICE_A_IFNAME, ifname_c, strlen(ifname_c) + 1);
+  netlink_attr(&nlmsg, WGDEVICE_A_PRIVATE_KEY, private_c, 32);
+  netlink_attr(&nlmsg, WGDEVICE_A_LISTEN_PORT, &listen_c, 2);
+  netlink_nest(&nlmsg, NLA_F_NESTED | WGDEVICE_A_PEERS);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_a, 32);
+  netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_a_v6,
+               sizeof(endpoint_a_v6));
+  netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+               &persistent_keepalives[4], 2);
+  netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v4,
+               sizeof(first_half_v4));
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+  netlink_done(&nlmsg);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v6,
+               sizeof(first_half_v6));
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_b, 32);
+  netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_b_v4,
+               sizeof(endpoint_b_v4));
+  netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+               &persistent_keepalives[5], 2);
+  netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v4,
+               sizeof(second_half_v4));
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+  netlink_done(&nlmsg);
+  netlink_nest(&nlmsg, NLA_F_NESTED | 0);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v6,
+               sizeof(second_half_v6));
+  netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  netlink_done(&nlmsg);
+  err = netlink_send(&nlmsg, sock);
+  if (err) {
+  }
+
+error:
+  close(sock);
+}
+static void initialize_netdevices(void)
+{
+  char netdevsim[16];
+  sprintf(netdevsim, "netdevsim%d", (int)procid);
+  struct {
+    const char* type;
+    const char* dev;
+  } devtypes[] = {
+      {"ip6gretap", "ip6gretap0"}, {"bridge", "bridge0"},
+      {"vcan", "vcan0"},           {"bond", "bond0"},
+      {"team", "team0"},           {"dummy", "dummy0"},
+      {"nlmon", "nlmon0"},         {"caif", "caif0"},
+      {"batadv", "batadv0"},       {"vxcan", "vxcan1"},
+      {"netdevsim", netdevsim},    {"veth", 0},
+      {"xfrm", "xfrm0"},           {"wireguard", "wg0"},
+      {"wireguard", "wg1"},        {"wireguard", "wg2"},
+  };
+  const char* devmasters[] = {"bridge", "bond", "team", "batadv"};
+  struct {
+    const char* name;
+    int macsize;
+    bool noipv6;
+  } devices[] = {
+      {"lo", ETH_ALEN},
+      {"sit0", 0},
+      {"bridge0", ETH_ALEN},
+      {"vcan0", 0, true},
+      {"tunl0", 0},
+      {"gre0", 0},
+      {"gretap0", ETH_ALEN},
+      {"ip_vti0", 0},
+      {"ip6_vti0", 0},
+      {"ip6tnl0", 0},
+      {"ip6gre0", 0},
+      {"ip6gretap0", ETH_ALEN},
+      {"erspan0", ETH_ALEN},
+      {"bond0", ETH_ALEN},
+      {"veth0", ETH_ALEN},
+      {"veth1", ETH_ALEN},
+      {"team0", ETH_ALEN},
+      {"veth0_to_bridge", ETH_ALEN},
+      {"veth1_to_bridge", ETH_ALEN},
+      {"veth0_to_bond", ETH_ALEN},
+      {"veth1_to_bond", ETH_ALEN},
+      {"veth0_to_team", ETH_ALEN},
+      {"veth1_to_team", ETH_ALEN},
+      {"veth0_to_hsr", ETH_ALEN},
+      {"veth1_to_hsr", ETH_ALEN},
+      {"hsr0", 0},
+      {"dummy0", ETH_ALEN},
+      {"nlmon0", 0},
+      {"vxcan0", 0, true},
+      {"vxcan1", 0, true},
+      {"caif0", ETH_ALEN},
+      {"batadv0", ETH_ALEN},
+      {netdevsim, ETH_ALEN},
+      {"xfrm0", ETH_ALEN},
+      {"veth0_virt_wifi", ETH_ALEN},
+      {"veth1_virt_wifi", ETH_ALEN},
+      {"virt_wifi0", ETH_ALEN},
+      {"veth0_vlan", ETH_ALEN},
+      {"veth1_vlan", ETH_ALEN},
+      {"vlan0", ETH_ALEN},
+      {"vlan1", ETH_ALEN},
+      {"macvlan0", ETH_ALEN},
+      {"macvlan1", ETH_ALEN},
+      {"ipvlan0", ETH_ALEN},
+      {"ipvlan1", ETH_ALEN},
+      {"veth0_macvtap", ETH_ALEN},
+      {"veth1_macvtap", ETH_ALEN},
+      {"macvtap0", ETH_ALEN},
+      {"macsec0", ETH_ALEN},
+      {"veth0_to_batadv", ETH_ALEN},
+      {"veth1_to_batadv", ETH_ALEN},
+      {"batadv_slave_0", ETH_ALEN},
+      {"batadv_slave_1", ETH_ALEN},
+      {"geneve0", ETH_ALEN},
+      {"geneve1", ETH_ALEN},
+      {"wg0", 0},
+      {"wg1", 0},
+      {"wg2", 0},
+  };
+  int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+  if (sock == -1)
+    exit(1);
+  unsigned i;
+  for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++)
+    netlink_add_device(&nlmsg, sock, devtypes[i].type, devtypes[i].dev);
+  for (i = 0; i < sizeof(devmasters) / (sizeof(devmasters[0])); i++) {
+    char master[32], slave0[32], veth0[32], slave1[32], veth1[32];
+    sprintf(slave0, "%s_slave_0", devmasters[i]);
+    sprintf(veth0, "veth0_to_%s", devmasters[i]);
+    netlink_add_veth(&nlmsg, sock, slave0, veth0);
+    sprintf(slave1, "%s_slave_1", devmasters[i]);
+    sprintf(veth1, "veth1_to_%s", devmasters[i]);
+    netlink_add_veth(&nlmsg, sock, slave1, veth1);
+    sprintf(master, "%s0", devmasters[i]);
+    netlink_device_change(&nlmsg, sock, slave0, false, master, 0, 0, NULL);
+    netlink_device_change(&nlmsg, sock, slave1, false, master, 0, 0, NULL);
+  }
+  netlink_device_change(&nlmsg, sock, "bridge_slave_0", true, 0, 0, 0, NULL);
+  netlink_device_change(&nlmsg, sock, "bridge_slave_1", true, 0, 0, 0, NULL);
+  netlink_add_veth(&nlmsg, sock, "hsr_slave_0", "veth0_to_hsr");
+  netlink_add_veth(&nlmsg, sock, "hsr_slave_1", "veth1_to_hsr");
+  netlink_add_hsr(&nlmsg, sock, "hsr0", "hsr_slave_0", "hsr_slave_1");
+  netlink_device_change(&nlmsg, sock, "hsr_slave_0", true, 0, 0, 0, NULL);
+  netlink_device_change(&nlmsg, sock, "hsr_slave_1", true, 0, 0, 0, NULL);
+  netlink_add_veth(&nlmsg, sock, "veth0_virt_wifi", "veth1_virt_wifi");
+  netlink_add_linked(&nlmsg, sock, "virt_wifi", "virt_wifi0",
+                     "veth1_virt_wifi");
+  netlink_add_veth(&nlmsg, sock, "veth0_vlan", "veth1_vlan");
+  netlink_add_vlan(&nlmsg, sock, "vlan0", "veth0_vlan", 0, htons(ETH_P_8021Q));
+  netlink_add_vlan(&nlmsg, sock, "vlan1", "veth0_vlan", 1, htons(ETH_P_8021AD));
+  netlink_add_macvlan(&nlmsg, sock, "macvlan0", "veth1_vlan");
+  netlink_add_macvlan(&nlmsg, sock, "macvlan1", "veth1_vlan");
+  netlink_add_ipvlan(&nlmsg, sock, "ipvlan0", "veth0_vlan", IPVLAN_MODE_L2, 0);
+  netlink_add_ipvlan(&nlmsg, sock, "ipvlan1", "veth0_vlan", IPVLAN_MODE_L3S,
+                     IPVLAN_F_VEPA);
+  netlink_add_veth(&nlmsg, sock, "veth0_macvtap", "veth1_macvtap");
+  netlink_add_linked(&nlmsg, sock, "macvtap", "macvtap0", "veth0_macvtap");
+  netlink_add_linked(&nlmsg, sock, "macsec", "macsec0", "veth1_macvtap");
+  char addr[32];
+  sprintf(addr, DEV_IPV4, 14 + 10);
+  struct in_addr geneve_addr4;
+  if (inet_pton(AF_INET, addr, &geneve_addr4) <= 0)
+    exit(1);
+  struct in6_addr geneve_addr6;
+  if (inet_pton(AF_INET6, "fc00::01", &geneve_addr6) <= 0)
+    exit(1);
+  netlink_add_geneve(&nlmsg, sock, "geneve0", 0, &geneve_addr4, 0);
+  netlink_add_geneve(&nlmsg, sock, "geneve1", 1, 0, &geneve_addr6);
+  netdevsim_add((int)procid, 4);
+  netlink_wireguard_setup();
+  for (i = 0; i < sizeof(devices) / (sizeof(devices[0])); i++) {
+    char addr[32];
+    sprintf(addr, DEV_IPV4, i + 10);
+    netlink_add_addr4(&nlmsg, sock, devices[i].name, addr);
+    if (!devices[i].noipv6) {
+      sprintf(addr, DEV_IPV6, i + 10);
+      netlink_add_addr6(&nlmsg, sock, devices[i].name, addr);
+    }
+    uint64_t macaddr = DEV_MAC + ((i + 10ull) << 40);
+    netlink_device_change(&nlmsg, sock, devices[i].name, true, 0, &macaddr,
+                          devices[i].macsize, NULL);
+  }
+  close(sock);
+}
+static void initialize_netdevices_init(void)
+{
+  int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+  if (sock == -1)
+    exit(1);
+  struct {
+    const char* type;
+    int macsize;
+    bool noipv6;
+    bool noup;
+  } devtypes[] = {
+      {"nr", 7, true},
+      {"rose", 5, true, true},
+  };
+  unsigned i;
+  for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++) {
+    char dev[32], addr[32];
+    sprintf(dev, "%s%d", devtypes[i].type, (int)procid);
+    sprintf(addr, "172.30.%d.%d", i, (int)procid + 1);
+    netlink_add_addr4(&nlmsg, sock, dev, addr);
+    if (!devtypes[i].noipv6) {
+      sprintf(addr, "fe88::%02x:%02x", i, (int)procid + 1);
+      netlink_add_addr6(&nlmsg, sock, dev, addr);
+    }
+    int macsize = devtypes[i].macsize;
+    uint64_t macaddr = 0xbbbbbb +
+                       ((unsigned long long)i << (8 * (macsize - 2))) +
+                       (procid << (8 * (macsize - 1)));
+    netlink_device_change(&nlmsg, sock, dev, !devtypes[i].noup, 0, &macaddr,
+                          macsize, NULL);
+  }
+  close(sock);
+}
+
+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;
+  for (call = 0; call < 27; 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)
+{
+  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);
+  }
+}
+
+#ifndef __NR_bpf
+#define __NR_bpf 321
+#endif
+
+uint64_t r[10] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff,
+                  0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff,
+                  0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff,
+                  0xffffffffffffffff};
+
+void execute_call(int call)
+{
+  intptr_t res;
+  switch (call) {
+  case 0:
+    res = syscall(__NR_socket, 2ul, 1ul, 0ul);
+    if (res != -1)
+      r[0] = res;
+    break;
+  case 1:
+    NONFAILING(*(uint16_t*)0x20e5b000 = 2);
+    NONFAILING(*(uint16_t*)0x20e5b002 = htobe16(0x4e20));
+    NONFAILING(*(uint32_t*)0x20e5b004 = htobe32(0xe0000001));
+    syscall(__NR_bind, r[0], 0x20e5b000ul, 0x10ul);
+    break;
+  case 2:
+    NONFAILING(*(uint16_t*)0x20ccb000 = 2);
+    NONFAILING(*(uint16_t*)0x20ccb002 = htobe16(0x4e20));
+    NONFAILING(*(uint32_t*)0x20ccb004 = htobe32(0));
+    syscall(__NR_connect, r[0], 0x20ccb000ul, 0x10ul);
+    break;
+  case 3:
+    syscall(__NR_bpf, 5ul, 0ul, 0ul);
+    break;
+  case 4:
+    res = syscall(__NR_socket, 0x29ul, 5ul, 0ul);
+    if (res != -1)
+      r[1] = res;
+    break;
+  case 5:
+    res = syscall(__NR_socket, 2ul, 1ul, 0ul);
+    if (res != -1)
+      r[2] = res;
+    break;
+  case 6:
+    syscall(__NR_bind, r[2], 0ul, 0ul);
+    break;
+  case 7:
+    syscall(__NR_connect, r[2], 0ul, 0ul);
+    break;
+  case 8:
+    syscall(__NR_bpf, 5ul, 0ul, 0ul);
+    break;
+  case 9:
+    res = syscall(__NR_socket, 0x29ul, 0ul, 0ul);
+    if (res != -1)
+      r[3] = res;
+    break;
+  case 10:
+    syscall(__NR_ioctl, r[3], 0x89e0ul, 0ul);
+    break;
+  case 11:
+    res = syscall(__NR_socket, 2ul, 1ul, 0ul);
+    if (res != -1)
+      r[4] = res;
+    break;
+  case 12:
+    syscall(__NR_bind, r[4], 0ul, 0ul);
+    break;
+  case 13:
+    syscall(__NR_setsockopt, -1, 0x84ul, 8ul, 0ul, 0ul);
+    break;
+  case 14:
+    syscall(__NR_bpf, 5ul, 0ul, 0ul);
+    break;
+  case 15:
+    res = syscall(__NR_socket, 0x29ul, 5ul, 0ul);
+    if (res != -1)
+      r[5] = res;
+    break;
+  case 16:
+    res = syscall(__NR_openat, 0xffffffffffffff9cul, 0ul, 0xa6c0ul, 0ul);
+    if (res != -1)
+      r[6] = res;
+    break;
+  case 17:
+    syscall(__NR_getsockopt, -1, 0x113ul, 2ul, 0ul, 0ul);
+    break;
+  case 18:
+    syscall(__NR_ioctl, r[6], 0x890bul, 0ul);
+    break;
+  case 19:
+    syscall(__NR_ioctl, r[5], 0x89e0ul, 0ul);
+    break;
+  case 20:
+    res = syscall(__NR_socket, 2ul, 1ul, 0ul);
+    if (res != -1)
+      r[7] = res;
+    break;
+  case 21:
+    syscall(__NR_bind, r[7], 0ul, 0ul);
+    break;
+  case 22:
+    syscall(__NR_connect, r[7], 0ul, 0ul);
+    break;
+  case 23:
+    NONFAILING(*(uint32_t*)0x20000100 = 1);
+    NONFAILING(*(uint32_t*)0x20000104 = 3);
+    NONFAILING(*(uint64_t*)0x20000108 = 0x20000200);
+    NONFAILING(memcpy(
+        (void*)0x20000200,
+        "\x18\x00\x00\x00\x03\x00\xff\xf8\x00\x00\x00\x00\x26\xd0\x00\x00\x95"
+        "\x00\x2b\x00\x00\x00\x00\x00\x93\xad\xff\xa8\x22\x55\xf6\x74\x41\x2d"
+        "\x02\x00\x00\x00\x00\x00\x00\x5a\xb5\x27\xee\x36\x97\xf5\x7f\xe1\x2e"
+        "\xa7\x50\x9e\x1f\xcf\xc0\xba\x6b\x34\xf9\x81\xaa\x25\x63\xe9\x6d\xda"
+        "\x6d\x2a\xfe\xe3\x30\x25\xa3\x0b\x45\xbd\xcf\x1d\x27\x36\x88\xfd\x5a"
+        "\x4a\x03\x5d\x71\x41\x0d\xca\x87\x78\xad\x83\x34\x88\xcf\x88\x10\x9e"
+        "\xd2\x04\x9e\xdd\x0d\x69\x61\x3d\x3c\xd6\x1f\x00\x2f\x8e\x6e\x8b\xa4"
+        "\x8e\x3f\x37\xb9\x9a\xf5\xee\x85\x32\x15\x1d\x72\xab\xca\xba\xa9\x65"
+        "\x23\x00\x00\x00\x00\x00\x00\x00\xbe\x26\xad\x2a\x31\xe7\xfb\x19\x4e"
+        "\xe5\x2f\x41\xc6\x2e\x57\x72\xe5\x64\x6f\x4c\x1e\xd0\x1e\x6c\xa6\xca"
+        "\x37\xd5\xed\x26\x0f\x76\x7c\xde\x2b\x96\x00\xe7\x02\xef\x23\x9e\x47"
+        "\xfd\xfe\xe4\xd7\x71\x00\x00\x00\x00\x00\x00\x00\x01\xce\x33\x6a\xc4"
+        "\x54\x22\xe4\x10\x79\xe3\x9f\x9c\x5d\x00\xe3\xb9\xde\xac\x9b\x45\x61"
+        "\x6e\x3e\xe4\x5e\xbc\x98\x00\x00\x00\x00\x00\x00\xcb\x3d\xe5\x3d\xe7"
+        "\x17\xfa\xf5\x2d\x30\x21\x84\x6f\x14\xdb\x9f\x5f\x6a\xa9\xe6\xa8\x00"
+        "\x25\x68\x52\xbd\x0d\xc6\x20\xd0\xc3\xa4\xb0\x19\x3d\x0d\x1b\x29\x1f"
+        "\xec\x41\x1b\x76\x69\xde\x81\x54\xe7\x5e\x22\x6d\x6b\xef\x68\x12\x86"
+        "\xb8\x0a\x58\x47\xf8\x39\xdf\x39\xe7\xcc\x91\x1b\x03\x40\xb9\x9d\xa6"
+        "\x8a\xab\x60\x13\x89\x44\x99\x14\xea\xc5\x2d\x62\x61\x65\xc1\xc4\x7f"
+        "\xfc\x66\xbd\x00\x2e\xb8\x84\xf3\x0b\x46\xde\xb8\x99\x75\xb2\xed\x84"
+        "\x35\xe2\x08\x7a\xe5\x8e\xf7\x01\x57\xac\xcb\x9b\x7a\x0c\xe2\x95\xcc"
+        "\x66\x35\xb2\x4d\x7f\x8e\x89\xc1\x52",
+        366));
+    NONFAILING(*(uint64_t*)0x20000110 = 0x202bf000);
+    NONFAILING(memcpy((void*)0x202bf000, "syzkaller\000", 10));
+    NONFAILING(*(uint32_t*)0x20000118 = 4);
+    NONFAILING(*(uint32_t*)0x2000011c = 0x436);
+    NONFAILING(*(uint64_t*)0x20000120 = 0x20000040);
+    NONFAILING(*(uint32_t*)0x20000128 = 0);
+    NONFAILING(*(uint32_t*)0x2000012c = 0);
+    NONFAILING(*(uint8_t*)0x20000130 = 0);
+    NONFAILING(*(uint8_t*)0x20000131 = 0);
+    NONFAILING(*(uint8_t*)0x20000132 = 0);
+    NONFAILING(*(uint8_t*)0x20000133 = 0);
+    NONFAILING(*(uint8_t*)0x20000134 = 0);
+    NONFAILING(*(uint8_t*)0x20000135 = 0);
+    NONFAILING(*(uint8_t*)0x20000136 = 0);
+    NONFAILING(*(uint8_t*)0x20000137 = 0);
+    NONFAILING(*(uint8_t*)0x20000138 = 0);
+    NONFAILING(*(uint8_t*)0x20000139 = 0);
+    NONFAILING(*(uint8_t*)0x2000013a = 0);
+    NONFAILING(*(uint8_t*)0x2000013b = 0);
+    NONFAILING(*(uint8_t*)0x2000013c = 0);
+    NONFAILING(*(uint8_t*)0x2000013d = 0);
+    NONFAILING(*(uint8_t*)0x2000013e = 0);
+    NONFAILING(*(uint8_t*)0x2000013f = 0);
+    NONFAILING(*(uint32_t*)0x20000140 = 0);
+    NONFAILING(*(uint32_t*)0x20000144 = 0);
+    NONFAILING(*(uint32_t*)0x20000148 = -1);
+    NONFAILING(*(uint32_t*)0x2000014c = 8);
+    NONFAILING(*(uint64_t*)0x20000150 = 0x20000000);
+    NONFAILING(*(uint32_t*)0x20000000 = 0);
+    NONFAILING(*(uint32_t*)0x20000004 = 0);
+    NONFAILING(*(uint32_t*)0x20000158 = 0);
+    NONFAILING(*(uint32_t*)0x2000015c = 0x10);
+    NONFAILING(*(uint64_t*)0x20000160 = 0x20000000);
+    NONFAILING(*(uint32_t*)0x20000000 = 0);
+    NONFAILING(*(uint32_t*)0x20000004 = 0);
+    NONFAILING(*(uint32_t*)0x20000008 = 0);
+    NONFAILING(*(uint32_t*)0x2000000c = 0);
+    NONFAILING(*(uint32_t*)0x20000168 = 0);
+    NONFAILING(*(uint32_t*)0x2000016c = 0);
+    NONFAILING(*(uint32_t*)0x20000170 = -1);
+    res = syscall(__NR_bpf, 5ul, 0x20000100ul, 0x48ul);
+    if (res != -1)
+      r[8] = res;
+    break;
+  case 24:
+    res = syscall(__NR_socket, 0x29ul, 5ul, 0ul);
+    if (res != -1)
+      r[9] = res;
+    break;
+  case 25:
+    NONFAILING(*(uint32_t*)0x20000380 = r[7]);
+    NONFAILING(*(uint32_t*)0x20000384 = r[8]);
+    syscall(__NR_ioctl, r[9], 0x89e0ul, 0x20000380ul);
+    break;
+  case 26:
+    NONFAILING(*(uint32_t*)0x20000380 = r[0]);
+    NONFAILING(*(uint32_t*)0x20000384 = r[8]);
+    syscall(__NR_ioctl, r[1], 0x89e0ul, 0x20000380ul);
+    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/1f706432ca737fb13daad699aa349696d56a959e.c b/syzkaller-repros/linux/1f706432ca737fb13daad699aa349696d56a959e.c
new file mode 100644
index 0000000..e51bf54
--- /dev/null
+++ b/syzkaller-repros/linux/1f706432ca737fb13daad699aa349696d56a959e.c
@@ -0,0 +1,125 @@
+// KASAN: null-ptr-deref Read in do_con_trol
+// https://syzkaller.appspot.com/bug?id=1f706432ca737fb13daad699aa349696d56a959e
+// status:open
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <endian.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
+{
+  if (a0 == 0xc || a0 == 0xb) {
+    char buf[128];
+    sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_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 = 0;
+  *(uint32_t*)0x20000004 = 0;
+  *(uint32_t*)0x20000008 = 0;
+  *(uint32_t*)0x2000000c = 0;
+  *(uint32_t*)0x20000010 = 0;
+  *(uint32_t*)0x20000014 = 0;
+  *(uint32_t*)0x20000018 = 4;
+  *(uint32_t*)0x2000001c = 2;
+  *(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, 0x15);
+  if (res != -1)
+    r[1] = res;
+  *(uint8_t*)0x20000140 = 0xe;
+  *(uint8_t*)0x20000141 = 0x9b;
+  *(uint8_t*)0x20000142 = 0x41;
+  *(uint8_t*)0x20000143 = 0x9b;
+  *(uint8_t*)0x20000144 = 0;
+  *(uint8_t*)0x20000145 = 0;
+  *(uint8_t*)0x20000146 = 0x50;
+  *(uint8_t*)0x20000147 = 0;
+  *(uint64_t*)0x20000148 = 0;
+  *(uint16_t*)0x20000150 = 0;
+  *(uint16_t*)0x20000152 = 0;
+  *(uint32_t*)0x20000154 = 0;
+  *(uint64_t*)0x20000158 = 0;
+  *(uint64_t*)0x20000160 = 0x40;
+  *(uint64_t*)0x20000168 = 0;
+  *(uint32_t*)0x20000170 = 0;
+  *(uint16_t*)0x20000174 = 0;
+  *(uint16_t*)0x20000176 = 0x38;
+  *(uint16_t*)0x20000178 = 0;
+  *(uint16_t*)0x2000017a = 0;
+  *(uint16_t*)0x2000017c = 0;
+  *(uint16_t*)0x2000017e = 0;
+  *(uint32_t*)0x20000180 = 0;
+  *(uint32_t*)0x20000184 = 0;
+  *(uint64_t*)0x20000188 = 0;
+  *(uint64_t*)0x20000190 = 0;
+  *(uint64_t*)0x20000198 = 0;
+  *(uint64_t*)0x200001a0 = 0;
+  *(uint64_t*)0x200001a8 = 0;
+  *(uint64_t*)0x200001b0 = 0;
+  syscall(__NR_write, r[1], 0x20000140ul, 0x78ul);
+  return 0;
+}
diff --git a/syzkaller-repros/linux/1fbcb607cf49d8b5a3c8e056971f045f9bfa34f3.c b/syzkaller-repros/linux/1fbcb607cf49d8b5a3c8e056971f045f9bfa34f3.c
new file mode 100644
index 0000000..64c4fa8
--- /dev/null
+++ b/syzkaller-repros/linux/1fbcb607cf49d8b5a3c8e056971f045f9bfa34f3.c
@@ -0,0 +1,82 @@
+// general protection fault in nldev_stat_set_doit
+// https://syzkaller.appspot.com/bug?id=1fbcb607cf49d8b5a3c8e056971f045f9bfa34f3
+// 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>
+
+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, 0x14ul);
+  if (res != -1)
+    r[0] = res;
+  *(uint64_t*)0x200031c0 = 0;
+  *(uint32_t*)0x200031c8 = 0;
+  *(uint64_t*)0x200031d0 = 0x20003180;
+  *(uint64_t*)0x20003180 = 0x20003000;
+  *(uint32_t*)0x20003000 = 0x38;
+  *(uint16_t*)0x20003004 = 0x1403;
+  *(uint16_t*)0x20003006 = 1;
+  *(uint32_t*)0x20003008 = 0;
+  *(uint32_t*)0x2000300c = 0;
+  *(uint16_t*)0x20003010 = 9;
+  *(uint16_t*)0x20003012 = 2;
+  memcpy((void*)0x20003014, "syz1\000", 5);
+  *(uint16_t*)0x2000301c = 8;
+  *(uint16_t*)0x2000301e = 0x41;
+  memcpy((void*)0x20003020, "siw\000", 4);
+  *(uint16_t*)0x20003024 = 0x14;
+  *(uint16_t*)0x20003026 = 0x33;
+  memcpy((void*)0x20003028,
+         "lo\000\000\000\000\000\000\000\000\000\000\000\000\000\000", 16);
+  *(uint64_t*)0x20003188 = 0x38;
+  *(uint64_t*)0x200031d8 = 1;
+  *(uint64_t*)0x200031e0 = 0;
+  *(uint64_t*)0x200031e8 = 0;
+  *(uint32_t*)0x200031f0 = 0;
+  syscall(__NR_sendmsg, r[0], 0x200031c0ul, 0ul);
+  res = syscall(__NR_socket, 0x10ul, 3ul, 0x14ul);
+  if (res != -1)
+    r[1] = res;
+  *(uint64_t*)0x20000240 = 0;
+  *(uint32_t*)0x20000248 = 0;
+  *(uint64_t*)0x20000250 = 0x20000200;
+  *(uint64_t*)0x20000200 = 0x20000180;
+  *(uint32_t*)0x20000180 = 0x30;
+  *(uint16_t*)0x20000184 = 0x1410;
+  *(uint16_t*)0x20000186 = 1;
+  *(uint32_t*)0x20000188 = 0;
+  *(uint32_t*)0x2000018c = 0;
+  *(uint16_t*)0x20000190 = 8;
+  *(uint16_t*)0x20000192 = 0x4b;
+  *(uint32_t*)0x20000194 = 0x13;
+  *(uint16_t*)0x20000198 = 8;
+  *(uint16_t*)0x2000019a = 0x4a;
+  *(uint32_t*)0x2000019c = 0;
+  *(uint16_t*)0x200001a0 = 8;
+  *(uint16_t*)0x200001a2 = 1;
+  *(uint32_t*)0x200001a4 = 0;
+  *(uint16_t*)0x200001a8 = 8;
+  *(uint16_t*)0x200001aa = 3;
+  *(uint32_t*)0x200001ac = 1;
+  *(uint64_t*)0x20000208 = 0x30;
+  *(uint64_t*)0x20000258 = 1;
+  *(uint64_t*)0x20000260 = 0;
+  *(uint64_t*)0x20000268 = 0;
+  *(uint32_t*)0x20000270 = 0x20000021;
+  syscall(__NR_sendmsg, r[1], 0x20000240ul, 0ul);
+  return 0;
+}
diff --git a/syzkaller-repros/linux/2071c9ec1152c0e1c11b091afbe4cdeaa1cd56a2.c b/syzkaller-repros/linux/2071c9ec1152c0e1c11b091afbe4cdeaa1cd56a2.c
new file mode 100644
index 0000000..1c428cd
--- /dev/null
+++ b/syzkaller-repros/linux/2071c9ec1152c0e1c11b091afbe4cdeaa1cd56a2.c
@@ -0,0 +1,907 @@
+// BUG: soft lockup in do_signal
+// https://syzkaller.appspot.com/bug?id=2071c9ec1152c0e1c11b091afbe4cdeaa1cd56a2
+// status:dup
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+
+#define _GNU_SOURCE
+
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.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 <time.h>
+#include <unistd.h>
+
+#include <linux/futex.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 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;
+  }
+}
+
+#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 = 0,
+  USB_RAW_EVENT_CONNECT = 1,
+  USB_RAW_EVENT_CONTROL = 2,
+};
+
+struct usb_raw_event {
+  __u32 type;
+  __u32 length;
+  __u8 data[0];
+};
+
+struct usb_raw_ep_io {
+  __u16 ep;
+  __u16 flags;
+  __u32 length;
+  __u8 data[0];
+};
+
+#define USB_RAW_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_write(int fd, struct usb_raw_ep_io* io)
+{
+  return ioctl(fd, USB_RAW_IOCTL_EP_WRITE, 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 int lookup_interface(int fd, uint8_t bInterfaceNumber,
+                            uint8_t bAlternateSetting)
+{
+  struct usb_device_index* index = lookup_usb_index(fd);
+  int i;
+  if (!index)
+    return -1;
+  for (i = 0; i < index->ifaces_num; i++) {
+    if (index->ifaces[i].bInterfaceNumber == bInterfaceNumber &&
+        index->ifaces[i].bAlternateSetting == bAlternateSetting)
+      return i;
+  }
+  return -1;
+}
+
+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;
+}
+
+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_raw_control_event event;
+  event.inner.type = 0;
+  event.inner.length = USB_MAX_PACKET_SIZE;
+  int rv = usb_raw_event_fetch(fd, (struct usb_raw_event*)&event);
+  if (rv < 0) {
+    return rv;
+  }
+  if (event.inner.type != USB_RAW_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 {
+    if ((event.ctrl.bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD ||
+        event.ctrl.bRequest == USB_REQ_SET_INTERFACE) {
+      int iface_num = event.ctrl.wIndex;
+      int alt_set = event.ctrl.wValue;
+      int iface_index = lookup_interface(fd, iface_num, alt_set);
+      if (iface_index < 0) {
+      } else {
+        set_interface(fd, iface_index);
+      }
+    }
+    response_length = event.ctrl.wLength;
+  }
+  struct usb_raw_ep_io_data response;
+  response.inner.ep = 0;
+  response.inner.flags = 0;
+  if (response_length > sizeof(response.data))
+    response_length = 0;
+  if (event.ctrl.wLength < response_length)
+    response_length = event.ctrl.wLength;
+  if ((event.ctrl.bRequestType & USB_DIR_IN) && !event.ctrl.wLength) {
+    response_length = USB_MAX_PACKET_SIZE;
+  }
+  response.inner.length = response_length;
+  if (response_data)
+    memcpy(&response.data[0], response_data, response_length);
+  else
+    memset(&response.data[0], 0, response_length);
+  if ((event.ctrl.bRequestType & USB_DIR_IN) && event.ctrl.wLength) {
+    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 0;
+}
+
+static volatile long syz_usb_ep_write(volatile long a0, volatile long a1,
+                                      volatile long a2, volatile long a3)
+{
+  int fd = a0;
+  uint16_t ep = a1;
+  uint32_t len = a2;
+  char* data = (char*)a3;
+  struct usb_raw_ep_io_data io_data;
+  io_data.inner.ep = ep;
+  io_data.inner.flags = 0;
+  if (len > sizeof(io_data.data))
+    len = sizeof(io_data.data);
+  io_data.inner.length = len;
+  memcpy(&io_data.data[0], data, len);
+  int rv = usb_raw_ep_write(fd, (struct usb_raw_ep_io*)&io_data);
+  if (rv < 0) {
+    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;
+}
+
+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;
+  int collide = 0;
+again:
+  for (call = 0; call < 5; 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 + (call == 0 ? 2000 : 0) + (call == 1 ? 300 : 0) +
+                          (call == 2 ? 2000 : 0) + (call == 3 ? 300 : 0) +
+                          (call == 4 ? 300 : 0));
+      break;
+    }
+  }
+  for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+    sleep_ms(1);
+  if (!collide) {
+    collide = 1;
+    goto again;
+  }
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_call(int call)
+{
+  intptr_t res;
+  switch (call) {
+  case 0:
+    memcpy((void*)0x20000380,
+           "\x12\x01\x00\x00\x41\x43\x53\x20\x41\x0e\x51\x50\xe8\xd5\x00\x00"
+           "\x00\x01\x09\x02\x1b\x00\x01\x00\x00\x00\x00\x09\x04\x01\x00\x01"
+           "\x21\xae\x0d\x00\x09\x05\x82\x17\x36\xa1\x02\x00\x00\x00\x00\x00"
+           "\x00\x9b\x29\x29\x36\xe2\x10\xeb\x41\xc7\x1d\xd4\xfc\x46\x5a\x86"
+           "\x05\x56\xc3\x63\xec\xc7\xd9\xe7\xa4\x0f\x72\x2c\x6f\x2f\x24\xef"
+           "\xe1\xa0\x97\x15\xd8\x71\xb3\xa4\x5e\x79\xd9\xd6\x97\x8a\x1c\x1b"
+           "\xae\x14\xe9\x0a\x9e\x6c\xd8\x55\x55\x7a\x76\xcc\x85\x2d\xd7\x85"
+           "\x1c\x02\x49\xdc\x3c\xd1\x8b\x95\xdb\xfa\x5e\x1a\x93\xb9\x12\x90"
+           "\xab\x4e\xce\x4c\x19\x0f\x84\xd4\xd4\xdd\xd4\xb3\xe8\x7e\xee\x24"
+           "\x52\x72\x39\x75\x71\xf7\xfd\x6a\x6a\x7e\x60\x21\x17\x44\x10\x43"
+           "\x70\xee\x69\xa2\x26\x9f\xae\xf0\x3d\x8e\xfe\xe1\xb8\x64\x0d\xec"
+           "\xf9\x49\x85\xf0\x29\x23\x7d\xde\x69\xa4\xe7",
+           187);
+    res = syz_usb_connect(0, 0x2d, 0x20000380, 0);
+    if (res != -1)
+      r[0] = res;
+    break;
+  case 1:
+    syz_usb_disconnect(r[0]);
+    break;
+  case 2:
+    memcpy(
+        (void*)0x20000000,
+        "\x12\x01\x00\x00\x00\x00\x00\x40\x26\x09\x33\x33\x00\x00\x00\x00\x00"
+        "\x01\x09\x02\x24\x00\x01\x00\x00\x00\x00\x09\x04\x00\x00\xff\x03\x00"
+        "\x00\x00\x09\x21\x00\x00\x00\x01\x22\x22\x00\x09\x05\x81\x03\xf1\x01"
+        "\x00\x00\x00\x9b\xb6\xb4\x67\x77\x8e\xaa\x96\x73\xb2\xe1\x75\xd7\x5d"
+        "\x68\x06\x05\x28\x7c\x6e\x7b\x39\xa1\xc9\x0c\x29\x79\x37\xa2\x4b\x86"
+        "\xfc\x83\x01\x4c\x19\x6b\xb8\x74\x60\xed\x0f\xe0\x7b\xe2\xa4\xbe\xd1"
+        "\xe5\x65\x84\x62\xe0\xd3\x7f\x12\x47\x0b\xf2\x59\x28\x3f\xcb\x66\xf2"
+        "\x3b\x85\xfb\x9d\xb0\x71\x09\x67\xa8\x5c\x91\x43\xce\x17\x5d\xab\x99"
+        "\xc0\xbd\xa8\x49\x21\x7e\xc7\x02\x25\xdc\xbc\x42\x8c\x20\xe8\x25\x0c"
+        "\x81\xa8\xd2\x8b\x55\x35\x52\xb4\x30\xb0\x10\xa5\x4c\xee\x61\xdf\xc3"
+        "\x17\x03\x17\x92\x24\x02\x00\x4d\x0d\x01\x14\x58\xa7\x68\x34\xd3\xfc"
+        "\xbd\x59\x36\xd9\x4c\x0e\xc1\x71\x78\x62\xeb\xea\xd0\x71\x39\xe1\xf7"
+        "\xb4\x44\xab\xed\x06\xaa\x79\x1b\xac\xa4\x1a\xb1\x18\x1c\x53\x39\x98"
+        "\x3a\x2e\x81\xee\x8e\x23\x31\x89\xa5\xce\xa3\x0a\xc6\x5c\x03\xe8\xd9"
+        "\x8c\xe4\xe8\x24\x4f\x02\x7a\x8d\xa7\x3b\xd6\x3b\x64\x02\xf0\x28\x03"
+        "\x20\x43\x56\x42\x48\x51\x89\xb5\xc2\xc0\x1a\xf9\x3b\x7c\xdb\x3d\x01"
+        "\x7d\x00\x66\x62\x22\x44\xc7\x41\x55\x8a\x41\x4c\x42\x44\x55\xa1\x36"
+        "\xa3\x9e\xf6\x49\x84\x6d\x90\x24\xf1\xe6\xc5\x12\xc8\x17\x95\x58\xc8"
+        "\x0a\xbf\x9c\x69\xd5\x4a\x9e\x4c\xf5\x46\x8d\x8e\xe5\x76\x1c\x2a\x81"
+        "\x08\x47\x03\x5d\x61\x8c\xf6\x1c\xea\xdd\xf0\xb6\xce\x3b\x58\x85\xfe"
+        "\x93\x10\x78\x66\x73\x1e\x4a\xf5\x9b\x2b\xcd\xf7\x14\x2e\x91\x5d\x0f"
+        "\x6b\x9a\xfe\xb2\x7c\x1a\x3b\x19\x88\x12\xe9\xb4\xfe\xac\x2f\xa8\x2d"
+        "\xbd\xce\x2e\x8d\x66\xc2\x66\x89\x34\x9a\x89\x03\x15\x89\x86\x52\x5b"
+        "\x7c\xec\x8f\x87\xfc\x74\xfc\xdc\x48\x85\x6f\x3f\x08\x51\x6c\xc1\xbe"
+        "\x7f\xc3\xa7\x10\xc5\x21\xc7\x21\x92\xd2\xd5\xab\xe9\x5c\x13\x59\x7c"
+        "\xb0\x0f\xa5\x90\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+        "\x00\x00\x00\x00\x00\x00\x00\x9f\xa2\x9c\xf7\xe2\x33\x61\x4d\x77\xdf"
+        "\x7b\x9e\x92\xc7\x8f\xb5\xc0\xc3\x4a\xb2\xcc\x27\xde\x67\x48\x8d\x2a"
+        "\x7d\x17\x07\x5f\xfc\xbc\x08\xe2\x5b\x71\x86\x6e\x1d\xa9\x92\xdd\xc7"
+        "\x31\x78\x48\xbc\xbe\x2a\xa8\x7d\x5d\x26\xa0\x57\x19\xcb\x7b\x17\x7e"
+        "\x76\x90\xb6\x28\xff\x27\xa1\x18\xf1\x67\x1e\xfd\x59\x82\xfe\xc1\x99"
+        "\x45\x44\x1d\xcc\x4f\xbd\x26\xe7\x25\xea\xd1\xe4\xf1\xee\xb1\x9f",
+        543);
+    res = syz_usb_connect(0, 0x36, 0x20000000, 0);
+    if (res != -1)
+      r[1] = res;
+    break;
+  case 3:
+    syz_usb_control_io(r[1], 0, 0);
+    break;
+  case 4:
+    memcpy((void*)0x20000b80, "\x5d\x2d\xd9\xd6\x79\xd7\xea\x95\x0f\x3a\x2b\xa0"
+                              "\x58\xb8\xf4\x34\x83\x36\x9e\x4e\x68\xe3\x13\x14"
+                              "\x39\xf9\xff\x55\xff\x52\x9c\xee\x88\xee\xe3\x23"
+                              "\x13\xa5\x4e\xc6\x10\xba\x6f\x0a\xf1",
+           45);
+    syz_usb_ep_write(r[0], 0, 0x2d, 0x20000b80);
+    break;
+  }
+}
+int main(void)
+{
+  syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
+  loop();
+  return 0;
+}
diff --git a/syzkaller-repros/linux/216cd418881b71c6b40b3a1acfa8b44882fb45fa.c b/syzkaller-repros/linux/216cd418881b71c6b40b3a1acfa8b44882fb45fa.c
new file mode 100644
index 0000000..e9d6bfa
--- /dev/null
+++ b/syzkaller-repros/linux/216cd418881b71c6b40b3a1acfa8b44882fb45fa.c
@@ -0,0 +1,160 @@
+// KASAN: use-after-free Write in ex_handler_refcount
+// https://syzkaller.appspot.com/bug?id=216cd418881b71c6b40b3a1acfa8b44882fb45fa
+// 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 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[1] = {0xffffffffffffffff};
+
+void execute_one(void)
+{
+  intptr_t res = 0;
+  memcpy((void*)0x200003c0, "/sys/kernel/debug/bluetooth/6lowpan_enable\000",
+         43);
+  res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x200003c0ul, 2ul, 0ul);
+  if (res != -1)
+    r[0] = res;
+  memcpy((void*)0x20000140, "1", 1);
+  syscall(__NR_write, r[0], 0x20000140ul, 1ul);
+}
+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/232223b1e1dc405ba8ca60125d643ea8bbeb65ac.c b/syzkaller-repros/linux/232223b1e1dc405ba8ca60125d643ea8bbeb65ac.c
new file mode 100644
index 0000000..658a729
--- /dev/null
+++ b/syzkaller-repros/linux/232223b1e1dc405ba8ca60125d643ea8bbeb65ac.c
@@ -0,0 +1,1274 @@
+// INFO: rcu detected stall in ksys_ioctl
+// https://syzkaller.appspot.com/bug?id=232223b1e1dc405ba8ca60125d643ea8bbeb65ac
+// 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 <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.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/kvm.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;
+}
+
+#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))))
+
+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);
+  }
+}
+
+const char kvm_asm16_cpl3[] = "\x0f\x20\xc0\x66\x83\xc8\x01\x0f\x22\xc0\xb8\xa0"
+                              "\x00\x0f\x00\xd8\xb8\x2b\x00\x8e\xd8\x8e\xc0\x8e"
+                              "\xe0\x8e\xe8\xbc\x00\x01\xc7\x06\x00\x01\x1d\xba"
+                              "\xc7\x06\x02\x01\x23\x00\xc7\x06\x04\x01\x00\x01"
+                              "\xc7\x06\x06\x01\x2b\x00\xcb";
+const char kvm_asm32_paged[] = "\x0f\x20\xc0\x0d\x00\x00\x00\x80\x0f\x22\xc0";
+const char kvm_asm32_vm86[] =
+    "\x66\xb8\xb8\x00\x0f\x00\xd8\xea\x00\x00\x00\x00\xd0\x00";
+const char kvm_asm32_paged_vm86[] = "\x0f\x20\xc0\x0d\x00\x00\x00\x80\x0f\x22"
+                                    "\xc0\x66\xb8\xb8\x00\x0f\x00\xd8\xea\x00"
+                                    "\x00\x00\x00\xd0\x00";
+const char kvm_asm64_enable_long[] = "\x0f\x20\xc0\x0d\x00\x00\x00\x80\x0f\x22"
+                                     "\xc0\xea\xde\xc0\xad\x0b\x50\x00\x48\xc7"
+                                     "\xc0\xd8\x00\x00\x00\x0f\x00\xd8";
+const char kvm_asm64_init_vm[] =
+    "\x0f\x20\xc0\x0d\x00\x00\x00\x80\x0f\x22\xc0\xea\xde\xc0\xad\x0b\x50\x00"
+    "\x48\xc7\xc0\xd8\x00\x00\x00\x0f\x00\xd8\x48\xc7\xc1\x3a\x00\x00\x00\x0f"
+    "\x32\x48\x83\xc8\x05\x0f\x30\x0f\x20\xe0\x48\x0d\x00\x20\x00\x00\x0f\x22"
+    "\xe0\x48\xc7\xc1\x80\x04\x00\x00\x0f\x32\x48\xc7\xc2\x00\x60\x00\x00\x89"
+    "\x02\x48\xc7\xc2\x00\x70\x00\x00\x89\x02\x48\xc7\xc0\x00\x5f\x00\x00\xf3"
+    "\x0f\xc7\x30\x48\xc7\xc0\x08\x5f\x00\x00\x66\x0f\xc7\x30\x0f\xc7\x30\x48"
+    "\xc7\xc1\x81\x04\x00\x00\x0f\x32\x48\x83\xc8\x3f\x48\x21\xd0\x48\xc7\xc2"
+    "\x00\x40\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x02\x40\x00\x00\x48\xb8\x84\x9e"
+    "\x99\xf3\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x1e\x40\x00\x00\x48\xc7"
+    "\xc0\x81\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc1\x83\x04\x00\x00\x0f\x32\x48"
+    "\x0d\xff\x6f\x03\x00\x48\x21\xd0\x48\xc7\xc2\x0c\x40\x00\x00\x0f\x79\xd0"
+    "\x48\xc7\xc1\x84\x04\x00\x00\x0f\x32\x48\x0d\xff\x17\x00\x00\x48\x21\xd0"
+    "\x48\xc7\xc2\x12\x40\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x04\x2c\x00\x00\x48"
+    "\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x00\x28\x00\x00\x48\xc7"
+    "\xc0\xff\xff\xff\xff\x0f\x79\xd0\x48\xc7\xc2\x02\x0c\x00\x00\x48\xc7\xc0"
+    "\x50\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc0\x58\x00\x00\x00\x48\xc7\xc2\x00"
+    "\x0c\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x04\x0c\x00\x00\x0f\x79\xd0\x48\xc7"
+    "\xc2\x06\x0c\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x08\x0c\x00\x00\x0f\x79\xd0"
+    "\x48\xc7\xc2\x0a\x0c\x00\x00\x0f\x79\xd0\x48\xc7\xc0\xd8\x00\x00\x00\x48"
+    "\xc7\xc2\x0c\x0c\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x02\x2c\x00\x00\x48\xc7"
+    "\xc0\x00\x05\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x00\x4c\x00\x00\x48\xc7\xc0"
+    "\x50\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x10\x6c\x00\x00\x48\xc7\xc0\x00"
+    "\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x12\x6c\x00\x00\x48\xc7\xc0\x00\x00"
+    "\x00\x00\x0f\x79\xd0\x0f\x20\xc0\x48\xc7\xc2\x00\x6c\x00\x00\x48\x89\xc0"
+    "\x0f\x79\xd0\x0f\x20\xd8\x48\xc7\xc2\x02\x6c\x00\x00\x48\x89\xc0\x0f\x79"
+    "\xd0\x0f\x20\xe0\x48\xc7\xc2\x04\x6c\x00\x00\x48\x89\xc0\x0f\x79\xd0\x48"
+    "\xc7\xc2\x06\x6c\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7"
+    "\xc2\x08\x6c\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2"
+    "\x0a\x6c\x00\x00\x48\xc7\xc0\x00\x3a\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x0c"
+    "\x6c\x00\x00\x48\xc7\xc0\x00\x10\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x0e\x6c"
+    "\x00\x00\x48\xc7\xc0\x00\x38\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x14\x6c\x00"
+    "\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x16\x6c\x00\x00"
+    "\x48\x8b\x04\x25\x10\x5f\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x00\x00\x00\x00"
+    "\x48\xc7\xc0\x01\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x02\x00\x00\x00\x48"
+    "\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x00\x20\x00\x00\x48\xc7"
+    "\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x02\x20\x00\x00\x48\xc7\xc0"
+    "\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x04\x20\x00\x00\x48\xc7\xc0\x00"
+    "\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x06\x20\x00\x00\x48\xc7\xc0\x00\x00"
+    "\x00\x00\x0f\x79\xd0\x48\xc7\xc1\x77\x02\x00\x00\x0f\x32\x48\xc1\xe2\x20"
+    "\x48\x09\xd0\x48\xc7\xc2\x00\x2c\x00\x00\x48\x89\xc0\x0f\x79\xd0\x48\xc7"
+    "\xc2\x04\x40\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2"
+    "\x0a\x40\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x0e"
+    "\x40\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x10\x40"
+    "\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x16\x40\x00"
+    "\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x14\x40\x00\x00"
+    "\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x00\x60\x00\x00\x48"
+    "\xc7\xc0\xff\xff\xff\xff\x0f\x79\xd0\x48\xc7\xc2\x02\x60\x00\x00\x48\xc7"
+    "\xc0\xff\xff\xff\xff\x0f\x79\xd0\x48\xc7\xc2\x1c\x20\x00\x00\x48\xc7\xc0"
+    "\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x1e\x20\x00\x00\x48\xc7\xc0\x00"
+    "\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x20\x20\x00\x00\x48\xc7\xc0\x00\x00"
+    "\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x22\x20\x00\x00\x48\xc7\xc0\x00\x00\x00"
+    "\x00\x0f\x79\xd0\x48\xc7\xc2\x00\x08\x00\x00\x48\xc7\xc0\x58\x00\x00\x00"
+    "\x0f\x79\xd0\x48\xc7\xc2\x02\x08\x00\x00\x48\xc7\xc0\x50\x00\x00\x00\x0f"
+    "\x79\xd0\x48\xc7\xc2\x04\x08\x00\x00\x48\xc7\xc0\x58\x00\x00\x00\x0f\x79"
+    "\xd0\x48\xc7\xc2\x06\x08\x00\x00\x48\xc7\xc0\x58\x00\x00\x00\x0f\x79\xd0"
+    "\x48\xc7\xc2\x08\x08\x00\x00\x48\xc7\xc0\x58\x00\x00\x00\x0f\x79\xd0\x48"
+    "\xc7\xc2\x0a\x08\x00\x00\x48\xc7\xc0\x58\x00\x00\x00\x0f\x79\xd0\x48\xc7"
+    "\xc2\x0c\x08\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2"
+    "\x0e\x08\x00\x00\x48\xc7\xc0\xd8\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x12"
+    "\x68\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x14\x68"
+    "\x00\x00\x48\xc7\xc0\x00\x3a\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x16\x68\x00"
+    "\x00\x48\xc7\xc0\x00\x10\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x18\x68\x00\x00"
+    "\x48\xc7\xc0\x00\x38\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x00\x48\x00\x00\x48"
+    "\xc7\xc0\xff\xff\x0f\x00\x0f\x79\xd0\x48\xc7\xc2\x02\x48\x00\x00\x48\xc7"
+    "\xc0\xff\xff\x0f\x00\x0f\x79\xd0\x48\xc7\xc2\x04\x48\x00\x00\x48\xc7\xc0"
+    "\xff\xff\x0f\x00\x0f\x79\xd0\x48\xc7\xc2\x06\x48\x00\x00\x48\xc7\xc0\xff"
+    "\xff\x0f\x00\x0f\x79\xd0\x48\xc7\xc2\x08\x48\x00\x00\x48\xc7\xc0\xff\xff"
+    "\x0f\x00\x0f\x79\xd0\x48\xc7\xc2\x0a\x48\x00\x00\x48\xc7\xc0\xff\xff\x0f"
+    "\x00\x0f\x79\xd0\x48\xc7\xc2\x0c\x48\x00\x00\x48\xc7\xc0\x00\x00\x00\x00"
+    "\x0f\x79\xd0\x48\xc7\xc2\x0e\x48\x00\x00\x48\xc7\xc0\xff\x1f\x00\x00\x0f"
+    "\x79\xd0\x48\xc7\xc2\x10\x48\x00\x00\x48\xc7\xc0\xff\x1f\x00\x00\x0f\x79"
+    "\xd0\x48\xc7\xc2\x12\x48\x00\x00\x48\xc7\xc0\xff\x1f\x00\x00\x0f\x79\xd0"
+    "\x48\xc7\xc2\x14\x48\x00\x00\x48\xc7\xc0\x93\x40\x00\x00\x0f\x79\xd0\x48"
+    "\xc7\xc2\x16\x48\x00\x00\x48\xc7\xc0\x9b\x20\x00\x00\x0f\x79\xd0\x48\xc7"
+    "\xc2\x18\x48\x00\x00\x48\xc7\xc0\x93\x40\x00\x00\x0f\x79\xd0\x48\xc7\xc2"
+    "\x1a\x48\x00\x00\x48\xc7\xc0\x93\x40\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x1c"
+    "\x48\x00\x00\x48\xc7\xc0\x93\x40\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x1e\x48"
+    "\x00\x00\x48\xc7\xc0\x93\x40\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x20\x48\x00"
+    "\x00\x48\xc7\xc0\x82\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x22\x48\x00\x00"
+    "\x48\xc7\xc0\x8b\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x1c\x68\x00\x00\x48"
+    "\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x1e\x68\x00\x00\x48\xc7"
+    "\xc0\x00\x91\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x20\x68\x00\x00\x48\xc7\xc0"
+    "\x02\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x06\x28\x00\x00\x48\xc7\xc0\x00"
+    "\x05\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x0a\x28\x00\x00\x48\xc7\xc0\x00\x00"
+    "\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x0c\x28\x00\x00\x48\xc7\xc0\x00\x00\x00"
+    "\x00\x0f\x79\xd0\x48\xc7\xc2\x0e\x28\x00\x00\x48\xc7\xc0\x00\x00\x00\x00"
+    "\x0f\x79\xd0\x48\xc7\xc2\x10\x28\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f"
+    "\x79\xd0\x0f\x20\xc0\x48\xc7\xc2\x00\x68\x00\x00\x48\x89\xc0\x0f\x79\xd0"
+    "\x0f\x20\xd8\x48\xc7\xc2\x02\x68\x00\x00\x48\x89\xc0\x0f\x79\xd0\x0f\x20"
+    "\xe0\x48\xc7\xc2\x04\x68\x00\x00\x48\x89\xc0\x0f\x79\xd0\x48\xc7\xc0\x18"
+    "\x5f\x00\x00\x48\x8b\x10\x48\xc7\xc0\x20\x5f\x00\x00\x48\x8b\x08\x48\x31"
+    "\xc0\x0f\x78\xd0\x48\x31\xc8\x0f\x79\xd0\x0f\x01\xc2\x48\xc7\xc2\x00\x44"
+    "\x00\x00\x0f\x78\xd0\xf4";
+const char kvm_asm64_vm_exit[] = "\x48\xc7\xc3\x00\x44\x00\x00\x0f\x78\xda\x48"
+                                 "\xc7\xc3\x02\x44\x00\x00\x0f\x78\xd9\x48\xc7"
+                                 "\xc0\x00\x64\x00\x00\x0f\x78\xc0\x48\xc7\xc3"
+                                 "\x1e\x68\x00\x00\x0f\x78\xdb\xf4";
+const char kvm_asm64_cpl3[] =
+    "\x0f\x20\xc0\x0d\x00\x00\x00\x80\x0f\x22\xc0\xea\xde\xc0\xad\x0b\x50\x00"
+    "\x48\xc7\xc0\xd8\x00\x00\x00\x0f\x00\xd8\x48\xc7\xc0\x6b\x00\x00\x00\x8e"
+    "\xd8\x8e\xc0\x8e\xe0\x8e\xe8\x48\xc7\xc4\x80\x0f\x00\x00\x48\xc7\x04\x24"
+    "\x1d\xba\x00\x00\x48\xc7\x44\x24\x04\x63\x00\x00\x00\x48\xc7\x44\x24\x08"
+    "\x80\x0f\x00\x00\x48\xc7\x44\x24\x0c\x6b\x00\x00\x00\xcb";
+
+#define ADDR_TEXT 0x0000
+#define ADDR_GDT 0x1000
+#define ADDR_LDT 0x1800
+#define ADDR_PML4 0x2000
+#define ADDR_PDP 0x3000
+#define ADDR_PD 0x4000
+#define ADDR_STACK0 0x0f80
+#define ADDR_VAR_HLT 0x2800
+#define ADDR_VAR_SYSRET 0x2808
+#define ADDR_VAR_SYSEXIT 0x2810
+#define ADDR_VAR_IDT 0x3800
+#define ADDR_VAR_TSS64 0x3a00
+#define ADDR_VAR_TSS64_CPL3 0x3c00
+#define ADDR_VAR_TSS16 0x3d00
+#define ADDR_VAR_TSS16_2 0x3e00
+#define ADDR_VAR_TSS16_CPL3 0x3f00
+#define ADDR_VAR_TSS32 0x4800
+#define ADDR_VAR_TSS32_2 0x4a00
+#define ADDR_VAR_TSS32_CPL3 0x4c00
+#define ADDR_VAR_TSS32_VM86 0x4e00
+#define ADDR_VAR_VMXON_PTR 0x5f00
+#define ADDR_VAR_VMCS_PTR 0x5f08
+#define ADDR_VAR_VMEXIT_PTR 0x5f10
+#define ADDR_VAR_VMWRITE_FLD 0x5f18
+#define ADDR_VAR_VMWRITE_VAL 0x5f20
+#define ADDR_VAR_VMXON 0x6000
+#define ADDR_VAR_VMCS 0x7000
+#define ADDR_VAR_VMEXIT_CODE 0x9000
+#define ADDR_VAR_USER_CODE 0x9100
+#define ADDR_VAR_USER_CODE2 0x9120
+
+#define SEL_LDT (1 << 3)
+#define SEL_CS16 (2 << 3)
+#define SEL_DS16 (3 << 3)
+#define SEL_CS16_CPL3 ((4 << 3) + 3)
+#define SEL_DS16_CPL3 ((5 << 3) + 3)
+#define SEL_CS32 (6 << 3)
+#define SEL_DS32 (7 << 3)
+#define SEL_CS32_CPL3 ((8 << 3) + 3)
+#define SEL_DS32_CPL3 ((9 << 3) + 3)
+#define SEL_CS64 (10 << 3)
+#define SEL_DS64 (11 << 3)
+#define SEL_CS64_CPL3 ((12 << 3) + 3)
+#define SEL_DS64_CPL3 ((13 << 3) + 3)
+#define SEL_CGATE16 (14 << 3)
+#define SEL_TGATE16 (15 << 3)
+#define SEL_CGATE32 (16 << 3)
+#define SEL_TGATE32 (17 << 3)
+#define SEL_CGATE64 (18 << 3)
+#define SEL_CGATE64_HI (19 << 3)
+#define SEL_TSS16 (20 << 3)
+#define SEL_TSS16_2 (21 << 3)
+#define SEL_TSS16_CPL3 ((22 << 3) + 3)
+#define SEL_TSS32 (23 << 3)
+#define SEL_TSS32_2 (24 << 3)
+#define SEL_TSS32_CPL3 ((25 << 3) + 3)
+#define SEL_TSS32_VM86 (26 << 3)
+#define SEL_TSS64 (27 << 3)
+#define SEL_TSS64_HI (28 << 3)
+#define SEL_TSS64_CPL3 ((29 << 3) + 3)
+#define SEL_TSS64_CPL3_HI (30 << 3)
+
+#define MSR_IA32_FEATURE_CONTROL 0x3a
+#define MSR_IA32_VMX_BASIC 0x480
+#define MSR_IA32_SMBASE 0x9e
+#define MSR_IA32_SYSENTER_CS 0x174
+#define MSR_IA32_SYSENTER_ESP 0x175
+#define MSR_IA32_SYSENTER_EIP 0x176
+#define MSR_IA32_STAR 0xC0000081
+#define MSR_IA32_LSTAR 0xC0000082
+#define MSR_IA32_VMX_PROCBASED_CTLS2 0x48B
+
+#define NEXT_INSN $0xbadc0de
+#define PREFIX_SIZE 0xba1d
+
+#define KVM_SMI _IO(KVMIO, 0xb7)
+
+#define CR0_PE 1
+#define CR0_MP (1 << 1)
+#define CR0_EM (1 << 2)
+#define CR0_TS (1 << 3)
+#define CR0_ET (1 << 4)
+#define CR0_NE (1 << 5)
+#define CR0_WP (1 << 16)
+#define CR0_AM (1 << 18)
+#define CR0_NW (1 << 29)
+#define CR0_CD (1 << 30)
+#define CR0_PG (1 << 31)
+
+#define CR4_VME 1
+#define CR4_PVI (1 << 1)
+#define CR4_TSD (1 << 2)
+#define CR4_DE (1 << 3)
+#define CR4_PSE (1 << 4)
+#define CR4_PAE (1 << 5)
+#define CR4_MCE (1 << 6)
+#define CR4_PGE (1 << 7)
+#define CR4_PCE (1 << 8)
+#define CR4_OSFXSR (1 << 8)
+#define CR4_OSXMMEXCPT (1 << 10)
+#define CR4_UMIP (1 << 11)
+#define CR4_VMXE (1 << 13)
+#define CR4_SMXE (1 << 14)
+#define CR4_FSGSBASE (1 << 16)
+#define CR4_PCIDE (1 << 17)
+#define CR4_OSXSAVE (1 << 18)
+#define CR4_SMEP (1 << 20)
+#define CR4_SMAP (1 << 21)
+#define CR4_PKE (1 << 22)
+
+#define EFER_SCE 1
+#define EFER_LME (1 << 8)
+#define EFER_LMA (1 << 10)
+#define EFER_NXE (1 << 11)
+#define EFER_SVME (1 << 12)
+#define EFER_LMSLE (1 << 13)
+#define EFER_FFXSR (1 << 14)
+#define EFER_TCE (1 << 15)
+#define PDE32_PRESENT 1
+#define PDE32_RW (1 << 1)
+#define PDE32_USER (1 << 2)
+#define PDE32_PS (1 << 7)
+#define PDE64_PRESENT 1
+#define PDE64_RW (1 << 1)
+#define PDE64_USER (1 << 2)
+#define PDE64_ACCESSED (1 << 5)
+#define PDE64_DIRTY (1 << 6)
+#define PDE64_PS (1 << 7)
+#define PDE64_G (1 << 8)
+
+struct tss16 {
+  uint16_t prev;
+  uint16_t sp0;
+  uint16_t ss0;
+  uint16_t sp1;
+  uint16_t ss1;
+  uint16_t sp2;
+  uint16_t ss2;
+  uint16_t ip;
+  uint16_t flags;
+  uint16_t ax;
+  uint16_t cx;
+  uint16_t dx;
+  uint16_t bx;
+  uint16_t sp;
+  uint16_t bp;
+  uint16_t si;
+  uint16_t di;
+  uint16_t es;
+  uint16_t cs;
+  uint16_t ss;
+  uint16_t ds;
+  uint16_t ldt;
+} __attribute__((packed));
+
+struct tss32 {
+  uint16_t prev, prevh;
+  uint32_t sp0;
+  uint16_t ss0, ss0h;
+  uint32_t sp1;
+  uint16_t ss1, ss1h;
+  uint32_t sp2;
+  uint16_t ss2, ss2h;
+  uint32_t cr3;
+  uint32_t ip;
+  uint32_t flags;
+  uint32_t ax;
+  uint32_t cx;
+  uint32_t dx;
+  uint32_t bx;
+  uint32_t sp;
+  uint32_t bp;
+  uint32_t si;
+  uint32_t di;
+  uint16_t es, esh;
+  uint16_t cs, csh;
+  uint16_t ss, ssh;
+  uint16_t ds, dsh;
+  uint16_t fs, fsh;
+  uint16_t gs, gsh;
+  uint16_t ldt, ldth;
+  uint16_t trace;
+  uint16_t io_bitmap;
+} __attribute__((packed));
+
+struct tss64 {
+  uint32_t reserved0;
+  uint64_t rsp[3];
+  uint64_t reserved1;
+  uint64_t ist[7];
+  uint64_t reserved2;
+  uint32_t reserved3;
+  uint32_t io_bitmap;
+} __attribute__((packed));
+
+static void fill_segment_descriptor(uint64_t* dt, uint64_t* lt,
+                                    struct kvm_segment* seg)
+{
+  uint16_t index = seg->selector >> 3;
+  uint64_t limit = seg->g ? seg->limit >> 12 : seg->limit;
+  uint64_t sd = (limit & 0xffff) | (seg->base & 0xffffff) << 16 |
+                (uint64_t)seg->type << 40 | (uint64_t)seg->s << 44 |
+                (uint64_t)seg->dpl << 45 | (uint64_t)seg->present << 47 |
+                (limit & 0xf0000ULL) << 48 | (uint64_t)seg->avl << 52 |
+                (uint64_t)seg->l << 53 | (uint64_t)seg->db << 54 |
+                (uint64_t)seg->g << 55 | (seg->base & 0xff000000ULL) << 56;
+  dt[index] = sd;
+  lt[index] = sd;
+}
+
+static void fill_segment_descriptor_dword(uint64_t* dt, uint64_t* lt,
+                                          struct kvm_segment* seg)
+{
+  fill_segment_descriptor(dt, lt, seg);
+  uint16_t index = seg->selector >> 3;
+  dt[index + 1] = 0;
+  lt[index + 1] = 0;
+}
+
+static void setup_syscall_msrs(int cpufd, uint16_t sel_cs, uint16_t sel_cs_cpl3)
+{
+  char buf[sizeof(struct kvm_msrs) + 5 * sizeof(struct kvm_msr_entry)];
+  memset(buf, 0, sizeof(buf));
+  struct kvm_msrs* msrs = (struct kvm_msrs*)buf;
+  struct kvm_msr_entry* entries = msrs->entries;
+  msrs->nmsrs = 5;
+  entries[0].index = MSR_IA32_SYSENTER_CS;
+  entries[0].data = sel_cs;
+  entries[1].index = MSR_IA32_SYSENTER_ESP;
+  entries[1].data = ADDR_STACK0;
+  entries[2].index = MSR_IA32_SYSENTER_EIP;
+  entries[2].data = ADDR_VAR_SYSEXIT;
+  entries[3].index = MSR_IA32_STAR;
+  entries[3].data = ((uint64_t)sel_cs << 32) | ((uint64_t)sel_cs_cpl3 << 48);
+  entries[4].index = MSR_IA32_LSTAR;
+  entries[4].data = ADDR_VAR_SYSRET;
+  ioctl(cpufd, KVM_SET_MSRS, msrs);
+}
+
+static void setup_32bit_idt(struct kvm_sregs* sregs, char* host_mem,
+                            uintptr_t guest_mem)
+{
+  sregs->idt.base = guest_mem + ADDR_VAR_IDT;
+  sregs->idt.limit = 0x1ff;
+  uint64_t* idt = (uint64_t*)(host_mem + sregs->idt.base);
+  int i;
+  for (i = 0; i < 32; i++) {
+    struct kvm_segment gate;
+    gate.selector = i << 3;
+    switch (i % 6) {
+    case 0:
+      gate.type = 6;
+      gate.base = SEL_CS16;
+      break;
+    case 1:
+      gate.type = 7;
+      gate.base = SEL_CS16;
+      break;
+    case 2:
+      gate.type = 3;
+      gate.base = SEL_TGATE16;
+      break;
+    case 3:
+      gate.type = 14;
+      gate.base = SEL_CS32;
+      break;
+    case 4:
+      gate.type = 15;
+      gate.base = SEL_CS32;
+      break;
+    case 6:
+      gate.type = 11;
+      gate.base = SEL_TGATE32;
+      break;
+    }
+    gate.limit = guest_mem + ADDR_VAR_USER_CODE2;
+    gate.present = 1;
+    gate.dpl = 0;
+    gate.s = 0;
+    gate.g = 0;
+    gate.db = 0;
+    gate.l = 0;
+    gate.avl = 0;
+    fill_segment_descriptor(idt, idt, &gate);
+  }
+}
+
+static void setup_64bit_idt(struct kvm_sregs* sregs, char* host_mem,
+                            uintptr_t guest_mem)
+{
+  sregs->idt.base = guest_mem + ADDR_VAR_IDT;
+  sregs->idt.limit = 0x1ff;
+  uint64_t* idt = (uint64_t*)(host_mem + sregs->idt.base);
+  int i;
+  for (i = 0; i < 32; i++) {
+    struct kvm_segment gate;
+    gate.selector = (i * 2) << 3;
+    gate.type = (i & 1) ? 14 : 15;
+    gate.base = SEL_CS64;
+    gate.limit = guest_mem + ADDR_VAR_USER_CODE2;
+    gate.present = 1;
+    gate.dpl = 0;
+    gate.s = 0;
+    gate.g = 0;
+    gate.db = 0;
+    gate.l = 0;
+    gate.avl = 0;
+    fill_segment_descriptor_dword(idt, idt, &gate);
+  }
+}
+
+struct kvm_text {
+  uintptr_t typ;
+  const void* text;
+  uintptr_t size;
+};
+
+struct kvm_opt {
+  uint64_t typ;
+  uint64_t val;
+};
+
+#define KVM_SETUP_PAGING (1 << 0)
+#define KVM_SETUP_PAE (1 << 1)
+#define KVM_SETUP_PROTECTED (1 << 2)
+#define KVM_SETUP_CPL3 (1 << 3)
+#define KVM_SETUP_VIRT86 (1 << 4)
+#define KVM_SETUP_SMM (1 << 5)
+#define KVM_SETUP_VM (1 << 6)
+static long syz_kvm_setup_cpu(volatile long a0, volatile long a1,
+                              volatile long a2, volatile long a3,
+                              volatile long a4, volatile long a5,
+                              volatile long a6, volatile long a7)
+{
+  const int vmfd = a0;
+  const int cpufd = a1;
+  char* const host_mem = (char*)a2;
+  const struct kvm_text* const text_array_ptr = (struct kvm_text*)a3;
+  const uintptr_t text_count = a4;
+  const uintptr_t flags = a5;
+  const struct kvm_opt* const opt_array_ptr = (struct kvm_opt*)a6;
+  uintptr_t opt_count = a7;
+  const uintptr_t page_size = 4 << 10;
+  const uintptr_t ioapic_page = 10;
+  const uintptr_t guest_mem_size = 24 * page_size;
+  const uintptr_t guest_mem = 0;
+  (void)text_count;
+  int text_type = 0;
+  const void* text = 0;
+  uintptr_t text_size = 0;
+  text_type = text_array_ptr[0].typ;
+  text = text_array_ptr[0].text;
+  text_size = text_array_ptr[0].size;
+  uintptr_t i;
+  for (i = 0; i < guest_mem_size / page_size; i++) {
+    struct kvm_userspace_memory_region memreg;
+    memreg.slot = i;
+    memreg.flags = 0;
+    memreg.guest_phys_addr = guest_mem + i * page_size;
+    if (i == ioapic_page)
+      memreg.guest_phys_addr = 0xfec00000;
+    memreg.memory_size = page_size;
+    memreg.userspace_addr = (uintptr_t)host_mem + i * page_size;
+    ioctl(vmfd, KVM_SET_USER_MEMORY_REGION, &memreg);
+  }
+  struct kvm_userspace_memory_region memreg;
+  memreg.slot = 1 + (1 << 16);
+  memreg.flags = 0;
+  memreg.guest_phys_addr = 0x30000;
+  memreg.memory_size = 64 << 10;
+  memreg.userspace_addr = (uintptr_t)host_mem;
+  ioctl(vmfd, KVM_SET_USER_MEMORY_REGION, &memreg);
+  struct kvm_sregs sregs;
+  if (ioctl(cpufd, KVM_GET_SREGS, &sregs))
+    return -1;
+  struct kvm_regs regs;
+  memset(&regs, 0, sizeof(regs));
+  regs.rip = guest_mem + ADDR_TEXT;
+  regs.rsp = ADDR_STACK0;
+  sregs.gdt.base = guest_mem + ADDR_GDT;
+  sregs.gdt.limit = 256 * sizeof(uint64_t) - 1;
+  uint64_t* gdt = (uint64_t*)(host_mem + sregs.gdt.base);
+  struct kvm_segment seg_ldt;
+  seg_ldt.selector = SEL_LDT;
+  seg_ldt.type = 2;
+  seg_ldt.base = guest_mem + ADDR_LDT;
+  seg_ldt.limit = 256 * sizeof(uint64_t) - 1;
+  seg_ldt.present = 1;
+  seg_ldt.dpl = 0;
+  seg_ldt.s = 0;
+  seg_ldt.g = 0;
+  seg_ldt.db = 1;
+  seg_ldt.l = 0;
+  sregs.ldt = seg_ldt;
+  uint64_t* ldt = (uint64_t*)(host_mem + sregs.ldt.base);
+  struct kvm_segment seg_cs16;
+  seg_cs16.selector = SEL_CS16;
+  seg_cs16.type = 11;
+  seg_cs16.base = 0;
+  seg_cs16.limit = 0xfffff;
+  seg_cs16.present = 1;
+  seg_cs16.dpl = 0;
+  seg_cs16.s = 1;
+  seg_cs16.g = 0;
+  seg_cs16.db = 0;
+  seg_cs16.l = 0;
+  struct kvm_segment seg_ds16 = seg_cs16;
+  seg_ds16.selector = SEL_DS16;
+  seg_ds16.type = 3;
+  struct kvm_segment seg_cs16_cpl3 = seg_cs16;
+  seg_cs16_cpl3.selector = SEL_CS16_CPL3;
+  seg_cs16_cpl3.dpl = 3;
+  struct kvm_segment seg_ds16_cpl3 = seg_ds16;
+  seg_ds16_cpl3.selector = SEL_DS16_CPL3;
+  seg_ds16_cpl3.dpl = 3;
+  struct kvm_segment seg_cs32 = seg_cs16;
+  seg_cs32.selector = SEL_CS32;
+  seg_cs32.db = 1;
+  struct kvm_segment seg_ds32 = seg_ds16;
+  seg_ds32.selector = SEL_DS32;
+  seg_ds32.db = 1;
+  struct kvm_segment seg_cs32_cpl3 = seg_cs32;
+  seg_cs32_cpl3.selector = SEL_CS32_CPL3;
+  seg_cs32_cpl3.dpl = 3;
+  struct kvm_segment seg_ds32_cpl3 = seg_ds32;
+  seg_ds32_cpl3.selector = SEL_DS32_CPL3;
+  seg_ds32_cpl3.dpl = 3;
+  struct kvm_segment seg_cs64 = seg_cs16;
+  seg_cs64.selector = SEL_CS64;
+  seg_cs64.l = 1;
+  struct kvm_segment seg_ds64 = seg_ds32;
+  seg_ds64.selector = SEL_DS64;
+  struct kvm_segment seg_cs64_cpl3 = seg_cs64;
+  seg_cs64_cpl3.selector = SEL_CS64_CPL3;
+  seg_cs64_cpl3.dpl = 3;
+  struct kvm_segment seg_ds64_cpl3 = seg_ds64;
+  seg_ds64_cpl3.selector = SEL_DS64_CPL3;
+  seg_ds64_cpl3.dpl = 3;
+  struct kvm_segment seg_tss32;
+  seg_tss32.selector = SEL_TSS32;
+  seg_tss32.type = 9;
+  seg_tss32.base = ADDR_VAR_TSS32;
+  seg_tss32.limit = 0x1ff;
+  seg_tss32.present = 1;
+  seg_tss32.dpl = 0;
+  seg_tss32.s = 0;
+  seg_tss32.g = 0;
+  seg_tss32.db = 0;
+  seg_tss32.l = 0;
+  struct kvm_segment seg_tss32_2 = seg_tss32;
+  seg_tss32_2.selector = SEL_TSS32_2;
+  seg_tss32_2.base = ADDR_VAR_TSS32_2;
+  struct kvm_segment seg_tss32_cpl3 = seg_tss32;
+  seg_tss32_cpl3.selector = SEL_TSS32_CPL3;
+  seg_tss32_cpl3.base = ADDR_VAR_TSS32_CPL3;
+  struct kvm_segment seg_tss32_vm86 = seg_tss32;
+  seg_tss32_vm86.selector = SEL_TSS32_VM86;
+  seg_tss32_vm86.base = ADDR_VAR_TSS32_VM86;
+  struct kvm_segment seg_tss16 = seg_tss32;
+  seg_tss16.selector = SEL_TSS16;
+  seg_tss16.base = ADDR_VAR_TSS16;
+  seg_tss16.limit = 0xff;
+  seg_tss16.type = 1;
+  struct kvm_segment seg_tss16_2 = seg_tss16;
+  seg_tss16_2.selector = SEL_TSS16_2;
+  seg_tss16_2.base = ADDR_VAR_TSS16_2;
+  seg_tss16_2.dpl = 0;
+  struct kvm_segment seg_tss16_cpl3 = seg_tss16;
+  seg_tss16_cpl3.selector = SEL_TSS16_CPL3;
+  seg_tss16_cpl3.base = ADDR_VAR_TSS16_CPL3;
+  seg_tss16_cpl3.dpl = 3;
+  struct kvm_segment seg_tss64 = seg_tss32;
+  seg_tss64.selector = SEL_TSS64;
+  seg_tss64.base = ADDR_VAR_TSS64;
+  seg_tss64.limit = 0x1ff;
+  struct kvm_segment seg_tss64_cpl3 = seg_tss64;
+  seg_tss64_cpl3.selector = SEL_TSS64_CPL3;
+  seg_tss64_cpl3.base = ADDR_VAR_TSS64_CPL3;
+  seg_tss64_cpl3.dpl = 3;
+  struct kvm_segment seg_cgate16;
+  seg_cgate16.selector = SEL_CGATE16;
+  seg_cgate16.type = 4;
+  seg_cgate16.base = SEL_CS16 | (2 << 16);
+  seg_cgate16.limit = ADDR_VAR_USER_CODE2;
+  seg_cgate16.present = 1;
+  seg_cgate16.dpl = 0;
+  seg_cgate16.s = 0;
+  seg_cgate16.g = 0;
+  seg_cgate16.db = 0;
+  seg_cgate16.l = 0;
+  seg_cgate16.avl = 0;
+  struct kvm_segment seg_tgate16 = seg_cgate16;
+  seg_tgate16.selector = SEL_TGATE16;
+  seg_tgate16.type = 3;
+  seg_cgate16.base = SEL_TSS16_2;
+  seg_tgate16.limit = 0;
+  struct kvm_segment seg_cgate32 = seg_cgate16;
+  seg_cgate32.selector = SEL_CGATE32;
+  seg_cgate32.type = 12;
+  seg_cgate32.base = SEL_CS32 | (2 << 16);
+  struct kvm_segment seg_tgate32 = seg_cgate32;
+  seg_tgate32.selector = SEL_TGATE32;
+  seg_tgate32.type = 11;
+  seg_tgate32.base = SEL_TSS32_2;
+  seg_tgate32.limit = 0;
+  struct kvm_segment seg_cgate64 = seg_cgate16;
+  seg_cgate64.selector = SEL_CGATE64;
+  seg_cgate64.type = 12;
+  seg_cgate64.base = SEL_CS64;
+  int kvmfd = open("/dev/kvm", O_RDWR);
+  char buf[sizeof(struct kvm_cpuid2) + 128 * sizeof(struct kvm_cpuid_entry2)];
+  memset(buf, 0, sizeof(buf));
+  struct kvm_cpuid2* cpuid = (struct kvm_cpuid2*)buf;
+  cpuid->nent = 128;
+  ioctl(kvmfd, KVM_GET_SUPPORTED_CPUID, cpuid);
+  ioctl(cpufd, KVM_SET_CPUID2, cpuid);
+  close(kvmfd);
+  const char* text_prefix = 0;
+  int text_prefix_size = 0;
+  char* host_text = host_mem + ADDR_TEXT;
+  if (text_type == 8) {
+    if (flags & KVM_SETUP_SMM) {
+      if (flags & KVM_SETUP_PROTECTED) {
+        sregs.cs = seg_cs16;
+        sregs.ds = sregs.es = sregs.fs = sregs.gs = sregs.ss = seg_ds16;
+        sregs.cr0 |= CR0_PE;
+      } else {
+        sregs.cs.selector = 0;
+        sregs.cs.base = 0;
+      }
+
+      *(host_mem + ADDR_TEXT) = 0xf4;
+      host_text = host_mem + 0x8000;
+      ioctl(cpufd, KVM_SMI, 0);
+    } else if (flags & KVM_SETUP_VIRT86) {
+      sregs.cs = seg_cs32;
+      sregs.ds = sregs.es = sregs.fs = sregs.gs = sregs.ss = seg_ds32;
+      sregs.cr0 |= CR0_PE;
+      sregs.efer |= EFER_SCE;
+      setup_syscall_msrs(cpufd, SEL_CS32, SEL_CS32_CPL3);
+      setup_32bit_idt(&sregs, host_mem, guest_mem);
+      if (flags & KVM_SETUP_PAGING) {
+        uint64_t pd_addr = guest_mem + ADDR_PD;
+        uint64_t* pd = (uint64_t*)(host_mem + ADDR_PD);
+        pd[0] = PDE32_PRESENT | PDE32_RW | PDE32_USER | PDE32_PS;
+        sregs.cr3 = pd_addr;
+        sregs.cr4 |= CR4_PSE;
+        text_prefix = kvm_asm32_paged_vm86;
+        text_prefix_size = sizeof(kvm_asm32_paged_vm86) - 1;
+      } else {
+        text_prefix = kvm_asm32_vm86;
+        text_prefix_size = sizeof(kvm_asm32_vm86) - 1;
+      }
+    } else {
+      sregs.cs.selector = 0;
+      sregs.cs.base = 0;
+    }
+  } else if (text_type == 16) {
+    if (flags & KVM_SETUP_CPL3) {
+      sregs.cs = seg_cs16;
+      sregs.ds = sregs.es = sregs.fs = sregs.gs = sregs.ss = seg_ds16;
+      text_prefix = kvm_asm16_cpl3;
+      text_prefix_size = sizeof(kvm_asm16_cpl3) - 1;
+    } else {
+      sregs.cr0 |= CR0_PE;
+      sregs.cs = seg_cs16;
+      sregs.ds = sregs.es = sregs.fs = sregs.gs = sregs.ss = seg_ds16;
+    }
+  } else if (text_type == 32) {
+    sregs.cr0 |= CR0_PE;
+    sregs.efer |= EFER_SCE;
+    setup_syscall_msrs(cpufd, SEL_CS32, SEL_CS32_CPL3);
+    setup_32bit_idt(&sregs, host_mem, guest_mem);
+    if (flags & KVM_SETUP_SMM) {
+      sregs.cs = seg_cs32;
+      sregs.ds = sregs.es = sregs.fs = sregs.gs = sregs.ss = seg_ds32;
+
+      *(host_mem + ADDR_TEXT) = 0xf4;
+      host_text = host_mem + 0x8000;
+      ioctl(cpufd, KVM_SMI, 0);
+    } else if (flags & KVM_SETUP_PAGING) {
+      sregs.cs = seg_cs32;
+      sregs.ds = sregs.es = sregs.fs = sregs.gs = sregs.ss = seg_ds32;
+      uint64_t pd_addr = guest_mem + ADDR_PD;
+      uint64_t* pd = (uint64_t*)(host_mem + ADDR_PD);
+      pd[0] = PDE32_PRESENT | PDE32_RW | PDE32_USER | PDE32_PS;
+      sregs.cr3 = pd_addr;
+      sregs.cr4 |= CR4_PSE;
+      text_prefix = kvm_asm32_paged;
+      text_prefix_size = sizeof(kvm_asm32_paged) - 1;
+    } else if (flags & KVM_SETUP_CPL3) {
+      sregs.cs = seg_cs32_cpl3;
+      sregs.ds = sregs.es = sregs.fs = sregs.gs = sregs.ss = seg_ds32_cpl3;
+    } else {
+      sregs.cs = seg_cs32;
+      sregs.ds = sregs.es = sregs.fs = sregs.gs = sregs.ss = seg_ds32;
+    }
+  } else {
+    sregs.efer |= EFER_LME | EFER_SCE;
+    sregs.cr0 |= CR0_PE;
+    setup_syscall_msrs(cpufd, SEL_CS64, SEL_CS64_CPL3);
+    setup_64bit_idt(&sregs, host_mem, guest_mem);
+    sregs.cs = seg_cs32;
+    sregs.ds = sregs.es = sregs.fs = sregs.gs = sregs.ss = seg_ds32;
+    uint64_t pml4_addr = guest_mem + ADDR_PML4;
+    uint64_t* pml4 = (uint64_t*)(host_mem + ADDR_PML4);
+    uint64_t pdpt_addr = guest_mem + ADDR_PDP;
+    uint64_t* pdpt = (uint64_t*)(host_mem + ADDR_PDP);
+    uint64_t pd_addr = guest_mem + ADDR_PD;
+    uint64_t* pd = (uint64_t*)(host_mem + ADDR_PD);
+    pml4[0] = PDE64_PRESENT | PDE64_RW | PDE64_USER | pdpt_addr;
+    pdpt[0] = PDE64_PRESENT | PDE64_RW | PDE64_USER | pd_addr;
+    pd[0] = PDE64_PRESENT | PDE64_RW | PDE64_USER | PDE64_PS;
+    sregs.cr3 = pml4_addr;
+    sregs.cr4 |= CR4_PAE;
+    if (flags & KVM_SETUP_VM) {
+      sregs.cr0 |= CR0_NE;
+
+      *((uint64_t*)(host_mem + ADDR_VAR_VMXON_PTR)) = ADDR_VAR_VMXON;
+      *((uint64_t*)(host_mem + ADDR_VAR_VMCS_PTR)) = ADDR_VAR_VMCS;
+      memcpy(host_mem + ADDR_VAR_VMEXIT_CODE, kvm_asm64_vm_exit,
+             sizeof(kvm_asm64_vm_exit) - 1);
+      *((uint64_t*)(host_mem + ADDR_VAR_VMEXIT_PTR)) = ADDR_VAR_VMEXIT_CODE;
+      text_prefix = kvm_asm64_init_vm;
+      text_prefix_size = sizeof(kvm_asm64_init_vm) - 1;
+    } else if (flags & KVM_SETUP_CPL3) {
+      text_prefix = kvm_asm64_cpl3;
+      text_prefix_size = sizeof(kvm_asm64_cpl3) - 1;
+    } else {
+      text_prefix = kvm_asm64_enable_long;
+      text_prefix_size = sizeof(kvm_asm64_enable_long) - 1;
+    }
+  }
+  struct tss16 tss16;
+  memset(&tss16, 0, sizeof(tss16));
+  tss16.ss0 = tss16.ss1 = tss16.ss2 = SEL_DS16;
+  tss16.sp0 = tss16.sp1 = tss16.sp2 = ADDR_STACK0;
+  tss16.ip = ADDR_VAR_USER_CODE2;
+  tss16.flags = (1 << 1);
+  tss16.cs = SEL_CS16;
+  tss16.es = tss16.ds = tss16.ss = SEL_DS16;
+  tss16.ldt = SEL_LDT;
+  struct tss16* tss16_addr = (struct tss16*)(host_mem + seg_tss16_2.base);
+  memcpy(tss16_addr, &tss16, sizeof(tss16));
+  memset(&tss16, 0, sizeof(tss16));
+  tss16.ss0 = tss16.ss1 = tss16.ss2 = SEL_DS16;
+  tss16.sp0 = tss16.sp1 = tss16.sp2 = ADDR_STACK0;
+  tss16.ip = ADDR_VAR_USER_CODE2;
+  tss16.flags = (1 << 1);
+  tss16.cs = SEL_CS16_CPL3;
+  tss16.es = tss16.ds = tss16.ss = SEL_DS16_CPL3;
+  tss16.ldt = SEL_LDT;
+  struct tss16* tss16_cpl3_addr =
+      (struct tss16*)(host_mem + seg_tss16_cpl3.base);
+  memcpy(tss16_cpl3_addr, &tss16, sizeof(tss16));
+  struct tss32 tss32;
+  memset(&tss32, 0, sizeof(tss32));
+  tss32.ss0 = tss32.ss1 = tss32.ss2 = SEL_DS32;
+  tss32.sp0 = tss32.sp1 = tss32.sp2 = ADDR_STACK0;
+  tss32.ip = ADDR_VAR_USER_CODE;
+  tss32.flags = (1 << 1) | (1 << 17);
+  tss32.ldt = SEL_LDT;
+  tss32.cr3 = sregs.cr3;
+  tss32.io_bitmap = offsetof(struct tss32, io_bitmap);
+  struct tss32* tss32_addr = (struct tss32*)(host_mem + seg_tss32_vm86.base);
+  memcpy(tss32_addr, &tss32, sizeof(tss32));
+  memset(&tss32, 0, sizeof(tss32));
+  tss32.ss0 = tss32.ss1 = tss32.ss2 = SEL_DS32;
+  tss32.sp0 = tss32.sp1 = tss32.sp2 = ADDR_STACK0;
+  tss32.ip = ADDR_VAR_USER_CODE;
+  tss32.flags = (1 << 1);
+  tss32.cr3 = sregs.cr3;
+  tss32.es = tss32.ds = tss32.ss = tss32.gs = tss32.fs = SEL_DS32;
+  tss32.cs = SEL_CS32;
+  tss32.ldt = SEL_LDT;
+  tss32.cr3 = sregs.cr3;
+  tss32.io_bitmap = offsetof(struct tss32, io_bitmap);
+  struct tss32* tss32_cpl3_addr = (struct tss32*)(host_mem + seg_tss32_2.base);
+  memcpy(tss32_cpl3_addr, &tss32, sizeof(tss32));
+  struct tss64 tss64;
+  memset(&tss64, 0, sizeof(tss64));
+  tss64.rsp[0] = ADDR_STACK0;
+  tss64.rsp[1] = ADDR_STACK0;
+  tss64.rsp[2] = ADDR_STACK0;
+  tss64.io_bitmap = offsetof(struct tss64, io_bitmap);
+  struct tss64* tss64_addr = (struct tss64*)(host_mem + seg_tss64.base);
+  memcpy(tss64_addr, &tss64, sizeof(tss64));
+  memset(&tss64, 0, sizeof(tss64));
+  tss64.rsp[0] = ADDR_STACK0;
+  tss64.rsp[1] = ADDR_STACK0;
+  tss64.rsp[2] = ADDR_STACK0;
+  tss64.io_bitmap = offsetof(struct tss64, io_bitmap);
+  struct tss64* tss64_cpl3_addr =
+      (struct tss64*)(host_mem + seg_tss64_cpl3.base);
+  memcpy(tss64_cpl3_addr, &tss64, sizeof(tss64));
+  if (text_size > 1000)
+    text_size = 1000;
+  if (text_prefix) {
+    memcpy(host_text, text_prefix, text_prefix_size);
+    void* patch = 0;
+    patch = memmem(host_text, text_prefix_size, "\xde\xc0\xad\x0b", 4);
+    if (patch)
+      *((uint32_t*)patch) =
+          guest_mem + ADDR_TEXT + ((char*)patch - host_text) + 6;
+    uint16_t magic = PREFIX_SIZE;
+    patch = 0;
+    patch = memmem(host_text, text_prefix_size, &magic, sizeof(magic));
+    if (patch)
+      *((uint16_t*)patch) = guest_mem + ADDR_TEXT + text_prefix_size;
+  }
+  memcpy((void*)(host_text + text_prefix_size), text, text_size);
+  *(host_text + text_prefix_size + text_size) = 0xf4;
+
+  memcpy(host_mem + ADDR_VAR_USER_CODE, text, text_size);
+  *(host_mem + ADDR_VAR_USER_CODE + text_size) = 0xf4;
+
+  *(host_mem + ADDR_VAR_HLT) = 0xf4;
+  memcpy(host_mem + ADDR_VAR_SYSRET, "\x0f\x07\xf4", 3);
+  memcpy(host_mem + ADDR_VAR_SYSEXIT, "\x0f\x35\xf4", 3);
+
+  *(uint64_t*)(host_mem + ADDR_VAR_VMWRITE_FLD) = 0;
+  *(uint64_t*)(host_mem + ADDR_VAR_VMWRITE_VAL) = 0;
+  if (opt_count > 2)
+    opt_count = 2;
+  for (i = 0; i < opt_count; i++) {
+    uint64_t typ = 0;
+    uint64_t val = 0;
+    typ = opt_array_ptr[i].typ;
+    val = opt_array_ptr[i].val;
+    switch (typ % 9) {
+    case 0:
+      sregs.cr0 ^= val & (CR0_MP | CR0_EM | CR0_ET | CR0_NE | CR0_WP | CR0_AM |
+                          CR0_NW | CR0_CD);
+      break;
+    case 1:
+      sregs.cr4 ^=
+          val & (CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_MCE | CR4_PGE |
+                 CR4_PCE | CR4_OSFXSR | CR4_OSXMMEXCPT | CR4_UMIP | CR4_VMXE |
+                 CR4_SMXE | CR4_FSGSBASE | CR4_PCIDE | CR4_OSXSAVE | CR4_SMEP |
+                 CR4_SMAP | CR4_PKE);
+      break;
+    case 2:
+      sregs.efer ^= val & (EFER_SCE | EFER_NXE | EFER_SVME | EFER_LMSLE |
+                           EFER_FFXSR | EFER_TCE);
+      break;
+    case 3:
+      val &=
+          ((1 << 8) | (1 << 9) | (1 << 10) | (1 << 12) | (1 << 13) | (1 << 14) |
+           (1 << 15) | (1 << 18) | (1 << 19) | (1 << 20) | (1 << 21));
+      regs.rflags ^= val;
+      tss16_addr->flags ^= val;
+      tss16_cpl3_addr->flags ^= val;
+      tss32_addr->flags ^= val;
+      tss32_cpl3_addr->flags ^= val;
+      break;
+    case 4:
+      seg_cs16.type = val & 0xf;
+      seg_cs32.type = val & 0xf;
+      seg_cs64.type = val & 0xf;
+      break;
+    case 5:
+      seg_cs16_cpl3.type = val & 0xf;
+      seg_cs32_cpl3.type = val & 0xf;
+      seg_cs64_cpl3.type = val & 0xf;
+      break;
+    case 6:
+      seg_ds16.type = val & 0xf;
+      seg_ds32.type = val & 0xf;
+      seg_ds64.type = val & 0xf;
+      break;
+    case 7:
+      seg_ds16_cpl3.type = val & 0xf;
+      seg_ds32_cpl3.type = val & 0xf;
+      seg_ds64_cpl3.type = val & 0xf;
+      break;
+    case 8:
+      *(uint64_t*)(host_mem + ADDR_VAR_VMWRITE_FLD) = (val & 0xffff);
+      *(uint64_t*)(host_mem + ADDR_VAR_VMWRITE_VAL) = (val >> 16);
+      break;
+    default:
+      exit(1);
+    }
+  }
+  regs.rflags |= 2;
+  fill_segment_descriptor(gdt, ldt, &seg_ldt);
+  fill_segment_descriptor(gdt, ldt, &seg_cs16);
+  fill_segment_descriptor(gdt, ldt, &seg_ds16);
+  fill_segment_descriptor(gdt, ldt, &seg_cs16_cpl3);
+  fill_segment_descriptor(gdt, ldt, &seg_ds16_cpl3);
+  fill_segment_descriptor(gdt, ldt, &seg_cs32);
+  fill_segment_descriptor(gdt, ldt, &seg_ds32);
+  fill_segment_descriptor(gdt, ldt, &seg_cs32_cpl3);
+  fill_segment_descriptor(gdt, ldt, &seg_ds32_cpl3);
+  fill_segment_descriptor(gdt, ldt, &seg_cs64);
+  fill_segment_descriptor(gdt, ldt, &seg_ds64);
+  fill_segment_descriptor(gdt, ldt, &seg_cs64_cpl3);
+  fill_segment_descriptor(gdt, ldt, &seg_ds64_cpl3);
+  fill_segment_descriptor(gdt, ldt, &seg_tss32);
+  fill_segment_descriptor(gdt, ldt, &seg_tss32_2);
+  fill_segment_descriptor(gdt, ldt, &seg_tss32_cpl3);
+  fill_segment_descriptor(gdt, ldt, &seg_tss32_vm86);
+  fill_segment_descriptor(gdt, ldt, &seg_tss16);
+  fill_segment_descriptor(gdt, ldt, &seg_tss16_2);
+  fill_segment_descriptor(gdt, ldt, &seg_tss16_cpl3);
+  fill_segment_descriptor_dword(gdt, ldt, &seg_tss64);
+  fill_segment_descriptor_dword(gdt, ldt, &seg_tss64_cpl3);
+  fill_segment_descriptor(gdt, ldt, &seg_cgate16);
+  fill_segment_descriptor(gdt, ldt, &seg_tgate16);
+  fill_segment_descriptor(gdt, ldt, &seg_cgate32);
+  fill_segment_descriptor(gdt, ldt, &seg_tgate32);
+  fill_segment_descriptor_dword(gdt, ldt, &seg_cgate64);
+  if (ioctl(cpufd, KVM_SET_SREGS, &sregs))
+    return -1;
+  if (ioctl(cpufd, KVM_SET_REGS, &regs))
+    return -1;
+  return 0;
+}
+
+static void kill_and_wait(int pid, int* status)
+{
+  kill(-pid, SIGKILL);
+  kill(pid, SIGKILL);