xref: /freebsd/tools/test/stress2/misc/syzkaller61.sh (revision a4e5e0106ac7145f56eb39a691e302cabb4635be)
1#!/bin/sh
2
3# Seen:
4# [root@mercat1 /usr/src/tools/test/stress2/misc]# pgrep syzkaller61 | xargs procstat -k
5#   PID    TID COMM                TDNAME              KSTACK
6#   13332 106396 syzkaller61         -                   mi_switch thread_suspend_check ast_suspend ast_handler ast doreti_ast
7#   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
8#   13332 560776 syzkaller61         -                   mi_switch thread_suspend_switch thread_single fork1 sys_rfork amd64_syscall fast_syscall_common
9#   13662 356440 syzkaller61         -                   mi_switch thread_suspend_check ast_suspend ast_handler ast doreti_ast
10#   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
11#   13662 561160 syzkaller61         -                   mi_switch thread_suspend_switch thread_single fork1 sys_rfork amd64_syscall fast_syscall_common
12#   [root@mercat1 /usr/src/tools/test/stress2/misc]#
13
14[ `uname -p` != "amd64" ] && exit 0
15
16. ../default.cfg
17cat > /tmp/syzkaller61.c <<EOF
18// https://syzkaller.appspot.com/bug?id=00d8ca63243899ffb67b15ec93aee4ffa2f06637
19// autogenerated by syzkaller (https://github.com/google/syzkaller)
20// Reported-by: syzbot+647212368c3f32c6f13f@syzkaller.appspotmail.com
21
22#define _GNU_SOURCE
23
24#include <sys/types.h>
25
26#include <errno.h>
27#include <pthread.h>
28#include <pwd.h>
29#include <setjmp.h>
30#include <signal.h>
31#include <stdarg.h>
32#include <stdbool.h>
33#include <stdint.h>
34#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
37#include <sys/endian.h>
38#include <sys/syscall.h>
39#include <sys/wait.h>
40#include <time.h>
41#include <unistd.h>
42
43static __thread int clone_ongoing;
44static __thread int skip_segv;
45static __thread jmp_buf segv_env;
46
47static void segv_handler(int sig, siginfo_t* info, void* ctx __unused)
48{
49  if (__atomic_load_n(&clone_ongoing, __ATOMIC_RELAXED) != 0) {
50    exit(sig);
51  }
52  uintptr_t addr = (uintptr_t)info->si_addr;
53  const uintptr_t prog_start = 1 << 20;
54  const uintptr_t prog_end = 100 << 20;
55  int skip = __atomic_load_n(&skip_segv, __ATOMIC_RELAXED) != 0;
56  int valid = addr < prog_start || addr > prog_end;
57  if (sig == SIGBUS)
58    valid = 1;
59  if (skip && valid) {
60    _longjmp(segv_env, 1);
61  }
62  exit(sig);
63}
64
65static void install_segv_handler(void)
66{
67  struct sigaction sa;
68  memset(&sa, 0, sizeof(sa));
69  sa.sa_sigaction = segv_handler;
70  sa.sa_flags = SA_NODEFER | SA_SIGINFO;
71  sigaction(SIGSEGV, &sa, NULL);
72  sigaction(SIGBUS, &sa, NULL);
73}
74
75#define NONFAILING(...)                                                        \
76  ({                                                                           \
77    int ok = 1;                                                                \
78    __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST);                       \
79    if (_setjmp(segv_env) == 0) {                                              \
80      __VA_ARGS__;                                                             \
81    } else                                                                     \
82      ok = 0;                                                                  \
83    __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST);                       \
84    ok;                                                                        \
85  })
86
87static void kill_and_wait(int pid, int* status)
88{
89  kill(pid, SIGKILL);
90  while (waitpid(-1, status, 0) != pid) {
91  }
92}
93
94static void sleep_ms(uint64_t ms)
95{
96  usleep(ms * 1000);
97}
98
99static uint64_t current_time_ms(void)
100{
101  struct timespec ts;
102  if (clock_gettime(CLOCK_MONOTONIC, &ts))
103    exit(1);
104  return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
105}
106
107static void thread_start(void* (*fn)(void*), void* arg)
108{
109  pthread_t th;
110  pthread_attr_t attr;
111  pthread_attr_init(&attr);
112  pthread_attr_setstacksize(&attr, 128 << 10);
113  int i = 0;
114  for (; i < 100; i++) {
115    if (pthread_create(&th, &attr, fn, arg) == 0) {
116      pthread_attr_destroy(&attr);
117      return;
118    }
119    if (errno == EAGAIN) {
120      usleep(50);
121      continue;
122    }
123    break;
124  }
125  exit(1);
126}
127
128typedef struct {
129  pthread_mutex_t mu;
130  pthread_cond_t cv;
131  int state;
132} event_t;
133
134static void event_init(event_t* ev)
135{
136  if (pthread_mutex_init(&ev->mu, 0))
137    exit(1);
138  if (pthread_cond_init(&ev->cv, 0))
139    exit(1);
140  ev->state = 0;
141}
142
143static void event_reset(event_t* ev)
144{
145  ev->state = 0;
146}
147
148static void event_set(event_t* ev)
149{
150  pthread_mutex_lock(&ev->mu);
151  if (ev->state)
152    exit(1);
153  ev->state = 1;
154  pthread_mutex_unlock(&ev->mu);
155  pthread_cond_broadcast(&ev->cv);
156}
157
158static void event_wait(event_t* ev)
159{
160  pthread_mutex_lock(&ev->mu);
161  while (!ev->state)
162    pthread_cond_wait(&ev->cv, &ev->mu);
163  pthread_mutex_unlock(&ev->mu);
164}
165
166static int event_isset(event_t* ev)
167{
168  pthread_mutex_lock(&ev->mu);
169  int res = ev->state;
170  pthread_mutex_unlock(&ev->mu);
171  return res;
172}
173
174static int event_timedwait(event_t* ev, uint64_t timeout)
175{
176  uint64_t start = current_time_ms();
177  uint64_t now = start;
178  pthread_mutex_lock(&ev->mu);
179  for (;;) {
180    if (ev->state)
181      break;
182    uint64_t remain = timeout - (now - start);
183    struct timespec ts;
184    ts.tv_sec = remain / 1000;
185    ts.tv_nsec = (remain % 1000) * 1000 * 1000;
186    pthread_cond_timedwait(&ev->cv, &ev->mu, &ts);
187    now = current_time_ms();
188    if (now - start > timeout)
189      break;
190  }
191  int res = ev->state;
192  pthread_mutex_unlock(&ev->mu);
193  return res;
194}
195
196struct thread_t {
197  int created, call;
198  event_t ready, done;
199};
200
201static struct thread_t threads[16];
202static void execute_call(int call);
203static int running;
204
205static void* thr(void* arg)
206{
207  struct thread_t* th = (struct thread_t*)arg;
208  for (;;) {
209    event_wait(&th->ready);
210    event_reset(&th->ready);
211    execute_call(th->call);
212    __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
213    event_set(&th->done);
214  }
215  return 0;
216}
217
218static void execute_one(void)
219{
220  int i, call, thread;
221  for (call = 0; call < 2; call++) {
222    for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
223         thread++) {
224      struct thread_t* th = &threads[thread];
225      if (!th->created) {
226        th->created = 1;
227        event_init(&th->ready);
228        event_init(&th->done);
229        event_set(&th->done);
230        thread_start(thr, th);
231      }
232      if (!event_isset(&th->done))
233        continue;
234      event_reset(&th->done);
235      th->call = call;
236      __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
237      event_set(&th->ready);
238      event_timedwait(&th->done, 50);
239      break;
240    }
241  }
242  for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
243    sleep_ms(1);
244}
245
246static void execute_one(void);
247
248#define WAIT_FLAGS 0
249
250static void loop(void)
251{
252  int iter __unused = 0;
253  for (;; iter++) {
254    int pid = fork();
255    if (pid < 0)
256      exit(1);
257    if (pid == 0) {
258      execute_one();
259      exit(0);
260    }
261    int status = 0;
262    uint64_t start = current_time_ms();
263    for (;;) {
264      if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
265        break;
266      sleep_ms(1);
267      if (current_time_ms() - start < 5000)
268        continue;
269      kill_and_wait(pid, &status);
270      break;
271    }
272  }
273}
274
275void execute_call(int call)
276{
277  switch (call) {
278  case 0:
279    NONFAILING(*(uint32_t*)0x20001f00 = 0x16);
280    NONFAILING(*(uint32_t*)0x20001f04 = 0);
281    NONFAILING(*(uint32_t*)0x20001f08 = 0);
282    NONFAILING(*(uint32_t*)0x20001f0c = 0);
283    NONFAILING(*(uint32_t*)0x20001f10 = 0);
284    NONFAILING(memset((void*)0x20001f14, 0, 60));
285    syscall(SYS_procctl, 0ul, 0, 6ul, 0x20001f00ul);
286    break;
287  case 1:
288    syscall(SYS_rfork, 0x85000ul);
289    break;
290  }
291}
292int main(void)
293{
294  syscall(SYS_mmap, 0x20000000ul, 0x1000000ul, 7ul, 0x1012ul, -1, 0ul);
295  install_segv_handler();
296  loop();
297  return 0;
298}
299EOF
300mycc -o /tmp/syzkaller61 -Wall -Wextra -O0 /tmp/syzkaller61.c -lpthread ||
301    exit 1
302
303(cd ../testcases/swap; ./swap -t 3m -i 10 -l 100 > /dev/null 2>&1) &
304for i in `jot 300`; do
305	(cd /tmp; timeout -k 3s 2s ./syzkaller61) &
306	pids="$pids $!"
307done
308sleep 5
309pkill -9 syzkaller61 swap; sleep 1
310pgrep -q syzkaller61 && { pgrep syzkaller61 | xargs ps -lHp; exit 1; }
311for pid in $pids; do
312	wait $pid
313done
314while pkill swap; do :; done
315wait
316
317rm -rf /tmp/syzkaller61 /tmp/syzkaller61.c /tmp/syzkaller61.core \
318    /tmp/syzkaller.??????
319exit 0
320