xref: /freebsd/tools/test/stress2/misc/syzkaller61.sh (revision 7f658f99f7ed5d1d0e0802073bb22eb8a0a784fb)
15b42ac29SPeter Holm#!/bin/sh
25b42ac29SPeter Holm
35b42ac29SPeter Holm# Seen:
45b42ac29SPeter Holm# [root@mercat1 /usr/src/tools/test/stress2/misc]# pgrep syzkaller61 | xargs procstat -k
55b42ac29SPeter Holm#   PID    TID COMM                TDNAME              KSTACK
65b42ac29SPeter Holm#   13332 106396 syzkaller61         -                   mi_switch thread_suspend_check ast_suspend ast_handler ast doreti_ast
75b42ac29SPeter Holm#   13332 560662 syzkaller61         -                   mi_switch sleepq_switch sleepq_catch_signals sleepq_wait_sig _sleep umtxq_sleep do_wait __umtx_op_wait_uint_private sys__umtx_op amd64_syscall fast_syscall_common
85b42ac29SPeter Holm#   13332 560776 syzkaller61         -                   mi_switch thread_suspend_switch thread_single fork1 sys_rfork amd64_syscall fast_syscall_common
95b42ac29SPeter Holm#   13662 356440 syzkaller61         -                   mi_switch thread_suspend_check ast_suspend ast_handler ast doreti_ast
105b42ac29SPeter Holm#   13662 561098 syzkaller61         -                   mi_switch sleepq_switch sleepq_catch_signals sleepq_wait_sig _sleep umtxq_sleep do_wait __umtx_op_wait_uint_private sys__umtx_op amd64_syscall fast_syscall_common
115b42ac29SPeter Holm#   13662 561160 syzkaller61         -                   mi_switch thread_suspend_switch thread_single fork1 sys_rfork amd64_syscall fast_syscall_common
125b42ac29SPeter Holm#   [root@mercat1 /usr/src/tools/test/stress2/misc]#
135b42ac29SPeter Holm
145b42ac29SPeter Holm[ `uname -p` != "amd64" ] && exit 0
155b42ac29SPeter Holm
165b42ac29SPeter Holm. ../default.cfg
175b42ac29SPeter Holmcat > /tmp/syzkaller61.c <<EOF
185b42ac29SPeter Holm// https://syzkaller.appspot.com/bug?id=00d8ca63243899ffb67b15ec93aee4ffa2f06637
195b42ac29SPeter Holm// autogenerated by syzkaller (https://github.com/google/syzkaller)
205b42ac29SPeter Holm// Reported-by: syzbot+647212368c3f32c6f13f@syzkaller.appspotmail.com
215b42ac29SPeter Holm
225b42ac29SPeter Holm#define _GNU_SOURCE
235b42ac29SPeter Holm
245b42ac29SPeter Holm#include <sys/types.h>
255b42ac29SPeter Holm
265b42ac29SPeter Holm#include <errno.h>
275b42ac29SPeter Holm#include <pthread.h>
285b42ac29SPeter Holm#include <pwd.h>
295b42ac29SPeter Holm#include <setjmp.h>
305b42ac29SPeter Holm#include <signal.h>
315b42ac29SPeter Holm#include <stdarg.h>
325b42ac29SPeter Holm#include <stdbool.h>
335b42ac29SPeter Holm#include <stdint.h>
345b42ac29SPeter Holm#include <stdio.h>
355b42ac29SPeter Holm#include <stdlib.h>
365b42ac29SPeter Holm#include <string.h>
375b42ac29SPeter Holm#include <sys/endian.h>
385b42ac29SPeter Holm#include <sys/syscall.h>
395b42ac29SPeter Holm#include <sys/wait.h>
405b42ac29SPeter Holm#include <time.h>
415b42ac29SPeter Holm#include <unistd.h>
425b42ac29SPeter Holm
435b42ac29SPeter Holmstatic __thread int clone_ongoing;
445b42ac29SPeter Holmstatic __thread int skip_segv;
455b42ac29SPeter Holmstatic __thread jmp_buf segv_env;
465b42ac29SPeter Holm
475b42ac29SPeter Holmstatic void segv_handler(int sig, siginfo_t* info, void* ctx __unused)
485b42ac29SPeter Holm{
495b42ac29SPeter Holm  if (__atomic_load_n(&clone_ongoing, __ATOMIC_RELAXED) != 0) {
505b42ac29SPeter Holm    exit(sig);
515b42ac29SPeter Holm  }
525b42ac29SPeter Holm  uintptr_t addr = (uintptr_t)info->si_addr;
535b42ac29SPeter Holm  const uintptr_t prog_start = 1 << 20;
545b42ac29SPeter Holm  const uintptr_t prog_end = 100 << 20;
555b42ac29SPeter Holm  int skip = __atomic_load_n(&skip_segv, __ATOMIC_RELAXED) != 0;
565b42ac29SPeter Holm  int valid = addr < prog_start || addr > prog_end;
575b42ac29SPeter Holm  if (sig == SIGBUS)
585b42ac29SPeter Holm    valid = 1;
595b42ac29SPeter Holm  if (skip && valid) {
605b42ac29SPeter Holm    _longjmp(segv_env, 1);
615b42ac29SPeter Holm  }
625b42ac29SPeter Holm  exit(sig);
635b42ac29SPeter Holm}
645b42ac29SPeter Holm
655b42ac29SPeter Holmstatic void install_segv_handler(void)
665b42ac29SPeter Holm{
675b42ac29SPeter Holm  struct sigaction sa;
685b42ac29SPeter Holm  memset(&sa, 0, sizeof(sa));
695b42ac29SPeter Holm  sa.sa_sigaction = segv_handler;
705b42ac29SPeter Holm  sa.sa_flags = SA_NODEFER | SA_SIGINFO;
715b42ac29SPeter Holm  sigaction(SIGSEGV, &sa, NULL);
725b42ac29SPeter Holm  sigaction(SIGBUS, &sa, NULL);
735b42ac29SPeter Holm}
745b42ac29SPeter Holm
755b42ac29SPeter Holm#define NONFAILING(...)                                                        \
765b42ac29SPeter Holm  ({                                                                           \
775b42ac29SPeter Holm    int ok = 1;                                                                \
785b42ac29SPeter Holm    __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST);                       \
795b42ac29SPeter Holm    if (_setjmp(segv_env) == 0) {                                              \
805b42ac29SPeter Holm      __VA_ARGS__;                                                             \
815b42ac29SPeter Holm    } else                                                                     \
825b42ac29SPeter Holm      ok = 0;                                                                  \
835b42ac29SPeter Holm    __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST);                       \
845b42ac29SPeter Holm    ok;                                                                        \
855b42ac29SPeter Holm  })
865b42ac29SPeter Holm
875b42ac29SPeter Holmstatic void kill_and_wait(int pid, int* status)
885b42ac29SPeter Holm{
895b42ac29SPeter Holm  kill(pid, SIGKILL);
905b42ac29SPeter Holm  while (waitpid(-1, status, 0) != pid) {
915b42ac29SPeter Holm  }
925b42ac29SPeter Holm}
935b42ac29SPeter Holm
945b42ac29SPeter Holmstatic void sleep_ms(uint64_t ms)
955b42ac29SPeter Holm{
965b42ac29SPeter Holm  usleep(ms * 1000);
975b42ac29SPeter Holm}
985b42ac29SPeter Holm
995b42ac29SPeter Holmstatic uint64_t current_time_ms(void)
1005b42ac29SPeter Holm{
1015b42ac29SPeter Holm  struct timespec ts;
1025b42ac29SPeter Holm  if (clock_gettime(CLOCK_MONOTONIC, &ts))
1035b42ac29SPeter Holm    exit(1);
1045b42ac29SPeter Holm  return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
1055b42ac29SPeter Holm}
1065b42ac29SPeter Holm
1075b42ac29SPeter Holmstatic void thread_start(void* (*fn)(void*), void* arg)
1085b42ac29SPeter Holm{
1095b42ac29SPeter Holm  pthread_t th;
1105b42ac29SPeter Holm  pthread_attr_t attr;
1115b42ac29SPeter Holm  pthread_attr_init(&attr);
1125b42ac29SPeter Holm  pthread_attr_setstacksize(&attr, 128 << 10);
1135b42ac29SPeter Holm  int i = 0;
1145b42ac29SPeter Holm  for (; i < 100; i++) {
1155b42ac29SPeter Holm    if (pthread_create(&th, &attr, fn, arg) == 0) {
1165b42ac29SPeter Holm      pthread_attr_destroy(&attr);
1175b42ac29SPeter Holm      return;
1185b42ac29SPeter Holm    }
1195b42ac29SPeter Holm    if (errno == EAGAIN) {
1205b42ac29SPeter Holm      usleep(50);
1215b42ac29SPeter Holm      continue;
1225b42ac29SPeter Holm    }
1235b42ac29SPeter Holm    break;
1245b42ac29SPeter Holm  }
1255b42ac29SPeter Holm  exit(1);
1265b42ac29SPeter Holm}
1275b42ac29SPeter Holm
1285b42ac29SPeter Holmtypedef struct {
1295b42ac29SPeter Holm  pthread_mutex_t mu;
1305b42ac29SPeter Holm  pthread_cond_t cv;
1315b42ac29SPeter Holm  int state;
1325b42ac29SPeter Holm} event_t;
1335b42ac29SPeter Holm
1345b42ac29SPeter Holmstatic void event_init(event_t* ev)
1355b42ac29SPeter Holm{
1365b42ac29SPeter Holm  if (pthread_mutex_init(&ev->mu, 0))
1375b42ac29SPeter Holm    exit(1);
1385b42ac29SPeter Holm  if (pthread_cond_init(&ev->cv, 0))
1395b42ac29SPeter Holm    exit(1);
1405b42ac29SPeter Holm  ev->state = 0;
1415b42ac29SPeter Holm}
1425b42ac29SPeter Holm
1435b42ac29SPeter Holmstatic void event_reset(event_t* ev)
1445b42ac29SPeter Holm{
1455b42ac29SPeter Holm  ev->state = 0;
1465b42ac29SPeter Holm}
1475b42ac29SPeter Holm
1485b42ac29SPeter Holmstatic void event_set(event_t* ev)
1495b42ac29SPeter Holm{
1505b42ac29SPeter Holm  pthread_mutex_lock(&ev->mu);
1515b42ac29SPeter Holm  if (ev->state)
1525b42ac29SPeter Holm    exit(1);
1535b42ac29SPeter Holm  ev->state = 1;
1545b42ac29SPeter Holm  pthread_mutex_unlock(&ev->mu);
1555b42ac29SPeter Holm  pthread_cond_broadcast(&ev->cv);
1565b42ac29SPeter Holm}
1575b42ac29SPeter Holm
1585b42ac29SPeter Holmstatic void event_wait(event_t* ev)
1595b42ac29SPeter Holm{
1605b42ac29SPeter Holm  pthread_mutex_lock(&ev->mu);
1615b42ac29SPeter Holm  while (!ev->state)
1625b42ac29SPeter Holm    pthread_cond_wait(&ev->cv, &ev->mu);
1635b42ac29SPeter Holm  pthread_mutex_unlock(&ev->mu);
1645b42ac29SPeter Holm}
1655b42ac29SPeter Holm
1665b42ac29SPeter Holmstatic int event_isset(event_t* ev)
1675b42ac29SPeter Holm{
1685b42ac29SPeter Holm  pthread_mutex_lock(&ev->mu);
1695b42ac29SPeter Holm  int res = ev->state;
1705b42ac29SPeter Holm  pthread_mutex_unlock(&ev->mu);
1715b42ac29SPeter Holm  return res;
1725b42ac29SPeter Holm}
1735b42ac29SPeter Holm
1745b42ac29SPeter Holmstatic int event_timedwait(event_t* ev, uint64_t timeout)
1755b42ac29SPeter Holm{
1765b42ac29SPeter Holm  uint64_t start = current_time_ms();
1775b42ac29SPeter Holm  uint64_t now = start;
1785b42ac29SPeter Holm  pthread_mutex_lock(&ev->mu);
1795b42ac29SPeter Holm  for (;;) {
1805b42ac29SPeter Holm    if (ev->state)
1815b42ac29SPeter Holm      break;
1825b42ac29SPeter Holm    uint64_t remain = timeout - (now - start);
1835b42ac29SPeter Holm    struct timespec ts;
1845b42ac29SPeter Holm    ts.tv_sec = remain / 1000;
1855b42ac29SPeter Holm    ts.tv_nsec = (remain % 1000) * 1000 * 1000;
1865b42ac29SPeter Holm    pthread_cond_timedwait(&ev->cv, &ev->mu, &ts);
1875b42ac29SPeter Holm    now = current_time_ms();
1885b42ac29SPeter Holm    if (now - start > timeout)
1895b42ac29SPeter Holm      break;
1905b42ac29SPeter Holm  }
1915b42ac29SPeter Holm  int res = ev->state;
1925b42ac29SPeter Holm  pthread_mutex_unlock(&ev->mu);
1935b42ac29SPeter Holm  return res;
1945b42ac29SPeter Holm}
1955b42ac29SPeter Holm
1965b42ac29SPeter Holmstruct thread_t {
1975b42ac29SPeter Holm  int created, call;
1985b42ac29SPeter Holm  event_t ready, done;
1995b42ac29SPeter Holm};
2005b42ac29SPeter Holm
2015b42ac29SPeter Holmstatic struct thread_t threads[16];
2025b42ac29SPeter Holmstatic void execute_call(int call);
2035b42ac29SPeter Holmstatic int running;
2045b42ac29SPeter Holm
2055b42ac29SPeter Holmstatic void* thr(void* arg)
2065b42ac29SPeter Holm{
2075b42ac29SPeter Holm  struct thread_t* th = (struct thread_t*)arg;
2085b42ac29SPeter Holm  for (;;) {
2095b42ac29SPeter Holm    event_wait(&th->ready);
2105b42ac29SPeter Holm    event_reset(&th->ready);
2115b42ac29SPeter Holm    execute_call(th->call);
2125b42ac29SPeter Holm    __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
2135b42ac29SPeter Holm    event_set(&th->done);
2145b42ac29SPeter Holm  }
2155b42ac29SPeter Holm  return 0;
2165b42ac29SPeter Holm}
2175b42ac29SPeter Holm
2185b42ac29SPeter Holmstatic void execute_one(void)
2195b42ac29SPeter Holm{
2205b42ac29SPeter Holm  int i, call, thread;
2215b42ac29SPeter Holm  for (call = 0; call < 2; call++) {
2225b42ac29SPeter Holm    for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
2235b42ac29SPeter Holm         thread++) {
2245b42ac29SPeter Holm      struct thread_t* th = &threads[thread];
2255b42ac29SPeter Holm      if (!th->created) {
2265b42ac29SPeter Holm        th->created = 1;
2275b42ac29SPeter Holm        event_init(&th->ready);
2285b42ac29SPeter Holm        event_init(&th->done);
2295b42ac29SPeter Holm        event_set(&th->done);
2305b42ac29SPeter Holm        thread_start(thr, th);
2315b42ac29SPeter Holm      }
2325b42ac29SPeter Holm      if (!event_isset(&th->done))
2335b42ac29SPeter Holm        continue;
2345b42ac29SPeter Holm      event_reset(&th->done);
2355b42ac29SPeter Holm      th->call = call;
2365b42ac29SPeter Holm      __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
2375b42ac29SPeter Holm      event_set(&th->ready);
2385b42ac29SPeter Holm      event_timedwait(&th->done, 50);
2395b42ac29SPeter Holm      break;
2405b42ac29SPeter Holm    }
2415b42ac29SPeter Holm  }
2425b42ac29SPeter Holm  for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
2435b42ac29SPeter Holm    sleep_ms(1);
2445b42ac29SPeter Holm}
2455b42ac29SPeter Holm
2465b42ac29SPeter Holmstatic void execute_one(void);
2475b42ac29SPeter Holm
2485b42ac29SPeter Holm#define WAIT_FLAGS 0
2495b42ac29SPeter Holm
2505b42ac29SPeter Holmstatic void loop(void)
2515b42ac29SPeter Holm{
252*7f658f99SPeter Holm  int iter __unused = 0;
2535b42ac29SPeter Holm  for (;; iter++) {
2545b42ac29SPeter Holm    int pid = fork();
2555b42ac29SPeter Holm    if (pid < 0)
2565b42ac29SPeter Holm      exit(1);
2575b42ac29SPeter Holm    if (pid == 0) {
2585b42ac29SPeter Holm      execute_one();
2595b42ac29SPeter Holm      exit(0);
2605b42ac29SPeter Holm    }
2615b42ac29SPeter Holm    int status = 0;
2625b42ac29SPeter Holm    uint64_t start = current_time_ms();
2635b42ac29SPeter Holm    for (;;) {
2645b42ac29SPeter Holm      if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
2655b42ac29SPeter Holm        break;
2665b42ac29SPeter Holm      sleep_ms(1);
2675b42ac29SPeter Holm      if (current_time_ms() - start < 5000)
2685b42ac29SPeter Holm        continue;
2695b42ac29SPeter Holm      kill_and_wait(pid, &status);
2705b42ac29SPeter Holm      break;
2715b42ac29SPeter Holm    }
2725b42ac29SPeter Holm  }
2735b42ac29SPeter Holm}
2745b42ac29SPeter Holm
2755b42ac29SPeter Holmvoid execute_call(int call)
2765b42ac29SPeter Holm{
2775b42ac29SPeter Holm  switch (call) {
2785b42ac29SPeter Holm  case 0:
2795b42ac29SPeter Holm    NONFAILING(*(uint32_t*)0x20001f00 = 0x16);
2805b42ac29SPeter Holm    NONFAILING(*(uint32_t*)0x20001f04 = 0);
2815b42ac29SPeter Holm    NONFAILING(*(uint32_t*)0x20001f08 = 0);
2825b42ac29SPeter Holm    NONFAILING(*(uint32_t*)0x20001f0c = 0);
2835b42ac29SPeter Holm    NONFAILING(*(uint32_t*)0x20001f10 = 0);
2845b42ac29SPeter Holm    NONFAILING(memset((void*)0x20001f14, 0, 60));
2855b42ac29SPeter Holm    syscall(SYS_procctl, 0ul, 0, 6ul, 0x20001f00ul);
2865b42ac29SPeter Holm    break;
2875b42ac29SPeter Holm  case 1:
2885b42ac29SPeter Holm    syscall(SYS_rfork, 0x85000ul);
2895b42ac29SPeter Holm    break;
2905b42ac29SPeter Holm  }
2915b42ac29SPeter Holm}
2925b42ac29SPeter Holmint main(void)
2935b42ac29SPeter Holm{
2945b42ac29SPeter Holm  syscall(SYS_mmap, 0x20000000ul, 0x1000000ul, 7ul, 0x1012ul, -1, 0ul);
2955b42ac29SPeter Holm  install_segv_handler();
2965b42ac29SPeter Holm  loop();
2975b42ac29SPeter Holm  return 0;
2985b42ac29SPeter Holm}
2995b42ac29SPeter HolmEOF
3005b42ac29SPeter Holmmycc -o /tmp/syzkaller61 -Wall -Wextra -O0 /tmp/syzkaller61.c -lpthread ||
3015b42ac29SPeter Holm    exit 1
3025b42ac29SPeter Holm
3035b42ac29SPeter Holm(cd ../testcases/swap; ./swap -t 3m -i 10 -l 100 > /dev/null 2>&1) &
3045b42ac29SPeter Holmfor i in `jot 300`; do
3055b42ac29SPeter Holm	(cd /tmp; timeout -k 3s 2s ./syzkaller61) &
3065b42ac29SPeter Holm	pids="$pids $!"
3075b42ac29SPeter Holmdone
3085b42ac29SPeter Holmsleep 5
3095b42ac29SPeter Holmpkill -9 syzkaller61 swap; sleep 1
3105b42ac29SPeter Holmpgrep -q syzkaller61 && { pgrep syzkaller61 | xargs ps -lHp; exit 1; }
3115b42ac29SPeter Holmfor pid in $pids; do
3125b42ac29SPeter Holm	wait $pid
3135b42ac29SPeter Holmdone
3145b42ac29SPeter Holmwhile pkill swap; do :; done
3155b42ac29SPeter Holmwait
3165b42ac29SPeter Holm
3175b42ac29SPeter Holmrm -rf /tmp/syzkaller61 /tmp/syzkaller61.c /tmp/syzkaller61.core \
3185b42ac29SPeter Holm    /tmp/syzkaller.??????
3195b42ac29SPeter Holmexit 0
320