// https://syzkaller.appspot.com/bug?id=955cd77de977580908213f467a54d5832edc8e14 // autogenerated by syzkaller (http://github.com/google/syzkaller) #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include __attribute__((noreturn)) static void doexit(int status) { volatile unsigned i; syscall(__NR_exit_group, status); for (i = 0;; i++) { } } #include #include #include #include #include #include #include #include const int kFailStatus = 67; const int kRetryStatus = 69; static void fail(const char* msg, ...) { int e = errno; va_list args; va_start(args, msg); vfprintf(stderr, msg, args); va_end(args); fprintf(stderr, " (errno %d)\n", e); doexit((e == ENOMEM || e == EAGAIN) ? kRetryStatus : kFailStatus); } static __thread int skip_segv; static __thread jmp_buf segv_env; static void segv_handler(int sig, siginfo_t* info, void* uctx) { uintptr_t addr = (uintptr_t)info->si_addr; const uintptr_t prog_start = 1 << 20; const uintptr_t prog_end = 100 << 20; if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED) && (addr < prog_start || addr > prog_end)) { _longjmp(segv_env, 1); } doexit(sig); } static void install_segv_handler() { struct sigaction sa; memset(&sa, 0, sizeof(sa)); sa.sa_handler = SIG_IGN; syscall(SYS_rt_sigaction, 0x20, &sa, NULL, 8); syscall(SYS_rt_sigaction, 0x21, &sa, NULL, 8); memset(&sa, 0, sizeof(sa)); sa.sa_sigaction = segv_handler; sa.sa_flags = SA_NODEFER | SA_SIGINFO; sigaction(SIGSEGV, &sa, NULL); sigaction(SIGBUS, &sa, NULL); } #define NONFAILING(...) \ { \ __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \ if (_setjmp(segv_env) == 0) { \ __VA_ARGS__; \ } \ __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \ } static uint64_t current_time_ms() { struct timespec ts; if (clock_gettime(CLOCK_MONOTONIC, &ts)) fail("clock_gettime failed"); return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000; } static uintptr_t syz_open_procfs(uintptr_t a0, uintptr_t a1) { char buf[128]; memset(buf, 0, sizeof(buf)); if (a0 == 0) { NONFAILING(snprintf(buf, sizeof(buf), "/proc/self/%s", (char*)a1)); } else if (a0 == (uintptr_t)-1) { NONFAILING(snprintf(buf, sizeof(buf), "/proc/thread-self/%s", (char*)a1)); } else { NONFAILING(snprintf(buf, sizeof(buf), "/proc/self/task/%d/%s", (int)a0, (char*)a1)); } int fd = open(buf, O_RDWR); if (fd == -1) fd = open(buf, O_RDONLY); return fd; } static void execute_one(); extern unsigned long long procid; static void loop() { int iter; for (iter = 0;; iter++) { int pid = fork(); if (pid < 0) fail("clone failed"); if (pid == 0) { prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0); setpgrp(); execute_one(); doexit(0); } int status = 0; uint64_t start = current_time_ms(); for (;;) { int res = waitpid(-1, &status, __WALL | WNOHANG); if (res == pid) { break; } usleep(1000); if (current_time_ms() - start < 3 * 1000) continue; kill(-pid, SIGKILL); kill(pid, SIGKILL); while (waitpid(-1, &status, __WALL) != pid) { } break; } } } 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; } } } } uint64_t r[1] = {0xffffffffffffffff}; unsigned long long procid; void execute_call(int call) { long res; switch (call) { case 0: NONFAILING(memcpy( (void*)0x20000240, "\x6d\x6f\x75\x6e\x74\x69\x6e\x66\x6f\x00\x19\x30\x12\x5d\xae\x49\xa1" "\x7b\x17\x61\x42\x81\x81\xd5\x16\xa8\xbc\xe1\x36\x44\xdb\x3d\x9e\xe6" "\x04\xfe\x65\xa9\x92\x6b\xe5\x3b\x0d\xa7\x44\x86\xb3\x66\x11\xe6\xcc" "\xd5\xc0\x49\x35\xa4\x96\xdd\x19\xcc\xd9\x33\x59\xb6\x48\x58\x26\x9d" "\xbf\x35\x69\x0b\xbb\x79\x9b\x22\x8e\x06\x5d\xa4\xc3\x53\x56\x70\x05" "\x6a\xa8\xa8\xaa\xd0\xa3\x30\x32\xc7\x85\x64\x45\x9b\xec\x02\x77\xce" "\x71\x69\xcb\x22\xdf\x16\xda\xab\x16\x6f\xe1\x32\x46\xa1\x3d\x7c\xc7" "\xf5\x20\x44\x11\xca\x84\x88\x78\x4b\xd8\xbf\x20\xd2\xe6\xa1\x22\xbd" "\x5f\xcf\xe8\xd5\x92\x13\x0e\xfd\x28\xae\x0d\x8e\x2f\x1c\x26\x50\x19" "\x8f\x35\xa5\x2d\xbc\x7d\xe8\x6d\x35\xfb\x09\x9d\x06\x5f\xa7\x66\xd0" "\x7d\x9e\x7d\x68\x81\x04\xe0\xcc\x0c\x76\x71\x09\xd3\x5e\x3d\x64\x99" "\x62\x20\x4a\xcd\xe0\xaf\x0f\x84\x83\xdd\x4e\xed\x56\x1c\x76\x68\x30" "\x51\x70\x1f\x0f\xfb\xbc\xa7\x1e\x0f\x2a\x68\xd8\x48\x8d\xf4\xf7\xbd" "\x9a\x4c\x87\xb3\xd4\x31\x8f\x10\x76\x7f\x99\xb9\xb6\x42\x25\xcf\x7c" "\x4c\x14\x9e\xc3\xe1\x3b\x75\x50\x0b\xc6\xe3\x4e\x48\x44\xec\x10\xbf" "\x9f\x8e\xe4\x87\xdf\xd2\x58\x0b\x0c\x29\x97\x91\x97\xde\x75\x48\x79" "\x2a\x66\x6b\x49\x38\xf8\xdd\x7b\xf8\x4c\xd8\x60\xb1\x84\xd6\x46\x69" "\xd8\x64\x90\x72\x05\x62\xda\xdc\x24\xea\x18\xbf\xd3\x8a\x1a\x99\x81" "\xe5\xf5\x5b\x0b\x4f\x74\x81\x75\xfe\xbc\x14\x58\x84\xf2\x80\x3a\x1d" "\x8f\xe3\x50\x9b\x34\x93\x9a\x2d\xbd\x5c\x6e\x49\x78\xe7\x2c\x2f\xbf" "\x67\xc3\xd0\xb3\x42\x09\x12\xd9\x62\x9a\xf4\x19\xa4\xb4\xfd\x5e\xe4" "\x52\x42\xdc\x6e\x17\xf3\x91\xe4\x31\xa2\x9b\x0b\xfa\x31\xd3\xc0\x8e" "\x9d\x2f\xc8\x2a\x49\xb8\x2b\xe6\x31\xba\x77\x53\xcb\xed\xcd\xec", 390)); res = syz_open_procfs(0, 0x20000240); if (res != -1) r[0] = res; break; case 1: NONFAILING(*(uint64_t*)0x200023c0 = 0x200012c0); NONFAILING(*(uint64_t*)0x200023c8 = 0x1000); syscall(__NR_preadv, r[0], 0x200023c0, 1, 0); break; } } void execute_one() { execute(2); } int main() { syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0); for (procid = 0; procid < 4; procid++) { if (fork() == 0) { install_segv_handler(); for (;;) { loop(); } } } sleep(1000000); return 0; }