github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/executor/common_fuchsia.h (about) 1 // Copyright 2017 syzkaller project authors. All rights reserved. 2 // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. 3 4 // This file is shared between executor and csource package. 5 6 #include <fcntl.h> 7 #include <lib/fdio/directory.h> 8 #include <poll.h> 9 #include <signal.h> 10 #include <stdlib.h> 11 #include <sys/file.h> 12 #include <sys/ioctl.h> 13 #include <sys/socket.h> 14 #include <sys/stat.h> 15 #include <sys/time.h> 16 #include <sys/types.h> 17 #include <sys/uio.h> 18 #include <time.h> 19 #include <unistd.h> 20 #include <utime.h> 21 #include <zircon/process.h> 22 #include <zircon/status.h> 23 #include <zircon/syscalls.h> 24 25 #if SYZ_EXECUTOR || __NR_get_root_resource 26 #include <lib/ddk/driver.h> 27 #endif 28 29 #if SYZ_EXECUTOR || SYZ_HANDLE_SEGV 30 #include <pthread.h> 31 #include <setjmp.h> 32 #include <zircon/syscalls/debug.h> 33 #include <zircon/syscalls/exception.h> 34 #include <zircon/syscalls/object.h> 35 36 static __thread int skip_segv; 37 static __thread jmp_buf segv_env; 38 39 static void segv_handler(void) 40 { 41 if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED)) { 42 debug("recover: skipping\n"); 43 longjmp(segv_env, 1); 44 } 45 debug("recover: exiting\n"); 46 doexit(SIGSEGV); 47 } 48 49 static zx_status_t update_exception_thread_regs(zx_handle_t exception) 50 { 51 zx_handle_t thread; 52 zx_status_t status = zx_exception_get_thread(exception, &thread); 53 if (status != ZX_OK) { 54 debug("zx_exception_get_thread failed: %s (%d)\n", zx_status_get_string(status), status); 55 return status; 56 } 57 58 zx_thread_state_general_regs_t regs; 59 status = zx_thread_read_state(thread, ZX_THREAD_STATE_GENERAL_REGS, 60 ®s, sizeof(regs)); 61 if (status != ZX_OK) { 62 debug("zx_thread_read_state failed: %d %s (%d)\n", 63 (int)sizeof(regs), zx_status_get_string(status), status); 64 } else { 65 #if GOARCH_amd64 66 regs.rip = (uint64)(void*)&segv_handler; 67 #elif GOARCH_arm64 68 regs.pc = (uint64)(void*)&segv_handler; 69 #else 70 #error "unsupported arch" 71 #endif 72 status = zx_thread_write_state(thread, ZX_THREAD_STATE_GENERAL_REGS, ®s, sizeof(regs)); 73 if (status != ZX_OK) { 74 debug("zx_thread_write_state failed: %s (%d)\n", zx_status_get_string(status), status); 75 } 76 } 77 78 zx_handle_close(thread); 79 return status; 80 } 81 82 static void* ex_handler(void* arg) 83 { 84 zx_handle_t exception_channel = (zx_handle_t)(long)arg; 85 for (int i = 0; i < 10000; i++) { 86 zx_status_t status = zx_object_wait_one(exception_channel, ZX_CHANNEL_READABLE, ZX_TIME_INFINITE, NULL); 87 if (status != ZX_OK) { 88 debug("zx_object_wait_one failed: %s (%d)\n", zx_status_get_string(status), status); 89 continue; 90 } 91 92 zx_exception_info_t info; 93 zx_handle_t exception; 94 status = zx_channel_read(exception_channel, 0, &info, &exception, sizeof(info), 1, NULL, NULL); 95 if (status != ZX_OK) { 96 debug("zx_channel_read failed: %s (%d)\n", zx_status_get_string(status), status); 97 continue; 98 } 99 100 debug("got exception: type=%d tid=%llu\n", info.type, (unsigned long long)(info.tid)); 101 status = update_exception_thread_regs(exception); 102 if (status != ZX_OK) { 103 debug("failed to update exception thread registers: %s (%d)\n", zx_status_get_string(status), status); 104 } 105 106 uint32 state = ZX_EXCEPTION_STATE_HANDLED; 107 status = zx_object_set_property(exception, ZX_PROP_EXCEPTION_STATE, &state, sizeof(state)); 108 if (status != ZX_OK) { 109 debug("zx_object_set_property(ZX_PROP_EXCEPTION_STATE) failed: %s (%d)\n", zx_status_get_string(status), status); 110 } 111 zx_handle_close(exception); 112 } 113 doexit(1); 114 return 0; 115 } 116 117 static void install_segv_handler(void) 118 { 119 zx_status_t status; 120 zx_handle_t exception_channel; 121 if ((status = zx_task_create_exception_channel(zx_process_self(), 0, &exception_channel)) != ZX_OK) 122 failmsg("zx_task_create_exception_channel failed", 123 "status=%s (%d)", zx_status_get_string(status), status); 124 pthread_t th; 125 if (pthread_create(&th, 0, ex_handler, (void*)(long)exception_channel)) 126 fail("pthread_create failed"); 127 } 128 129 #define NONFAILING(...) \ 130 ({ \ 131 int ok = 1; \ 132 __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \ 133 if (sigsetjmp(segv_env, 0) == 0) { \ 134 __VA_ARGS__; \ 135 } else \ 136 ok = 0; \ 137 __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \ 138 ok; \ 139 }) 140 #endif 141 142 #if SYZ_EXECUTOR || SYZ_THREADED 143 #include <unistd.h> 144 145 // Fuchsia's pthread_cond_timedwait just returns immidiately, so we use simple spin wait. 146 typedef struct { 147 int state; 148 } event_t; 149 150 static void event_init(event_t* ev) 151 { 152 ev->state = 0; 153 } 154 155 static void event_reset(event_t* ev) 156 { 157 ev->state = 0; 158 } 159 160 static void event_set(event_t* ev) 161 { 162 if (ev->state) 163 exitf("event already set"); 164 __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE); 165 } 166 167 static void event_wait(event_t* ev) 168 { 169 while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE)) 170 usleep(200); 171 } 172 173 static int event_isset(event_t* ev) 174 { 175 return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE); 176 } 177 178 static int event_timedwait(event_t* ev, uint64 timeout_ms) 179 { 180 uint64 start = current_time_ms(); 181 for (;;) { 182 if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED)) 183 return 1; 184 if (current_time_ms() - start > timeout_ms) 185 return 0; 186 usleep(200); 187 } 188 } 189 #endif 190 191 #if SYZ_EXECUTOR || __NR_syz_mmap 192 long syz_mmap(size_t addr, size_t size) 193 { 194 zx_handle_t root = zx_vmar_root_self(); 195 zx_info_vmar_t info; 196 zx_status_t status = zx_object_get_info(root, ZX_INFO_VMAR, &info, sizeof(info), 0, 0); 197 if (status != ZX_OK) { 198 debug("zx_object_get_info(ZX_INFO_VMAR) failed: %s (%d)", zx_status_get_string(status), status); 199 return status; 200 } 201 zx_handle_t vmo; 202 status = zx_vmo_create(size, 0, &vmo); 203 if (status != ZX_OK) { 204 debug("zx_vmo_create failed: %s (%d)\n", zx_status_get_string(status), status); 205 return status; 206 } 207 208 uintptr_t mapped_addr; 209 status = zx_vmar_map(root, ZX_VM_FLAG_SPECIFIC_OVERWRITE | ZX_VM_FLAG_PERM_READ | ZX_VM_FLAG_PERM_WRITE, 210 addr - info.base, vmo, 0, size, 211 &mapped_addr); 212 213 zx_status_t close_vmo_status = zx_handle_close(vmo); 214 if (close_vmo_status != ZX_OK) { 215 debug("zx_handle_close(vmo) failed with: %s (%d)\n", zx_status_get_string(close_vmo_status), close_vmo_status); 216 } 217 return status; 218 } 219 #endif 220 221 #if SYZ_EXECUTOR || __NR_syz_process_self 222 static long syz_process_self(void) 223 { 224 return zx_process_self(); 225 } 226 #endif 227 228 #if SYZ_EXECUTOR || __NR_syz_thread_self 229 static long syz_thread_self(void) 230 { 231 return zx_thread_self(); 232 } 233 #endif 234 235 #if SYZ_EXECUTOR || __NR_syz_vmar_root_self 236 static long syz_vmar_root_self(void) 237 { 238 return zx_vmar_root_self(); 239 } 240 #endif 241 242 #if SYZ_EXECUTOR || __NR_syz_job_default 243 static long syz_job_default(void) 244 { 245 return zx_job_default(); 246 } 247 #endif 248 249 #if SYZ_EXECUTOR || __NR_syz_future_time 250 static long syz_future_time(volatile long when) 251 { 252 zx_time_t delta_ms = 10000; 253 switch (when) { 254 case 0: 255 delta_ms = 5; 256 break; 257 case 1: 258 delta_ms = 30; 259 break; 260 } 261 zx_time_t now = 0; 262 zx_clock_read(ZX_CLOCK_MONOTONIC, &now); 263 return now + delta_ms * 1000 * 1000; 264 } 265 #endif 266 267 #if SYZ_EXECUTOR || SYZ_SANDBOX_NONE 268 static void loop(); 269 static int do_sandbox_none(void) 270 { 271 loop(); 272 return 0; 273 } 274 #endif 275 276 // Ugly way to work around gcc's "error: function called through a non-compatible type". 277 // The macro is used in generated C code. 278 #define CAST(f) ({void* p = (void*)f; p; })