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