// https://syzkaller.appspot.com/bug?id=0041bf1423916e9ae458b08b760e269a33c14960 // autogenerated by syzkaller (https://github.com/google/syzkaller) #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include 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); if (pthread_create(&th, &attr, fn, arg)) exit(1); pthread_attr_destroy(&attr); } 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); } 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_RELAXED)) return 1; now = current_time_ms(); if (now - start > timeout) return 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; for (call = 0; call < 4; 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); event_timedwait(&th->done, 45); break; } } for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++) sleep_ms(1); } uint64_t r[1] = {0xffffffffffffffff}; void execute_call(int call) { long res; switch (call) { case 0: memcpy((void*)0x20000040, "/dev/rtc0", 10); res = syscall(__NR_openat, 0xffffffffffffff9c, 0x20000040, 0, 0); if (res != -1) r[0] = res; break; case 1: syscall(__NR_ioctl, r[0], 0x7003); break; case 2: *(uint32_t*)0x20000000 = 0; *(uint32_t*)0x20000004 = 0; *(uint32_t*)0x20000008 = 0; *(uint32_t*)0x2000000c = 0x1f; *(uint32_t*)0x20000010 = 0; *(uint32_t*)0x20000014 = 0xa0; *(uint32_t*)0x20000018 = 0; *(uint32_t*)0x2000001c = 0; *(uint32_t*)0x20000020 = 0; syscall(__NR_ioctl, r[0], 0x4024700a, 0x20000000); break; case 3: memcpy((void*)0x200000c0, "\x2a\xf4\x9e\xe8\x10\xa9\xdb\x8a\xd3\x10\x2f\x61\x86\xaa\x74\x0f" "\xf0\x9a\x70\x78\x21\x19\xad\xe7\xa3\xb6\x79\x3d\x91\xaf\xcd\x26" "\xe6\x3f\xeb\x21\xf7\x60\xbf\xe8\x45\x3a\x86\xc5\xfb\xc7\xcb\x66" "\x39\x41\x6e\x63\x70\xa4\x71\x34\xee\xef\xbe\x23\xbe\x3a\x8d\xf8" "\x0b\xcf\x38\xe3\x1d\xb8\x51\x73\x54\x80\xfa\x50\xb1\x99\xdb\x1e" "\xa6\xf1\x7a\x36\x1e\xbb\x5e\xfd\x4b\xaf\x08\x31\x07\xcf\x22\xc7" "\xb9\xc2\xa0\x9d\xb8\x3f\x6c\xa2\xb1\xdb\x67\x5e\xf4\xe2\xf9\x90" "\x83\x75\x63\xb6\xeb\x49\xb7\xc7\xa7\x50\x3a\x0a\xff\x9f\xda\xc4" "\x8e\x96\xd9\x30\xfe\x55\xb5\x95\x83\x94\xb4\x92\x8b\x14\x3c\xb7" "\x34\xc1\xbf\x7e\x63\x9b\x25\x74\x64\x5d\xd1\xf9\x06\x75\x21\xec" "\x70\xde\x55\xb1\xbc\x07\xe0\xd9\x7c\x0c\x49\xc3\x19\x74\x0d\xa6" "\xb9\xc6\xd7\xe9\x19\x85\x38\x97\x24\x4d\x6e\x2c\x99\x5f\x57\xe1" "\xb4\xa4\xd2\x69\x93\xcd\x58\x6f\x1a\x89\xeb\x9e\x0b\x14\x47\x01" "\x83\x51\xbc\x3c\xe1\x9e\x95\x43\x80\x62\xb3\x0a\x76\x3b\x94\x1e" "\x7b\x8d\xbd\x3f\x9f\x90\xf1\x12\x8b\xf7\xb8\xa9\x3d\x32\x2e\xac" "\xe1\xa9\xb4\xb8\x55\x07\x26\x47\x6a\x08\xa3\xbc\xb6\x7f\x07\x8b", 256); syscall(__NR_ioctl, r[0], 0x41009432, 0x200000c0); break; } } int main(void) { syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0); loop(); return 0; }