// AUTOGENERATED FROM executor/common_fuchsia.h package csource var commonHeaderFuchsia = ` #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(SYZ_EXECUTOR) || defined(SYZ_THREADED) || defined(SYZ_COLLIDE) || defined(SYZ_HANDLE_SEGV) #include #include #endif #if defined(SYZ_EXECUTOR) || (defined(SYZ_REPEAT) && defined(SYZ_WAIT_REPEAT) && defined(SYZ_USE_TMP_DIR)) #include #endif #if defined(SYZ_EXECUTOR) || (defined(SYZ_REPEAT) && defined(SYZ_WAIT_REPEAT)) #include #include #include #include #include #endif #if defined(SYZ_EXECUTOR) || defined(SYZ_HANDLE_SEGV) #include #include #include #include #endif #if defined(SYZ_EXECUTOR) || (defined(SYZ_REPEAT) && defined(SYZ_WAIT_REPEAT)) || \ defined(SYZ_USE_TMP_DIR) || defined(SYZ_HANDLE_SEGV) || defined(SYZ_TUN_ENABLE) || \ defined(SYZ_SANDBOX_NAMESPACE) || defined(SYZ_SANDBOX_SETUID) || \ defined(SYZ_SANDBOX_NONE) || defined(SYZ_FAULT_INJECTION) || \ defined(__NR_syz_mmap) __attribute__((noreturn)) static void doexit(int status) { _exit(status); for (;;) { } } #endif #include #include #if defined(SYZ_EXECUTOR) || (defined(SYZ_REPEAT) && defined(SYZ_WAIT_REPEAT)) || \ defined(SYZ_USE_TMP_DIR) || defined(SYZ_TUN_ENABLE) || defined(SYZ_SANDBOX_NAMESPACE) || \ defined(SYZ_SANDBOX_NONE) || defined(SYZ_SANDBOX_SETUID) || defined(SYZ_FAULT_INJECTION) || \ defined(__NR_syz_kvm_setup_cpu) || defined(__NR_syz_init_net_socket) || \ defined(__NR_syz_mmap) #include #include #include #endif #if defined(SYZ_EXECUTOR) || defined(SYZ_USE_TMP_DIR) #include #include #endif #if defined(SYZ_EXECUTOR) || defined(SYZ_HANDLE_SEGV) #include #include #include #endif #if defined(SYZ_EXECUTOR) || defined(SYZ_DEBUG) #include #include #endif #if defined(SYZ_EXECUTOR) #define exit vsnprintf #define _exit vsnprintf typedef unsigned long long uint64; typedef unsigned int uint32; typedef unsigned short uint16; typedef unsigned char uint8; #ifdef SYZ_EXECUTOR const int kInPipeFd = 250; const int kOutPipeFd = 251; #endif #if defined(__GNUC__) #define SYSCALLAPI #define NORETURN __attribute__((noreturn)) #define ALIGNED(N) __attribute__((aligned(N))) #define PRINTF __attribute__((format(printf, 1, 2))) #else #define SYSCALLAPI WINAPI #define NORETURN __declspec(noreturn) #define ALIGNED(N) __declspec(align(N)) #define PRINTF #endif typedef long(SYSCALLAPI* syscall_t)(long, long, long, long, long, long, long, long, long); struct call_t { const char* name; int sys_nr; syscall_t call; }; #endif #if defined(SYZ_EXECUTOR) || (defined(SYZ_REPEAT) && defined(SYZ_WAIT_REPEAT)) || \ defined(SYZ_USE_TMP_DIR) || defined(SYZ_TUN_ENABLE) || defined(SYZ_SANDBOX_NAMESPACE) || \ defined(SYZ_SANDBOX_NONE) || defined(SYZ_SANDBOX_SETUID) || defined(SYZ_FAULT_INJECTION) || \ defined(__NR_syz_kvm_setup_cpu) || defined(__NR_syz_mmap) const int kFailStatus = 67; const int kRetryStatus = 69; #endif #if defined(SYZ_EXECUTOR) const int kErrorStatus = 68; #endif #if defined(SYZ_EXECUTOR) || (defined(SYZ_REPEAT) && defined(SYZ_WAIT_REPEAT)) || \ defined(SYZ_USE_TMP_DIR) || defined(SYZ_TUN_ENABLE) || defined(SYZ_SANDBOX_NAMESPACE) || \ defined(SYZ_SANDBOX_NONE) || defined(SYZ_SANDBOX_SETUID) || defined(__NR_syz_kvm_setup_cpu) || \ defined(__NR_syz_init_net_socket) && \ (defined(SYZ_SANDBOX_NONE) || defined(SYZ_SANDBOX_SETUID) || defined(SYZ_SANDBOX_NAMESPACE)) || \ defined(__NR_syz_mmap) NORETURN PRINTF 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); } #endif #if defined(SYZ_EXECUTOR) NORETURN PRINTF static void error(const char* msg, ...) { va_list args; va_start(args, msg); vfprintf(stderr, msg, args); va_end(args); fprintf(stderr, "\n"); doexit(kErrorStatus); } #endif #if defined(SYZ_EXECUTOR) || (defined(SYZ_REPEAT) && defined(SYZ_WAIT_REPEAT) && defined(SYZ_USE_TMP_DIR)) || defined(SYZ_FAULT_INJECTION) NORETURN PRINTF static void exitf(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(kRetryStatus); } #endif #if defined(SYZ_EXECUTOR) || defined(SYZ_DEBUG) static int flag_debug; PRINTF static void debug(const char* msg, ...) { if (!flag_debug) return; va_list args; va_start(args, msg); vfprintf(stderr, msg, args); va_end(args); fflush(stderr); } #endif #if defined(SYZ_EXECUTOR) || defined(SYZ_USE_BITMASKS) #define BITMASK_LEN(type, bf_len) (type)((1ull << (bf_len)) - 1) #define BITMASK_LEN_OFF(type, bf_off, bf_len) (type)(BITMASK_LEN(type, (bf_len)) << (bf_off)) #define STORE_BY_BITMASK(type, addr, val, bf_off, bf_len) \ if ((bf_off) == 0 && (bf_len) == 0) { \ *(type*)(addr) = (type)(val); \ } else { \ type new_val = *(type*)(addr); \ new_val &= ~BITMASK_LEN_OFF(type, (bf_off), (bf_len)); \ new_val |= ((type)(val)&BITMASK_LEN(type, (bf_len))) << (bf_off); \ *(type*)(addr) = new_val; \ } #endif #if defined(SYZ_EXECUTOR) || defined(SYZ_USE_CHECKSUMS) struct csum_inet { uint32 acc; }; static void csum_inet_init(struct csum_inet* csum) { csum->acc = 0; } static void csum_inet_update(struct csum_inet* csum, const uint8* data, size_t length) { if (length == 0) return; size_t i; for (i = 0; i < length - 1; i += 2) csum->acc += *(uint16*)&data[i]; if (length & 1) csum->acc += (uint16)data[length - 1]; while (csum->acc > 0xffff) csum->acc = (csum->acc & 0xffff) + (csum->acc >> 16); } static uint16 csum_inet_digest(struct csum_inet* csum) { return ~csum->acc; } #endif #if defined(SYZ_EXECUTOR) || defined(SYZ_HANDLE_SEGV) static __thread int skip_segv; static __thread jmp_buf segv_env; static void segv_handler() { if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED)) { debug("recover: skipping\n"); longjmp(segv_env, 1); } debug("recover: exiting\n"); doexit(SIGSEGV); } static void* ex_handler(void* arg) { zx_handle_t port = (zx_handle_t)(long)arg; for (int i = 0; i < 10000; i++) { zx_port_packet_t packet = {}; zx_status_t status = zx_port_wait(port, ZX_TIME_INFINITE, &packet); if (status != ZX_OK) { debug("zx_port_wait failed: %d\n", status); continue; } debug("got exception packet: type=%d status=%d tid=%llu\n", packet.type, packet.status, (unsigned long long)(packet.exception.tid)); zx_handle_t thread; status = zx_object_get_child(zx_process_self(), packet.exception.tid, ZX_RIGHT_SAME_RIGHTS, &thread); if (status != ZX_OK) { debug("zx_object_get_child failed: %d\n", status); continue; } zx_thread_state_general_regs_t regs; status = zx_thread_read_state(thread, ZX_THREAD_STATE_GENERAL_REGS, ®s, sizeof(regs)); if (status != ZX_OK) { debug("zx_thread_read_state failed: %d (%d)\n", (int)sizeof(regs), status); } else { #if defined(__x86_64__) regs.rip = (uint64)(void*)&segv_handler; #elif defined(__aarch64__) regs.pc = (uint64)(void*)&segv_handler; #else #error "unsupported arch" #endif status = zx_thread_write_state(thread, ZX_THREAD_STATE_GENERAL_REGS, ®s, sizeof(regs)); if (status != ZX_OK) { debug("zx_thread_write_state failed: %d\n", status); } } status = zx_task_resume(thread, ZX_RESUME_EXCEPTION); if (status != ZX_OK) { debug("zx_task_resume failed: %d\n", status); } zx_handle_close(thread); } doexit(1); return 0; } static void install_segv_handler() { zx_status_t status; zx_handle_t port; if ((status = zx_port_create(0, &port)) != ZX_OK) fail("zx_port_create failed: %d", status); if ((status = zx_task_bind_exception_port(zx_process_self(), port, 0, 0)) != ZX_OK) fail("zx_task_bind_exception_port failed: %d", status); pthread_t th; if (pthread_create(&th, 0, ex_handler, (void*)(long)port)) fail("pthread_create failed"); } #define NONFAILING(...) \ { \ __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \ if (sigsetjmp(segv_env, 0) == 0) { \ __VA_ARGS__; \ } \ __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \ } #endif #if defined(SYZ_EXECUTOR) || (defined(SYZ_REPEAT) && defined(SYZ_WAIT_REPEAT)) static uint64 current_time_ms() { struct timespec ts; if (clock_gettime(CLOCK_MONOTONIC, &ts)) fail("clock_gettime failed"); return (uint64)ts.tv_sec * 1000 + (uint64)ts.tv_nsec / 1000000; } #endif #if defined(SYZ_EXECUTOR) static void sleep_ms(uint64 ms) { usleep(ms * 1000); } #endif #if defined(SYZ_EXECUTOR) || defined(SYZ_FAULT_INJECTION) static int inject_fault(int nth) { return 0; } static int fault_injected(int fail_fd) { return 0; } #endif #if defined(SYZ_EXECUTOR) || defined(__NR_syz_mmap) long syz_mmap(size_t addr, size_t size) { zx_handle_t root = zx_vmar_root_self(); zx_info_vmar_t info; zx_status_t status = zx_object_get_info(root, ZX_INFO_VMAR, &info, sizeof(info), 0, 0); if (status != ZX_OK) fail("zx_object_get_info(ZX_INFO_VMAR) failed: %d", status); zx_handle_t vmo; status = zx_vmo_create(size, 0, &vmo); if (status != ZX_OK) return status; uintptr_t mapped_addr; status = zx_vmar_map(root, addr - info.base, vmo, 0, size, ZX_VM_FLAG_SPECIFIC_OVERWRITE | ZX_VM_FLAG_PERM_READ | ZX_VM_FLAG_PERM_WRITE | ZX_VM_FLAG_PERM_EXECUTE, &mapped_addr); return status; } #endif #if defined(SYZ_EXECUTOR) || defined(__NR_syz_process_self) long syz_process_self() { return zx_process_self(); } #endif #if defined(SYZ_EXECUTOR) || defined(__NR_syz_thread_self) long syz_thread_self() { return zx_thread_self(); } #endif #if defined(SYZ_EXECUTOR) || defined(__NR_syz_vmar_root_self) long syz_vmar_root_self() { return zx_vmar_root_self(); } #endif #if defined(SYZ_EXECUTOR) || defined(__NR_syz_job_default) long syz_job_default() { return zx_job_default(); } #endif #if defined(SYZ_EXECUTOR) || defined(__NR_syz_future_time) long syz_future_time(long when) { zx_time_t delta_ms; switch (when) { case 0: delta_ms = 5; case 1: delta_ms = 30; default: delta_ms = 10000; } zx_time_t now = zx_clock_get(ZX_CLOCK_MONOTONIC); return now + delta_ms * 1000 * 1000; } #endif #if defined(SYZ_SANDBOX_NONE) static void loop(); static int do_sandbox_none(void) { loop(); return 0; } #endif #if defined(SYZ_USE_TMP_DIR) static void use_temporary_dir() { char tmpdir_template[] = "./syzkaller.XXXXXX"; char* tmpdir = mkdtemp(tmpdir_template); if (!tmpdir) fail("failed to mkdtemp"); if (chmod(tmpdir, 0777)) fail("failed to chmod"); if (chdir(tmpdir)) fail("failed to chdir"); } #endif #if defined(SYZ_REPEAT) && defined(SYZ_WAIT_REPEAT) && defined(SYZ_USE_TMP_DIR) static void remove_dir(const char* dir) { struct dirent* ep; DIR* dp = opendir(dir); if (dp == NULL) exitf("opendir(%s) failed", dir); while ((ep = readdir(dp))) { if (strcmp(ep->d_name, ".") == 0 || strcmp(ep->d_name, "..") == 0) continue; char filename[FILENAME_MAX]; snprintf(filename, sizeof(filename), "%s/%s", dir, ep->d_name); struct stat st; if (lstat(filename, &st)) exitf("lstat(%s) failed", filename); if (S_ISDIR(st.st_mode)) { remove_dir(filename); continue; } if (unlink(filename)) exitf("unlink(%s) failed", filename); } closedir(dp); if (rmdir(dir)) exitf("rmdir(%s) failed", dir); } #endif #if defined(SYZ_EXECUTOR) || defined(SYZ_REPEAT) static void execute_one(); extern unsigned long long procid; #if defined(SYZ_EXECUTOR) void reply_handshake(); void receive_execute(); void reply_execute(int status); extern uint32* output_data; extern uint32* output_pos; #endif #if defined(SYZ_WAIT_REPEAT) static void loop() { #if defined(SYZ_EXECUTOR) reply_handshake(); #endif int iter; for (iter = 0;; iter++) { #if defined(SYZ_EXECUTOR) || defined(SYZ_USE_TMP_DIR) char cwdbuf[32]; sprintf(cwdbuf, "./%d", iter); if (mkdir(cwdbuf, 0777)) fail("failed to mkdir"); #endif #if defined(SYZ_EXECUTOR) receive_execute(); #endif int pid = fork(); if (pid < 0) fail("clone failed"); if (pid == 0) { #if defined(SYZ_EXECUTOR) || defined(SYZ_USE_TMP_DIR) if (chdir(cwdbuf)) fail("failed to chdir"); #endif #if defined(SYZ_EXECUTOR) close(kInPipeFd); close(kOutPipeFd); #endif #if defined(SYZ_EXECUTOR) output_pos = output_data; #endif execute_one(); debug("worker exiting\n"); doexit(0); } debug("spawned worker pid %d\n", pid); int status = 0; uint64 start = current_time_ms(); #if defined(SYZ_EXECUTOR) uint64 last_executed = start; uint32 executed_calls = __atomic_load_n(output_data, __ATOMIC_RELAXED); #endif for (;;) { int res = waitpid(-1, &status, WNOHANG); if (res == pid) { debug("waitpid(%d)=%d\n", pid, res); break; } usleep(1000); #if defined(SYZ_EXECUTOR) uint64 now = current_time_ms(); uint32 now_executed = __atomic_load_n(output_data, __ATOMIC_RELAXED); if (executed_calls != now_executed) { executed_calls = now_executed; last_executed = now; } if ((now - start < 3 * 1000) && (now - start < 1000 || now - last_executed < 500)) continue; #else if (current_time_ms() - start < 3 * 1000) continue; #endif debug("waitpid(%d)=%d\n", pid, res); debug("killing\n"); kill(-pid, SIGKILL); kill(pid, SIGKILL); while (waitpid(-1, &status, 0) != pid) { } break; } #if defined(SYZ_EXECUTOR) status = WEXITSTATUS(status); if (status == kFailStatus) fail("child failed"); if (status == kErrorStatus) error("child errored"); reply_execute(0); #endif #if defined(SYZ_EXECUTOR) || defined(SYZ_USE_TMP_DIR) remove_dir(cwdbuf); #endif } } #else void loop() { while (1) { execute_one(); } } #endif #endif #if defined(SYZ_THREADED) 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; #if defined(SYZ_COLLIDE) static int collide; #endif static void* thr(void* arg) { struct thread_t* th = (struct thread_t*)arg; for (;;) { while (!__atomic_load_n(&th->running, __ATOMIC_ACQUIRE)) usleep(200); execute_call(th->call); __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED); __atomic_store_n(&th->running, 0, __ATOMIC_RELEASE); } return 0; } static void execute(int num_calls) { int i, 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); #if defined(SYZ_COLLIDE) if (collide && call % 2) break; #endif for (i = 0; i < 100; i++) { if (!__atomic_load_n(&th->running, __ATOMIC_ACQUIRE)) break; usleep(200); } if (__atomic_load_n(&running, __ATOMIC_RELAXED)) usleep((call == num_calls - 1) ? 10000 : 1000); break; } } } } #endif `