xref: /freebsd/tools/test/stress2/misc/syzkaller25.sh (revision ec0ea6efa1ad229d75c394c1a9b9cac33af2b1d3)
1#!/bin/sh
2
3# Fatal trap 9: general protection fault while in kernel mode
4# cpuid = 5; apic id = 05
5# instruction pointer     = 0x20:0xffffffff8237cbac
6# stack pointer           = 0x28:0xfffffe01026e4910
7# frame pointer           = 0x28:0xfffffe01026e4980
8# code segment            = base 0x0, limit 0xfffff, type 0x1b
9#                         = DPL 0, pres 1, long 1, def32 0, gran 1
10# processor eflags        = interrupt enabled, resume, IOPL = 0
11# current process         = 45836 (syzkaller25)
12# trap number             = 9
13# panic: general protection fault
14# cpuid = 5
15# time = 1601745366
16# KDB: stack backtrace:
17# db_trace_self_wrapper() at db_trace_self_wrapper+0x2b/frame 0xfffffe01026e4620
18# vpanic() at vpanic+0x182/frame 0xfffffe01026e4670
19# panic() at panic+0x43/frame 0xfffffe01026e46d0
20# trap_fatal() at trap_fatal+0x387/frame 0xfffffe01026e4730
21# trap() at trap+0xa4/frame 0xfffffe01026e4840
22# calltrap() at calltrap+0x8/frame 0xfffffe01026e4840
23# --- trap 0x9, rip = 0xffffffff8237cbac, rsp = 0xfffffe01026e4910, rbp = 0xfffffe01026e4980 ---
24# sctp_inpcb_bind() at sctp_inpcb_bind+0x3cc/frame 0xfffffe01026e4980
25# sctp_connect() at sctp_connect+0x14f/frame 0xfffffe01026e49e0
26# soconnectat() at soconnectat+0xd0/frame 0xfffffe01026e4a30
27# kern_connectat() at kern_connectat+0xe2/frame 0xfffffe01026e4a90
28# sys_connect() at sys_connect+0x75/frame 0xfffffe01026e4ad0
29# amd64_syscall() at amd64_syscall+0x14e/frame 0xfffffe01026e4bf0
30# fast_syscall_common() at fast_syscall_common+0xf8/frame 0xfffffe01026e4bf0
31# --- syscall (0, FreeBSD ELF64, nosys), rip = 0x8003b0a1a, rsp = 0x7fffdfffdbb8, rbp = 0x7fffdfffdf90 ---
32# KDB: enter: panic
33# [ thread pid 45836 tid 101772 ]
34# Stopped at      kdb_enter+0x37: movq    $0,0x10ac846(%rip)
35# db> x/s version
36# version: FreeBSD 13.0-CURRENT #0 r366401: Sat Oct  3 19:00:37 CEST 2020
37# pho@t2.osted.lan:/usr/src/sys/amd64/compile/PHO
38# db>
39
40[ `uname -p` != "amd64" ] && exit 0
41
42. ../default.cfg
43kldstat -v | grep -q sctp || kldload sctp.ko
44
45cat > /tmp/syzkaller25.c <<EOF
46// https://syzkaller.appspot.com/bug?id=2e4fc04b5a5775777770f7244613571ca85da78a
47// autogenerated by syzkaller (https://github.com/google/syzkaller)
48// Reported-by: syzbot+77fcf6a9d28f301bc2e5@syzkaller.appspotmail.com
49
50#define _GNU_SOURCE
51
52#include <sys/types.h>
53
54#include <dirent.h>
55#include <errno.h>
56#include <pthread.h>
57#include <pwd.h>
58#include <setjmp.h>
59#include <signal.h>
60#include <stdarg.h>
61#include <stdbool.h>
62#include <stdint.h>
63#include <stdio.h>
64#include <stdlib.h>
65#include <string.h>
66#include <sys/endian.h>
67#include <sys/resource.h>
68#include <sys/stat.h>
69#include <sys/syscall.h>
70#include <sys/wait.h>
71#include <time.h>
72#include <unistd.h>
73
74static unsigned long long procid;
75
76static __thread int skip_segv;
77static __thread jmp_buf segv_env;
78
79static void segv_handler(int sig, siginfo_t* info, void* ctx __unused)
80{
81  uintptr_t addr = (uintptr_t)info->si_addr;
82  const uintptr_t prog_start = 1 << 20;
83  const uintptr_t prog_end = 100 << 20;
84  int skip = __atomic_load_n(&skip_segv, __ATOMIC_RELAXED) != 0;
85  int valid = addr < prog_start || addr > prog_end;
86  if (sig == SIGBUS) {
87    valid = 1;
88  }
89  if (skip && valid) {
90    _longjmp(segv_env, 1);
91  }
92  exit(sig);
93}
94
95static void install_segv_handler(void)
96{
97  struct sigaction sa;
98  memset(&sa, 0, sizeof(sa));
99  sa.sa_sigaction = segv_handler;
100  sa.sa_flags = SA_NODEFER | SA_SIGINFO;
101  sigaction(SIGSEGV, &sa, NULL);
102  sigaction(SIGBUS, &sa, NULL);
103}
104
105#define NONFAILING(...)                                                        \
106  ({                                                                           \
107    int ok = 1;                                                                \
108    __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST);                       \
109    if (_setjmp(segv_env) == 0) {                                              \
110      __VA_ARGS__;                                                             \
111    } else                                                                     \
112      ok = 0;                                                                  \
113    __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST);                       \
114    ok;                                                                        \
115  })
116
117static void kill_and_wait(int pid, int* status)
118{
119  kill(pid, SIGKILL);
120  while (waitpid(-1, status, 0) != pid) {
121  }
122}
123
124static void sleep_ms(uint64_t ms)
125{
126  usleep(ms * 1000);
127}
128
129static uint64_t current_time_ms(void)
130{
131  struct timespec ts;
132  if (clock_gettime(CLOCK_MONOTONIC, &ts))
133    exit(1);
134  return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
135}
136
137static void use_temporary_dir(void)
138{
139  char tmpdir_template[] = "./syzkaller.XXXXXX";
140  char* tmpdir = mkdtemp(tmpdir_template);
141  if (!tmpdir)
142    exit(1);
143  if (chmod(tmpdir, 0777))
144    exit(1);
145  if (chdir(tmpdir))
146    exit(1);
147}
148
149static void __attribute__((noinline)) remove_dir(const char* dir)
150{
151  DIR* dp = opendir(dir);
152  if (dp == NULL) {
153    if (errno == EACCES) {
154      if (rmdir(dir))
155        exit(1);
156      return;
157    }
158    exit(1);
159  }
160  struct dirent* ep = 0;
161  while ((ep = readdir(dp))) {
162    if (strcmp(ep->d_name, ".") == 0 || strcmp(ep->d_name, "..") == 0)
163      continue;
164    char filename[FILENAME_MAX];
165    snprintf(filename, sizeof(filename), "%s/%s", dir, ep->d_name);
166    struct stat st;
167    if (lstat(filename, &st))
168      exit(1);
169    if (S_ISDIR(st.st_mode)) {
170      remove_dir(filename);
171      continue;
172    }
173    if (unlink(filename))
174      exit(1);
175  }
176  closedir(dp);
177  if (rmdir(dir))
178    exit(1);
179}
180
181static void thread_start(void* (*fn)(void*), void* arg)
182{
183  pthread_t th;
184  pthread_attr_t attr;
185  pthread_attr_init(&attr);
186  pthread_attr_setstacksize(&attr, 128 << 10);
187  int i = 0;
188  for (; i < 100; i++) {
189    if (pthread_create(&th, &attr, fn, arg) == 0) {
190      pthread_attr_destroy(&attr);
191      return;
192    }
193    if (errno == EAGAIN) {
194      usleep(50);
195      continue;
196    }
197    break;
198  }
199  exit(1);
200}
201
202typedef struct {
203  pthread_mutex_t mu;
204  pthread_cond_t cv;
205  int state;
206} event_t;
207
208static void event_init(event_t* ev)
209{
210  if (pthread_mutex_init(&ev->mu, 0))
211    exit(1);
212  if (pthread_cond_init(&ev->cv, 0))
213    exit(1);
214  ev->state = 0;
215}
216
217static void event_reset(event_t* ev)
218{
219  ev->state = 0;
220}
221
222static void event_set(event_t* ev)
223{
224  pthread_mutex_lock(&ev->mu);
225  if (ev->state)
226    exit(1);
227  ev->state = 1;
228  pthread_mutex_unlock(&ev->mu);
229  pthread_cond_broadcast(&ev->cv);
230}
231
232static void event_wait(event_t* ev)
233{
234  pthread_mutex_lock(&ev->mu);
235  while (!ev->state)
236    pthread_cond_wait(&ev->cv, &ev->mu);
237  pthread_mutex_unlock(&ev->mu);
238}
239
240static int event_isset(event_t* ev)
241{
242  pthread_mutex_lock(&ev->mu);
243  int res = ev->state;
244  pthread_mutex_unlock(&ev->mu);
245  return res;
246}
247
248static int event_timedwait(event_t* ev, uint64_t timeout)
249{
250  uint64_t start = current_time_ms();
251  uint64_t now = start;
252  pthread_mutex_lock(&ev->mu);
253  for (;;) {
254    if (ev->state)
255      break;
256    uint64_t remain = timeout - (now - start);
257    struct timespec ts;
258    ts.tv_sec = remain / 1000;
259    ts.tv_nsec = (remain % 1000) * 1000 * 1000;
260    pthread_cond_timedwait(&ev->cv, &ev->mu, &ts);
261    now = current_time_ms();
262    if (now - start > timeout)
263      break;
264  }
265  int res = ev->state;
266  pthread_mutex_unlock(&ev->mu);
267  return res;
268}
269
270static void sandbox_common()
271{
272  if (setsid() == -1)
273    exit(1);
274  struct rlimit rlim;
275  rlim.rlim_cur = rlim.rlim_max = 128 << 20;
276  setrlimit(RLIMIT_AS, &rlim);
277  rlim.rlim_cur = rlim.rlim_max = 8 << 20;
278  setrlimit(RLIMIT_MEMLOCK, &rlim);
279  rlim.rlim_cur = rlim.rlim_max = 1 << 20;
280  setrlimit(RLIMIT_FSIZE, &rlim);
281  rlim.rlim_cur = rlim.rlim_max = 1 << 20;
282  setrlimit(RLIMIT_STACK, &rlim);
283  rlim.rlim_cur = rlim.rlim_max = 0;
284  setrlimit(RLIMIT_CORE, &rlim);
285  rlim.rlim_cur = rlim.rlim_max = 256;
286  setrlimit(RLIMIT_NOFILE, &rlim);
287}
288
289static void loop();
290
291static int do_sandbox_none(void)
292{
293  sandbox_common();
294  loop();
295  return 0;
296}
297
298struct thread_t {
299  int created, call;
300  event_t ready, done;
301};
302
303static struct thread_t threads[16];
304static void execute_call(int call);
305static int running;
306
307static void* thr(void* arg)
308{
309  struct thread_t* th = (struct thread_t*)arg;
310  for (;;) {
311    event_wait(&th->ready);
312    event_reset(&th->ready);
313    execute_call(th->call);
314    __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
315    event_set(&th->done);
316  }
317  return 0;
318}
319
320static void execute_one(void)
321{
322  int i, call, thread;
323  int collide = 0;
324again:
325  for (call = 0; call < 4; call++) {
326    for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
327         thread++) {
328      struct thread_t* th = &threads[thread];
329      if (!th->created) {
330        th->created = 1;
331        event_init(&th->ready);
332        event_init(&th->done);
333        event_set(&th->done);
334        thread_start(thr, th);
335      }
336      if (!event_isset(&th->done))
337        continue;
338      event_reset(&th->done);
339      th->call = call;
340      __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
341      event_set(&th->ready);
342      if (collide && (call % 2) == 0)
343        break;
344      event_timedwait(&th->done, 45);
345      break;
346    }
347  }
348  for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
349    sleep_ms(1);
350  if (!collide) {
351    collide = 1;
352    goto again;
353  }
354}
355
356static void execute_one(void);
357
358#define WAIT_FLAGS 0
359
360static void loop(void)
361{
362  int iter = 0;
363  for (;; iter++) {
364    char cwdbuf[32];
365    sprintf(cwdbuf, "./%d", iter);
366    if (mkdir(cwdbuf, 0777))
367      exit(1);
368    int pid = fork();
369    if (pid < 0)
370      exit(1);
371    if (pid == 0) {
372      if (chdir(cwdbuf))
373        exit(1);
374      execute_one();
375      exit(0);
376    }
377    int status = 0;
378    uint64_t start = current_time_ms();
379    for (;;) {
380      if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
381        break;
382      sleep_ms(1);
383      if (current_time_ms() - start < 5 * 1000)
384        continue;
385      kill_and_wait(pid, &status);
386      break;
387    }
388    remove_dir(cwdbuf);
389  }
390}
391
392uint64_t r[1] = {0xffffffffffffffff};
393
394void execute_call(int call)
395{
396  intptr_t res = 0;
397  switch (call) {
398  case 0:
399    res = syscall(SYS_socket, 2ul, 5ul, 0x84);
400    if (res != -1)
401      r[0] = res;
402    break;
403  case 1:
404    NONFAILING(*(uint8_t*)0x20000300 = 0x10);
405    NONFAILING(*(uint8_t*)0x20000301 = 2);
406    NONFAILING(*(uint16_t*)0x20000302 = htobe16(0x4e23 + procid * 4));
407    NONFAILING(*(uint32_t*)0x20000304 = htobe32(0));
408    NONFAILING(*(uint8_t*)0x20000308 = 0);
409    NONFAILING(*(uint8_t*)0x20000309 = 0);
410    NONFAILING(*(uint8_t*)0x2000030a = 0);
411    NONFAILING(*(uint8_t*)0x2000030b = 0);
412    NONFAILING(*(uint8_t*)0x2000030c = 0);
413    NONFAILING(*(uint8_t*)0x2000030d = 0);
414    NONFAILING(*(uint8_t*)0x2000030e = 0);
415    NONFAILING(*(uint8_t*)0x2000030f = 0);
416    syscall(SYS_bind, r[0], 0x20000300ul, 0x10ul);
417    break;
418  case 2:
419    NONFAILING(*(uint8_t*)0x20000040 = 0x10);
420    NONFAILING(*(uint8_t*)0x20000041 = 2);
421    NONFAILING(*(uint16_t*)0x20000042 = htobe16(0x4e23 + procid * 4));
422    NONFAILING(*(uint32_t*)0x20000044 = htobe32(0x7f000001));
423    NONFAILING(*(uint8_t*)0x20000048 = 0);
424    NONFAILING(*(uint8_t*)0x20000049 = 0);
425    NONFAILING(*(uint8_t*)0x2000004a = 0);
426    NONFAILING(*(uint8_t*)0x2000004b = 0);
427    NONFAILING(*(uint8_t*)0x2000004c = 0);
428    NONFAILING(*(uint8_t*)0x2000004d = 0);
429    NONFAILING(*(uint8_t*)0x2000004e = 0);
430    NONFAILING(*(uint8_t*)0x2000004f = 0);
431    syscall(SYS_connect, r[0], 0x20000040ul, 0x10ul);
432    break;
433  case 3:
434    NONFAILING(*(uint8_t*)0x20000000 = 0x10);
435    NONFAILING(*(uint8_t*)0x20000001 = 2);
436    NONFAILING(*(uint16_t*)0x20000002 = htobe16(0x4e23 + procid * 4));
437    NONFAILING(*(uint8_t*)0x20000004 = 0xac);
438    NONFAILING(*(uint8_t*)0x20000005 = 0x14);
439    NONFAILING(*(uint8_t*)0x20000006 = 0 + procid * 1);
440    NONFAILING(*(uint8_t*)0x20000007 = 0xaa);
441    NONFAILING(*(uint8_t*)0x20000008 = 0);
442    NONFAILING(*(uint8_t*)0x20000009 = 0);
443    NONFAILING(*(uint8_t*)0x2000000a = 0);
444    NONFAILING(*(uint8_t*)0x2000000b = 0);
445    NONFAILING(*(uint8_t*)0x2000000c = 0);
446    NONFAILING(*(uint8_t*)0x2000000d = 0);
447    NONFAILING(*(uint8_t*)0x2000000e = 0);
448    NONFAILING(*(uint8_t*)0x2000000f = 0);
449    syscall(SYS_connect, r[0], 0x20000000ul, 0x10ul);
450    break;
451  }
452}
453int main(void)
454{
455  syscall(SYS_mmap, 0x20000000ul, 0x1000000ul, 7ul, 0x1012ul, -1, 0ul);
456  install_segv_handler();
457  for (procid = 0; procid < 4; procid++) {
458    if (fork() == 0) {
459      use_temporary_dir();
460      do_sandbox_none();
461    }
462  }
463  sleep(1000000);
464  return 0;
465}
466EOF
467mycc -o /tmp/syzkaller25 -Wall -Wextra -O0 /tmp/syzkaller25.c -lpthread ||
468    exit 1
469
470(cd ../testcases/swap; ./swap -t 1m -i 20 -h > /dev/null 2>&1) &
471(cd /tmp; timeout 3m ./syzkaller25)
472while pkill swap; do :; done
473wait
474
475rm -rf /tmp/syzkaller25 syzkaller25.c /tmp/syzkaller.*
476exit 0
477