// https://syzkaller.appspot.com/bug?id=32f49c56127fb8eb57e0f02a9b8ef6114c28a2e9
// autogenerated by syzkaller (http://github.com/google/syzkaller)

#define _GNU_SOURCE
#include <endian.h>
#include <linux/futex.h>
#include <pthread.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/syscall.h>
#include <unistd.h>

#define BITMASK_LEN(type, bf_len) (type)((1ull << (bf_len)) - 1)

#define BITMASK_LEN_OFF(type, bf_off, bf_len)                                  \
  (type)(BITMASK_LEN(type, (bf_len)) << (bf_off))

#define STORE_BY_BITMASK(type, addr, val, bf_off, bf_len)                      \
  if ((bf_off) == 0 && (bf_len) == 0) {                                        \
    *(type*)(addr) = (type)(val);                                              \
  } else {                                                                     \
    type new_val = *(type*)(addr);                                             \
    new_val &= ~BITMASK_LEN_OFF(type, (bf_off), (bf_len));                     \
    new_val |= ((type)(val)&BITMASK_LEN(type, (bf_len))) << (bf_off);          \
    *(type*)(addr) = new_val;                                                  \
  }

struct csum_inet {
  uint32_t acc;
};

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

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

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

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

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

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

struct thread_t {
  int created, running, call;
  pthread_t th;
};

static struct thread_t threads[16];
static void execute_call(int call);
static int running;

static void* thr(void* arg)
{
  struct thread_t* th = (struct thread_t*)arg;
  for (;;) {
    while (!__atomic_load_n(&th->running, __ATOMIC_ACQUIRE))
      syscall(SYS_futex, &th->running, FUTEX_WAIT, 0, 0);
    execute_call(th->call);
    __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
    __atomic_store_n(&th->running, 0, __ATOMIC_RELEASE);
    syscall(SYS_futex, &th->running, FUTEX_WAKE);
  }
  return 0;
}

static void execute(int num_calls)
{
  int call, thread;
  running = 0;
  for (call = 0; call < num_calls; call++) {
    for (thread = 0; thread < sizeof(threads) / sizeof(threads[0]); thread++) {
      struct thread_t* th = &threads[thread];
      if (!th->created) {
        th->created = 1;
        pthread_attr_t attr;
        pthread_attr_init(&attr);
        pthread_attr_setstacksize(&attr, 128 << 10);
        pthread_create(&th->th, &attr, thr, th);
      }
      if (!__atomic_load_n(&th->running, __ATOMIC_ACQUIRE)) {
        th->call = call;
        __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
        __atomic_store_n(&th->running, 1, __ATOMIC_RELEASE);
        syscall(SYS_futex, &th->running, FUTEX_WAKE);
        struct timespec ts;
        ts.tv_sec = 0;
        ts.tv_nsec = 20 * 1000 * 1000;
        syscall(SYS_futex, &th->running, FUTEX_WAIT, 1, &ts);
        if (running)
          usleep((call == num_calls - 1) ? 10000 : 1000);
        break;
      }
    }
  }
}

long r[2];
void execute_call(int call)
{
  switch (call) {
  case 0:
    syscall(__NR_mmap, 0x20000000, 0xfff000, 3, 0x32, -1, 0);
    break;
  case 1:
    r[0] = syscall(__NR_socket, 2, 1, 0);
    break;
  case 2:
    memcpy((void*)0x20472000, "tls", 4);
    syscall(__NR_setsockopt, r[0], 6, 0x1f, 0x20472000, 4);
    break;
  case 3:
    *(uint16_t*)0x20d10ff0 = 2;
    *(uint16_t*)0x20d10ff2 = htobe16(0x4e20);
    *(uint32_t*)0x20d10ff4 = htobe32(0);
    *(uint8_t*)0x20d10ff8 = 0;
    *(uint8_t*)0x20d10ff9 = 0;
    *(uint8_t*)0x20d10ffa = 0;
    *(uint8_t*)0x20d10ffb = 0;
    *(uint8_t*)0x20d10ffc = 0;
    *(uint8_t*)0x20d10ffd = 0;
    *(uint8_t*)0x20d10ffe = 0;
    *(uint8_t*)0x20d10fff = 0;
    syscall(__NR_bind, r[0], 0x20d10ff0, 0x10);
    break;
  case 4:
    syscall(__NR_listen, r[0], 0);
    break;
  case 5:
    *(uint32_t*)0x20b9fffc = 0x60;
    syscall(__NR_accept4, r[0], 0x20c52fa0, 0x20b9fffc, 0);
    break;
  case 6:
    r[1] = syscall(__NR_socket, 2, 1, 0);
    break;
  case 7:
    *(uint16_t*)0x20ba6000 = 2;
    *(uint16_t*)0x20ba6002 = htobe16(0x4e20);
    *(uint32_t*)0x20ba6004 = htobe32(0x7f000001);
    *(uint8_t*)0x20ba6008 = 0;
    *(uint8_t*)0x20ba6009 = 0;
    *(uint8_t*)0x20ba600a = 0;
    *(uint8_t*)0x20ba600b = 0;
    *(uint8_t*)0x20ba600c = 0;
    *(uint8_t*)0x20ba600d = 0;
    *(uint8_t*)0x20ba600e = 0;
    *(uint8_t*)0x20ba600f = 0;
    syscall(__NR_connect, r[1], 0x20ba6000, 0x10);
    break;
  case 8:
    *(uint8_t*)0x20791fd1 = 0xaa;
    *(uint8_t*)0x20791fd2 = 0xaa;
    *(uint8_t*)0x20791fd3 = 0xaa;
    *(uint8_t*)0x20791fd4 = 0xaa;
    *(uint8_t*)0x20791fd5 = 0;
    *(uint8_t*)0x20791fd6 = 0xaa;
    *(uint8_t*)0x20791fd7 = 0xaa;
    *(uint8_t*)0x20791fd8 = 0xaa;
    *(uint8_t*)0x20791fd9 = 0xaa;
    *(uint8_t*)0x20791fda = 0xaa;
    *(uint8_t*)0x20791fdb = 0;
    *(uint8_t*)0x20791fdc = 0;
    *(uint16_t*)0x20791fdd = htobe16(0x800);
    STORE_BY_BITMASK(uint8_t, 0x20791fdf, 5, 0, 4);
    STORE_BY_BITMASK(uint8_t, 0x20791fdf, 4, 4, 4);
    STORE_BY_BITMASK(uint8_t, 0x20791fe0, 0, 0, 2);
    STORE_BY_BITMASK(uint8_t, 0x20791fe0, 0, 2, 6);
    *(uint16_t*)0x20791fe1 = htobe16(0x14);
    *(uint16_t*)0x20791fe3 = 0;
    *(uint16_t*)0x20791fe5 = htobe16(0);
    *(uint8_t*)0x20791fe7 = 0;
    *(uint8_t*)0x20791fe8 = 2;
    *(uint16_t*)0x20791fe9 = 0;
    *(uint32_t*)0x20791feb = htobe32(0);
    *(uint32_t*)0x20791fef = htobe32(-1);
    *(uint8_t*)0x20791ff3 = 0;
    *(uint8_t*)0x20791ff4 = 0;
    *(uint16_t*)0x20791ff5 = 0;
    *(uint8_t*)0x20791ff7 = 0xac;
    *(uint8_t*)0x20791ff8 = 0x14;
    *(uint8_t*)0x20791ff9 = 0;
    *(uint8_t*)0x20791ffa = 0;
    *(uint32_t*)0x20ae9000 = 0;
    *(uint32_t*)0x20ae9004 = 1;
    *(uint32_t*)0x20ae9008 = 0x9df;
    struct csum_inet csum_1;
    csum_inet_init(&csum_1);
    csum_inet_update(&csum_1, (const uint8_t*)0x20791ff3, 8);
    *(uint16_t*)0x20791ff5 = csum_inet_digest(&csum_1);
    struct csum_inet csum_2;
    csum_inet_init(&csum_2);
    csum_inet_update(&csum_2, (const uint8_t*)0x20791fdf, 20);
    *(uint16_t*)0x20791fe9 = csum_inet_digest(&csum_2);
    break;
  }
}

void loop()
{
  memset(r, -1, sizeof(r));
  execute(9);
}

int main()
{
  loop();
  return 0;
}