// https://syzkaller.appspot.com/bug?id=53599a7fc4882bf655e43ac53edfe43e7740baab // autogenerated by syzkaller (https://github.com/google/syzkaller) #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static __thread int skip_segv; static __thread jmp_buf segv_env; static void segv_handler(int sig, siginfo_t* info, void* ctx) { uintptr_t addr = (uintptr_t)info->si_addr; const uintptr_t prog_start = 1 << 20; const uintptr_t prog_end = 100 << 20; int skip = __atomic_load_n(&skip_segv, __ATOMIC_RELAXED) != 0; int valid = addr < prog_start || addr > prog_end; if (skip && valid) { _longjmp(segv_env, 1); } exit(sig); } static void install_segv_handler(void) { 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 void sleep_ms(uint64_t ms) { usleep(ms * 1000); } static uint64_t current_time_ms(void) { struct timespec ts; if (clock_gettime(CLOCK_MONOTONIC, &ts)) exit(1); return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000; } static void thread_start(void* (*fn)(void*), void* arg) { pthread_t th; pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setstacksize(&attr, 128 << 10); int i = 0; for (; i < 100; i++) { if (pthread_create(&th, &attr, fn, arg) == 0) { pthread_attr_destroy(&attr); return; } if (errno == EAGAIN) { usleep(50); continue; } break; } exit(1); } typedef struct { int state; } event_t; static void event_init(event_t* ev) { ev->state = 0; } static void event_reset(event_t* ev) { ev->state = 0; } static void event_set(event_t* ev) { if (ev->state) exit(1); __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE); syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1000000); } static void event_wait(event_t* ev) { while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE)) syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0); } static int event_isset(event_t* ev) { return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE); } static int event_timedwait(event_t* ev, uint64_t timeout) { uint64_t start = current_time_ms(); uint64_t now = start; for (;;) { uint64_t remain = timeout - (now - start); struct timespec ts; ts.tv_sec = remain / 1000; ts.tv_nsec = (remain % 1000) * 1000 * 1000; syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts); if (__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE)) return 1; now = current_time_ms(); if (now - start > timeout) return 0; } } static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2) { if (a0 == 0xc || a0 == 0xb) { char buf[128]; sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1, (uint8_t)a2); return open(buf, O_RDWR, 0); } else { char buf[1024]; char* hash; strncpy(buf, (char*)a0, sizeof(buf) - 1); buf[sizeof(buf) - 1] = 0; while ((hash = strchr(buf, '#'))) { *hash = '0' + (char)(a1 % 10); a1 /= 10; } return open(buf, a2, 0); } } struct thread_t { int created, call; event_t ready, done; }; 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 (;;) { event_wait(&th->ready); event_reset(&th->ready); execute_call(th->call); __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED); event_set(&th->done); } return 0; } static void loop(void) { int i, call, thread; int collide = 0; again: for (call = 0; call < 6; call++) { for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0])); thread++) { struct thread_t* th = &threads[thread]; if (!th->created) { th->created = 1; event_init(&th->ready); event_init(&th->done); event_set(&th->done); thread_start(thr, th); } if (!event_isset(&th->done)) continue; event_reset(&th->done); th->call = call; __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED); event_set(&th->ready); if (collide && (call % 2) == 0) break; event_timedwait(&th->done, 45); break; } } for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++) sleep_ms(1); if (!collide) { collide = 1; goto again; } } #ifndef __NR_memfd_create #define __NR_memfd_create 319 #endif uint64_t r[3] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff}; void execute_call(int call) { intptr_t res = 0; switch (call) { case 0: NONFAILING(memcpy((void*)0x20000200, "/dev/loop#\000", 11)); res = -1; NONFAILING(res = syz_open_dev(0x20000200, 0, 0)); if (res != -1) r[0] = res; break; case 1: NONFAILING(memcpy((void*)0x20000180, "\020\001\000t\t-\201E\2667\222^" "\324\201E\263-1\246)\231+/" "\337\200\000\000\000Hc\232g\217\243" "\256\016\255\215\314\000\000\000", 42)); res = syscall(__NR_memfd_create, 0x20000180ul, 0ul); if (res != -1) r[1] = res; break; case 2: NONFAILING(*(uint64_t*)0x200005c0 = 0x20000340); NONFAILING(memcpy( (void*)0x20000340, "\x8d\x57\xec\x69\xb7\x31\x33\x6d\x98\x82\x49\x8f\xea\x0c\x29\x85\x0e" "\xaf\xf2\x5b\x88\xf1\xc9\xec\x5e\x79\x7d\xa5\x6c\xcc\xad\x89\x73\x5e" "\xf0\xd5\xed\xdb\x92\x69\xc8\x8b\x2c\xaa\x3f\x93\x6c\x2e\xae\x27\xb1" "\x7f\xd2\xf6\xa6\xec\x5e\x12\xe5\x55\x86\x73\x89\x3f\x28\x66\xff\xf4" "\x5c\x4c\xdf\xef\x85\xf0\xec\xae\xd0\x10\x57\xab\x9f\x5f\x94\x6e\x3b" "\xe2\x62\x99\x5c\x39\x24\x42\x73\x93\x75\x50\xd8\x73\x0f\x4c\x5c\xaa" "\x42\x2e\xad\x8b\xeb\xda\x85\x48\x68\x2e\xa7\x9a\x3b\x4a\x45\x68\xc1" "\x99\x44\x30\x82\xf5\x4a\x54\xe0\x51\x50\xbd\x97\xfb\xee\xed\x93\x6f" "\x6d\x01\x7d\x64\xa2\x82\x13", 143)); NONFAILING(*(uint64_t*)0x200005c8 = 0x8f); NONFAILING(*(uint64_t*)0x200005d0 = 0x20000400); NONFAILING(memcpy( (void*)0x20000400, "\x3d\xb6\x18\x9e\xda\x17\x0a\x92\xfa\xb0\xb0\x95\x2f\x92\x2b\x1e\x28" "\xa1\x6d\xd7\xb5\xa0\xa2\x6c\xb9\x9e\x73\x6c\xd1\x75\x56\x8b\xe4\x55" "\x8c\xf1\xa6\xc0\x89\x99\x37\x25\x17\x97\x8a\x66\x40\xc7\x2e\xa6\xdc" "\x58\x98\x6d\x9e\x59\xe8\xa9\xba\xa2\xf3\x67\xfa\x35\x25\x20\x9d\xee" "\xc9\xba\x1f\xb3\x1b\x90\xf2\x3e\x5b\x5e\x11\x36\x8d\x23\x15\xd7\xd3" "\x8a\x25\x7b\x54\x6a\xfc\x7a\x33\x7c\x43\x23\xfd\x54\xa2\xf2\x7b\xa8" "\x6d\xcd\xc9\xa8\x24\x31\x57\xba\xc7\x48\x10\x60\xe9", 115)); NONFAILING(*(uint64_t*)0x200005d8 = 0x73); NONFAILING(*(uint64_t*)0x200005e0 = 0x200004c0); NONFAILING(memcpy( (void*)0x200004c0, "\x2c\x8c\xaa\x02\x36\x20\x82\xd4\x0c\xea\x43\xad\x87\xbd\xfe\xae\x15" "\x44\x43\x84\x66\x72\x7d\x60\xd1\x96\x31\xfe\xa3\x72\xfc\x6d\x5d\x1b" "\x66\xa8\x2d\x18\x01\xb7\x51\x40\x6c\xf8\xe7\x1f\x87\xd4\xc5\x42\x42" "\x9b\x3b\xcd\xef\x87\x0b\x6c\x5d\x23\x97\x71\x26\x3b\xdc\xfd\x1d\x81" "\x7b\x6c\x0e\xcd\xec\x2e\x95\xdc\x87\x72\xa6\x36\xb2\x33\x05\x96\xb7" "\xd2\x9b\xe8\x78\x91\x53\x17\x66\x2a\x58\x5c\xf1\xc7\x89\xc3\x29\x76" "\xd1\x11\x11\x41\x28\xe5\x58\xa5\x1f\xea\x8a\xb6\x76\xfd\x4a\xde\x12" "\x5a\x21\x78\x2c\xb7\x2b\x95\xf0\x38\xe2\x62\xb7\x3b\xe6\xdc\x70\x2c" "\x06\x42\x8d\xa9\xee\x2f\xba\x11\x44\xeb\xb2\x29\xe9\xa2\x6f\x0a\xef" "\x18\x82\xeb\xaa\x1e\x85\xe0\x0a\xf5\x28\xb7\x2f\xb2\x13\xa6\xb3\x72" "\x00\x01\x4f\xca\x96\x32\x94\x50\x2f\x5c\x8d\xdf\x72\x12\xd5\x30\xd4" "\xec\xc2\x43\x4b\x39\x41\x80", 194)); NONFAILING(*(uint64_t*)0x200005e8 = 0xc2); NONFAILING(*(uint64_t*)0x200005f0 = 0x20000700); NONFAILING(memcpy((void*)0x20000700, "\x9a\xd1\xc3\xb5\xef\x2e\xf3\xa5\x86\x72\x33\x69\x27\xf4" "\x65\x0f\x17\x47\x08\xe1\xd0\x0d\xc0\xee\xc5\x6c\x79\x25" "\x3d\x63\x83\x06\xab\xab\x81\x0d\x64\xed\xc9\xda\x7c\xb8" "\x61\x9b\xe3\xb0\x37\x0c\x3b\x3e\xd5\x90\x60\x31\x12\x08" "\xbe\x8a\x2d\x46", 60)); NONFAILING(*(uint64_t*)0x200005f8 = 0x3c); syscall(__NR_pwritev, r[1], 0x200005c0ul, 4ul, 0, 0); break; case 3: syscall(__NR_ioctl, r[0], 0x4c00, r[1]); break; case 4: NONFAILING(memcpy((void*)0x20000080, "/dev/loop#\000", 11)); res = -1; NONFAILING(res = syz_open_dev(0x20000080, 0, 0x1cd842)); if (res != -1) r[2] = res; break; case 5: syscall(__NR_mmap, 0x20000000ul, 0x600000ul, 0x3fbcbab16c80fabul, 0x11ul, r[2], 0ul); break; } } int main(void) { syscall(__NR_mmap, 0x1ffff000ul, 0x1000ul, 0ul, 0x32ul, -1, 0ul); syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 7ul, 0x32ul, -1, 0ul); syscall(__NR_mmap, 0x21000000ul, 0x1000ul, 0ul, 0x32ul, -1, 0ul); install_segv_handler(); loop(); return 0; }