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 <ddk/driver.h>
7 #include <fcntl.h>
8 #include <lib/fdio/util.h>
9 #include <poll.h>
10 #include <signal.h>
11 #include <stdlib.h>
12 #include <sys/file.h>
13 #include <sys/ioctl.h>
14 #include <sys/socket.h>
15 #include <sys/stat.h>
16 #include <sys/time.h>
17 #include <sys/types.h>
18 #include <sys/uio.h>
19 #include <time.h>
20 #include <unistd.h>
21 #include <utime.h>
22 #include <zircon/process.h>
23 #include <zircon/syscalls.h>
24
25 #if SYZ_EXECUTOR || SYZ_HANDLE_SEGV
26 #include <pthread.h>
27 #include <setjmp.h>
28 #include <zircon/syscalls/debug.h>
29 #include <zircon/syscalls/exception.h>
30 #include <zircon/syscalls/object.h>
31 #include <zircon/syscalls/port.h>
32
33 static __thread int skip_segv;
34 static __thread jmp_buf segv_env;
35
segv_handler()36 static void segv_handler()
37 {
38 if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED)) {
39 debug("recover: skipping\n");
40 longjmp(segv_env, 1);
41 }
42 debug("recover: exiting\n");
43 doexit(SIGSEGV);
44 }
45
ex_handler(void * arg)46 static void* ex_handler(void* arg)
47 {
48 zx_handle_t port = (zx_handle_t)(long)arg;
49 for (int i = 0; i < 10000; i++) {
50 zx_port_packet_t packet = {};
51 zx_status_t status = zx_port_wait(port, ZX_TIME_INFINITE, &packet);
52 if (status != ZX_OK) {
53 debug("zx_port_wait failed: %d\n", status);
54 continue;
55 }
56 debug("got exception packet: type=%d status=%d tid=%llu\n",
57 packet.type, packet.status, (unsigned long long)(packet.exception.tid));
58 zx_handle_t thread;
59 status = zx_object_get_child(zx_process_self(), packet.exception.tid,
60 ZX_RIGHT_SAME_RIGHTS, &thread);
61 if (status != ZX_OK) {
62 debug("zx_object_get_child failed: %d\n", status);
63 continue;
64 }
65 zx_thread_state_general_regs_t regs;
66 status = zx_thread_read_state(thread, ZX_THREAD_STATE_GENERAL_REGS,
67 ®s, sizeof(regs));
68 if (status != ZX_OK) {
69 debug("zx_thread_read_state failed: %d (%d)\n",
70 (int)sizeof(regs), status);
71 } else {
72 #if GOARCH_amd64
73 regs.rip = (uint64)(void*)&segv_handler;
74 #elif GOARCH_arm64
75 regs.pc = (uint64)(void*)&segv_handler;
76 #else
77 #error "unsupported arch"
78 #endif
79 status = zx_thread_write_state(thread, ZX_THREAD_STATE_GENERAL_REGS, ®s, sizeof(regs));
80 if (status != ZX_OK) {
81 debug("zx_thread_write_state failed: %d\n", status);
82 }
83 }
84 status = zx_task_resume(thread, ZX_RESUME_EXCEPTION);
85 if (status != ZX_OK) {
86 debug("zx_task_resume failed: %d\n", status);
87 }
88 zx_handle_close(thread);
89 }
90 doexit(1);
91 return 0;
92 }
93
install_segv_handler()94 static void install_segv_handler()
95 {
96 zx_status_t status;
97 zx_handle_t port;
98 if ((status = zx_port_create(0, &port)) != ZX_OK)
99 fail("zx_port_create failed: %d", status);
100 if ((status = zx_task_bind_exception_port(zx_process_self(), port, 0, 0)) != ZX_OK)
101 fail("zx_task_bind_exception_port failed: %d", status);
102 pthread_t th;
103 if (pthread_create(&th, 0, ex_handler, (void*)(long)port))
104 fail("pthread_create failed");
105 }
106
107 #define NONFAILING(...) \
108 { \
109 __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \
110 if (sigsetjmp(segv_env, 0) == 0) { \
111 __VA_ARGS__; \
112 } \
113 __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \
114 }
115 #endif
116
117 #if SYZ_EXECUTOR || SYZ_THREADED
118 #include <unistd.h>
119
120 // Fuchsia's pthread_cond_timedwait just returns immidiately, so we use simple spin wait.
121 typedef struct {
122 int state;
123 } event_t;
124
event_init(event_t * ev)125 static void event_init(event_t* ev)
126 {
127 ev->state = 0;
128 }
129
event_reset(event_t * ev)130 static void event_reset(event_t* ev)
131 {
132 ev->state = 0;
133 }
134
event_set(event_t * ev)135 static void event_set(event_t* ev)
136 {
137 if (ev->state)
138 fail("event already set");
139 __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
140 }
141
event_wait(event_t * ev)142 static void event_wait(event_t* ev)
143 {
144 while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
145 usleep(200);
146 }
147
event_isset(event_t * ev)148 static int event_isset(event_t* ev)
149 {
150 return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
151 }
152
event_timedwait(event_t * ev,uint64 timeout_ms)153 static int event_timedwait(event_t* ev, uint64 timeout_ms)
154 {
155 uint64 start = current_time_ms();
156 for (;;) {
157 if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
158 return 1;
159 if (current_time_ms() - start > timeout_ms)
160 return 0;
161 usleep(200);
162 }
163 }
164 #endif
165
166 #if SYZ_EXECUTOR || __NR_syz_mmap
syz_mmap(size_t addr,size_t size)167 long syz_mmap(size_t addr, size_t size)
168 {
169 zx_handle_t root = zx_vmar_root_self();
170 zx_info_vmar_t info;
171 zx_status_t status = zx_object_get_info(root, ZX_INFO_VMAR, &info, sizeof(info), 0, 0);
172 if (status != ZX_OK)
173 fail("zx_object_get_info(ZX_INFO_VMAR) failed: %d", status);
174 zx_handle_t vmo;
175 status = zx_vmo_create(size, 0, &vmo);
176 if (status != ZX_OK)
177 return status;
178 uintptr_t mapped_addr;
179 status = zx_vmar_map(root, addr - info.base, vmo, 0, size,
180 ZX_VM_FLAG_SPECIFIC_OVERWRITE | ZX_VM_FLAG_PERM_READ |
181 ZX_VM_FLAG_PERM_WRITE | ZX_VM_FLAG_PERM_EXECUTE,
182 &mapped_addr);
183 return status;
184 }
185 #endif
186
187 #if SYZ_EXECUTOR || __NR_syz_process_self
syz_process_self()188 static long syz_process_self()
189 {
190 return zx_process_self();
191 }
192 #endif
193
194 #if SYZ_EXECUTOR || __NR_syz_thread_self
syz_thread_self()195 static long syz_thread_self()
196 {
197 return zx_thread_self();
198 }
199 #endif
200
201 #if SYZ_EXECUTOR || __NR_syz_vmar_root_self
syz_vmar_root_self()202 static long syz_vmar_root_self()
203 {
204 return zx_vmar_root_self();
205 }
206 #endif
207
208 #if SYZ_EXECUTOR || __NR_syz_job_default
syz_job_default()209 static long syz_job_default()
210 {
211 return zx_job_default();
212 }
213 #endif
214
215 #if SYZ_EXECUTOR || __NR_syz_future_time
syz_future_time(long when)216 static long syz_future_time(long when)
217 {
218 zx_time_t delta_ms;
219 switch (when) {
220 case 0:
221 delta_ms = 5;
222 case 1:
223 delta_ms = 30;
224 default:
225 delta_ms = 10000;
226 }
227 zx_time_t now = zx_clock_get(ZX_CLOCK_MONOTONIC);
228 return now + delta_ms * 1000 * 1000;
229 }
230 #endif
231
232 #if SYZ_EXECUTOR || SYZ_SANDBOX_NONE
233 static void loop();
do_sandbox_none(void)234 static int do_sandbox_none(void)
235 {
236 loop();
237 return 0;
238 }
239 #endif
240
241 #if SYZ_EXECUTOR
242 #define do_sandbox_setuid() 0
243 #define do_sandbox_namespace() 0
244 #endif
245